Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main'
Browse files Browse the repository at this point in the history
# Conflicts:
#	spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/handler/predicate/PathRoutePredicateFactory.java
  • Loading branch information
Guofuyinan committed Nov 24, 2024
2 parents 754db49 + cd15734 commit df11e83
Show file tree
Hide file tree
Showing 83 changed files with 1,132 additions and 205 deletions.
4 changes: 2 additions & 2 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ author credit if we do. Active contributors might be asked to join the core tea
given the ability to merge pull requests.

## Code of Conduct
This project adheres to the Contributor Covenant [Code of conduct](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report
This project adheres to the Contributor Covenant [Code of conduct](https://github.com/spring-cloud/spring-cloud-build/blob/main/docs/modules/ROOT/partials/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report
unacceptable behavior to [email protected].

## Code Conventions and Housekeeping
Expand All @@ -41,4 +41,4 @@ added after the original pull request but before a merge.
other target branch in the main project).
* When writing a commit message please follow [these conventions](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html),
if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit
message (where XXXX is the issue number).
message (where XXXX is the issue number).
2 changes: 1 addition & 1 deletion .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
- name: Build with Maven
run: ./mvnw clean install -B -U -Pspring -Dmaven.test.redirectTestOutputToFile=true -Dmaven.wagon.http.pool=false -Dmaven.wagon.httpconnectionManager.ttlSeconds=120
- name: Publish Test Report
uses: mikepenz/action-junit-report@v4
uses: mikepenz/action-junit-report@v5
if: always() # always run even if the previous step fails
with:
report_paths: '**/surefire-reports/TEST-*.xml'
4 changes: 2 additions & 2 deletions README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ given the ability to merge pull requests.

[[code-of-conduct]]
== Code of Conduct
This project adheres to the Contributor Covenant https://github.com/spring-cloud/spring-cloud-build/blob/main/docs/src/main/asciidoc/code-of-conduct.adoc[code of
This project adheres to the Contributor Covenant https://github.com/spring-cloud/spring-cloud-build/blob/main/docs/modules/ROOT/partials/code-of-conduct.adoc[code of
conduct]. By participating, you are expected to uphold this code. Please report
unacceptable behavior to spring-code-of-conduct@pivotal.io.
unacceptable behavior to code-of-conduct@spring.io.

