This is an automated email from the ASF dual-hosted git repository.

tomsun28 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git


The following commit(s) were added to refs/heads/master by this push:
     new 0a38a73756 [improve] form-urlencode SQL request body in 
GreptimeSqlQueryExecutor (#4223)
0a38a73756 is described below

commit 0a38a7375621220d2f9dec9b713f9edebd6ac4df
Author: Duansg <[email protected]>
AuthorDate: Tue Jul 21 23:19:43 2026 +0800

    [improve] form-urlencode SQL request body in GreptimeSqlQueryExecutor 
(#4223)
    
    Co-authored-by: Tomsun28 <[email protected]>
---
 .../warehouse/db/GreptimeSqlQueryExecutor.java     |  4 ++-
 .../warehouse/db/GreptimeSqlQueryExecutorTest.java | 36 ++++++++++++++++++++++
 2 files changed, 39 insertions(+), 1 deletion(-)

diff --git 
a/hertzbeat-warehouse/src/main/java/org/apache/hertzbeat/warehouse/db/GreptimeSqlQueryExecutor.java
 
b/hertzbeat-warehouse/src/main/java/org/apache/hertzbeat/warehouse/db/GreptimeSqlQueryExecutor.java
index 0afcc8fe20..bfac687599 100644
--- 
a/hertzbeat-warehouse/src/main/java/org/apache/hertzbeat/warehouse/db/GreptimeSqlQueryExecutor.java
+++ 
b/hertzbeat-warehouse/src/main/java/org/apache/hertzbeat/warehouse/db/GreptimeSqlQueryExecutor.java
@@ -38,6 +38,8 @@ import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
 import org.springframework.web.client.RestTemplate;
 
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -79,7 +81,7 @@ public class GreptimeSqlQueryExecutor extends 
SqlQueryExecutor {
             headers.add(HttpHeaders.AUTHORIZATION, NetworkConstants.BASIC + 
SignConstants.BLANK + encodedAuth);
         }
 
-        String requestBody = "sql=" + queryString;
+        String requestBody = "sql=" + URLEncoder.encode(queryString, 
StandardCharsets.UTF_8);
         HttpEntity<String> httpEntity = new HttpEntity<>(requestBody, headers);
 
         String url = greptimeProperties.httpEndpoint() + QUERY_PATH;
diff --git 
a/hertzbeat-warehouse/src/test/java/org/apache/hertzbeat/warehouse/db/GreptimeSqlQueryExecutorTest.java
 
b/hertzbeat-warehouse/src/test/java/org/apache/hertzbeat/warehouse/db/GreptimeSqlQueryExecutorTest.java
index 1445ed5f0c..ea927bd403 100644
--- 
a/hertzbeat-warehouse/src/test/java/org/apache/hertzbeat/warehouse/db/GreptimeSqlQueryExecutorTest.java
+++ 
b/hertzbeat-warehouse/src/test/java/org/apache/hertzbeat/warehouse/db/GreptimeSqlQueryExecutorTest.java
@@ -20,12 +20,16 @@
 package org.apache.hertzbeat.warehouse.db;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -34,6 +38,7 @@ import 
org.apache.hertzbeat.warehouse.store.history.tsdb.greptime.GreptimeSqlQue
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.junit.jupiter.MockitoExtension;
 import org.springframework.http.HttpEntity;
@@ -90,6 +95,37 @@ class GreptimeSqlQueryExecutorTest {
         assertEquals(85.5, result.get(0).get("value"));
     }
 
+    @Test
+    @SuppressWarnings("unchecked")
+    void testRequestBodyIsFormEncoded() {
+        when(restTemplate.exchange(
+            any(String.class),
+            eq(HttpMethod.POST),
+            any(HttpEntity.class),
+            eq(GreptimeSqlQueryContent.class)
+        )).thenReturn(new ResponseEntity<>(new GreptimeSqlQueryContent(), 
HttpStatus.OK));
+
+        // SQL carrying form-urlencoded metacharacters that would pollute the 
request body
+        // if concatenated raw: '&' would start a second sql= parameter and 
override the query.
+        String sql = "SELECT * FROM t WHERE name = 'x&sql=DROP TABLE t'";
+        greptimeSqlQueryExecutor.execute(sql);
+
+        ArgumentCaptor<HttpEntity<String>> captor = 
ArgumentCaptor.forClass(HttpEntity.class);
+        verify(restTemplate).exchange(
+            any(String.class),
+            eq(HttpMethod.POST),
+            captor.capture(),
+            eq(GreptimeSqlQueryContent.class));
+
+        String body = captor.getValue().getBody();
+        assertNotNull(body);
+        // The body must be a single sql= parameter; the '&' inside the SQL 
must be encoded.
+        String encodedValue = body.substring("sql=".length());
+        assertFalse(encodedValue.contains("&"), "raw '&' in body causes HTTP 
parameter pollution");
+        // Decoding the value must yield exactly the original SQL, lossless 
round-trip.
+        assertEquals(sql, URLDecoder.decode(encodedValue, 
StandardCharsets.UTF_8));
+    }
+
     @Test
     void testExecuteError() {
         // Mock error response


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to