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

CalvinKirs 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 626b24c1ca9 [fix](fe) Fix HTTP system requests forwarded to the master 
(#68823)
626b24c1ca9 is described below

commit 626b24c1ca99ce0ec63ae18051e34100e2611185
Author: Calvin Kirs <[email protected]>
AuthorDate: Sat Oct 10 11:04:05 2026 +0800

    [fix](fe) Fix HTTP system requests forwarded to the master (#68823)
    
    ### What problem does this PR solve?
    
    An authorized `/rest/v1/system` request on a non-master FE forwards
    `SHOW PROC` with an HTTP context that has no negotiated MySQL
    capability. Reading that capability returns JSON business code 500. Skip
    MySQL protocol fields for this context while preserving forwarding for
    connections with an explicit capability.
    
    ### Release note
    
    Fix `/rest/v1/system` on non-master FEs.
    
    ### Check List (For Author)
    
    - Test: 21 targeted FE unit tests passed; Checkstyle passed. HTTP
    regression coverage added but not run locally (no cluster).
    - Behavior changed: Yes, authorized HTTP system requests can be
    forwarded successfully.
    - Does this need documentation: No.
---
 .../doris/mysql/protocol/MysqlProtocolAdapter.java |  8 +++++-
 .../mysql/protocol/MysqlProtocolAdapterTest.java   | 29 ++++++++++++++++++++--
 .../suites/auth_p0/test_http_rest_v1_auth.groovy   | 17 +++++++++++++
 3 files changed, 51 insertions(+), 3 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/protocol/MysqlProtocolAdapter.java
 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/protocol/MysqlProtocolAdapter.java
index 5f76d55772f..4279566e15c 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/mysql/protocol/MysqlProtocolAdapter.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/mysql/protocol/MysqlProtocolAdapter.java
@@ -18,6 +18,7 @@
 package org.apache.doris.mysql.protocol;
 
 import org.apache.doris.common.util.DebugUtil;
+import org.apache.doris.mysql.DummyMysqlChannel;
 import org.apache.doris.mysql.MysqlCapability;
 import org.apache.doris.mysql.MysqlChannel;
 import org.apache.doris.mysql.MysqlCommand;
@@ -168,10 +169,15 @@ public class MysqlProtocolAdapter implements 
ProtocolAdapter {
      * The master encodes the response of a forwarded statement for this 
connection's client, so
      * it needs the client's negotiated capabilities, and for a forwarded 
COM_STMT_EXECUTE the
      * execute packet and whether it asked for a cursor. {@link 
#restoreFromForwardRequest} is the
-     * master's side.
+     * master's side. HTTP and internal contexts have no client protocol state 
to forward.
      */
     @Override
     public void fillForwardRequest(ConnectContext ctx, TMasterOpRequest 
request) {
+        // HTTP and internal contexts have no negotiated capability. A dummy 
channel with an
+        // explicitly supplied capability still carries that state when 
forwarding.
+        if (channel instanceof DummyMysqlChannel && capability == null) {
+            return;
+        }
         if (ctx.getCommand() == MysqlCommand.COM_STMT_EXECUTE) {
             if (prepareExecuteBuffer != null) {
                 request.setPrepareExecuteBuffer(prepareExecuteBuffer);
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/protocol/MysqlProtocolAdapterTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/protocol/MysqlProtocolAdapterTest.java
index bc4fcb7ea71..22886f63941 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/protocol/MysqlProtocolAdapterTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/protocol/MysqlProtocolAdapterTest.java
@@ -277,9 +277,30 @@ public class MysqlProtocolAdapterTest {
         Assertions.assertEquals(1, channel.getOutbound().size());
     }
 
+    @Test
+    public void testHttpContextForwardsWithoutMysqlCapabilities() {
+        // HTTP controllers create an internal context without a MySQL 
handshake.
+        ConnectContext ctx = new ConnectContext();
+        Assertions.assertNull(ctx.getCapability());
+        TMasterOpRequest request = new TMasterOpRequest();
+
+        ctx.getProtocolAdapter().fillForwardRequest(ctx, request);
+
+        Assertions.assertFalse(request.isSetMysqlCapability());
+        Assertions.assertFalse(request.isSetClientDeprecatedEOF());
+        Assertions.assertFalse(request.isSetPrepareExecuteBuffer());
+        Assertions.assertFalse(request.isSetCursorFetchRequested());
+
+        // The master can execute the request using its default proxy 
capabilities.
+        ConnectContext proxy = ConnectContext.forMysqlProxy("http-session");
+        MysqlProtocolAdapter.of(proxy).restoreFromForwardRequest(proxy, 
request);
+        Assertions.assertNotNull(proxy.getCapability());
+        Assertions.assertFalse(proxy.getCapability().isDeprecatedEOF());
+    }
+
     @Test
     public void testForwardRequestCarriesWhatTheMasterNeedsToAnswerTheClient() 
{
-        RecordingMysqlChannel channel = new RecordingMysqlChannel();
+        MysqlChannel channel = Mockito.mock(MysqlChannel.class);
         ConnectContext ctx = new ConnectContext(new 
MysqlProtocolAdapter(channel));
         MysqlProtocolAdapter protocol = MysqlProtocolAdapter.of(ctx);
         int flags = MysqlCapability.DEFAULT_CAPABILITY.getFlags()
@@ -296,19 +317,23 @@ public class MysqlProtocolAdapterTest {
 
         // A COM_STMT_EXECUTE from a client that deprecated EOF: the execute 
packet and the cursor
         // flag travel too.
-        channel.setClientDeprecatedEOF();
+        flags |= MysqlCapability.Flag.CLIENT_DEPRECATE_EOF.getFlagBit();
+        ctx.setCapability(new MysqlCapability(flags));
+        Mockito.when(channel.clientDeprecatedEOF()).thenReturn(true);
         ctx.setCommand(MysqlCommand.COM_STMT_EXECUTE);
         ctx.setPrepareExecuteBuffer(ByteBuffer.wrap(new byte[] {7, 0, 0, 0}));
         ctx.setCursorFetchRequested(true);
         request = new TMasterOpRequest();
         protocol.fillForwardRequest(ctx, request);
         Assertions.assertTrue(request.isClientDeprecatedEOF());
+        Assertions.assertEquals(flags, request.getMysqlCapability());
         Assertions.assertArrayEquals(new byte[] {7, 0, 0, 0}, 
request.getPrepareExecuteBuffer());
         Assertions.assertTrue(request.isCursorFetchRequested());
 
         // The master's proxy context takes them over.
         ConnectContext proxy = ConnectContext.forMysqlProxy("session-1");
         MysqlProtocolAdapter.of(proxy).restoreFromForwardRequest(proxy, 
request);
+        Assertions.assertEquals(flags, proxy.getCapability().getFlags());
         Assertions.assertTrue(proxy.getCapability().isDeprecatedEOF());
         Assertions.assertTrue(proxy.getMysqlChannel().clientDeprecatedEOF());
         Assertions.assertTrue(proxy.isCursorFetchRequested());
diff --git a/regression-test/suites/auth_p0/test_http_rest_v1_auth.groovy 
b/regression-test/suites/auth_p0/test_http_rest_v1_auth.groovy
index f6cdd0444c8..66ad68320e2 100644
--- a/regression-test/suites/auth_p0/test_http_rest_v1_auth.groovy
+++ b/regression-test/suites/auth_p0/test_http_rest_v1_auth.groovy
@@ -87,4 +87,21 @@ suite("test_http_rest_v1_auth", "p0,auth") {
             assertEquals(200, respCode)
             assertEquals(200, parseJson(body).code)
     }
+
+    // Exercise both local execution on the master and SHOW PROC forwarding 
from other FEs.
+    sql_return_maparray("SHOW FRONTENDS").findAll {
+        "${it.Alive}".equalsIgnoreCase("true")
+    }.each { frontend ->
+        httpTest {
+            basicAuthorization "${user}", "${pwd}"
+            endpoint "${frontend.Host}:${frontend.HttpPort}"
+            uri "/rest/v1/system?path=/"
+            op "get"
+            check { respCode, body ->
+                log.info("system (${frontend.Host}:${frontend.HttpPort}) 
body:${body}")
+                assertEquals(200, respCode)
+                assertEquals(0, parseJson(body).code)
+            }
+        }
+    }
 }


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

Reply via email to