diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java index a3e94fac..20e5ff68 100644 --- a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfiguration.java @@ -39,6 +39,7 @@ import org.springframework.cloud.gateway.server.mvc.filter.HttpHeadersFilter.Res import org.springframework.cloud.gateway.server.mvc.filter.RemoveContentLengthRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.RemoveHopByHopRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.RemoveHopByHopResponseHeadersFilter; +import org.springframework.cloud.gateway.server.mvc.filter.RemoveHttp2StatusResponseHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.TransferEncodingNormalizationRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.WeightCalculatorFilter; import org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilter; @@ -163,6 +164,14 @@ public class GatewayServerMvcAutoConfiguration { return new RemoveContentLengthRequestHeadersFilter(); } + @Bean + @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = GatewayMvcProperties.PREFIX, + name = "remove-http2-status-response-headers-filter.enabled", matchIfMissing = true) + public RemoveHttp2StatusResponseHeadersFilter removeHttp2StatusResponseHeadersFilter() { + return new RemoveHttp2StatusResponseHeadersFilter(); + } + @Bean @ConditionalOnMissingBean @ConditionalOnProperty(prefix = GatewayMvcProperties.PREFIX, diff --git a/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RemoveHttp2StatusResponseHeadersFilter.java b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RemoveHttp2StatusResponseHeadersFilter.java new file mode 100644 index 00000000..36551378 --- /dev/null +++ b/spring-cloud-gateway-server-mvc/src/main/java/org/springframework/cloud/gateway/server/mvc/filter/RemoveHttp2StatusResponseHeadersFilter.java @@ -0,0 +1,44 @@ +/* + * Copyright 2013-2023 the original author or authors. + * + * Licensed 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 + * + * https://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.springframework.cloud.gateway.server.mvc.filter; + +import org.springframework.core.Ordered; +import org.springframework.http.HttpHeaders; +import org.springframework.web.servlet.function.ServerResponse; + +// jdk http client add the :status pseudo-header to the response. +// Copying this header to an upstream HTTP/2 connection will cause a protocol error. +public class RemoveHttp2StatusResponseHeadersFilter implements HttpHeadersFilter.ResponseHttpHeadersFilter, Ordered { + + @Override + public int getOrder() { + return 1000; + } + + @Override + public HttpHeaders apply(HttpHeaders input, ServerResponse serverResponse) { + if (input.containsKey(":status")) { + + HttpHeaders filtered = new HttpHeaders(); + filtered.addAll(input); + filtered.remove(":status"); + return filtered; + } + return input; + } + +} diff --git a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java index e8c139e7..0cdce409 100644 --- a/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java +++ b/spring-cloud-gateway-server-mvc/src/test/java/org/springframework/cloud/gateway/server/mvc/GatewayServerMvcAutoConfigurationTests.java @@ -28,6 +28,7 @@ import org.springframework.cloud.gateway.server.mvc.filter.ForwardedRequestHeade import org.springframework.cloud.gateway.server.mvc.filter.RemoveContentLengthRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.RemoveHopByHopRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.RemoveHopByHopResponseHeadersFilter; +import org.springframework.cloud.gateway.server.mvc.filter.RemoveHttp2StatusResponseHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.TransferEncodingNormalizationRequestHeadersFilter; import org.springframework.cloud.gateway.server.mvc.filter.WeightCalculatorFilter; import org.springframework.cloud.gateway.server.mvc.filter.XForwardedRequestHeadersFilter; @@ -46,6 +47,7 @@ public class GatewayServerMvcAutoConfigurationTests { "spring.cloud.gateway.mvc.remove-content-length-request-headers-filter.enabled=false", "spring.cloud.gateway.mvc.remove-hop-by-hop-request-headers-filter.enabled=false", "spring.cloud.gateway.mvc.remove-hop-by-hop-response-headers-filter.enabled=false", + "spring.cloud.gateway.mvc.remove-http2-status-response-headers-filter.enabled=false", "spring.cloud.gateway.mvc.transfer-encoding-normalization-request-headers-filter.enabled=false", "spring.cloud.gateway.mvc.weight-calculator-filter.enabled=false", "spring.cloud.gateway.mvc.x-forwarded-request-headers-filter.enabled=false") @@ -55,6 +57,7 @@ public class GatewayServerMvcAutoConfigurationTests { assertThat(context).doesNotHaveBean(RemoveContentLengthRequestHeadersFilter.class); assertThat(context).doesNotHaveBean(RemoveHopByHopRequestHeadersFilter.class); assertThat(context).doesNotHaveBean(RemoveHopByHopResponseHeadersFilter.class); + assertThat(context).doesNotHaveBean(RemoveHttp2StatusResponseHeadersFilter.class); assertThat(context).doesNotHaveBean(TransferEncodingNormalizationRequestHeadersFilter.class); assertThat(context).doesNotHaveBean(WeightCalculatorFilter.class); assertThat(context).doesNotHaveBean(XForwardedRequestHeadersFilter.class);