From 312ac31a0969f1039c32a42eb399670f0087b1f4 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Tue, 10 Apr 2007 11:59:41 +0000 Subject: [PATCH] Fixed SWS-105: GZip compression is not enabled --- .../AbstractWebServiceConnection.java | 60 ++++++++ .../AbstractHttpWebServiceConnection.java | 143 ++++++++++++++++++ .../AbstractHttpWebServiceMessageSender.java | 33 +++- .../transport/http/CommonsHttpConnection.java | 115 ++++---------- .../http/CommonsHttpMessageSender.java | 7 +- .../ws/transport/http/HttpUrlConnection.java | 138 +++++------------ .../http/HttpUrlConnectionMessageSender.java | 3 + ...viceMessageSenderIntegrationTestCase.java} | 124 +++++++++------ ...monsHttpMessageSenderIntegrationTest.java} | 2 +- ...nnectionMessageSenderIntegrationTest.java} | 3 +- src/changes/changes.xml | 1 + 11 files changed, 388 insertions(+), 241 deletions(-) create mode 100644 core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java create mode 100644 core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceConnection.java rename core/src/test/java/org/springframework/ws/transport/http/{AbstractHttpWebServiceMessageSenderTestCase.java => AbstractHttpWebServiceMessageSenderIntegrationTestCase.java} (65%) rename core/src/test/java/org/springframework/ws/transport/http/{CommonsHttpMessageSenderTest.java => CommonsHttpMessageSenderIntegrationTest.java} (87%) rename core/src/test/java/org/springframework/ws/transport/http/{HttpUrlConnectionMessageSenderTest.java => HttpUrlConnectionMessageSenderIntegrationTest.java} (85%) diff --git a/core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java new file mode 100644 index 00000000..c455fdcf --- /dev/null +++ b/core/src/main/java/org/springframework/ws/transport/AbstractWebServiceConnection.java @@ -0,0 +1,60 @@ +/* + * Copyright 2007 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 + * + * http://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.ws.transport; + +import java.io.IOException; + +/** + * Abstract base class for {@link WebServiceConnection} implementations. + * + * @author Arjen Poutsma + */ +public abstract class AbstractWebServiceConnection implements WebServiceConnection { + + private TransportOutputStream tos; + + private TransportInputStream tis; + + public final TransportOutputStream getTransportOutputStream() throws IOException { + if (tos == null) { + tos = createTransportOutputStream(); + } + return tos; + } + + public final TransportInputStream getTransportInputStream() throws IOException { + if (hasResponse()) { + if (tis == null) { + tis = createTransportInputStream(); + } + return tis; + } + else { + return null; + } + } + + /** Creates a new TransportOutputStream. The result is cached in a local variable. */ + protected abstract TransportOutputStream createTransportOutputStream() throws IOException; + + /** Creates a new TransportInputStream. The result is cached in a local variable. */ + protected abstract TransportInputStream createTransportInputStream() throws IOException; + + /** Indicates whether this connection has a response. */ + protected abstract boolean hasResponse() throws IOException; + +} diff --git a/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceConnection.java b/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceConnection.java new file mode 100644 index 00000000..83ce8ecd --- /dev/null +++ b/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceConnection.java @@ -0,0 +1,143 @@ +/* + * Copyright 2007 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 + * + * http://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.ws.transport.http; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.zip.GZIPInputStream; + +import org.springframework.util.FileCopyUtils; +import org.springframework.ws.transport.AbstractWebServiceConnection; +import org.springframework.ws.transport.FaultAwareWebServiceConnection; +import org.springframework.ws.transport.TransportInputStream; +import org.springframework.ws.transport.TransportOutputStream; +import org.springframework.ws.transport.WebServiceConnection; + +/** + * Abstract base class for {@link WebServiceConnection} implementations that use HTTP. + * + * @author Arjen Poutsma + */ +public abstract class AbstractHttpWebServiceConnection extends AbstractWebServiceConnection + implements FaultAwareWebServiceConnection { + + protected static final String HTTP_HEADER_CONTENT_ENCODING = "Content-Encoding"; + + protected static final String ENCODING_GZIP = "gzip"; + + protected static final int HTTP_STATUS_INTERNAL_ERROR = 500; + + private byte[] bufferedInput; + + protected final TransportOutputStream createTransportOutputStream() throws IOException { + return new HttpClientTransportOutputStream(); + } + + protected final boolean hasResponse() throws IOException { + long contentLength = getResponseContentLength(); + if (contentLength == -1) { + if (bufferedInput == null) { + bufferedInput = FileCopyUtils.copyToByteArray(getResponseInputStream()); + } + contentLength = bufferedInput.length; + } + return contentLength > 0; + } + + protected final TransportInputStream createTransportInputStream() throws IOException { + return new HttpClientTransportInputStream(); + } + + public final boolean hasFault() throws IOException { + return getResponseCode() == HTTP_STATUS_INTERNAL_ERROR; + } + + private InputStream getUncompressedResponseInputStream() throws IOException { + InputStream rawInputStream; + if (bufferedInput != null) { + rawInputStream = new ByteArrayInputStream(bufferedInput); + } + else { + rawInputStream = getResponseInputStream(); + } + return isGzipResponse() ? new GZIPInputStream(rawInputStream) : rawInputStream; + } + + /** Determine whether the given response is a GZIP response. */ + private boolean isGzipResponse() throws IOException { + for (Iterator iterator = getResponseHeaders(HTTP_HEADER_CONTENT_ENCODING); iterator.hasNext();) { + String encodingHeader = (String) iterator.next(); + return encodingHeader.toLowerCase().indexOf(ENCODING_GZIP) != -1; + } + return false; + } + + protected abstract void addRequestHeader(String name, String value) throws IOException; + + protected abstract OutputStream getRequestOutputStream() throws IOException; + + protected abstract void open() throws IOException; + + protected abstract int getResponseCode() throws IOException; + + protected abstract long getResponseContentLength() throws IOException; + + protected abstract Iterator getResponseHeaderNames() throws IOException; + + protected abstract Iterator getResponseHeaders(String name) throws IOException; + + protected abstract InputStream getResponseInputStream() throws IOException; + + /** Implementation of {@link TransportOutputStream} for client-side HTTP. */ + class HttpClientTransportOutputStream extends TransportOutputStream { + + public void addHeader(String name, String value) throws IOException { + addRequestHeader(name, value); + } + + protected OutputStream createOutputStream() throws IOException { + return getRequestOutputStream(); + } + + public void close() throws IOException { + super.close(); + open(); + } + } + + /** Implementation of {@link TransportInputStream} for client-side HTTP. */ + class HttpClientTransportInputStream extends TransportInputStream { + + protected InputStream createInputStream() throws IOException { + return getUncompressedResponseInputStream(); + } + + public Iterator getHeaderNames() throws IOException { + return getResponseHeaderNames(); + } + + public Iterator getHeaders(String name) throws IOException { + return getResponseHeaders(name); + } + + } + + +} diff --git a/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSender.java b/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSender.java index 70398cf5..6f5861b4 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSender.java +++ b/core/src/main/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSender.java @@ -32,20 +32,41 @@ public abstract class AbstractHttpWebServiceMessageSender implements WebServiceM private URL url; - /** - * Returns the url used by this message sender. - */ + private boolean acceptGzipEncoding = true; + + protected static final String HTTP_HEADER_ACCEPT_ENCODING = "Accept-Encoding"; + + protected static final String ENCODING_GZIP = "gzip"; + + /** Returns the url used by this message sender. */ public URL getUrl() { return url; } - /** - * Sets the url used by this message sender. - */ + /** Sets the url used by this message sender. */ public void setUrl(URL url) { this.url = url; } + /** + * Return whether to accept GZIP encoding, that is, whether to send the HTTP Accept-Encoding header + * with gzip as value. + */ + public boolean isAcceptGzipEncoding() { + return acceptGzipEncoding; + } + + /** + * Set whether to accept GZIP encoding, that is, whether to send the HTTP Accept-Encoding header with + * gzip as value. + *

+ * Default is true. Turn this flag off if you do not want GZIP response compression even if enabled on + * the HTTP server. + */ + public void setAcceptGzipEncoding(boolean acceptGzipEncoding) { + this.acceptGzipEncoding = acceptGzipEncoding; + } + public void afterPropertiesSet() throws Exception { Assert.notNull(url, "url is required"); } diff --git a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpConnection.java b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpConnection.java index 2e7d7e31..e9e29b3d 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpConnection.java @@ -16,7 +16,6 @@ package org.springframework.ws.transport.http; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -26,15 +25,10 @@ import java.util.Iterator; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; -import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; import org.apache.commons.httpclient.methods.PostMethod; import org.springframework.util.Assert; -import org.springframework.util.FileCopyUtils; -import org.springframework.ws.transport.FaultAwareWebServiceConnection; -import org.springframework.ws.transport.TransportInputStream; -import org.springframework.ws.transport.TransportOutputStream; import org.springframework.ws.transport.WebServiceConnection; /** @@ -43,13 +37,13 @@ import org.springframework.ws.transport.WebServiceConnection; * * @author Arjen Poutsma */ -public class CommonsHttpConnection implements FaultAwareWebServiceConnection { +public class CommonsHttpConnection extends AbstractHttpWebServiceConnection { private final HttpClient httpClient; private final PostMethod postMethod; - private byte[] bufferedInput; + private ByteArrayOutputStream bufferedOutput = new ByteArrayOutputStream(); public CommonsHttpConnection(HttpClient httpClient, PostMethod postMethod) { Assert.notNull(httpClient, "httpClient must not be null"); @@ -58,41 +52,33 @@ public class CommonsHttpConnection implements FaultAwareWebServiceConnection { this.postMethod = postMethod; } - /** Returns the wrapped PostMethod. */ - public HttpMethod getPostMethod() { - return postMethod; - } - public void close() throws IOException { postMethod.releaseConnection(); } - public TransportOutputStream getTransportOutputStream() { - return new CommonsHttpTransportOutputStream(); + protected void addRequestHeader(String name, String value) throws IOException { + postMethod.addRequestHeader(name, value); } - public TransportInputStream getTransportInputStream() throws IOException { - return getContentLength() > 0 ? new CommonsHttpTransportInputStream() : null; + protected OutputStream getRequestOutputStream() throws IOException { + return bufferedOutput; } - public boolean hasFault() throws IOException { - return postMethod.getStatusCode() == HttpStatus.SC_INTERNAL_SERVER_ERROR; + protected void open() throws IOException { + postMethod.setRequestEntity(new ByteArrayRequestEntity(bufferedOutput.toByteArray())); + bufferedOutput = null; + httpClient.executeMethod(postMethod); } - private long getContentLength() throws IOException { - if (postMethod.getResponseContentLength() != -1) { - return postMethod.getResponseContentLength(); - } - else if (bufferedInput != null) { - return bufferedInput.length; - } - else { - bufferedInput = FileCopyUtils.copyToByteArray(getInputStream()); - return bufferedInput.length; - } + protected int getResponseCode() throws IOException { + return postMethod.getStatusCode(); } - private InputStream getInputStream() throws IOException { + protected long getResponseContentLength() throws IOException { + return postMethod.getResponseContentLength(); + } + + protected InputStream getResponseInputStream() throws IOException { if (postMethod.getStatusCode() != HttpStatus.SC_INTERNAL_SERVER_ERROR && postMethod.getStatusCode() / 100 != 2) { throw new HttpTransportException("Did not receive successful HTTP response: status code = " + @@ -101,65 +87,22 @@ public class CommonsHttpConnection implements FaultAwareWebServiceConnection { return postMethod.getResponseBodyAsStream(); } - /** - * Implementation of {@link TransportInputStream} based on the {@link PostMethod} field. - * - * @see CommonsHttpConnection#postMethod - */ - class CommonsHttpTransportInputStream extends TransportInputStream { - - protected InputStream createInputStream() throws IOException { - if (bufferedInput != null) { - return new ByteArrayInputStream(bufferedInput); - } - else { - return getInputStream(); - } - } - - public Iterator getHeaderNames() throws IOException { - Header[] headers = postMethod.getResponseHeaders(); - String[] names = new String[headers.length]; - for (int i = 0; i < headers.length; i++) { - names[i] = headers[i].getName(); - } - return Arrays.asList(names).iterator(); - } - - public Iterator getHeaders(String name) throws IOException { - Header[] headers = postMethod.getResponseHeaders(name); - String[] values = new String[headers.length]; - for (int i = 0; i < headers.length; i++) { - values[i] = headers[i].getValue(); - } - return Arrays.asList(values).iterator(); + protected Iterator getResponseHeaderNames() throws IOException { + Header[] headers = postMethod.getResponseHeaders(); + String[] names = new String[headers.length]; + for (int i = 0; i < headers.length; i++) { + names[i] = headers[i].getName(); } + return Arrays.asList(names).iterator(); } - /** - * Implementation of {@link TransportOutputStream} based on the {@link PostMethod} field. - * - * @see CommonsHttpConnection#postMethod - */ - class CommonsHttpTransportOutputStream extends TransportOutputStream { - - private final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - - public void addHeader(String name, String value) throws IOException { - postMethod.addRequestHeader(name, value); + protected Iterator getResponseHeaders(String name) throws IOException { + Header[] headers = postMethod.getResponseHeaders(name); + String[] values = new String[headers.length]; + for (int i = 0; i < headers.length; i++) { + values[i] = headers[i].getValue(); } - - protected OutputStream createOutputStream() throws IOException { - return bos; - } - - public void close() throws IOException { - super.close(); - postMethod.setRequestEntity(new ByteArrayRequestEntity(bos.toByteArray())); - httpClient.executeMethod(postMethod); - } - + return Arrays.asList(values).iterator(); } - } diff --git a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java index 1869f259..db835c78 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java +++ b/core/src/main/java/org/springframework/ws/transport/http/CommonsHttpMessageSender.java @@ -80,8 +80,11 @@ public class CommonsHttpMessageSender extends AbstractHttpWebServiceMessageSende } public WebServiceConnection createConnection() throws IOException { - PostMethod method = new PostMethod(getUrl().toString()); - return new CommonsHttpConnection(getHttpClient(), method); + PostMethod postMethod = new PostMethod(getUrl().toString()); + if (isAcceptGzipEncoding()) { + postMethod.addRequestHeader(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP); + } + return new CommonsHttpConnection(getHttpClient(), postMethod); } } diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnection.java b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnection.java index 4213d168..7986177f 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnection.java +++ b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnection.java @@ -16,12 +16,10 @@ package org.springframework.ws.transport.http; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; -import java.net.ProtocolException; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -29,11 +27,7 @@ import java.util.List; import java.util.Set; import org.springframework.util.Assert; -import org.springframework.util.FileCopyUtils; import org.springframework.util.StringUtils; -import org.springframework.ws.transport.FaultAwareWebServiceConnection; -import org.springframework.ws.transport.TransportInputStream; -import org.springframework.ws.transport.TransportOutputStream; import org.springframework.ws.transport.WebServiceConnection; /** @@ -41,53 +35,71 @@ import org.springframework.ws.transport.WebServiceConnection; * * @author Arjen Poutsma */ -public class HttpUrlConnection implements FaultAwareWebServiceConnection { +public class HttpUrlConnection extends AbstractHttpWebServiceConnection { private final HttpURLConnection connection; - private byte[] bufferedInput; - - /** Creates a new instance of the HttpUrlConnection with the given HttpURLConnection. */ - public HttpUrlConnection(HttpURLConnection connection) throws ProtocolException { + /** + * Creates a new instance of the HttpUrlConnection with the given HttpURLConnection. + * + * @param connection the HttpURLConnection + */ + public HttpUrlConnection(HttpURLConnection connection) { Assert.notNull(connection, "connection must not be null"); this.connection = connection; } - /** Returns the wrapped HttpURLConnection. */ - public HttpURLConnection getConnection() { - return connection; - } - public void close() { connection.disconnect(); } - public TransportOutputStream getTransportOutputStream() { - return new HttpUrlConnectionTransportOutputStream(); + protected void addRequestHeader(String name, String value) throws IOException { + connection.addRequestProperty(name, value); } - public TransportInputStream getTransportInputStream() throws IOException { - return getContentLength() > 0 ? new HttpUrlConnectionTransportInputStream() : null; + protected OutputStream getRequestOutputStream() throws IOException { + return connection.getOutputStream(); } - public boolean hasFault() throws IOException { - return connection.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR; + protected void open() throws IOException { + connection.connect(); } - private int getContentLength() throws IOException { - if (connection.getContentLength() != -1) { - return connection.getContentLength(); + protected long getResponseContentLength() throws IOException { + return connection.getContentLength(); + } + + protected Iterator getResponseHeaderNames() throws IOException { + List headerNames = new ArrayList(); + // Header field 0 is the status line, so we start at 1 + int i = 1; + while (true) { + String headerName = connection.getHeaderFieldKey(i); + if (!StringUtils.hasLength(headerName)) { + break; + } + headerNames.add(headerName); + i++; } - else if (bufferedInput != null) { - return bufferedInput.length; + return headerNames.iterator(); + } + + protected Iterator getResponseHeaders(String name) throws IOException { + String headerField = connection.getHeaderField(name); + if (headerField == null) { + return Collections.EMPTY_LIST.iterator(); } else { - bufferedInput = FileCopyUtils.copyToByteArray(getInputStream()); - return bufferedInput.length; + Set tokens = StringUtils.commaDelimitedListToSet(headerField); + return tokens.iterator(); } } - private InputStream getInputStream() throws IOException { + protected int getResponseCode() throws IOException { + return connection.getResponseCode(); + } + + protected InputStream getResponseInputStream() throws IOException { if (connection.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) { return connection.getErrorStream(); } @@ -100,70 +112,4 @@ public class HttpUrlConnection implements FaultAwareWebServiceConnection { } } - /** - * Implementation of {@link TransportInputStream} based on the {@link HttpURLConnection} field. - * - * @see HttpUrlConnection#connection - */ - - class HttpUrlConnectionTransportInputStream extends TransportInputStream { - - protected InputStream createInputStream() throws IOException { - if (bufferedInput != null) { - return new ByteArrayInputStream(bufferedInput); - } - else { - return getInputStream(); - } - } - - public Iterator getHeaderNames() throws IOException { - List headerNames = new ArrayList(); - // Header field 0 is the status line, so we start at 1 - int i = 1; - while (true) { - String headerName = connection.getHeaderFieldKey(i); - if (!StringUtils.hasLength(headerName)) { - break; - } - headerNames.add(headerName); - i++; - } - return headerNames.iterator(); - } - - public Iterator getHeaders(String name) throws IOException { - String headerField = connection.getHeaderField(name); - if (headerField == null) { - return Collections.EMPTY_LIST.iterator(); - } - else { - Set tokens = StringUtils.commaDelimitedListToSet(headerField); - return tokens.iterator(); - } - } - - } - - /** - * Implementation of {@link TransportOutputStream} based on the {@link HttpURLConnection} field. - * - * @see HttpUrlConnection#connection - */ - class HttpUrlConnectionTransportOutputStream extends TransportOutputStream { - - public void addHeader(String name, String value) throws IOException { - connection.addRequestProperty(name, value); - } - - protected OutputStream createOutputStream() throws IOException { - return connection.getOutputStream(); - } - - public void close() throws IOException { - super.close(); - connection.connect(); - } - } - } diff --git a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java index e51f4e60..347c3054 100644 --- a/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java +++ b/core/src/main/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSender.java @@ -48,6 +48,9 @@ public class HttpUrlConnectionMessageSender extends AbstractHttpWebServiceMessag httpURLConnection.setUseCaches(false); httpURLConnection.setDoInput(true); httpURLConnection.setDoOutput(true); + if (isAcceptGzipEncoding()) { + httpURLConnection.setRequestProperty(HTTP_HEADER_ACCEPT_ENCODING, ENCODING_GZIP); + } return new HttpUrlConnection(httpURLConnection); } } diff --git a/core/src/test/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSenderTestCase.java b/core/src/test/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSenderIntegrationTestCase.java similarity index 65% rename from core/src/test/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSenderTestCase.java rename to core/src/test/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSenderIntegrationTestCase.java index 52fed79e..be0d7adb 100644 --- a/core/src/test/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSenderTestCase.java +++ b/core/src/test/java/org/springframework/ws/transport/http/AbstractHttpWebServiceMessageSenderIntegrationTestCase.java @@ -19,11 +19,10 @@ package org.springframework.ws.transport.http; import java.io.IOException; import java.net.URL; import java.util.Iterator; -import javax.servlet.GenericServlet; +import java.util.zip.GZIPOutputStream; import javax.servlet.Servlet; import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -38,7 +37,7 @@ import org.springframework.ws.transport.TransportInputStream; import org.springframework.ws.transport.TransportOutputStream; import org.springframework.ws.transport.WebServiceConnection; -public abstract class AbstractHttpWebServiceMessageSenderTestCase extends XMLTestCase { +public abstract class AbstractHttpWebServiceMessageSenderIntegrationTestCase extends XMLTestCase { protected Server jettyServer; @@ -75,16 +74,40 @@ public abstract class AbstractHttpWebServiceMessageSenderTestCase extends XMLTes } public void testSendAndReceiveResponse() throws Exception { - validateResponse(new MyServlet(true)); + validateResponse(new ResponseServlet()); } public void testSendAndReceiveResponseInvalidContentLength() throws Exception { - validateResponse(new MyServlet(true, HttpServletResponse.SC_OK, false)); + ResponseServlet servlet = new ResponseServlet(); + servlet.setInvalidContentLength(true); + validateResponse(servlet); + } + + public void testSendAndReceiveNoResponse() throws Exception { + validateNonResponse(new NoResponseServlet()); + } + + public void testSendAndReceiveNoResponseAccepted() throws Exception { + NoResponseServlet servlet = new NoResponseServlet(); + servlet.setResponseStatus(HttpServletResponse.SC_ACCEPTED); + validateNonResponse(servlet); + } + + public void testSendAndReceiveNoResponseInvalidContentLength() throws Exception { + NoResponseServlet servlet = new NoResponseServlet(); + servlet.setInvalidContentLength(true); + validateNonResponse(servlet); + } + + public void testSendAndReceiveCompressed() throws Exception { + validateResponse(new CompressedResponseServlet()); + } public void testSendAndReceiveFault() throws Exception { - jettyContext - .addServlet(new ServletHolder(new MyServlet(true, HttpServletResponse.SC_INTERNAL_SERVER_ERROR)), "/"); + ResponseServlet servlet = new ResponseServlet(); + servlet.setResponseStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + jettyContext.addServlet(new ServletHolder(servlet), "/"); jettyServer.start(); FaultAwareWebServiceConnection connection = (FaultAwareWebServiceConnection) messageSender.createConnection(); try { @@ -131,18 +154,6 @@ public abstract class AbstractHttpWebServiceMessageSenderTestCase extends XMLTes } } - public void testSendAndReceiveNoResponse() throws Exception { - validateNonResponse(new MyServlet(false)); - } - - public void testSendAndReceiveNoResponseAccepted() throws Exception { - validateNonResponse(new MyServlet(false, HttpServletResponse.SC_ACCEPTED)); - } - - public void testSendAndReceiveNoResponseInvalidContentLength() throws Exception { - validateNonResponse(new MyServlet(false, HttpServletResponse.SC_OK, false)); - } - private void validateNonResponse(Servlet servlet) throws Exception { jettyContext.addServlet(new ServletHolder(servlet), "/"); jettyServer.start(); @@ -159,45 +170,60 @@ public abstract class AbstractHttpWebServiceMessageSenderTestCase extends XMLTes } } - private static class MyServlet extends GenericServlet { + private static class NoResponseServlet extends HttpServlet { - private boolean response; + protected int responseStatus = HttpServletResponse.SC_OK; - private int responseStatus; + protected boolean invalidContentLength = false; - private boolean validContentLength; - - public MyServlet(boolean response) { - this(response, HttpServletResponse.SC_OK, true); - } - - public MyServlet(boolean response, int responseStatus) { - this(response, responseStatus, true); - } - - public MyServlet(boolean response, int responseStatus, boolean validContentLength) { - this.response = response; + public void setResponseStatus(int responseStatus) { this.responseStatus = responseStatus; - this.validContentLength = validContentLength; } - public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { - HttpServletRequest httpServletRequest = (HttpServletRequest) req; - HttpServletResponse httpServletResponse = (HttpServletResponse) res; + public void setInvalidContentLength(boolean invalidContentLength) { + this.invalidContentLength = invalidContentLength; + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { assertEquals("Invalid header value received on server side", REQUEST_HEADER_VALUE, - httpServletRequest.getHeader(REQUEST_HEADER_NAME)); - String receivedRequest = new String(FileCopyUtils.copyToByteArray(req.getInputStream()), "UTF-8"); + request.getHeader(REQUEST_HEADER_NAME)); + String receivedRequest = new String(FileCopyUtils.copyToByteArray(request.getInputStream()), "UTF-8"); assertEquals("Invalid request received", REQUEST, receivedRequest); - httpServletResponse.setStatus(responseStatus); - if (!validContentLength) { - httpServletResponse.setContentLength(-1); - } - if (response) { - httpServletResponse.addHeader(RESPONSE_HEADER_NAME, RESPONSE_HEADER_VALUE); - httpServletResponse.setContentType("text/xml"); - FileCopyUtils.copy(RESPONSE.getBytes("UTF-8"), res.getOutputStream()); + response.setStatus(responseStatus); + if (invalidContentLength) { + response.setContentLength(-1); } + createResponse(request, response); + } + + protected void createResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { + } + } + + private static class ResponseServlet extends NoResponseServlet { + + protected void createResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.setContentType("text/xml"); + response.addHeader(RESPONSE_HEADER_NAME, RESPONSE_HEADER_VALUE); + byte[] buffer = RESPONSE.getBytes("UTF-8"); + response.setContentLength(buffer.length); + FileCopyUtils.copy(buffer, response.getOutputStream()); + } + } + + private static class CompressedResponseServlet extends NoResponseServlet { + + protected void createResponse(HttpServletRequest request, HttpServletResponse response) throws IOException { + assertEquals("Invalid Accept-Encoding header value received on server side", "gzip", + request.getHeader("Accept-Encoding")); + response.setStatus(HttpServletResponse.SC_OK); + response.setContentType("text/xml"); + response.addHeader(RESPONSE_HEADER_NAME, RESPONSE_HEADER_VALUE); + response.addHeader("Content-Encoding", "gzip"); + byte[] buffer = RESPONSE.getBytes("UTF-8"); + FileCopyUtils.copy(buffer, new GZIPOutputStream(response.getOutputStream())); } } } diff --git a/core/src/test/java/org/springframework/ws/transport/http/CommonsHttpMessageSenderTest.java b/core/src/test/java/org/springframework/ws/transport/http/CommonsHttpMessageSenderIntegrationTest.java similarity index 87% rename from core/src/test/java/org/springframework/ws/transport/http/CommonsHttpMessageSenderTest.java rename to core/src/test/java/org/springframework/ws/transport/http/CommonsHttpMessageSenderIntegrationTest.java index 6f16e3c2..497180b4 100644 --- a/core/src/test/java/org/springframework/ws/transport/http/CommonsHttpMessageSenderTest.java +++ b/core/src/test/java/org/springframework/ws/transport/http/CommonsHttpMessageSenderIntegrationTest.java @@ -16,7 +16,7 @@ package org.springframework.ws.transport.http; -public class CommonsHttpMessageSenderTest extends AbstractHttpWebServiceMessageSenderTestCase { +public class CommonsHttpMessageSenderIntegrationTest extends AbstractHttpWebServiceMessageSenderIntegrationTestCase { protected AbstractHttpWebServiceMessageSender createMessageSender() { return new CommonsHttpMessageSender(); diff --git a/core/src/test/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSenderTest.java b/core/src/test/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSenderIntegrationTest.java similarity index 85% rename from core/src/test/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSenderTest.java rename to core/src/test/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSenderIntegrationTest.java index 905f7b32..299c2cd9 100644 --- a/core/src/test/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSenderTest.java +++ b/core/src/test/java/org/springframework/ws/transport/http/HttpUrlConnectionMessageSenderIntegrationTest.java @@ -16,7 +16,8 @@ package org.springframework.ws.transport.http; -public class HttpUrlConnectionMessageSenderTest extends AbstractHttpWebServiceMessageSenderTestCase { +public class HttpUrlConnectionMessageSenderIntegrationTest + extends AbstractHttpWebServiceMessageSenderIntegrationTestCase { protected AbstractHttpWebServiceMessageSender createMessageSender() { return new HttpUrlConnectionMessageSender(); diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 91458ae6..67de6313 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -6,6 +6,7 @@ + GZip compression is not enabled WebServiceConnection is now container for TransportInputStream and TransportOutputStream, used on both client- and server-side