[[code-conventions-and-housekeeping]]
== Code Conventions and Housekeeping
Expand Down
2 changes: 1 addition & 1 deletion docs/modules/ROOT/nav.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
//*** xref:spring-cloud-gateway-server-mvc/filters/local-cache-response-filter.adoc[]
*** xref:spring-cloud-gateway-server-mvc/filters/maprequestheader.adoc[]
*** xref:spring-cloud-gateway-server-mvc/filters/modifyrequestbody.adoc[]
//*** xref:spring-cloud-gateway-server-mvc/filters/modifyresponsebody.adoc[]
*** xref:spring-cloud-gateway-server-mvc/filters/modifyresponsebody.adoc[]
*** xref:spring-cloud-gateway-server-mvc/filters/prefixpath.adoc[]
*** xref:spring-cloud-gateway-server-mvc/filters/preservehostheader.adoc[]
*** xref:spring-cloud-gateway-server-mvc/filters/redirectto.adoc[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ The following listing shows how to modify a response body filter:
[source,java]
----
@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
return builder.routes()
.route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org")
.filters(f -> f.prefixPath("/httpbin")
.modifyResponseBody(String.class, String.class,
(exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri))
.build();
public RouterFunction<ServerResponse> gatewayRouterFunctionsModifyResponseBodySimple() {
return route("modify_response_body")
.GET("/anything/modifyresponsebody", http())
.before(new HttpbinUriResolver())
.after(modifyResponseBody(String.class, String.class, null,
(request, response, s) -> s.replace("fooval", "FOOVAL")))
.build();
}
----
.GatewaySampleApplication.java
Expand All @@ -35,12 +35,9 @@ class RouteConfiguration {
public RouterFunction<ServerResponse> gatewayRouterFunctionsAddReqHeader() {
return route("rewrite_request_obj")
.route(host("*.rewriterequestobj.org"), http("https://example.org"))
.before(modifyResponseBody(String.class, String.class, MediaType.APPLICATION_JSON_VALUE, (request, s) -> s.toUpperCase()))
.before(modifyResponseBody(String.class, String.class, MediaType.APPLICATION_JSON_VALUE, (request, response, s) -> s.toUpperCase()))
.build();
}
}
----

NOTE: If the response has no body, the `RewriteFilter` is passed `null`. `Mono.empty()` should be returned to assign a missing body in the response.

Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
= Configuration properties
:page-section-summary-toc: 1

To see the list of all Spring Cloud Gateway related configuration properties, see link:appendix.html[the appendix].
To see the list of all Spring Cloud Gateway related configuration properties, see link:../appendix.html[the appendix].
3 changes: 3 additions & 0 deletions docs/modules/ROOT/partials/_configprops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
|spring.cloud.gateway.httpclient.max-initial-line-length | | The max initial line length.
|spring.cloud.gateway.httpclient.pool.acquire-timeout | | Only for type FIXED, the maximum time in millis to wait for acquiring.
|spring.cloud.gateway.httpclient.pool.eviction-interval | `+++0+++` | Perform regular eviction checks in the background at a specified interval. Disabled by default ({@link Duration#ZERO})
|spring.cloud.gateway.httpclient.pool.leasing-strategy | `+++fifo+++` | Configures the leasing strategy for the pool, defaults to FIFO which is Netty's default.
|spring.cloud.gateway.httpclient.pool.max-connections | | Only for type FIXED, the maximum number of connections before starting pending acquisition on existing ones.
|spring.cloud.gateway.httpclient.pool.max-idle-time | | Time in millis after which the channel will be closed. If NULL, there is no max idle time.
|spring.cloud.gateway.httpclient.pool.max-life-time | | Duration after which the channel will be closed. If NULL, there is no max life time.
Expand All @@ -105,6 +106,7 @@
|spring.cloud.gateway.httpclient.ssl.key-store-password | | Keystore password.
|spring.cloud.gateway.httpclient.ssl.key-store-provider | | Keystore provider for Netty HttpClient, optional field.
|spring.cloud.gateway.httpclient.ssl.key-store-type | `+++JKS+++` | Keystore type for Netty HttpClient, default is JKS.
|spring.cloud.gateway.httpclient.ssl.ssl-bundle | | The name of the SSL bundle to use.
|spring.cloud.gateway.httpclient.ssl.trusted-x509-certificates | | Trusted certificates for verifying the remote endpoint's certificate.
|spring.cloud.gateway.httpclient.ssl.use-insecure-trust-manager | `+++false+++` | Installs the netty InsecureTrustManagerFactory. This is insecure and not suitable for production.
|spring.cloud.gateway.httpclient.websocket.max-frame-payload-length | | Max frame payload length.
Expand Down Expand Up @@ -166,6 +168,7 @@
|spring.cloud.gateway.redis-rate-limiter.requested-tokens-header | `+++X-RateLimit-Requested-Tokens+++` | The name of the header that returns the requested tokens configuration.
|spring.cloud.gateway.redis-route-definition-repository.enabled | `+++true+++` | If RedisRouteDefinitionRepository should be enabled.
|spring.cloud.gateway.restrictive-property-accessor.enabled | `+++true+++` | Restricts method and property access in SpEL.
|spring.cloud.gateway.route-filter-cache-enabled | `+++false+++` | Enables the route filter cache, defaults to false.
|spring.cloud.gateway.route-refresh-listener.enabled | `+++true+++` | If RouteRefreshListener should be turned on.
|spring.cloud.gateway.routes | | List of Routes.
|spring.cloud.gateway.set-status.original-status-header-name | | The name of the header which contains http code of the proxied request.
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<bucket4j.version>8.10.1</bucket4j.version>
<blockhound.version>1.0.8.RELEASE</blockhound.version>
<java.version>17</java.version>
<junit-pioneer.version>2.2.0</junit-pioneer.version>
<junit-pioneer.version>2.3.0</junit-pioneer.version>
<spring-cloud-circuitbreaker.version>3.2.0-SNAPSHOT</spring-cloud-circuitbreaker.version>
<spring-cloud-commons.version>4.2.0-SNAPSHOT</spring-cloud-commons.version>
</properties>
Expand Down
2 changes: 1 addition & 1 deletion spring-cloud-gateway-integration-tests/grpc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<properties>
<protoc.version>3.25.1</protoc.version>
<grpc.version>1.64.0</grpc.version>
<grpc.version>1.68.1</grpc.version>
</properties>

<parent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.Vector;
import java.util.function.Function;
Expand Down Expand Up @@ -234,7 +235,7 @@ public ProxyExchange<T> excluded(String... names) {

this.excluded.clear();
for (String name : names) {
this.excluded.add(name.toLowerCase());
this.excluded.add(name.toLowerCase(Locale.ROOT));
}
return this;
}
Expand Down Expand Up @@ -384,7 +385,7 @@ private Set<String> filterHeaderKeys(HttpHeaders headers) {
private Set<String> filterHeaderKeys(Collection<String> headerNames) {
final Set<String> excludedHeaders = this.excluded != null ? this.excluded : Collections.emptySet();
return headerNames.stream()
.filter(header -> !excludedHeaders.contains(header.toLowerCase()))
.filter(header -> !excludedHeaders.contains(header.toLowerCase(Locale.ROOT)))
.collect(Collectors.toSet());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.lang.reflect.Type;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Set;

import jakarta.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -101,7 +102,7 @@ private HttpHeaders extractAutoForwardedHeaders(NativeWebRequest webRequest) {
HttpHeaders headers = new HttpHeaders();
while (headerNames.hasMoreElements()) {
String header = headerNames.nextElement();
if (this.autoForwardedHeaders.contains(header.toLowerCase())) {
if (this.autoForwardedHeaders.contains(header.toLowerCase(Locale.ROOT))) {
headers.addAll(header, Collections.list(nativeRequest.getHeaders(header)));
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.cloud.gateway.sample;

import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;

Expand Down Expand Up @@ -77,7 +78,7 @@ public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
.addResponseHeader("X-TestHeader", "rewrite_request")
.modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
(exchange, s) -> {
return Mono.just(new Hello(s.toUpperCase()));
return Mono.just(new Hello(s.toUpperCase(Locale.ROOT)));
})
).uri(uri)
)
Expand All @@ -86,7 +87,7 @@ public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
.addResponseHeader("X-TestHeader", "rewrite_request_upper")
.modifyRequestBody(String.class, String.class,
(exchange, s) -> {
return Mono.just(s.toUpperCase() + s.toUpperCase());
return Mono.just(s.toUpperCase(Locale.ROOT) + s.toUpperCase(Locale.ROOT));
})
).uri(uri)
)
Expand All @@ -95,7 +96,7 @@ public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
.addResponseHeader("X-TestHeader", "rewrite_response_upper")
.modifyResponseBody(String.class, String.class,
(exchange, s) -> {
return Mono.just(s.toUpperCase());
return Mono.just(s.toUpperCase(Locale.ROOT));
})
).uri(uri)
)
Expand All @@ -107,7 +108,7 @@ public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
if (s == null) {
return Mono.just("emptybody");
}
return Mono.just(s.toUpperCase());
return Mono.just(s.toUpperCase(Locale.ROOT));
})

).uri(uri)
Expand All @@ -120,7 +121,7 @@ public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
if (s == null) {
return Mono.error(new IllegalArgumentException("this should not happen"));
}
return Mono.just(s.toUpperCase());
return Mono.just(s.toUpperCase(Locale.ROOT));
})
).uri(uri)
)
Expand Down
5 changes: 5 additions & 0 deletions spring-cloud-gateway-server-mvc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-properties-migrator</artifactId>
<scope>test</scope>
</dependency>
<!-- Third party test dependencies -->
<dependency>
<groupId>com.bucket4j</groupId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,19 @@

