Java tutorial
/* * Copyright 2001-2004 The Apache Software Foundation. * * 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 com.hp.it.spf.wsrp.axis.transport.http; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.Iterator; import javax.xml.soap.MimeHeader; import javax.xml.soap.MimeHeaders; import javax.xml.soap.SOAPException; import org.apache.axis.AxisFault; import org.apache.axis.Constants; import org.apache.axis.Message; import org.apache.axis.MessageContext; import org.apache.axis.components.net.BooleanHolder; import org.apache.axis.components.net.DefaultSocketFactory; import org.apache.axis.components.net.SocketFactory; import org.apache.axis.components.net.SocketFactoryFactory; import org.apache.axis.encoding.Base64; import org.apache.axis.handlers.BasicHandler; import org.apache.axis.soap.SOAP12Constants; import org.apache.axis.soap.SOAPConstants; import org.apache.axis.transport.http.ChunkedInputStream; import org.apache.axis.transport.http.ChunkedOutputStream; import org.apache.axis.transport.http.HTTPConstants; import org.apache.axis.transport.http.SocketHolder; import org.apache.axis.transport.http.SocketInputStream; import org.apache.axis.utils.Messages; import org.apache.axis.utils.TeeOutputStream; //import org.apache.commons.logging.Log; //import org.apache.axis.components.logger.LogFactory; import org.apache.log4j.Logger; /** * This is meant to be used on a SOAP Client to call a SOAP server. * * @author Doug Davis (dug@us.ibm.com) * @author Davanum Srinivas (dims@yahoo.com) * * This class was copied from SPP (Shared Portal Platform) codebase were it is used for WSRP * communication. The original AXIS version of this class has been modified to fix the issue * described below. * * *************************************** * BUG FIX NOTIFICATION * *************************************** * * Bug Summary: * The class variable "targetURL" is THREAD UNSAFE. * * Fix Summary: * This class variable is removed and scoped within the invoke method to avoid any potential thread synchronization issues. * * Bug description: * When two threads concurrently access the handler, the data encapsulated inside the targetURL * is unexpectedly modified by one of the thread when another thread is in the process of reading it. * In case when the threads perform SOAP call over two different protocols, the above is clearly noticeable. * When tests have been performed over two different thread calls one uses HTTP and another HTTPS concurrently * accessing this handler the following has been observed. * If HTTPS call is made over HTTP port, the result is SSLHandshake exception * If HTTP call is made over SSL port, the result is (0)null (NULL RESPONSE) * */ public class HTTPSender extends BasicHandler { // protected static Log log = LogFactory.getLog(HTTPSender.class.getName()); protected static Logger log = Logger.getLogger(HTTPSender.class.getName()); private static final String ACCEPT_HEADERS = HTTPConstants.HEADER_ACCEPT + //Limit to the types that are meaningful to us. ": " + HTTPConstants.HEADER_ACCEPT_APPL_SOAP + ", " + HTTPConstants.HEADER_ACCEPT_APPLICATION_DIME + ", " + HTTPConstants.HEADER_ACCEPT_MULTIPART_RELATED + ", " + HTTPConstants.HEADER_ACCEPT_TEXT_ALL + "\r\n" + HTTPConstants.HEADER_USER_AGENT + //Tell who we are. ": " + Messages.getMessage("axisUserAgent") + "\r\n"; private static final String CACHE_HEADERS = HTTPConstants.HEADER_CACHE_CONTROL + //Stop caching proxies from caching SOAP reqeuest. ": " + HTTPConstants.HEADER_CACHE_CONTROL_NOCACHE + "\r\n" + HTTPConstants.HEADER_PRAGMA + ": " + HTTPConstants.HEADER_CACHE_CONTROL_NOCACHE + "\r\n"; private static final String CHUNKED_HEADER = HTTPConstants.HEADER_TRANSFER_ENCODING + ": " + HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED + "\r\n"; private static final String HEADER_CONTENT_TYPE_LC = HTTPConstants.HEADER_CONTENT_TYPE.toLowerCase(); private static final String HEADER_LOCATION_LC = HTTPConstants.HEADER_LOCATION.toLowerCase(); private static final String HEADER_CONTENT_LOCATION_LC = HTTPConstants.HEADER_CONTENT_LOCATION.toLowerCase(); private static final String HEADER_CONTENT_LENGTH_LC = HTTPConstants.HEADER_CONTENT_LENGTH.toLowerCase(); private static final String HEADER_TRANSFER_ENCODING_LC = HTTPConstants.HEADER_TRANSFER_ENCODING.toLowerCase(); /** * the url; used for error reporting */ //Removed as part of BUG FIX. This variable is no longer needed //URL targetURL; /** * invoke creates a socket connection, sends the request SOAP message and then * reads the response SOAP message back from the SOAP server * * @param msgContext the messsage context * * @throws AxisFault */ public void invoke(MessageContext msgContext) throws AxisFault { if (log.isDebugEnabled()) { log.debug(Messages.getMessage("enter00", "HTTPSender::invoke")); } SocketHolder socketHolder = new SocketHolder(null); try { BooleanHolder useFullURL = new BooleanHolder(false); StringBuffer otherHeaders = new StringBuffer(); //The Global variable scope is reduced to method scope to prevent threads modifying the data encapsulated within the object URL targetURL = new URL(msgContext.getStrProp(MessageContext.TRANS_URL)); /* * This method will no longer be used. // Send the SOAP request to the server InputStream inp = writeToSocket(socketHolder, msgContext, targetURL, otherHeaders, host, port, msgContext.getTimeout(), useFullURL); */ /** * This method will be called by Axis which avoids redundant data being passed on to it. * The original method passes the URL object targetURL along with other details (host, port) * which are again part of the same object. This is unnecessary and removed it in the new method * */ //Send the SOAP request to the server InputStream inp = writeToSocket(socketHolder, msgContext, targetURL, otherHeaders, msgContext.getTimeout(), useFullURL); // Read the response back from the server Hashtable headers = new Hashtable(); inp = readHeadersFromSocket(socketHolder, msgContext, inp, headers); readFromSocket(socketHolder, msgContext, inp, headers); } catch (Exception e) { log.debug(e); try { if (socketHolder.getSocket() != null) { socketHolder.getSocket().close(); } } catch (IOException ie) { // we shouldn't get here. } throw AxisFault.makeFault(e); } if (log.isDebugEnabled()) { log.debug(Messages.getMessage("exit00", "HTTPDispatchHandler::invoke")); } } /** * Creates a socket connection to the SOAP server * * @param protocol "http" for standard, "https" for ssl. * @param host host name * @param port port to connect to * @param otherHeaders buffer for storing additional headers that need to be sent * @param useFullURL flag to indicate if the complete URL has to be sent * * @throws IOException */ protected void getSocket(SocketHolder sockHolder, MessageContext msgContext, String protocol, String host, int port, int timeout, StringBuffer otherHeaders, BooleanHolder useFullURL) throws Exception { Hashtable options = getOptions(); if (timeout > 0) { if (options == null) { options = new Hashtable(); } options.put(DefaultSocketFactory.CONNECT_TIMEOUT, Integer.toString(timeout)); } SocketFactory factory = SocketFactoryFactory.getFactory(protocol, options); if (factory == null) { throw new IOException(Messages.getMessage("noSocketFactory", protocol)); } Socket sock = factory.create(host, port, otherHeaders, useFullURL); if (log.isDebugEnabled()) log.debug("sppmsg:getSocket -> Socket created for Host = " + host + " Port = " + port + " Protocol = " + protocol); if (timeout > 0) { sock.setSoTimeout(timeout); } sockHolder.setSocket(sock); } /** * Send the soap request message to the server * * @param msgContext message context * @param targetURL url to connect to * @param otherHeaders other headers if any * @param useFullURL flag to indicate if the whole url needs to be sent * * @throws IOException */ private InputStream writeToSocket(SocketHolder sockHolder, MessageContext msgContext, URL targetURL, StringBuffer otherHeaders, int timeout, BooleanHolder useFullURL) throws Exception { String userID = msgContext.getUsername(); String passwd = msgContext.getPassword(); // Get SOAPAction, default to "" String action = msgContext.useSOAPAction() ? msgContext.getSOAPActionURI() : ""; if (action == null) { action = ""; } // if UserID is not part of the context, but is in the URL, use // the one in the URL. if ((userID == null) && (targetURL.getUserInfo() != null)) { String info = targetURL.getUserInfo(); int sep = info.indexOf(':'); if ((sep >= 0) && (sep + 1 < info.length())) { userID = info.substring(0, sep); passwd = info.substring(sep + 1); } else { userID = info; } } if (userID != null) { StringBuffer tmpBuf = new StringBuffer(); tmpBuf.append(userID).append(":").append((passwd == null) ? "" : passwd); otherHeaders.append(HTTPConstants.HEADER_AUTHORIZATION).append(": Basic ") .append(Base64.encode(tmpBuf.toString().getBytes())).append("\r\n"); } // don't forget the cookies! // mmm... cookies if (msgContext.getMaintainSession()) { fillHeaders(msgContext, HTTPConstants.HEADER_COOKIE, otherHeaders); fillHeaders(msgContext, HTTPConstants.HEADER_COOKIE2, otherHeaders); } StringBuffer header2 = new StringBuffer(); String webMethod = null; boolean posting = true; Message reqMessage = msgContext.getRequestMessage(); boolean http10 = true; //True if this is to use HTTP 1.0 / false HTTP 1.1 boolean httpChunkStream = false; //Use HTTP chunking or not. boolean httpContinueExpected = false; //Under HTTP 1.1 if false you *MAY* need to wait for a 100 rc, // if true the server MUST reply with 100 continue. String httpConnection = null; String httpver = msgContext.getStrProp(MessageContext.HTTP_TRANSPORT_VERSION); if (null == httpver) { httpver = HTTPConstants.HEADER_PROTOCOL_V10; } httpver = httpver.trim(); if (httpver.equals(HTTPConstants.HEADER_PROTOCOL_V11)) { http10 = false; } //process user defined headers for information. Hashtable userHeaderTable = (Hashtable) msgContext.getProperty(HTTPConstants.REQUEST_HEADERS); if (userHeaderTable != null) { if (null == otherHeaders) { otherHeaders = new StringBuffer(1024); } for (java.util.Iterator e = userHeaderTable.entrySet().iterator(); e.hasNext();) { java.util.Map.Entry me = (java.util.Map.Entry) e.next(); Object keyObj = me.getKey(); if (null == keyObj) continue; String key = keyObj.toString().trim(); if (key.equalsIgnoreCase(HTTPConstants.HEADER_TRANSFER_ENCODING)) { if (!http10) { String val = me.getValue().toString(); if (null != val && val.trim().equalsIgnoreCase(HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED)) httpChunkStream = true; } } else if (key.equalsIgnoreCase(HTTPConstants.HEADER_CONNECTION)) { if (!http10) { String val = me.getValue().toString(); if (val.trim().equalsIgnoreCase(HTTPConstants.HEADER_CONNECTION_CLOSE)) httpConnection = HTTPConstants.HEADER_CONNECTION_CLOSE; } //HTTP 1.0 will always close. //HTTP 1.1 will use persistent. //no need to specify } else { if (!http10 && key.equalsIgnoreCase(HTTPConstants.HEADER_EXPECT)) { String val = me.getValue().toString(); if (null != val && val.trim().equalsIgnoreCase(HTTPConstants.HEADER_EXPECT_100_Continue)) httpContinueExpected = true; } otherHeaders.append(key).append(": ").append(me.getValue()).append("\r\n"); } } } if (!http10) { //Force close for now. //TODO HTTP/1.1 httpConnection = HTTPConstants.HEADER_CONNECTION_CLOSE; } header2.append(" "); header2.append(http10 ? HTTPConstants.HEADER_PROTOCOL_10 : HTTPConstants.HEADER_PROTOCOL_11).append("\r\n"); MimeHeaders mimeHeaders = reqMessage.getMimeHeaders(); if (posting) { String contentType; final String[] header = mimeHeaders.getHeader(HTTPConstants.HEADER_CONTENT_TYPE); if (header != null && header.length > 0) { contentType = mimeHeaders.getHeader(HTTPConstants.HEADER_CONTENT_TYPE)[0]; } else { contentType = reqMessage.getContentType(msgContext.getSOAPConstants()); } //fix for AXIS-2027 if (contentType == null || contentType.equals("")) { throw new Exception(Messages.getMessage("missingContentType")); } header2.append(HTTPConstants.HEADER_CONTENT_TYPE).append(": ").append(contentType).append("\r\n"); } //Get host and port String host = targetURL.getHost(); int port = targetURL.getPort(); header2.append(ACCEPT_HEADERS).append(HTTPConstants.HEADER_HOST) //used for virtual connections .append(": ").append(host).append((port == -1) ? ("") : (":" + port)).append("\r\n") .append(CACHE_HEADERS).append(HTTPConstants.HEADER_SOAP_ACTION) //The SOAP action. .append(": \"").append(action).append("\"\r\n"); if (posting) { if (!httpChunkStream) { //Content length MUST be sent on HTTP 1.0 requests. header2.append(HTTPConstants.HEADER_CONTENT_LENGTH).append(": ") .append(reqMessage.getContentLength()).append("\r\n"); } else { //Do http chunking. header2.append(CHUNKED_HEADER); } } // Transfer MIME headers of SOAPMessage to HTTP headers. if (mimeHeaders != null) { for (Iterator i = mimeHeaders.getAllHeaders(); i.hasNext();) { MimeHeader mimeHeader = (MimeHeader) i.next(); String headerName = mimeHeader.getName(); if (headerName.equals(HTTPConstants.HEADER_CONTENT_TYPE) || headerName.equals(HTTPConstants.HEADER_SOAP_ACTION)) { continue; } header2.append(mimeHeader.getName()).append(": ").append(mimeHeader.getValue()).append("\r\n"); } } if (null != httpConnection) { header2.append(HTTPConstants.HEADER_CONNECTION); header2.append(": "); header2.append(httpConnection); header2.append("\r\n"); } getSocket(sockHolder, msgContext, targetURL.getProtocol(), host, port, timeout, otherHeaders, useFullURL); if (null != otherHeaders) { //Add other headers to the end. //for pre java1.4 support, we have to turn the string buffer argument into //a string before appending. header2.append(otherHeaders.toString()); } header2.append("\r\n"); //The empty line to start the BODY. StringBuffer header = new StringBuffer(); // If we're SOAP 1.2, allow the web method to be set from the // MessageContext. if (msgContext.getSOAPConstants() == SOAPConstants.SOAP12_CONSTANTS) { webMethod = msgContext.getStrProp(SOAP12Constants.PROP_WEBMETHOD); } if (webMethod == null) { webMethod = HTTPConstants.HEADER_POST; } else { posting = webMethod.equals(HTTPConstants.HEADER_POST); } header.append(webMethod).append(" "); if (useFullURL.value) { header.append(targetURL.toExternalForm()); } else { header.append((((targetURL.getFile() == null) || targetURL.getFile().equals("")) ? "/" : targetURL.getFile())); } header.append(header2.toString()); OutputStream out = sockHolder.getSocket().getOutputStream(); if (!posting) { out.write(header.toString().getBytes(HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING)); out.flush(); return null; } InputStream inp = null; if (httpChunkStream || httpContinueExpected) { out.write(header.toString().getBytes(HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING)); } if (httpContinueExpected) { //We need to get a reply from the server as to whether // it wants us send anything more. out.flush(); Hashtable cheaders = new Hashtable(); inp = readHeadersFromSocket(sockHolder, msgContext, null, cheaders); int returnCode = -1; Integer Irc = (Integer) msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_CODE); if (null != Irc) { returnCode = Irc.intValue(); } if (100 == returnCode) { // got 100 we may continue. //Need todo a little msgContext house keeping.... msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_CODE); msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE); } else { //If no 100 Continue then we must not send anything! String statusMessage = (String) msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE); AxisFault fault = new AxisFault("HTTP", "(" + returnCode + ")" + statusMessage, null, null); fault.setFaultDetailString(Messages.getMessage("return01", "" + returnCode, "")); throw fault; } } ByteArrayOutputStream baos = null; if (log.isDebugEnabled()) { log.debug(Messages.getMessage("xmlSent00")); log.debug("---------------------------------------------------"); baos = new ByteArrayOutputStream(); } if (httpChunkStream) { ChunkedOutputStream chunkedOutputStream = new ChunkedOutputStream(out); out = new BufferedOutputStream(chunkedOutputStream, Constants.HTTP_TXR_BUFFER_SIZE); try { if (baos != null) { out = new TeeOutputStream(out, baos); } reqMessage.writeTo(out); } catch (SOAPException e) { log.error(Messages.getMessage("exception00"), e); } out.flush(); chunkedOutputStream.eos(); } else { out = new BufferedOutputStream(out, Constants.HTTP_TXR_BUFFER_SIZE); try { if (!httpContinueExpected) { out.write(header.toString().getBytes(HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING)); } if (baos != null) { out = new TeeOutputStream(out, baos); } reqMessage.writeTo(out); } catch (SOAPException e) { log.error(Messages.getMessage("exception00"), e); } // Flush ONLY once. out.flush(); } if (log.isDebugEnabled()) { log.debug(header + new String(baos.toByteArray())); } return inp; } /** * Get cookies from message context and add it to the headers * @param msgContext * @param header * @param otherHeaders */ private void fillHeaders(MessageContext msgContext, String header, StringBuffer otherHeaders) { Object ck1 = msgContext.getProperty(header); if (ck1 != null) { if (ck1 instanceof String[]) { String[] cookies = (String[]) ck1; for (int i = 0; i < cookies.length; i++) { addCookie(otherHeaders, header, cookies[i]); } } else { addCookie(otherHeaders, header, (String) ck1); } } } /** * add cookie to headers * @param otherHeaders * @param header * @param cookie */ private void addCookie(StringBuffer otherHeaders, String header, String cookie) { otherHeaders.append(header).append(": ").append(cookie).append("\r\n"); } private InputStream readHeadersFromSocket(SocketHolder sockHolder, MessageContext msgContext, InputStream inp, Hashtable headers) throws IOException { byte b = 0; int len = 0; int colonIndex = -1; String name, value; int returnCode = 0; if (null == inp) { inp = new BufferedInputStream(sockHolder.getSocket().getInputStream()); } if (headers == null) { headers = new Hashtable(); } // Should help performance. Temporary fix only till its all stream oriented. // Need to add logic for getting the version # and the return code // but that's for tomorrow! /* Logic to read HTTP response headers */ boolean readTooMuch = false; for (ByteArrayOutputStream buf = new ByteArrayOutputStream(4097);;) { if (!readTooMuch) { b = (byte) inp.read(); } if (b == -1) { break; } readTooMuch = false; if ((b != '\r') && (b != '\n')) { if ((b == ':') && (colonIndex == -1)) { colonIndex = len; } len++; buf.write(b); } else if (b == '\r') { continue; } else { // b== '\n' if (len == 0) { break; } b = (byte) inp.read(); readTooMuch = true; // A space or tab at the begining of a line means the header continues. if ((b == ' ') || (b == '\t')) { continue; } buf.close(); byte[] hdata = buf.toByteArray(); buf.reset(); if (colonIndex != -1) { name = new String(hdata, 0, colonIndex, HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING); value = new String(hdata, colonIndex + 1, len - 1 - colonIndex, HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING); colonIndex = -1; } else { name = new String(hdata, 0, len, HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING); value = ""; } if (log.isDebugEnabled()) { log.debug(name + value); } if (msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_CODE) == null) { // Reader status code int start = name.indexOf(' ') + 1; String tmp = name.substring(start).trim(); int end = tmp.indexOf(' '); if (end != -1) { tmp = tmp.substring(0, end); } returnCode = Integer.parseInt(tmp); msgContext.setProperty(HTTPConstants.MC_HTTP_STATUS_CODE, new Integer(returnCode)); msgContext.setProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE, name.substring(start + end + 1)); } else { // if we are maintaining session state, // handle cookies (if any) if (msgContext.getMaintainSession()) { final String nameLowerCase = name.toLowerCase(); if (nameLowerCase.equalsIgnoreCase(HTTPConstants.HEADER_SET_COOKIE)) { handleCookie(HTTPConstants.HEADER_COOKIE, null, value, msgContext); } else if (nameLowerCase.equalsIgnoreCase(HTTPConstants.HEADER_SET_COOKIE2)) { handleCookie(HTTPConstants.HEADER_COOKIE2, null, value, msgContext); } else { headers.put(name.toLowerCase(), value); } } else { headers.put(name.toLowerCase(), value); } } len = 0; } } return inp; } /** * Reads the SOAP response back from the server * * @param msgContext message context * * @throws IOException */ private InputStream readFromSocket(SocketHolder socketHolder, MessageContext msgContext, InputStream inp, Hashtable headers) throws IOException { Message outMsg = null; byte b; Integer rc = (Integer) msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_CODE); int returnCode = 0; if (rc != null) { returnCode = rc.intValue(); } else { // No return code?? Should have one by now. } /* All HTTP headers have been read. */ String contentType = (String) headers.get(HEADER_CONTENT_TYPE_LC); contentType = (null == contentType) ? null : contentType.trim(); String location = (String) headers.get(HEADER_LOCATION_LC); location = (null == location) ? null : location.trim(); if ((returnCode > 199) && (returnCode < 300)) { if (returnCode == 202) { return inp; } // SOAP return is OK - so fall through } else if (msgContext.getSOAPConstants() == SOAPConstants.SOAP12_CONSTANTS) { // For now, if we're SOAP 1.2, fall through, since the range of // valid result codes is much greater } else if ((contentType != null) && !contentType.startsWith("text/html") && ((returnCode > 499) && (returnCode < 600))) { // SOAP Fault should be in here - so fall through } else if ((location != null) && ((returnCode == 302) || (returnCode == 307))) { // Temporary Redirect (HTTP: 302/307) // close old connection inp.close(); socketHolder.getSocket().close(); // remove former result and set new target url msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_CODE); msgContext.setProperty(MessageContext.TRANS_URL, location); // next try invoke(msgContext); return inp; } else if (returnCode == 100) { msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_CODE); msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE); readHeadersFromSocket(socketHolder, msgContext, inp, headers); return readFromSocket(socketHolder, msgContext, inp, headers); } else { // Unknown return code - so wrap up the content into a // SOAP Fault. ByteArrayOutputStream buf = new ByteArrayOutputStream(4097); while (-1 != (b = (byte) inp.read())) { buf.write(b); } String statusMessage = msgContext.getStrProp(HTTPConstants.MC_HTTP_STATUS_MESSAGE); AxisFault fault = new AxisFault("HTTP", "(" + returnCode + ")" + statusMessage, null, null); fault.setFaultDetailString(Messages.getMessage("return01", "" + returnCode, buf.toString())); fault.addFaultDetail(Constants.QNAME_FAULTDETAIL_HTTPERRORCODE, Integer.toString(returnCode)); throw fault; } String contentLocation = (String) headers.get(HEADER_CONTENT_LOCATION_LC); contentLocation = (null == contentLocation) ? null : contentLocation.trim(); String contentLength = (String) headers.get(HEADER_CONTENT_LENGTH_LC); contentLength = (null == contentLength) ? null : contentLength.trim(); String transferEncoding = (String) headers.get(HEADER_TRANSFER_ENCODING_LC); if (null != transferEncoding) { transferEncoding = transferEncoding.trim().toLowerCase(); if (transferEncoding.equals(HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED)) { inp = new ChunkedInputStream(inp); } } outMsg = new Message(new SocketInputStream(inp, socketHolder.getSocket()), false, contentType, contentLocation); // Transfer HTTP headers of HTTP message to MIME headers of SOAP message MimeHeaders mimeHeaders = outMsg.getMimeHeaders(); for (Enumeration e = headers.keys(); e.hasMoreElements();) { String key = (String) e.nextElement(); mimeHeaders.addHeader(key, ((String) headers.get(key)).trim()); } outMsg.setMessageType(Message.RESPONSE); msgContext.setResponseMessage(outMsg); if (log.isDebugEnabled()) { if (null == contentLength) { log.debug("\n" + Messages.getMessage("no00", "Content-Length")); } log.debug("\n" + Messages.getMessage("xmlRecd00")); log.debug("-----------------------------------------------"); log.debug(outMsg.getSOAPEnvelope().toString()); } return inp; } /** * little helper function for cookies. fills up the message context with * a string or an array of strings (if there are more than one Set-Cookie) * * @param cookieName * @param setCookieName * @param cookie * @param msgContext */ public void handleCookie(String cookieName, String setCookieName, String cookie, MessageContext msgContext) { cookie = cleanupCookie(cookie); int keyIndex = cookie.indexOf("="); String key = (keyIndex != -1) ? cookie.substring(0, keyIndex) : cookie; ArrayList cookies = new ArrayList(); Object oldCookies = msgContext.getProperty(cookieName); boolean alreadyExist = false; if (oldCookies != null) { if (oldCookies instanceof String[]) { String[] oldCookiesArray = (String[]) oldCookies; for (int i = 0; i < oldCookiesArray.length; i++) { String anOldCookie = oldCookiesArray[i]; if (key != null && anOldCookie.indexOf(key) == 0) { // same cookie key anOldCookie = cookie; // update to new one alreadyExist = true; } cookies.add(anOldCookie); } } else { String oldCookie = (String) oldCookies; if (key != null && oldCookie.indexOf(key) == 0) { // same cookie key oldCookie = cookie; // update to new one alreadyExist = true; } cookies.add(oldCookie); } } if (!alreadyExist) { cookies.add(cookie); } if (cookies.size() == 1) { msgContext.setProperty(cookieName, cookies.get(0)); } else if (cookies.size() > 1) { msgContext.setProperty(cookieName, cookies.toArray(new String[cookies.size()])); } } /** * cleanup the cookie value. * * @param cookie initial cookie value * * @return a cleaned up cookie value. */ private String cleanupCookie(String cookie) { cookie = cookie.trim(); // chop after first ; a la Apache SOAP (see HTTPUtils.java there) int index = cookie.indexOf(';'); if (index != -1) { cookie = cookie.substring(0, index); } return cookie; } }