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 95846ddfc9b branch-4.1: [improvement](fe) Move FE web dependencies to 
supported OSS releases #68862 (#69282)
95846ddfc9b is described below

commit 95846ddfc9b30feb4a6cd39a8dfbe74cf05e18bb
Author: Mingyu Chen (Rayner) <[email protected]>
AuthorDate: Tue Oct 20 03:24:15 2026 +0100

    branch-4.1: [improvement](fe) Move FE web dependencies to supported OSS 
releases #68862 (#69282)
    
    bp #68862
    
    Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
 .../authentication/plugin/ldap/LdapClientTest.java |   4 +-
 fe/fe-core/pom.xml                                 |  16 +-
 .../java/org/apache/doris/httpv2/HttpServer.java   |   2 +-
 .../httpv2/config/HttpToHttpsJettyConfig.java      |   8 +-
 .../apache/doris/httpv2/config/WebConfigurer.java  |  18 +-
 .../config/WebServerFactoryCustomizerConfig.java   |   8 +-
 .../httpv2/controller/HardwareInfoController.java  |   2 +-
 .../doris/tls/server/HttpServerTlsProvider.java    |   2 +-
 .../doris/tls/server/OssHttpServerTlsProvider.java |   4 +-
 .../org/apache/doris/http/ForwardToMasterTest.java |  30 +--
 .../doris/http/HttpServerCompatibilityTest.java    | 203 +++++++++++++++++++++
 .../mysql/authenticate/ldap/LdapClientTest.java    |   4 +-
 fe/pom.xml                                         |  75 ++++----
 13 files changed, 293 insertions(+), 83 deletions(-)

diff --git 
a/fe/fe-authentication/fe-authentication-plugins/fe-authentication-plugin-ldap/src/test/java/org/apache/doris/authentication/plugin/ldap/LdapClientTest.java
 
