INT-2455: Support HTTP Outbound 'encode-uri' Flag

The `<http:outbound-channel-adapter>` and `<http:outbound-gateway>` now provide
an `encode-uri` option that controls whether the request uri is encoded
(default `true`).

It can be useful in some scenarios with a non standard URL, e.g. RabbitMQ REST API:
'http://foo.RabbitMQ.com/api/queues/%2f/bar.queue' where we must not
encode the '%'.

https://jira.springsource.org/browse/INT-2455

INT-2455: Polishing based on PR comments

INT-2455: 'encode-uri' in the Reference Manual
This commit is contained in:
Artem Bilan
2013-02-26 13:34:32 +02:00
committed by Gary Russell
parent ab9b6fb1dd
commit bb77f508ec
8 changed files with 115 additions and 19 deletions

View File

@@ -9,15 +9,22 @@
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<si:chain input-channel="httpOutboundChannelAdapterWithinChain">
<outbound-channel-adapter url="http://localhost/test1" rest-template="restTemplate"/>
<outbound-channel-adapter url="http://localhost/test1/%2f" encode-uri="false" rest-template="restTemplate"/>
</si:chain>
<beans:bean id="restTemplate" class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandlerTests$MockRestTemplate2"/>
<beans:bean id="restTemplate" class="org.mockito.Mockito" factory-method="spy">
<beans:constructor-arg>
<beans:bean class="org.springframework.integration.http.outbound.HttpRequestExecutingMessageHandlerTests$MockRestTemplate2"/>
</beans:constructor-arg>
</beans:bean>
<si:chain input-channel="httpOutboundGatewayWithinChain" output-channel="replyChannel">
<outbound-gateway url="http://localhost:51235/testApps/httpOutboundGatewayWithinChain"
<outbound-gateway url="http://localhost:51235/%2f/testApps?param={param}"
rest-template="restTemplate"
expected-response-type="java.lang.String"/>
encode-uri="false"
expected-response-type="java.lang.String">
<uri-variable name="param" expression="T(org.apache.commons.httpclient.util.URIUtil).encodeWithinQuery('http Outbound Gateway Within Chain')"/>
</outbound-gateway>
</si:chain>
<si:channel id="replyChannel">

View File

@@ -29,6 +29,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
@@ -42,6 +43,7 @@ import javax.xml.transform.Source;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
@@ -673,23 +675,28 @@ public class HttpRequestExecutingMessageHandlerTests {
}
@Test //INT-2275
public void testOutboundChannelAdapterWithinChain() {
public void testOutboundChannelAdapterWithinChain() throws URISyntaxException {
ApplicationContext ctx = new ClassPathXmlApplicationContext("HttpOutboundWithinChainTests-context.xml", this.getClass());
MessageChannel channel = ctx.getBean("httpOutboundChannelAdapterWithinChain", MessageChannel.class);
RestTemplate restTemplate = ctx.getBean("restTemplate", RestTemplate.class);
channel.send(MessageBuilder.withPayload("test").build());
// It's just enough if it was sent successfully from chain without any failures
Mockito.verify(restTemplate).exchange(Mockito.eq(new URI("http://localhost/test1/%2f")), Mockito.eq(HttpMethod.POST),
Mockito.any(HttpEntity.class), Mockito.eq((Class<?>) null));
}
@Test //INT-1029
public void testHttpOutboundGatewayWithinChain() throws IOException {
public void testHttpOutboundGatewayWithinChain() throws IOException, URISyntaxException {
ApplicationContext ctx = new ClassPathXmlApplicationContext("HttpOutboundWithinChainTests-context.xml", this.getClass());
MessageChannel channel = ctx.getBean("httpOutboundGatewayWithinChain", MessageChannel.class);
RestTemplate restTemplate = ctx.getBean("restTemplate", RestTemplate.class);
channel.send(MessageBuilder.withPayload("test").build());
PollableChannel output = ctx.getBean("replyChannel", PollableChannel.class);
Message<?> receive = output.receive();
assertEquals(HttpStatus.OK, ((ResponseEntity<?>)receive.getPayload()).getStatusCode());
Mockito.verify(restTemplate)
.exchange(Mockito.eq(new URI("http://localhost:51235/%2f/testApps?param=http%20Outbound%20Gateway%20Within%20Chain")),
Mockito.eq(HttpMethod.POST), Mockito.any(HttpEntity.class), Mockito.eq(String.class));
}
@Test
@@ -698,7 +705,7 @@ public class HttpRequestExecutingMessageHandlerTests {
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler(
new SpelExpressionParser().parseExpression("headers['foo']"),
restTemplate);
String theURL = "http://bar/baz";
String theURL = "http://bar/baz?foo#bar";
Message<?> message = MessageBuilder.withPayload("").setHeader("foo", theURL).build();
try {
handler.handleRequestMessage(message);
@@ -707,6 +714,21 @@ public class HttpRequestExecutingMessageHandlerTests {
assertEquals(theURL, restTemplate.actualUrl.get());
}
@Test
public void testInt2455UriNotEncoded() {
MockRestTemplate restTemplate = new MockRestTemplate();
HttpRequestExecutingMessageHandler handler = new HttpRequestExecutingMessageHandler(
new SpelExpressionParser().parseExpression("'http://my.RabbitMQ.com/api/' + payload"),
restTemplate);
handler.setEncodeUri(false);
Message<?> message = MessageBuilder.withPayload("queues/%2f/si.test.queue?foo#bar").build();
try {
handler.handleRequestMessage(message);
}
catch (Exception e) {}
assertEquals("http://my.RabbitMQ.com/api/queues/%2f/si.test.queue?foo#bar", restTemplate.actualUrl.get());
}
@Test
public void nonCompatibleConversionService() throws Exception {
HttpRequestExecutingMessageHandler handler =
@@ -857,9 +879,9 @@ public class HttpRequestExecutingMessageHandlerTests {
private final AtomicReference<String> actualUrl = new AtomicReference<String>();
@Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
this.actualUrl.set(url);
public <T> ResponseEntity<T> exchange(URI uri, HttpMethod method, HttpEntity<?> requestEntity,
Class<T> responseType) throws RestClientException {
this.actualUrl.set(uri.toString());
this.lastRequestEntity.set(requestEntity);
throw new RuntimeException("intentional");
}
@@ -869,8 +891,8 @@ public class HttpRequestExecutingMessageHandlerTests {
private static class MockRestTemplate2 extends RestTemplate {
@Override
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,
Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
public <T> ResponseEntity<T> exchange(URI uri, HttpMethod method, HttpEntity<?> requestEntity,
Class<T> responseType) throws RestClientException {
return new ResponseEntity<T>(HttpStatus.OK);
}
}