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]