INT-2035 Support Simple Cookie Handling

Initial commit - TODO: namspace.

Saves off Set-Cookie header in http_transferredCookie MessageHeader.

Transferred cookies are converted to Cookie: headers on subsequent
outbound messages, thus handling 3 or more interactions.

INT-2035 Namespace, Docs

Change boolean name; add namspace and documentation.

INT-2035 Docs

Added docs for cookie handling.

INT-2035 Polishing

Simplify implementation to just transfer Set-Cookie to
Cookie in the inbound side.

INT-2035 XSD Docs

Updated to reflect new implementation.
This commit is contained in:
Gary Russell
2011-11-12 08:18:15 -05:00
committed by Mark Fisher
parent 497d07bdad
commit a61b3617f3
9 changed files with 262 additions and 9 deletions

View File

@@ -80,6 +80,7 @@ public class HttpOutboundGatewayParser extends AbstractConsumerEndpointParser {
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "request-timeout", "sendTimeout");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel", "outputChannel");
HttpAdapterParsingUtils.configureUriVariableExpressions(builder, element);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "transfer-cookies");
return builder;
}

View File

@@ -24,6 +24,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.transform.Source;
@@ -88,6 +89,8 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe
private volatile String charset = "UTF-8";
private volatile boolean transferCookies = false;
private volatile HeaderMapper<HttpHeaders> headerMapper = DefaultHttpHeaderMapper.outboundMapper();
private final Map<String, Expression> uriVariableExpressions = new HashMap<String, Expression>();
@@ -95,7 +98,6 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe
private final RestTemplate restTemplate;
private final StandardEvaluationContext evaluationContext;
/**
* Create a handler that will send requests to the provided URI.
@@ -215,6 +217,16 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe
}
}
/**
* Set to true if you wish 'Set-Cookie' headers in responses to be
* transferred as 'Cookie' headers in subsequent interactions for
* a message.
* @param transferCookies the transferCookies to set.
*/
public void setTransferCookies(boolean transferCookies) {
this.transferCookies = transferCookies;
}
@Override
public void onInit() {
super.onInit();
@@ -245,7 +257,11 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe
HttpEntity<?> httpRequest = this.generateHttpRequest(requestMessage);
ResponseEntity<?> httpResponse = this.restTemplate.exchange(this.uri, this.httpMethod, httpRequest, this.expectedResponseType, uriVariables);
if (this.expectReply) {
Map<String, ?> headers = this.headerMapper.toHeaders(httpResponse.getHeaders());
HttpHeaders httpHeaders = httpResponse.getHeaders();
Map<String, Object> headers = this.headerMapper.toHeaders(httpHeaders);
if (this.transferCookies) {
this.doConvertSetCookie(headers);
}
if (httpResponse.hasBody()) {
Object responseBody = httpResponse.getBody();
MessageBuilder<?> replyBuilder = (responseBody instanceof Message<?>) ?
@@ -269,6 +285,27 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe
}
}
/**
* Convert Set-Cookie to Cookie
*/
private void doConvertSetCookie(Map<String, Object> headers) {
String keyName = null;
for (String key : headers.keySet()) {
if (key.equalsIgnoreCase(DefaultHttpHeaderMapper.SET_COOKIE)) {
keyName = key;
break;
}
}
if (keyName != null) {
Object cookies = headers.remove(keyName);
headers.put(DefaultHttpHeaderMapper.COOKIE, cookies);
if (logger.isDebugEnabled()) {
logger.debug("Converted Set-Cookie header to Cookie for: "
+ cookies);
}
}
}
private HttpEntity<?> generateHttpRequest(Message<?> message) throws Exception {
Assert.notNull(message, "message must not be null");
return (this.extractPayload) ? this.createHttpEntityFromPayload(message)
@@ -281,8 +318,7 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe
// payload is already an HttpEntity, just return it as-is
return (HttpEntity<?>) payload;
}
HttpHeaders httpHeaders = new HttpHeaders();
this.headerMapper.fromHeaders(message.getHeaders(), httpHeaders);
HttpHeaders httpHeaders = this.mapHeaders(message);
if (!shouldIncludeRequestBody()) {
return new HttpEntity<Object>(httpHeaders);
}
@@ -302,8 +338,7 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe
}
private HttpEntity<?> createHttpEntityFromMessage(Message<?> message) {
HttpHeaders httpHeaders = new HttpHeaders();
this.headerMapper.fromHeaders(message.getHeaders(), httpHeaders);
HttpHeaders httpHeaders = mapHeaders(message);
if (shouldIncludeRequestBody()) {
httpHeaders.setContentType(new MediaType("application", "x-java-serialized-object"));
return new HttpEntity<Object>(message, httpHeaders);
@@ -311,6 +346,12 @@ public class HttpRequestExecutingMessageHandler extends AbstractReplyProducingMe
return new HttpEntity<Object>(httpHeaders);
}
protected HttpHeaders mapHeaders(Message<?> message) {
HttpHeaders httpHeaders = new HttpHeaders();
this.headerMapper.fromHeaders(message.getHeaders(), httpHeaders);
return httpHeaders;
}
@SuppressWarnings("unchecked")
private MediaType resolveContentType(Object content) {
MediaType contentType = null;

View File

@@ -100,7 +100,7 @@ public class DefaultHttpHeaderMapper implements HeaderMapper<HttpHeaders>, BeanF
private static final String CONTENT_TYPE = "Content-Type";
private static final String COOKIE = "Cookie";
public static final String COOKIE = "Cookie";
private static final String DATE = "Date";
@@ -146,7 +146,7 @@ public class DefaultHttpHeaderMapper implements HeaderMapper<HttpHeaders>, BeanF
private static final String SERVER = "Server";
private static final String SET_COOKIE = "Set-Cookie";
public static final String SET_COOKIE = "Set-Cookie";
private static final String TE = "TE";

View File

@@ -505,6 +505,15 @@ The String "HTTP_REQUEST_HEADERS" will match against any of the standard HTTP Re
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-startup" type="xsd:string" />
<xsd:attribute name="transfer-cookies" type="xsd:string" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
When set to "true", if a response contains a 'Set-Cookie' header, it will mapped to a 'Cookie' header. This enables simple
cookie handling where subsequent HTTP interactions in the same message flow can use a cookie
supplied by the server. Default "false".
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>