package org.springframework.cloud.gateway.server.mvc;

import java.util.Map;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.http.client.HttpClientAutoConfiguration;
import org.springframework.boot.autoconfigure.http.client.HttpClientProperties.Factory;
import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration;
import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.boot.web.client.ClientHttpRequestFactories;
import org.springframework.boot.web.client.ClientHttpRequestFactorySettings;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.http.client.ClientHttpRequestFactorySettings.Redirects;
import org.springframework.boot.web.client.RestClientCustomizer;
import org.springframework.cloud.gateway.server.mvc.common.ArgumentSupplierBeanPostProcessor;
import org.springframework.cloud.gateway.server.mvc.config.GatewayMvcAotRuntimeHintsRegistrar;
Expand All @@ -52,9 +55,11 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.JdkClientHttpRequestFactory;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestClient;

Expand All @@ -64,7 +69,8 @@
* @author Spencer Gibb
* @author Jürgen Wißkirchen
*/
@AutoConfiguration(after = { RestTemplateAutoConfiguration.class, RestClientAutoConfiguration.class })
@AutoConfiguration(after = { HttpClientAutoConfiguration.class, RestTemplateAutoConfiguration.class,
RestClientAutoConfiguration.class })
@ConditionalOnProperty(name = "spring.cloud.gateway.mvc.enabled", matchIfMissing = true)
@Import(GatewayMvcPropertiesBeanDefinitionRegistrar.class)
@ImportRuntimeHints(GatewayMvcAotRuntimeHintsRegistrar.class)
Expand All @@ -82,8 +88,12 @@ public RouterFunctionHolderFactory routerFunctionHolderFactory(Environment env)
}

