/* * Copyright 2005-2014 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.util.Iterator; import java.util.zip.GZIPInputStream; import javax.xml.namespace.QName; import org.springframework.util.FileCopyUtils; import org.springframework.util.StringUtils; import org.springframework.ws.transport.AbstractSenderConnection; import org.springframework.ws.transport.FaultAwareWebServiceConnection; import org.springframework.ws.transport.WebServiceConnection; /** * Abstract base class for {@link WebServiceConnection} implementations that send request over HTTP. * * @author Arjen Poutsma * @since 1.0.0 */ public abstract class AbstractHttpSenderConnection extends AbstractSenderConnection implements FaultAwareWebServiceConnection { /** Buffer used for reading the response, when the content length is invalid. */ private byte[] responseBuffer; @Override public final boolean hasError() throws IOException { return getResponseCode() / 100 != 2; } @Override public final String getErrorMessage() throws IOException { StringBuilder builder = new StringBuilder(); String responseMessage = getResponseMessage(); if (StringUtils.hasLength(responseMessage)) { builder.append(responseMessage); } builder.append(" ["); builder.append(getResponseCode()); builder.append(']'); return builder.toString(); } /* * Receiving response */ @Override protected final boolean hasResponse() throws IOException { int responseCode = getResponseCode(); if (HttpTransportConstants.STATUS_ACCEPTED == responseCode || HttpTransportConstants.STATUS_NO_CONTENT == responseCode) { return false; } long contentLength = getResponseContentLength(); if (contentLength < 0) { if (responseBuffer == null) { responseBuffer = FileCopyUtils.copyToByteArray(getRawResponseInputStream()); } contentLength = responseBuffer.length; } return contentLength > 0; } @Override protected final InputStream getResponseInputStream() throws IOException { InputStream inputStream; if (responseBuffer != null) { inputStream = new ByteArrayInputStream(responseBuffer); } else { inputStream = getRawResponseInputStream(); } return isGzipResponse() ? new GZIPInputStream(inputStream) : inputStream; } /** Determine whether the response is a GZIP response. */ private boolean isGzipResponse() throws IOException { Iterator<String> iterator = getResponseHeaders(HttpTransportConstants.HEADER_CONTENT_ENCODING); if (iterator.hasNext()) { String encodingHeader = iterator.next(); return encodingHeader.toLowerCase() .contains(HttpTransportConstants.CONTENT_ENCODING_GZIP); } return false; } /** Returns the HTTP status code of the response. */ protected abstract int getResponseCode() throws IOException; /** Returns the HTTP status message of the response. */ protected abstract String getResponseMessage() throws IOException; /** Returns the length of the response. */ protected abstract long getResponseContentLength() throws IOException; /** Returns the raw, possibly compressed input stream to read the response from. */ protected abstract InputStream getRawResponseInputStream() throws IOException; /* * Faults */ @Override public final boolean hasFault() throws IOException { // SOAP 1.1 specifies a 500 status code for faults // SOAP 1.2 specifies a 400 status code for sender faults, and 500 for all other faults switch (getResponseCode()) { case HttpTransportConstants.STATUS_INTERNAL_SERVER_ERROR: return isSoap11Response() || isSoap12Response(); case HttpTransportConstants.STATUS_BAD_REQUEST: return isSoap12Response(); default: return false; } } /** Determine whether the response is a SOAP 1.1 message. */ private boolean isSoap11Response() throws IOException { Iterator<String> iterator = getResponseHeaders(HttpTransportConstants.HEADER_CONTENT_TYPE); if (iterator.hasNext()) { String contentType = iterator.next().toLowerCase(); return contentType.contains("text/xml"); } return false; } /** Determine whether the response is a SOAP 1.1 message. */ private boolean isSoap12Response() throws IOException { Iterator<String> iterator = getResponseHeaders(HttpTransportConstants.HEADER_CONTENT_TYPE); if (iterator.hasNext()) { String contentType = iterator.next().toLowerCase(); return contentType.contains("application/soap+xml"); } return false; } @Override @Deprecated public final void setFault(boolean fault) { } @Override public final void setFaultCode(QName faultCode) throws IOException { } }