4 changed files with 180 additions and 0 deletions
@ -0,0 +1,63 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2013-2022 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.openfeign.loadbalancer; |
||||||
|
|
||||||
|
import java.net.URI; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import feign.Request; |
||||||
|
|
||||||
|
import org.springframework.cloud.client.ServiceInstance; |
||||||
|
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties; |
||||||
|
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer; |
||||||
|
|
||||||
|
/** |
||||||
|
* To add X-Forwarded-Host and X-Forwarded-Proto Headers. |
||||||
|
* |
||||||
|
* @author changjin wei(魏昌进) |
||||||
|
*/ |
||||||
|
public class XForwardedHeadersTransformer implements LoadBalancerFeignRequestTransformer { |
||||||
|
|
||||||
|
private final ReactiveLoadBalancer.Factory<ServiceInstance> factory; |
||||||
|
|
||||||
|
public XForwardedHeadersTransformer(ReactiveLoadBalancer.Factory<ServiceInstance> factory) { |
||||||
|
this.factory = factory; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Request transformRequest(Request request, ServiceInstance instance) { |
||||||
|
if (instance == null) { |
||||||
|
return request; |
||||||
|
} |
||||||
|
LoadBalancerProperties.XForwarded xForwarded = factory.getProperties(instance.getServiceId()).getXForwarded(); |
||||||
|
if (xForwarded.isEnabled()) { |
||||||
|
Map<String, Collection<String>> headers = new HashMap<>(request.headers()); |
||||||
|
URI uri = URI.create(request.url()); |
||||||
|
String xForwardedHost = uri.getHost(); |
||||||
|
String xForwardedProto = uri.getScheme(); |
||||||
|
headers.put("X-Forwarded-Host", Collections.singleton(xForwardedHost)); |
||||||
|
headers.put("X-Forwarded-Proto", Collections.singleton(xForwardedProto)); |
||||||
|
request = Request.create(request.httpMethod(), request.url(), headers, request.body(), request.charset(), |
||||||
|
request.requestTemplate()); |
||||||
|
} |
||||||
|
return request; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,98 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2013-2022 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.openfeign.loadbalancer; |
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import feign.Request; |
||||||
|
import org.junit.jupiter.api.Test; |
||||||
|
|
||||||
|
import org.springframework.cloud.client.DefaultServiceInstance; |
||||||
|
import org.springframework.cloud.client.ServiceInstance; |
||||||
|
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties; |
||||||
|
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; |
||||||
|
import org.springframework.http.HttpHeaders; |
||||||
|
import org.springframework.http.MediaType; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.mockito.Mockito.mock; |
||||||
|
import static org.mockito.Mockito.when; |
||||||
|
|
||||||
|
/** |
||||||
|
* Tests for |
||||||
|
* {@link XForwardedHeadersTransformer}. |
||||||
|
* |
||||||
|
* @author changjin wei(魏昌进) |
||||||
|
*/ |
||||||
|
class XForwardedHeadersTransformerTests { |
||||||
|
|
||||||
|
private final LoadBalancerClientFactory loadBalancerClientFactory = mock(LoadBalancerClientFactory.class); |
||||||
|
|
||||||
|
private final LoadBalancerProperties loadBalancerProperties = new LoadBalancerProperties(); |
||||||
|
|
||||||
|
private final ServiceInstance serviceInstance = new DefaultServiceInstance("test1", "test", "test.org", 8080, |
||||||
|
false); |
||||||
|
|
||||||
|
private final Request request = testRequest(); |
||||||
|
|
||||||
|
private Request testRequest() { |
||||||
|
return testRequest("spring.io"); |
||||||
|
} |
||||||
|
|
||||||
|
private Request testRequest(String host) { |
||||||
|
return Request.create(Request.HttpMethod.GET, "https://" + host + "/path", testHeaders(), "hello".getBytes(), |
||||||
|
StandardCharsets.UTF_8, null); |
||||||
|
} |
||||||
|
|
||||||
|
private Map<String, Collection<String>> testHeaders() { |
||||||
|
Map<String, Collection<String>> feignHeaders = new HashMap<>(); |
||||||
|
feignHeaders.put(HttpHeaders.CONTENT_TYPE, Collections.singletonList(MediaType.APPLICATION_JSON_VALUE)); |
||||||
|
return feignHeaders; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void shouldAppendXForwardedHeadersIfEnabled() { |
||||||
|
loadBalancerProperties.getXForwarded().setEnabled(true); |
||||||
|
when(loadBalancerClientFactory.getProperties("test")).thenReturn(loadBalancerProperties); |
||||||
|
XForwardedHeadersTransformer transformer = new XForwardedHeadersTransformer(loadBalancerClientFactory); |
||||||
|
|
||||||
|
Request newRequest = transformer.transformRequest(request, serviceInstance); |
||||||
|
|
||||||
|
assertThat(newRequest.headers()).containsKey("X-Forwarded-Host"); |
||||||
|
assertThat(newRequest.headers()).containsEntry("X-Forwarded-Host", Collections.singleton("spring.io")); |
||||||
|
assertThat(newRequest.headers()).containsKey("X-Forwarded-Proto"); |
||||||
|
assertThat(newRequest.headers()).containsEntry("X-Forwarded-Proto", Collections.singleton("https")); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
void shouldNotAppendXForwardedHeadersIfDefault() { |
||||||
|
when(loadBalancerClientFactory.getProperties("test")).thenReturn(loadBalancerProperties); |
||||||
|
XForwardedHeadersTransformer transformer = new XForwardedHeadersTransformer(loadBalancerClientFactory); |
||||||
|
|
||||||
|
Request newRequest = transformer.transformRequest(request, serviceInstance); |
||||||
|
|
||||||
|
assertThat(newRequest.headers()).doesNotContainKey("X-Forwarded-Host"); |
||||||
|
assertThat(newRequest.headers()).doesNotContainKey("X-Forwarded-Proto"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue