This is an automated email from the ASF dual-hosted git repository.
yiguolei pushed a commit to branch branch-4.1
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-4.1 by this push:
new 4413477105c [fix](fe) Fix HTTP system forwarding on follower FE
(#68827)
4413477105c is described below
commit 4413477105c1743e9401dbdb3708c20f9e13e0c2
Author: Calvin Kirs <[email protected]>
AuthorDate: Sat Oct 10 09:32:32 2026 +0800
[fix](fe) Fix HTTP system forwarding on follower FE (#68827)
https://github.com/apache/doris/pull/68823
---
.../java/org/apache/doris/qe/FEOpExecutor.java | 9 +++--
.../doris/qe/FEOpExecutorMysqlProtocolTest.java | 24 ++++++++++++
.../test_http_rest_v1_system_follower.groovy | 45 ++++++++++++++++++++++
3 files changed, 74 insertions(+), 4 deletions(-)
diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/FEOpExecutor.java
b/fe/fe-core/src/main/java/org/apache/doris/qe/FEOpExecutor.java
index fe0de92857d..21420b31c22 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/qe/FEOpExecutor.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/qe/FEOpExecutor.java
@@ -23,6 +23,7 @@ import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ClientPool;
import org.apache.doris.common.Config;
import org.apache.doris.common.ErrorCode;
+import org.apache.doris.mysql.DummyMysqlChannel;
import org.apache.doris.mysql.MysqlCommand;
import org.apache.doris.mysql.MysqlCursorFetchCompatibility;
import org.apache.doris.mysql.MysqlProto;
@@ -222,10 +223,10 @@ public class FEOpExecutor {
// Propagate the client's CLIENT_DEPRECATE_EOF capability so the
master FE
// generates packets matching the original client's protocol
expectations.
- // Only a MySQL connection negotiates this capability and owns a
MysqlChannel;
- // an Arrow Flight SQL session has none, and leaving the field unset
keeps the
- // master on its default packet layout.
- if (ctx.getConnectType() == ConnectType.MYSQL) {
+ // HTTP contexts use a dummy MySQL channel without a negotiated
capability.
+ // Leave their protocol fields unset so the master uses its default
packet layout.
+ if (ctx.getConnectType() == ConnectType.MYSQL
+ && !(ctx.getMysqlChannel() instanceof DummyMysqlChannel &&
ctx.getCapability() == null)) {
params.setClientDeprecatedEOF(ctx.getMysqlChannel().clientDeprecatedEOF());
params.setMysqlCapability(ctx.getCapability().getFlags());
}
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/qe/FEOpExecutorMysqlProtocolTest.java
b/fe/fe-core/src/test/java/org/apache/doris/qe/FEOpExecutorMysqlProtocolTest.java
index a3e235f56f5..de0c3e2ee8e 100644
---
a/fe/fe-core/src/test/java/org/apache/doris/qe/FEOpExecutorMysqlProtocolTest.java
+++
b/fe/fe-core/src/test/java/org/apache/doris/qe/FEOpExecutorMysqlProtocolTest.java
@@ -60,6 +60,7 @@ public class FEOpExecutorMysqlProtocolTest {
TMasterOpRequest request = new TestFEOpExecutor(context).build();
Assertions.assertTrue(request.isClientDeprecatedEOF());
+ Assertions.assertEquals(context.getCapability().getFlags(),
request.getMysqlCapability());
Assertions.assertTrue(request.isCursorFetchRequested());
Assertions.assertEquals("8.2.0",
request.getConnectAttributes().get("_client_version"));
@@ -107,6 +108,29 @@ public class FEOpExecutorMysqlProtocolTest {
}
}
+ @Test
+ public void testHttpForwardRequestUsesDefaultMysqlCapability() throws
Exception {
+ Env env = Mockito.mock(Env.class);
+ Mockito.when(env.getSelfNode()).thenReturn(new
SystemInfoService.HostInfo("127.0.0.1", 9010));
+ try (MockedStatic<Env> mockedEnv = Mockito.mockStatic(Env.class)) {
+ mockedEnv.when(Env::getCurrentEnv).thenReturn(env);
+ ConnectContext context = new ConnectContext();
+
context.setCurrentUserIdentity(UserIdentity.createAnalyzedUserIdentWithIp("alice",
"%"));
+ context.setRemoteIP("127.0.0.1");
+ Assertions.assertNull(context.getCapability());
+
+ TMasterOpRequest request = new TestFEOpExecutor(context).build();
+ Assertions.assertFalse(request.isSetClientDeprecatedEOF());
+ Assertions.assertFalse(request.isSetMysqlCapability());
+
+ ConnectContext forwardedContext = createContext();
+ ConnectProcessor.restoreForwardedMysqlContext(forwardedContext,
request);
+ int expectedFlags = MysqlCapability.DEFAULT_CAPABILITY.getFlags()
+ & ~MysqlCapability.Flag.CLIENT_DEPRECATE_EOF.getFlagBit();
+ Assertions.assertEquals(expectedFlags,
forwardedContext.getCapability().getFlags());
+ }
+ }
+
@Test
public void testForwardedCapabilityAndMissingCursorFlag() throws Exception
{
int legacyFlags = MysqlCapability.DEFAULT_CAPABILITY.getFlags()
diff --git
a/regression-test/suites/auth_p0/test_http_rest_v1_system_follower.groovy
b/regression-test/suites/auth_p0/test_http_rest_v1_system_follower.groovy
new file mode 100644
index 00000000000..b928969f2f9
--- /dev/null
+++ b/regression-test/suites/auth_p0/test_http_rest_v1_system_follower.groovy
@@ -0,0 +1,45 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+import org.apache.doris.regression.suite.ClusterOptions
+
+suite("test_http_rest_v1_system_follower", "docker") {
+ def options = new ClusterOptions()
+ options.setFeNum(2)
+ options.setBeNum(1)
+ docker(options) {
+ def follower = cluster.getAllFrontends(true).find { !it.isMaster }
+ assertNotNull(follower)
+
+ // Wait for the follower to replay the journal before authenticating
over HTTP.
+ String followerJdbcUrl =
"jdbc:mysql://${follower.host}:${follower.queryPort}/"
+ connect(context.config.jdbcUser, context.config.jdbcPassword,
followerJdbcUrl) {
+ sql "SYNC"
+ }
+
+ httpTest {
+ basicAuthorization "${context.config.jdbcUser}",
"${context.config.jdbcPassword}"
+ endpoint "${follower.host}:${follower.httpPort}"
+ uri "/rest/v1/system?path=/"
+ op "get"
+ check { respCode, body ->
+ assertEquals(200, respCode)
+ assertEquals(0, parseJson(body).code)
+ }
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]