@Bean
public RestClientCustomizer gatewayRestClientCustomizer(ClientHttpRequestFactory requestFactory) {
return restClientBuilder -> restClientBuilder.requestFactory(requestFactory);
public RestClientCustomizer gatewayRestClientCustomizer(
ObjectProvider<ClientHttpRequestFactory> requestFactoryProvider) {
return restClientBuilder -> {
// for backwards compatibility if user overrode
requestFactoryProvider.ifAvailable(restClientBuilder::requestFactory);
};
}

@Bean
Expand All @@ -108,36 +118,6 @@ public ForwardedRequestHeadersFilter forwardedRequestHeadersFilter() {
return new ForwardedRequestHeadersFilter();
}

@Bean
@ConditionalOnMissingBean
public ClientHttpRequestFactory gatewayClientHttpRequestFactory(GatewayMvcProperties gatewayMvcProperties,
SslBundles sslBundles) {
GatewayMvcProperties.HttpClient properties = gatewayMvcProperties.getHttpClient();

SslBundle sslBundle = null;
if (StringUtils.hasText(properties.getSslBundle())) {
sslBundle = sslBundles.getBundle(properties.getSslBundle());
}
ClientHttpRequestFactorySettings settings = new ClientHttpRequestFactorySettings(properties.getConnectTimeout(),
properties.getReadTimeout(), sslBundle);

if (properties.getType() == GatewayMvcProperties.HttpClientType.JDK) {
// TODO: customize restricted headers
String restrictedHeaders = System.getProperty("jdk.httpclient.allowRestrictedHeaders");
if (!StringUtils.hasText(restrictedHeaders)) {
System.setProperty("jdk.httpclient.allowRestrictedHeaders", "host");
}
else if (StringUtils.hasText(restrictedHeaders) && !restrictedHeaders.contains("host")) {
System.setProperty("jdk.httpclient.allowRestrictedHeaders", restrictedHeaders + ",host");
}

return ClientHttpRequestFactories.get(JdkClientHttpRequestFactory.class, settings);
}

// Autodetect
return ClientHttpRequestFactories.get(settings);
}

@Bean
@ConditionalOnMissingBean
public GatewayMvcProperties gatewayMvcProperties() {
Expand Down Expand Up @@ -219,4 +199,46 @@ public XForwardedRequestHeadersFilterProperties xForwardedRequestHeadersFilterPr
return new XForwardedRequestHeadersFilterProperties();
}

static class GatewayHttpClientEnvironmentPostProcessor implements EnvironmentPostProcessor {

static final boolean APACHE = ClassUtils.isPresent("org.apache.hc.client5.http.impl.classic.HttpClients", null);
static final boolean JETTY = ClassUtils.isPresent("org.eclipse.jetty.client.HttpClient", null);
static final boolean REACTOR_NETTY = ClassUtils.isPresent("reactor.netty.http.client.HttpClient", null);
static final boolean JDK = ClassUtils.isPresent("java.net.http.HttpClient", null);
static final boolean HIGHER_PRIORITY = APACHE || JETTY || REACTOR_NETTY;

@Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
Redirects redirects = environment.getProperty("spring.http.client.redirects", Redirects.class);
if (redirects == null) {
// the user hasn't set anything, change the default
environment.getPropertySources()
.addFirst(new MapPropertySource("gatewayHttpClientProperties",
Map.of("spring.http.client.redirects", Redirects.DONT_FOLLOW)));
}
Factory factory = environment.getProperty("spring.http.client.factory", Factory.class);
boolean setJdkHttpClientProperties = false;

if (factory == null && !HIGHER_PRIORITY) {
// autodetect
setJdkHttpClientProperties = JDK;
}
else if (factory == Factory.JDK) {
setJdkHttpClientProperties = JDK;
}

if (setJdkHttpClientProperties) {
// TODO: customize restricted headers
String restrictedHeaders = System.getProperty("jdk.httpclient.allowRestrictedHeaders");
if (!StringUtils.hasText(restrictedHeaders)) {
System.setProperty("jdk.httpclient.allowRestrictedHeaders", "host");
}
else if (StringUtils.hasText(restrictedHeaders) && !restrictedHeaders.contains("host")) {
System.setProperty("jdk.httpclient.allowRestrictedHeaders", restrictedHeaders + ",host");
}
}
}

}

}
Loading

0 comments on commit df11e83

Please sign in to comment.