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

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


The following commit(s) were added to refs/heads/master by this push:
     new aed8ecd889a [fix](be) Redact HTTP query details from request 
diagnostics (#69506)
aed8ecd889a is described below

commit aed8ecd889a1885944954e887e4b282a0660396b
Author: Jerry Hu <[email protected]>
AuthorDate: Mon Oct 26 18:40:43 2026 +0800

    [fix](be) Redact HTTP query details from request diagnostics (#69506)
    
    ### What problem does this PR solve?
    
    Issue Number: None
    
    Related PR: None
    
    Problem Summary: `HttpRequest::debug_string()` rendered the full request
    URI and every parsed parameter key and value, so query credentials could
    appear in BE diagnostics. The query-parse failure warning also included
    the raw query. Render the parsed path and parameter count instead, and
    omit query text from that warning. Request parsing and URI/parameter
    accessors retain their existing behavior. This change is limited to
    these logging paths; action-specific HTTP logs are unchanged.
    
    ### Release note
    
    BE `HttpRequest::debug_string()` no longer emits query strings or
    parameter keys and values. Query-parse failure warnings no longer emit
    the raw query.
    
    ### Check List (For Author)
    
    - Test:
    - Unit Test: `HttpRequestTest.*` passed (9/9). The unmodified full BE UT
    build was blocked by a pre-existing compile error in an unrelated test
    translation unit; the focused suite was run with that unit temporarily
    excluded from the UT build.
        - Build: `BUILD_TYPE=ASAN ./build.sh --be` passed.
    - Static and format checks: BE build hygiene, clang-format,
    check-format, and changed-line clang-tidy passed.
    - Regression test: Not run; this changes BE diagnostic log text, not SQL
    or HTTP responses.
    - Behavior changed: Yes (diagnostic log text only).
    - Does this need documentation: No.
---
 be/src/service/http/http_request.cpp       |  9 ++--
 be/test/service/http/http_request_test.cpp | 77 ++++++++++++++++++++++++++++++
 2 files changed, 80 insertions(+), 6 deletions(-)

diff --git a/be/src/service/http/http_request.cpp 
b/be/src/service/http/http_request.cpp
index e511ff577fd..a9182c9e4d5 100644
--- a/be/src/service/http/http_request.cpp
+++ b/be/src/service/http/http_request.cpp
@@ -105,7 +105,7 @@ int HttpRequest::init_from_evhttp() {
     struct evkeyvalq params;
     auto res = evhttp_parse_query_str(query, &params);
     if (res < 0) {
-        LOG(WARNING) << "parse query str failed, query=" << query;
+        LOG(WARNING) << "parse query str failed";
         return res;
     }
     for (auto param = params.tqh_first; param != nullptr; param = 
param->next.tqe_next) {
@@ -120,7 +120,7 @@ std::string HttpRequest::debug_string() const {
     std::stringstream ss;
     ss << "HttpRequest: \n"
        << "method:" << _method << "\n"
-       << "uri:" << _uri << "\n"
+       << "uri:" << _raw_path << "\n"
        << "raw_path:" << _raw_path << "\n"
        << "headers: \n";
     for (auto& iter : _headers) {
@@ -131,10 +131,7 @@ std::string HttpRequest::debug_string() const {
             ss << "key=" << iter.first << ", value=" << iter.second << "\n";
         }
     }
-    ss << "params: \n";
-    for (auto& iter : _params) {
-        ss << "key=" << iter.first << ", value=" << iter.second << "\n";
-    }
+    ss << "params_count:" << _params.size() << "\n";
 
     return ss.str();
 }
diff --git a/be/test/service/http/http_request_test.cpp 
b/be/test/service/http/http_request_test.cpp
index fdb9df43f75..228ceef241a 100644
--- a/be/test/service/http/http_request_test.cpp
+++ b/be/test/service/http/http_request_test.cpp
@@ -18,6 +18,7 @@
 #include "service/http/http_request.h"
 
 #include <event2/http.h>
+#include <event2/http_struct.h>
 #include <gtest/gtest.h>
 
 #include <cstring>
@@ -139,4 +140,80 @@ TEST_F(HttpRequestTest, 
non_sensitive_headers_are_untouched) {
     EXPECT_EQ(dumped.find(kMasked), std::string::npos) << dumped;
 }
 
+TEST_F(HttpRequestTest, query_credentials_are_not_exposed_in_debug_string) {
+    constexpr char uri[] = "/api/_download?token=synthetic-token-123&job_id=7";
+    auto* evhttp_req = evhttp_request_new(nullptr, nullptr);
+    evhttp_req->type = EVHTTP_REQ_GET;
+    evhttp_req->uri = const_cast<char*>(uri);
+    evhttp_req->uri_elems = evhttp_uri_parse(uri);
+
+    HttpRequest req(evhttp_req);
+    EXPECT_EQ(req.init_from_evhttp(), 0);
+    const std::string dumped = req.debug_string();
+    EXPECT_EQ(req.uri(), uri);
+    EXPECT_EQ(req.param("token"), "synthetic-token-123");
+    EXPECT_EQ(req.query_params().at("job_id"), "7");
+    EXPECT_NE(dumped.find("uri:/api/_download\n"), std::string::npos) << 
dumped;
+    EXPECT_NE(dumped.find("params_count:2\n"), std::string::npos) << dumped;
+    EXPECT_EQ(dumped.find("synthetic-token-123"), std::string::npos) << dumped;
+    EXPECT_EQ(dumped.find("?token="), std::string::npos) << dumped;
+    EXPECT_EQ(dumped.find("key=token"), std::string::npos) << dumped;
+    EXPECT_EQ(dumped.find("key=job_id"), std::string::npos) << dumped;
+    EXPECT_EQ(dumped.find("job_id=7"), std::string::npos) << dumped;
+
+    evhttp_uri_free(evhttp_req->uri_elems);
+    evhttp_req->uri = nullptr;
+    evhttp_req->uri_elems = nullptr;
+    evhttp_request_free(evhttp_req);
+}
+
+TEST_F(HttpRequestTest, 
encoded_query_and_route_params_are_not_exposed_in_debug_string) {
+    constexpr char uri[] = 
"/api/_download?Token=synthetic%2Bcredential&opaque=another-secret";
+    auto* evhttp_req = evhttp_request_new(nullptr, nullptr);
+    evhttp_req->type = EVHTTP_REQ_GET;
+    evhttp_req->uri = const_cast<char*>(uri);
+    evhttp_req->uri_elems = evhttp_uri_parse(uri);
+
+    HttpRequest req(evhttp_req);
+    EXPECT_EQ(req.init_from_evhttp(), 0);
+    req.params()->emplace("route_id", "private-route-value");
+    const std::string dumped = req.debug_string();
+    EXPECT_EQ(req.uri(), uri);
+    EXPECT_EQ(req.param("Token"), "synthetic+credential");
+    EXPECT_EQ(req.query_params().at("opaque"), "another-secret");
+    EXPECT_EQ(req.param("route_id"), "private-route-value");
+    EXPECT_NE(dumped.find("uri:/api/_download\n"), std::string::npos) << 
dumped;
+    EXPECT_NE(dumped.find("params_count:3\n"), std::string::npos) << dumped;
+    for (const std::string& secret :
+         {"synthetic%2Bcredential", "synthetic+credential", "another-secret", 
"Token", "opaque",
+          "route_id", "private-route-value"}) {
+        EXPECT_EQ(dumped.find(secret), std::string::npos) << dumped;
+    }
+
+    evhttp_uri_free(evhttp_req->uri_elems);
+    evhttp_req->uri = nullptr;
+    evhttp_req->uri_elems = nullptr;
+    evhttp_request_free(evhttp_req);
+}
+
+TEST_F(HttpRequestTest, request_without_query_keeps_path_in_debug_string) {
+    constexpr char uri[] = "/api/_download";
+    auto* evhttp_req = evhttp_request_new(nullptr, nullptr);
+    evhttp_req->type = EVHTTP_REQ_GET;
+    evhttp_req->uri = const_cast<char*>(uri);
+    evhttp_req->uri_elems = evhttp_uri_parse(uri);
+
+    HttpRequest req(evhttp_req);
+    EXPECT_EQ(req.init_from_evhttp(), 0);
+    const std::string dumped = req.debug_string();
+    EXPECT_EQ(req.uri(), uri);
+    EXPECT_NE(dumped.find("uri:/api/_download\n"), std::string::npos) << 
dumped;
+    EXPECT_NE(dumped.find("params_count:0\n"), std::string::npos) << dumped;
+
+    evhttp_uri_free(evhttp_req->uri_elems);
+    evhttp_req->uri = nullptr;
+    evhttp_req->uri_elems = nullptr;
+    evhttp_request_free(evhttp_req);
+}
+
 } // namespace doris


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

Reply via email to