b/fe/fe-authentication/fe-authentication-plugins/fe-authentication-plugin-ldap/src/test/java/org/apache/doris/authentication/plugin/ldap/LdapClientTest.java
index 7809795062c..45f912747f8 100644
--- 
a/fe/fe-authentication/fe-authentication-plugins/fe-authentication-plugin-ldap/src/test/java/org/apache/doris/authentication/plugin/ldap/LdapClientTest.java
+++ 
b/fe/fe-authentication/fe-authentication-plugins/fe-authentication-plugin-ldap/src/test/java/org/apache/doris/authentication/plugin/ldap/LdapClientTest.java
@@ -272,8 +272,8 @@ class LdapClientTest {
         String expected = "test\\2a\\28\\29\\5c\\00";
         Assertions.assertEquals(expected, LdapEncoder.filterEncode(input));
 
-        // Null input
-        Assertions.assertNull(LdapEncoder.filterEncode(null));
+        // Spring LDAP 4 requires a non-null value.
+        Assertions.assertThrows(NullPointerException.class, () -> 
LdapEncoder.filterEncode(null));
 
         // Normal username should not be altered
         Assertions.assertEquals("zhangsan", 
LdapEncoder.filterEncode("zhangsan"));
diff --git a/fe/fe-core/pom.xml b/fe/fe-core/pom.xml
index 2b928de3bde..2d6758989d5 100644
--- a/fe/fe-core/pom.xml
+++ b/fe/fe-core/pom.xml
@@ -159,11 +159,6 @@ under the License.
             <groupId>org.apache.commons</groupId>
             <artifactId>commons-text</artifactId>
         </dependency>
-        <!-- https://mvnrepository.com/artifact/cglib/cglib -->
-        <dependency>
-            <groupId>cglib</groupId>
-            <artifactId>cglib</artifactId>
-        </dependency>
         <!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
         <dependency>
             <groupId>commons-cli</groupId>
@@ -363,16 +358,21 @@ under the License.
             <artifactId>odps-sdk-table-api</artifactId>
             <version>${maxcompute.version}</version>
         </dependency>
-        <!-- 
https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web
 -->
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
+            <artifactId>spring-boot-starter-webmvc</artifactId>
+        </dependency>
+        <!-- Preserve the Jackson 2 response format used by existing FE HTTP 
clients. -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-jackson2</artifactId>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-jetty</artifactId>
         </dependency>
-        <!-- Jetty 12.0.38 calls Jakarta Servlet 6.1 APIs when writing 
Set-Cookie headers. -->
+        <!-- Declare the Servlet 6.1 API required by Spring Framework 7 and 
Jetty EE11 explicitly;
+             cookie attributes such as SameSite must also resolve against this 
API. -->
         <dependency>
             <groupId>jakarta.servlet</groupId>
             <artifactId>jakarta.servlet-api</artifactId>
diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/HttpServer.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/HttpServer.java
index 4c61088426e..7324870cc41 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/HttpServer.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/HttpServer.java
@@ -28,7 +28,7 @@ import org.apache.logging.log4j.Logger;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.builder.SpringApplicationBuilder;
 import 
org.springframework.boot.context.properties.EnableConfigurationProperties;
-import org.springframework.boot.web.servlet.ServletComponentScan;
+import 
org.springframework.boot.web.server.servlet.context.ServletComponentScan;
 import 
org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
 import org.springframework.context.ConfigurableApplicationContext;
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/HttpToHttpsJettyConfig.java
 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/HttpToHttpsJettyConfig.java
index 5952ffe8a04..306c64f8ef8 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/HttpToHttpsJettyConfig.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/HttpToHttpsJettyConfig.java
@@ -17,10 +17,10 @@
 
 package org.apache.doris.httpv2.config;
 
-import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
-import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
-import org.eclipse.jetty.ee10.webapp.AbstractConfiguration;
-import org.eclipse.jetty.ee10.webapp.WebAppContext;
+import org.eclipse.jetty.ee11.servlet.security.ConstraintMapping;
+import org.eclipse.jetty.ee11.servlet.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.ee11.webapp.AbstractConfiguration;
+import org.eclipse.jetty.ee11.webapp.WebAppContext;
 import org.eclipse.jetty.security.Constraint;
 
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/WebConfigurer.java 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/WebConfigurer.java
index def1edca261..49ce08710b5 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/WebConfigurer.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/WebConfigurer.java
@@ -20,13 +20,16 @@ package org.apache.doris.httpv2.config;
 import org.apache.doris.common.Config;
 import org.apache.doris.httpv2.interceptor.AuthInterceptor;
 
-import org.springframework.boot.web.server.ErrorPage;
+import org.springframework.boot.web.error.ErrorPage;
 import org.springframework.boot.web.server.WebServerFactoryCustomizer;
-import 
org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
+import 
org.springframework.boot.web.server.servlet.ConfigurableServletWebServerFactory;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
+import org.springframework.core.Ordered;
 import org.springframework.http.HttpStatus;
 import org.springframework.util.AntPathMatcher;
+import org.springframework.web.filter.UrlHandlerFilter;
 import 
org.springframework.web.multipart.support.StandardServletMultipartResolver;
 import org.springframework.web.servlet.config.annotation.CorsRegistry;
 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@@ -58,7 +61,16 @@ public class WebConfigurer implements WebMvcConfigurer {
     @Override
     public void configurePathMatch(PathMatchConfigurer configurer) {
         configurer.setPathMatcher(new AntPathMatcher());
-        configurer.setUseTrailingSlashMatch(true);
+    }
+
+    @Bean
+    public FilterRegistrationBean<UrlHandlerFilter> trailingSlashFilter() {
+        // Spring 7 removed optional trailing-slash matching. Wrap requests 
before MVC routing
+        // and authentication so existing clients keep their URLs, methods, 
bodies and queries.
+        FilterRegistrationBean<UrlHandlerFilter> registration = new 
FilterRegistrationBean<>(
+                
UrlHandlerFilter.trailingSlashHandler("/**").wrapRequest().build());
+        registration.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
+        return registration;
     }
 
     @Override
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/WebServerFactoryCustomizerConfig.java
 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/WebServerFactoryCustomizerConfig.java
index c1c191228eb..11c2fa68550 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/WebServerFactoryCustomizerConfig.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/config/WebServerFactoryCustomizerConfig.java
@@ -22,13 +22,13 @@ import 
org.apache.doris.tls.server.HttpServerTlsProviderFactory;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
-import org.eclipse.jetty.ee10.webapp.WebAppContext;
-import 
org.eclipse.jetty.ee10.websocket.server.config.JettyWebSocketServletContainerInitializer;
+import org.eclipse.jetty.ee11.webapp.WebAppContext;
+import 
org.eclipse.jetty.ee11.websocket.server.config.JettyWebSocketServletContainerInitializer;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.ServerConnector;
-import 
org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory;
-import 
org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
+import org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;
+import org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;
 import org.springframework.boot.web.server.WebServerFactoryCustomizer;
 import org.springframework.context.annotation.Configuration;
 
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/HardwareInfoController.java
 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/HardwareInfoController.java
index 2c90bed8764..203aa039e52 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/HardwareInfoController.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/httpv2/controller/HardwareInfoController.java
@@ -55,7 +55,7 @@ public class HardwareInfoController {
 
     private static final Logger LOG = 
LogManager.getLogger(HardwareInfoController.class);
 
-    @RequestMapping(path = "/hardware_info/fe/", method = RequestMethod.GET)
+    @RequestMapping(path = "/hardware_info/fe", method = RequestMethod.GET)
     public Object index() {
         Map<String, Map<String, String>> map = new HashMap<>();
         appendVersionInfo(map);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/tls/server/HttpServerTlsProvider.java
 
b/fe/fe-core/src/main/java/org/apache/doris/tls/server/HttpServerTlsProvider.java
index d42bd16e137..419ce99e229 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/tls/server/HttpServerTlsProvider.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/tls/server/HttpServerTlsProvider.java
@@ -17,7 +17,7 @@
 
 package org.apache.doris.tls.server;
 
-import 
org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory;
+import org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;
 
 public interface HttpServerTlsProvider {
     void customize(ConfigurableJettyWebServerFactory factory);
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/tls/server/OssHttpServerTlsProvider.java
 
b/fe/fe-core/src/main/java/org/apache/doris/tls/server/OssHttpServerTlsProvider.java
index 8279b636a3f..64e313558b4 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/tls/server/OssHttpServerTlsProvider.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/tls/server/OssHttpServerTlsProvider.java
@@ -23,8 +23,8 @@ import org.apache.doris.httpv2.config.HttpToHttpsJettyConfig;
 import org.eclipse.jetty.server.HttpConfiguration;
 import org.eclipse.jetty.server.HttpConnectionFactory;
 import org.eclipse.jetty.server.ServerConnector;
-import 
org.springframework.boot.web.embedded.jetty.ConfigurableJettyWebServerFactory;
-import 
org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
+import org.springframework.boot.jetty.ConfigurableJettyWebServerFactory;
+import org.springframework.boot.jetty.servlet.JettyServletWebServerFactory;
 
 import java.util.Collections;
 
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/http/ForwardToMasterTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/http/ForwardToMasterTest.java
index 0ba0b894340..85d523270d6 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/http/ForwardToMasterTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/http/ForwardToMasterTest.java
@@ -50,13 +50,13 @@ public class ForwardToMasterTest extends DorisHttpTestCase {
                 JSONObject object = (JSONObject) JSONValue.parse(respStr);
 
                 JSONObject data = (JSONObject) object.get("data");
-                JSONArray columnNames = (JSONArray) ((JSONObject) 
data.get("columnNames")).get("columnNames");
-                JSONArray rows = (JSONArray) ((JSONObject) 
data.get("rows")).get("rows");
-                int sz = columnNames.size();
+                JSONArray columnNames = (JSONArray) data.get("columnNames");
+                JSONArray rows = (JSONArray) data.get("rows");
                 int index = columnNames.indexOf("HeartbeatPort");
                 int existsbe = 0;
-                for (int i = 0; i < rows.size(); i += sz) {
-                    if (port.equals(rows.get(i + index).toString())) {
+                for (int i = 0; i < rows.size(); i++) {
+                    JSONArray row = (JSONArray) rows.get(i);
+                    if (port.equals(row.get(index).toString())) {
                         existsbe++;
                     }
                 }
@@ -100,13 +100,13 @@ public class ForwardToMasterTest extends 
DorisHttpTestCase {
 
                 JSONObject object = (JSONObject) JSONValue.parse(respStr);
                 JSONObject data = (JSONObject) object.get("data");
-                JSONArray columnNames = (JSONArray) ((JSONObject) 
data.get("columnNames")).get("columnNames");
-                JSONArray rows = (JSONArray) ((JSONObject) 
data.get("rows")).get("rows");
-                int sz = columnNames.size();
+                JSONArray columnNames = (JSONArray) data.get("columnNames");
+                JSONArray rows = (JSONArray) data.get("rows");
                 int index = columnNames.indexOf("HeartbeatPort");
                 int existsbe = 0;
-                for (int i = 0; i < rows.size(); i += sz) {
-                    if (port.equals(rows.get(i + index).toString())) {
+                for (int i = 0; i < rows.size(); i++) {
+                    JSONArray row = (JSONArray) rows.get(i);
+                    if (port.equals(row.get(index).toString())) {
                         existsbe++;
                     }
                 }
@@ -151,13 +151,13 @@ public class ForwardToMasterTest extends 
DorisHttpTestCase {
                 JSONObject object = (JSONObject) JSONValue.parse(respStr);
 
                 JSONObject data = (JSONObject) object.get("data");
-                JSONArray columnNames = (JSONArray) ((JSONObject) 
data.get("columnNames")).get("columnNames");
-                JSONArray rows = (JSONArray) ((JSONObject) 
data.get("rows")).get("rows");
-                int sz = columnNames.size();
+                JSONArray columnNames = (JSONArray) data.get("columnNames");
+                JSONArray rows = (JSONArray) data.get("rows");
                 int index = columnNames.indexOf("HeartbeatPort");
                 int existsbe = 0;
-                for (int i = 0; i < rows.size(); i += sz) {
-                    if (port.equals(rows.get(i + index).toString())) {
+                for (int i = 0; i < rows.size(); i++) {
+                    JSONArray row = (JSONArray) rows.get(i);
+                    if (port.equals(row.get(index).toString())) {
                         existsbe++;
                     }
                 }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/http/HttpServerCompatibilityTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/http/HttpServerCompatibilityTest.java
new file mode 100644
index 00000000000..a24c67c3342
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/http/HttpServerCompatibilityTest.java
@@ -0,0 +1,203 @@
+// 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.
+
+package org.apache.doris.http;
+
+import org.apache.doris.httpv2.config.WebConfigurer;
+import org.apache.doris.httpv2.config.WebServerFactoryCustomizerConfig;
+import org.apache.doris.httpv2.exception.RestApiExceptionHandler;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.WebApplicationType;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import 
org.springframework.boot.web.server.servlet.context.ServletWebServerApplicationContext;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDate;
+import java.util.Locale;
+import java.util.concurrent.TimeUnit;
+
+/** Exercises the FE web configuration against the embedded servlet container 
and real HTTP requests. */
+public class HttpServerCompatibilityTest {
+    private static final MediaType JSON = MediaType.parse("application/json");
+    private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
+            .connectTimeout(10, TimeUnit.SECONDS)
+            .followRedirects(false)
+            .build();
+    private static ServletWebServerApplicationContext applicationContext;
+    private static String baseUrl;
+
+    @BeforeAll
+    static void startServer() {
+        applicationContext = (ServletWebServerApplicationContext) new 
SpringApplicationBuilder(TestApplication.class)
+                .web(WebApplicationType.SERVLET)
+                .properties("server.address=127.0.0.1", "server.port=0", 
"spring.main.banner-mode=off")
+                .run();
+        baseUrl = "http://127.0.0.1:"; + 
applicationContext.getWebServer().getPort();
+    }
+
+    @AfterAll
+    static void stopServer() {
+        applicationContext.close();
+    }
+
+    @Test
+    void preservesJsonAndQueryParametersWithTrailingSlash() throws Exception {
+        for (String path : new String[] {"/api/dependency_compatibility", 
"/api/dependency_compatibility/"}) {
+            try (Response response = send(new Request.Builder().url(baseUrl + 
path + "?q=hello%20world")
+                    .get().build())) {
+                Assertions.assertEquals(200, response.code());
+                JsonObject body = 
JsonParser.parseString(response.body().string()).getAsJsonObject();
+                Assertions.assertEquals("hello world", 
body.get("snake_case").getAsString());
+                Assertions.assertEquals("2026-10-10", 
body.get("date").getAsString());
+                Assertions.assertFalse(body.has("value"));
+            }
+        }
+    }
+
+    @Test
+    void preservesPostMethodAndJsonBodyWithTrailingSlash() throws Exception {
+        for (String path : new String[] {"/api/dependency_compatibility", 
"/api/dependency_compatibility/"}) {
+            try (Response response = send(new Request.Builder().url(baseUrl + 
path + "?q=hello%20world")
+                    
.post(okhttp3.RequestBody.create("{\"snake_case\":\"body\",\"date\":\"2026-10-10\"}",
 JSON))
+                    .build())) {
+                Assertions.assertEquals(200, response.code());
+                JsonObject body = 
JsonParser.parseString(response.body().string()).getAsJsonObject();
+                Assertions.assertEquals("body:hello world", 
body.get("snake_case").getAsString());
+                Assertions.assertEquals("2026-10-10", 
body.get("date").getAsString());
+            }
+        }
+    }
+
+    @Test
+    void preservesCookieSecurityAttributes() throws Exception {
+        try (Response response = send(new Request.Builder().url(baseUrl + 
"/api/dependency_cookie").get().build())) {
+            Assertions.assertEquals(200, response.code());
+            String cookie = response.header("Set-Cookie");
+            Assertions.assertNotNull(cookie);
+            cookie = cookie.toLowerCase(Locale.ROOT);
+            Assertions.assertTrue(cookie.contains("httponly"));
+            Assertions.assertTrue(cookie.contains("samesite=lax"));
+        }
+    }
+
+    @Test
+    void requiresAuthenticationWithAndWithoutTrailingSlash() throws Exception {
+        for (String path : new String[] {"/rest/v1/dependency_compatibility", 
"/rest/v1/dependency_compatibility/"}) {
+            try (Response response = send(new Request.Builder().url(baseUrl + 
path).get().build())) {
+                // RestApiExceptionHandler reports an authentication failure 
as HTTP 200 with code 401 in the body.
+                Assertions.assertEquals(200, response.code());
+                JsonObject body = 
JsonParser.parseString(response.body().string()).getAsJsonObject();
+                Assertions.assertEquals(401, body.get("code").getAsInt());
+                Assertions.assertNull(response.header("Location"));
+            }
+        }
+    }
+
+    @Test
+    void preservesRootPath() throws Exception {
+        try (Response response = send(new Request.Builder().url(baseUrl + 
"/").get().build())) {
+            Assertions.assertEquals(200, response.code());
+            Assertions.assertEquals("root", response.body().string());
+        }
+    }
+
+    private Response send(Request request) throws Exception {
+        return CLIENT.newCall(request).execute();
+    }
+
+    @Configuration(proxyBeanMethods = false)
+    @EnableAutoConfiguration
+    @Import({WebConfigurer.class, WebServerFactoryCustomizerConfig.class,
+            RestApiExceptionHandler.class, CompatibilityController.class})
+    public static class TestApplication {
+    }
+
+    @RestController
+    public static class CompatibilityController {
+        @GetMapping("/api/dependency_compatibility")
+        public LegacyPayload get(@RequestParam("q") String query) {
+            return new LegacyPayload(query, LocalDate.of(2026, 10, 10));
+        }
+
+        @PostMapping("/api/dependency_compatibility")
+        public LegacyPayload post(@RequestBody LegacyPayload payload, 
HttpServletRequest request) {
+            return new LegacyPayload(payload.value() + ":" + 
request.getParameter("q"), payload.date());
+        }
+
+        @GetMapping("/api/dependency_cookie")
+        public String cookie(HttpServletResponse response) {
+            Cookie cookie = new Cookie("compatibility_session", "value");
+            cookie.setHttpOnly(true);
+            cookie.setAttribute("SameSite", "Lax");
+            response.addCookie(cookie);
+            return "ok";
+        }
+
+        @GetMapping("/rest/v1/dependency_compatibility")
+        public String protectedEndpoint() {
+            return "authenticated";
+        }
+
+        @GetMapping("/")
+        public String root() {
+            return "root";
+        }
+    }
+
+    public static class LegacyPayload {
+        private final String value;
+        private final LocalDate date;
+
+        @JsonCreator
+        public LegacyPayload(@JsonProperty("snake_case") String value, 
@JsonProperty("date") LocalDate date) {
+            this.value = value;
+            this.date = date;
+        }
+
+        @JsonProperty("snake_case")
+        public String value() {
+            return value;
+        }
+
+        @JsonProperty("date")
+        public LocalDate date() {
+            return date;
+        }
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/ldap/LdapClientTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/ldap/LdapClientTest.java
index 26695c687c7..0f8ebd5e11e 100644
--- 
a/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/ldap/LdapClientTest.java
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/mysql/authenticate/ldap/LdapClientTest.java
@@ -171,8 +171,8 @@ public class LdapClientTest {
         String expected = "test\\2a\\28\\29\\5c\\00";
         Assert.assertEquals(expected, LdapEncoder.filterEncode(input));
 
-        // Null input
-        Assert.assertNull(LdapEncoder.filterEncode(null));
+        // Spring LDAP 4 requires a non-null value.
+        Assert.assertThrows(NullPointerException.class, () -> 
LdapEncoder.filterEncode(null));
 
         // Normal username should not be altered
         Assert.assertEquals("zhangsan", LdapEncoder.filterEncode("zhangsan"));
diff --git a/fe/pom.xml b/fe/pom.xml
index 556c47639a6..9aa56bb2712 100644
--- a/fe/pom.xml
+++ b/fe/pom.xml
@@ -258,7 +258,6 @@ under the License.
         <skip.plugin>false</skip.plugin>
         <sonar.organization>apache</sonar.organization>
         <sonar.host.url>https://sonarcloud.io</sonar.host.url>
-        <cglib.version>2.2</cglib.version>
         <commons-cli.version>1.4</commons-cli.version>
         <commons-filerupload.version>1.6.0</commons-filerupload.version>
         <commons-configuration2.version>2.15.1</commons-configuration2.version>
@@ -277,10 +276,7 @@ under the License.
         <jackson.version>2.21.5</jackson.version>
         <javassist.version>3.18.2-GA</javassist.version>
         <javax.servlet-api.version>3.1.0</javax.servlet-api.version>
-        <!-- Jetty 12.0.38 (jetty-ee10-servlet) invokes 
jakarta.servlet.http.Cookie#getAttributes(),
-             which only exists since Jakarta Servlet 6.1. Pin the API to 6.1.0 
so it matches the
-             jetty version; otherwise the transitive 6.0.0 from spring-boot 
triggers NoSuchMethodError
-             when the FE HTTP server writes a Set-Cookie (SameSite) header. -->
+        <!-- Spring Framework 7 and Jetty EE11 require Jakarta Servlet 6.1. -->
         <jakarta.servlet-api.version>6.1.0</jakarta.servlet-api.version>
         <je.version>18.3.14-doris-SNAPSHOT</je.version>
         <jmockit.version>1.49</jmockit.version>
@@ -290,10 +286,10 @@ under the License.
         <junit.version>5.14.1</junit.version>
         <hikaricp.version>6.0.0</hikaricp.version>
         <thrift.version>0.24.0</thrift.version>
-        <tomcat-embed.version>9.0.104</tomcat-embed.version>
         <log4j2.version>2.25.5</log4j2.version>
         <log4j-1.2.version>2.25.5</log4j-1.2.version>
         <mqtt.version>1.2.5</mqtt.version>
+        
<jersey-apache-connector.version>3.1.11</jersey-apache-connector.version>
         <slf4j.version>2.0.17</slf4j.version>
         <metrics-core.version>4.0.2</metrics-core.version>
         <resilience4j.version>2.4.0</resilience4j.version>
@@ -328,7 +324,7 @@ under the License.
         <jetty-servlet.version>11.0.26</jetty-servlet.version>
         <jetty-websocket.version>9.4.58.v20250814</jetty-websocket.version>
         <okhttp.version>5.3.2</okhttp.version>
-        <snakeyaml.version>2.0</snakeyaml.version>
+        <snakeyaml.version>2.6</snakeyaml.version>
         <validation-api.version>2.0.1.Final</validation-api.version>
         <zjsonpatch.version>0.2.3</zjsonpatch.version>
         <kafka-clients.version>3.4.0</kafka-clients.version>
@@ -387,12 +383,12 @@ under the License.
         <antlr4.version>4.13.1</antlr4.version>
         <joda.version>2.8.1</joda.version>
         <project.scm.id>github</project.scm.id>
-        <!-- Spring Boot 3.5.16 manages fixed Spring LDAP 3.3.8, Spring Data 
3.5.13,
-             Micrometer 1.15.12, and Logback 1.5.34 releases for their 2026 
advisories. -->
-        <spring.version>3.5.16</spring.version>
-        <!-- Spring Framework 6.2.19 fixes the June 2026 security advisory 
set, including
-             CVE-2026-41848; keep the explicit framework BOM aligned with that 
release. -->
-        <spring-framework.version>6.2.19</spring-framework.version>
+        <!-- Boot 3.5 and Framework 6.2 have ended OSS support. Boot 4.1 
manages the
+             supported Spring LDAP and Spring Data generations. -->
+        <spring.version>4.1.1</spring.version>
+        <!-- 7.0.9 provides OSS fixes for the August 2026 advisories, including
+             CVE-2026-47883, CVE-2026-47889, and CVE-2026-47890. -->
+        <spring-framework.version>7.0.9</spring-framework.version>
         <orc.version>1.8.4</orc.version>
         <zookeeper.version>3.9.3</zookeeper.version>
         <velocity-engine-core.version>2.4</velocity-engine-core.version>
@@ -404,9 +400,8 @@ under the License.
         <woodstox.version>6.5.1</woodstox.version>
         <kerby.version>2.0.3</kerby.version>
         <jettison.version>1.5.4</jettison.version>
-        <!-- Jetty 12.0.34 is affected by CVE-2026-6790, CVE-2026-8384,
-             CVE-2026-10050, and CVE-2026-10051; 12.0.38 contains all 
published fixes. -->
-        <jetty.version>12.0.38</jetty.version>
+        <!-- Spring Framework 7 uses the Servlet 6.1 / Jetty EE11 baseline. -->
+        <jetty.version>12.1.14</jetty.version>
         <jetty-http.version>11.0.26</jetty-http.version>
         <!-- org.lz4:lz4-java is archived and vulnerable through its final 
1.8.x line.
              Resolve its official 1.8.1 relocation POM, then manage the 
maintained coordinate at
@@ -580,11 +575,10 @@ under the License.
                 <scope>import</scope>
                 <type>pom</type>
             </dependency>
-            <!-- The core Jetty BOM does not manage Jakarta EE 10 artifacts; 
import the matching
-                 EE10 BOM before Spring Boot so the complete Jetty 12 graph 
stays on 12.0.38. -->
+            <!-- Align the EE11 servlet modules with the core Jetty BOM before 
Spring Boot. -->
             <dependency>
-                <groupId>org.eclipse.jetty.ee10</groupId>
-                <artifactId>jetty-ee10-bom</artifactId>
+                <groupId>org.eclipse.jetty.ee11</groupId>
+                <artifactId>jetty-ee11-bom</artifactId>
                 <version>${jetty.version}</version>
                 <scope>import</scope>
                 <type>pom</type>
@@ -736,13 +730,19 @@ under the License.
             </dependency>
             <dependency>
                 <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-starter-web</artifactId>
+                <artifactId>spring-boot-starter-webmvc</artifactId>
                 <version>${spring.version}</version>
                 <exclusions>
                     <exclusion>
                         <groupId>org.springframework.boot</groupId>
                         <artifactId>spring-boot-starter-tomcat</artifactId>
                     </exclusion>
+                    <!-- Keep the FE's Jackson 2 HTTP serialization while its 
catalog and
+                         filesystem dependencies still use Jackson 2. -->
+                    <exclusion>
+                        <groupId>org.springframework.boot</groupId>
+                        <artifactId>spring-boot-starter-jackson</artifactId>
+                    </exclusion>
                     <exclusion>
                         <groupId>validator</groupId>
                         <artifactId>hibernate-validator</artifactId>
@@ -786,6 +786,11 @@ under the License.
                         <groupId>org.apache.hadoop</groupId>
                         <artifactId>hadoop-yarn-api</artifactId>
                     </exclusion>
+                    <!-- Doris does not use YARN; its client brings EOL Jetty 
9 WebSocket jars. -->
+                    <exclusion>
+                        <groupId>org.apache.hadoop</groupId>
+                        <artifactId>hadoop-yarn-client</artifactId>
+                    </exclusion>
                     <exclusion>
                         <groupId>org.slf4j</groupId>
                         <artifactId>slf4j-reload4j</artifactId>
@@ -855,18 +860,6 @@ under the License.
                 <artifactId>fe-common</artifactId>
                 <version>${project.version}</version>
             </dependency>
-            <!-- https://mvnrepository.com/artifact/cglib/cglib -->
-            <dependency>
-                <groupId>cglib</groupId>
-                <artifactId>cglib</artifactId>
-                <version>${cglib.version}</version>
-                <exclusions>
-                    <exclusion>
-                        <artifactId>asm</artifactId>
-                        <groupId>asm</groupId>
-                    </exclusion>
-                </exclusions>
-            </dependency>
             <!-- https://mvnrepository.com/artifact/commons-cli/commons-cli -->
             <dependency>
                 <groupId>commons-cli</groupId>
@@ -1095,6 +1088,14 @@ under the License.
                -->
                <scope>provided</scope>
             </dependency>
+            <!-- bce-java-sdk also depends on the Jersey Apache HttpClient 4 
connector. Jersey 4,
+                 managed by Spring Boot 4, no longer provides it, so the SDK 
would fall back to its
+                 own 2.9.1 and bring javax.ws.rs-api 2.0 with it. Keep the 3.1 
release instead. -->
+            <dependency>
+                <groupId>org.glassfish.jersey.connectors</groupId>
+                <artifactId>jersey-apache-connector</artifactId>
+                <version>${jersey-apache-connector.version}</version>
+            </dependency>
             <!-- velocity-engine-core dependency-->
             <dependency>
                 <groupId>org.apache.velocity</groupId>
@@ -1779,12 +1780,6 @@ under the License.
                 <artifactId>joda-time</artifactId>
                 <version>${joda.version}</version>
             </dependency>
-            <!--tomcat-->
-            <dependency>
-                <groupId>org.apache.tomcat.embed</groupId>
-                <artifactId>tomcat-embed-el</artifactId>
-                <version>${tomcat-embed.version}</version>
-            </dependency>
             <dependency>
                 <groupId>io.netty</groupId>
                 <artifactId>netty-tcnative-boringssl-static</artifactId>
@@ -1921,7 +1916,7 @@ under the License.
                         <artifactId>okio</artifactId>
                     </exclusion>
                     <!-- Trino 435 pulls a Servlet 5.0 API repackage that 
shadows Jakarta Servlet
-                         6.1 on the FE classpath and breaks Jetty 12.0.38 
cookie handling. -->
+                         6.1 on the FE classpath and breaks Jetty EE11 cookie 
handling. -->
                     <exclusion>
                         <groupId>org.eclipse.jetty.toolchain</groupId>
                         <artifactId>jetty-jakarta-servlet-api</artifactId>


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

Reply via email to