View Javadoc
1   /*
2    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
3    * The software in this package is published under the terms of the CPAL v1.0
4    * license, a copy of which has been included with this distribution in the
5    * LICENSE.txt file.
6    */
7   package org.mule.transport.soap.axis.extensions;
8   
9   import org.mule.module.cxf.SoapConstants;
10  import org.mule.util.StringUtils;
11  import org.mule.util.SystemUtils;
12  
13  import java.io.BufferedInputStream;
14  import java.io.BufferedOutputStream;
15  import java.io.IOException;
16  import java.io.InputStream;
17  import java.io.OutputStream;
18  import java.net.Socket;
19  import java.net.URL;
20  import java.util.Enumeration;
21  import java.util.Hashtable;
22  import java.util.Iterator;
23  
24  import javax.xml.soap.MimeHeader;
25  import javax.xml.soap.MimeHeaders;
26  import javax.xml.soap.SOAPException;
27  
28  import org.apache.axis.AxisFault;
29  import org.apache.axis.Constants;
30  import org.apache.axis.Message;
31  import org.apache.axis.MessageContext;
32  import org.apache.axis.client.Call;
33  import org.apache.axis.components.logger.LogFactory;
34  import org.apache.axis.components.net.BooleanHolder;
35  import org.apache.axis.components.net.DefaultSocketFactory;
36  import org.apache.axis.components.net.SocketFactory;
37  import org.apache.axis.components.net.SocketFactoryFactory;
38  import org.apache.axis.encoding.Base64;
39  import org.apache.axis.handlers.BasicHandler;
40  import org.apache.axis.soap.SOAP12Constants;
41  import org.apache.axis.soap.SOAPConstants;
42  import org.apache.axis.transport.http.ChunkedInputStream;
43  import org.apache.axis.transport.http.ChunkedOutputStream;
44  import org.apache.axis.transport.http.HTTPConstants;
45  import org.apache.axis.transport.http.HTTPSender;
46  import org.apache.axis.transport.http.SocketHolder;
47  import org.apache.axis.transport.http.SocketInputStream;
48  import org.apache.axis.utils.Messages;
49  import org.apache.axis.utils.TeeOutputStream;
50  import org.apache.commons.io.output.ByteArrayOutputStream;
51  import org.apache.commons.logging.Log;
52  
53  /**
54   * <code>MuleHttpSender</code> is a rewrite of the Axis HttpSender. Unfortunately,
55   * the Axis implementation is not extensible so this class is a copy of it with
56   * modifications. The enhancements made are to allow for asynchronous Http method
57   * calls which Mule initiates when the endpoint is asynchronous.
58   *
59   * @deprecated Use the UniversalSender instead
60   */
61  @Deprecated
62  public class MuleHttpSender extends BasicHandler
63  {
64      /**
65       * Serial version
66       */
67      private static final long serialVersionUID = -1730816323289419500L;
68  
69      protected static final Log log = LogFactory.getLog(HTTPSender.class.getName());
70  
71      private static final String ACCEPT_HEADERS = HTTPConstants.HEADER_ACCEPT
72                                                   // limit to the types that are
73                                                      // meaningful to us.
74                                                   + ": " + HTTPConstants.HEADER_ACCEPT_APPL_SOAP + ", "
75                                                   + HTTPConstants.HEADER_ACCEPT_APPLICATION_DIME + ", "
76                                                   + HTTPConstants.HEADER_ACCEPT_MULTIPART_RELATED + ", "
77                                                   + HTTPConstants.HEADER_ACCEPT_TEXT_ALL + "\r\n"
78                                                   + HTTPConstants.HEADER_USER_AGENT // Tell
79                                                                                      // who
80                                                                                      // we
81                                                                                      // are.
82                                                   + ": " + Messages.getMessage("axisUserAgent") + "\r\n";
83  
84      private static final String CACHE_HEADERS = HTTPConstants.HEADER_CACHE_CONTROL
85                                                  // stop caching proxies from caching
86                                                  // SOAP request.
87                                                  + ": " + HTTPConstants.HEADER_CACHE_CONTROL_NOCACHE + "\r\n"
88                                                  + HTTPConstants.HEADER_PRAGMA + ": "
89                                                  + HTTPConstants.HEADER_CACHE_CONTROL_NOCACHE + "\r\n";
90  
91      private static final String CHUNKED_HEADER = HTTPConstants.HEADER_TRANSFER_ENCODING + ": "
92                                                   + HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED + "\r\n";
93  
94      private static final String HEADER_CONTENT_TYPE_LC = HTTPConstants.HEADER_CONTENT_TYPE.toLowerCase();
95  
96      private static final String HEADER_LOCATION_LC = HTTPConstants.HEADER_LOCATION.toLowerCase();
97  
98      private static final String HEADER_CONTENT_LOCATION_LC = HTTPConstants.HEADER_CONTENT_LOCATION.toLowerCase();
99  
100     private static final String HEADER_CONTENT_LENGTH_LC = HTTPConstants.HEADER_CONTENT_LENGTH.toLowerCase();
101 
102     private static final String HEADER_TRANSFER_ENCODING_LC = HTTPConstants.HEADER_TRANSFER_ENCODING.toLowerCase();
103 
104     /**
105      * the url; used for error reporting
106      */
107     URL targetURL;
108 
109     /**
110      * invoke creates a socket connection, sends the request SOAP message and then
111      * reads the response SOAP message back from the SOAP server
112      * 
113      * @param msgContext the messsage context
114      * @throws AxisFault
115      */
116     public void invoke(MessageContext msgContext) throws AxisFault
117     {
118 
119         if (log.isDebugEnabled())
120         {
121             log.debug(Messages.getMessage("enter00", "HTTPSender::invoke"));
122         }
123         try
124         {
125             Call call = (Call)msgContext.getProperty("call_object");
126             String transURL = msgContext.getStrProp(MessageContext.TRANS_URL);
127             String uri = transURL;
128             if (call != null && call.useSOAPAction())
129             {
130                 uri = call.getSOAPActionURI();
131             }
132             msgContext.setProperty(SoapConstants.SOAP_ACTION_PROPERTY_CAPS, uri);
133 
134             BooleanHolder useFullURL = new BooleanHolder(false);
135             StringBuffer otherHeaders = new StringBuffer(64);
136             targetURL = new URL(transURL);
137             String host = targetURL.getHost();
138             int port = targetURL.getPort();
139 
140             SocketHolder socketHolder = new SocketHolder(null);
141 
142             // Send the SOAP request to the server
143             InputStream inp = writeToSocket(socketHolder, msgContext, targetURL, otherHeaders, host, port,
144                 msgContext.getTimeout(), useFullURL);
145 
146             if (msgContext.isClient() && call != null)
147             {
148                 if (Boolean.TRUE.equals(call.getProperty("axis.one.way")))
149                 {
150                     return;
151                 }
152             }
153 
154             // Read the response back from the server
155             Hashtable headers = new Hashtable();
156             inp = readHeadersFromSocket(socketHolder, msgContext, inp, headers);
157             readFromSocket(socketHolder, msgContext, inp, headers);
158         }
159         catch (Exception e)
160         {
161             log.debug(e);
162             throw AxisFault.makeFault(e);
163         }
164         if (log.isDebugEnabled())
165         {
166             log.debug(Messages.getMessage("exit00", "HTTPDispatchHandler::invoke"));
167         }
168     }
169 
170     /**
171      * Creates a socket connection to the SOAP server
172      * 
173      * @param protocol "http" for standard, "https" for ssl.
174      * @param host host name
175      * @param port port to connect to
176      * @param otherHeaders buffer for storing additional headers that need to be sent
177      * @param useFullURL flag to indicate if the complete URL has to be sent
178      * @throws java.io.IOException
179      */
180     protected void getSocket(SocketHolder sockHolder,
181                              MessageContext msgContext,
182                              String protocol,
183                              String host,
184                              int port,
185                              int timeout,
186                              StringBuffer otherHeaders,
187                              BooleanHolder useFullURL) throws Exception
188     {
189         Hashtable options = getOptions();
190         if (timeout > 0)
191         {
192             if (options == null)
193             {
194                 options = new Hashtable();
195             }
196             options.put(DefaultSocketFactory.CONNECT_TIMEOUT, Integer.toString(timeout));
197         }
198         SocketFactory factory = SocketFactoryFactory.getFactory(protocol, options);
199         if (factory == null)
200         {
201             throw new IOException(Messages.getMessage("noSocketFactory", protocol));
202         }
203         // log.fatal("Axis client: connect on socket: " + host + ":" + port);
204         Socket sock = null;
205         try
206         {
207             sock = factory.create(host, port, otherHeaders, useFullURL);
208         }
209         catch (Exception e)
210         {
211             Thread.sleep(1000);
212             try
213             {
214                 sock = factory.create(host, port, otherHeaders, useFullURL);
215             }
216             catch (Exception e1)
217             {
218                 log.fatal("Axis client Failed: connect on socket: " + host + ":" + port, e);
219                 throw e;
220             }
221         }
222         if (timeout > 0)
223         {
224             sock.setSoTimeout(timeout);
225         }
226         sockHolder.setSocket(sock);
227     }
228 
229     /**
230      * Send the soap request message to the server
231      * 
232      * @param msgContext message context
233      * @param tmpURL url to connect to
234      * @param otherHeaders other headers if any
235      * @param host host name
236      * @param port port
237      * @param useFullURL flag to indicate if the whole url needs to be sent
238      * @throws IOException
239      */
240     private InputStream writeToSocket(SocketHolder sockHolder,
241                                       MessageContext msgContext,
242                                       URL tmpURL,
243                                       StringBuffer otherHeaders,
244                                       String host,
245                                       int port,
246                                       int timeout,
247                                       BooleanHolder useFullURL) throws Exception
248     {
249 
250         String userID = msgContext.getUsername();
251         String passwd = msgContext.getPassword();
252 
253         // Get SOAPAction, default to ""
254         String action = msgContext.useSOAPAction() ? msgContext.getSOAPActionURI() : "";
255 
256         if (action == null)
257         {
258             action = "";
259         }
260 
261         // if UserID is not part of the context, but is in the URL, use
262         // the one in the URL.
263         if ((userID == null) && (tmpURL.getUserInfo() != null))
264         {
265             String info = tmpURL.getUserInfo();
266             int sep = info.indexOf(':');
267 
268             if ((sep >= 0) && (sep + 1 < info.length()))
269             {
270                 userID = info.substring(0, sep);
271                 passwd = info.substring(sep + 1);
272             }
273             else
274             {
275                 userID = info;
276             }
277         }
278         if (userID != null)
279         {
280             StringBuffer tmpBuf = new StringBuffer(64);
281             tmpBuf.append(userID).append(":").append((passwd == null) ? "" : passwd);
282             otherHeaders.append(HTTPConstants.HEADER_AUTHORIZATION).append(": Basic ").append(
283                 Base64.encode(tmpBuf.toString().getBytes())).append("\r\n");
284         }
285 
286         // don't forget the cookies!
287         // mmm... cookies
288         if (msgContext.getMaintainSession())
289         {
290             String cookie = msgContext.getStrProp(HTTPConstants.HEADER_COOKIE);
291             String cookie2 = msgContext.getStrProp(HTTPConstants.HEADER_COOKIE2);
292 
293             if (cookie != null)
294             {
295                 otherHeaders.append(HTTPConstants.HEADER_COOKIE).append(": ").append(cookie).append("\r\n");
296             }
297             if (cookie2 != null)
298             {
299                 otherHeaders.append(HTTPConstants.HEADER_COOKIE2).append(": ").append(cookie2).append("\r\n");
300             }
301         }
302 
303         StringBuffer header2 = new StringBuffer(64);
304 
305         String webMethod = null;
306         boolean posting = true;
307 
308         Message reqMessage = msgContext.getRequestMessage();
309 
310         boolean http10 = true; // True if this is to use HTTP 1.0 / false HTTP
311         // 1.1
312         boolean httpChunkStream = false; // Use HTTP chunking or not.
313         boolean httpContinueExpected = false; // Under HTTP 1.1 if false you
314         // *MAY* need to wait for a 100
315         // rc,
316         // if true the server MUST reply with 100 continue.
317         String httpConnection = null;
318 
319         String httpver = msgContext.getStrProp(MessageContext.HTTP_TRANSPORT_VERSION);
320         if (null == httpver)
321         {
322             httpver = HTTPConstants.HEADER_PROTOCOL_V10;
323         }
324         httpver = httpver.trim();
325         if (httpver.equals(HTTPConstants.HEADER_PROTOCOL_V11))
326         {
327             http10 = false;
328         }
329 
330         // process user defined headers for information.
331         Hashtable userHeaderTable = (Hashtable)msgContext.getProperty(HTTPConstants.REQUEST_HEADERS);
332 
333         if (userHeaderTable != null)
334         {
335             if (null == otherHeaders)
336             {
337                 otherHeaders = new StringBuffer(1024);
338             }
339 
340             for (java.util.Iterator e = userHeaderTable.entrySet().iterator(); e.hasNext();)
341             {
342 
343                 java.util.Map.Entry me = (java.util.Map.Entry)e.next();
344                 Object keyObj = me.getKey();
345                 if (null == keyObj)
346                 {
347                     continue;
348                 }
349                 String key = keyObj.toString().trim();
350 
351                 if (key.equalsIgnoreCase(HTTPConstants.HEADER_TRANSFER_ENCODING))
352                 {
353                     if (!http10)
354                     {
355                         String val = me.getValue().toString();
356                         if (null != val
357                             && val.trim().equalsIgnoreCase(HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED))
358                         {
359                             httpChunkStream = true;
360                         }
361                     }
362                 }
363                 else if (key.equalsIgnoreCase(HTTPConstants.HEADER_CONNECTION))
364                 {
365                     if (!http10)
366                     {
367                         String val = me.getValue().toString();
368                         if (val.trim().equalsIgnoreCase(HTTPConstants.HEADER_CONNECTION_CLOSE))
369                         {
370                             httpConnection = HTTPConstants.HEADER_CONNECTION_CLOSE;
371                         }
372                     }
373                     // HTTP 1.0 will always close.
374                     // HTTP 1.1 will use persistent. //no need to specify
375                 }
376                 else
377                 {
378                     if (!http10 && key.equalsIgnoreCase(HTTPConstants.HEADER_EXPECT))
379                     {
380                         String val = me.getValue().toString();
381                         if (null != val
382                             && val.trim().equalsIgnoreCase(HTTPConstants.HEADER_EXPECT_100_Continue))
383                         {
384                             httpContinueExpected = true;
385                         }
386                     }
387 
388                     otherHeaders.append(key).append(": ").append(me.getValue()).append("\r\n");
389                 }
390             }
391         }
392 
393         if (!http10)
394         {
395             // Force close for now.
396             // TODO HTTP/1.1
397             httpConnection = HTTPConstants.HEADER_CONNECTION_CLOSE;
398         }
399 
400         header2.append(" ");
401         header2.append(http10 ? HTTPConstants.HEADER_PROTOCOL_10 : HTTPConstants.HEADER_PROTOCOL_11).append(
402             "\r\n");
403         MimeHeaders mimeHeaders = reqMessage.getMimeHeaders();
404 
405         if (posting)
406         {
407             String contentType;
408             if (mimeHeaders.getHeader(HTTPConstants.HEADER_CONTENT_TYPE) != null)
409             {
410                 contentType = mimeHeaders.getHeader(HTTPConstants.HEADER_CONTENT_TYPE)[0];
411             }
412             else
413             {
414                 contentType = reqMessage.getContentType(msgContext.getSOAPConstants());
415             }
416             header2.append(HTTPConstants.HEADER_CONTENT_TYPE).append(": ").append(contentType).append("\r\n");
417         }
418 
419         header2.append(ACCEPT_HEADERS).append(HTTPConstants.HEADER_HOST)
420         // used for virtual connections
421             .append(": ")
422             .append(host)
423             .append((port == -1) ? ("") : (":" + port))
424             .append("\r\n")
425             .append(CACHE_HEADERS)
426             .append(HTTPConstants.HEADER_SOAP_ACTION)
427             // The SOAP action.
428             .append(": \"")
429             .append(action)
430             .append("\"\r\n");
431 
432         if (posting)
433         {
434             if (!httpChunkStream)
435             {
436                 // Content length MUST be sent on HTTP 1.0 requests.
437                 header2.append(HTTPConstants.HEADER_CONTENT_LENGTH).append(": ").append(
438                     reqMessage.getContentLength()).append("\r\n");
439             }
440             else
441             {
442                 // Do http chunking.
443                 header2.append(CHUNKED_HEADER);
444             }
445         }
446 
447         // Transfer MIME headers of SOAPMessage to HTTP headers.
448         if (mimeHeaders != null)
449         {
450             for (Iterator i = mimeHeaders.getAllHeaders(); i.hasNext();)
451             {
452                 MimeHeader mimeHeader = (MimeHeader)i.next();
453                 String headerName = mimeHeader.getName();
454                 if (headerName.equals(HTTPConstants.HEADER_CONTENT_TYPE)
455                     || headerName.equals(HTTPConstants.HEADER_SOAP_ACTION))
456                 {
457                     continue;
458                 }
459                 header2.append(mimeHeader.getName())
460                     .append(": ")
461                     .append(mimeHeader.getValue())
462                     .append("\r\n");
463             }
464         }
465 
466         if (null != httpConnection)
467         {
468             header2.append(HTTPConstants.HEADER_CONNECTION);
469             header2.append(": ");
470             header2.append(httpConnection);
471             header2.append("\r\n");
472         }
473 
474         getSocket(sockHolder, msgContext, targetURL.getProtocol(), host, port, timeout, otherHeaders,
475             useFullURL);
476 
477         if (null != otherHeaders)
478         {
479             // Add other headers to the end.
480             // for pre java1.4 support, we have to turn the string buffer
481             // argument into
482             // a string before appending.
483             header2.append(otherHeaders.toString());
484         }
485 
486         header2.append("\r\n"); // The empty line to start the BODY.
487 
488         StringBuffer header = new StringBuffer(128);
489 
490         // If we're SOAP 1.2, allow the web method to be set from the
491         // MessageContext.
492         if (msgContext.getSOAPConstants() == SOAPConstants.SOAP12_CONSTANTS)
493         {
494             webMethod = msgContext.getStrProp(SOAP12Constants.PROP_WEBMETHOD);
495         }
496         if (webMethod == null)
497         {
498             webMethod = HTTPConstants.HEADER_POST;
499         }
500         else
501         {
502             posting = webMethod.equals(HTTPConstants.HEADER_POST);
503         }
504 
505         header.append(webMethod).append(" ");
506         if (useFullURL.value)
507         {
508             header.append(tmpURL.toExternalForm());
509         }
510         else
511         {
512             header.append(StringUtils.isEmpty(tmpURL.getFile()) ? "/" : tmpURL.getFile());
513         }
514         header.append(header2.toString());
515 
516         OutputStream out = sockHolder.getSocket().getOutputStream();
517 
518         if (!posting)
519         {
520             out.write(header.toString().getBytes(HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING));
521             out.flush();
522             return null;
523         }
524 
525         InputStream inp = null;
526 
527         if (httpChunkStream || httpContinueExpected)
528         {
529             out.write(header.toString().getBytes(HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING));
530         }
531 
532         if (httpContinueExpected)
533         { // We need to get a reply from the server as
534             // to whether
535             // it wants us send anything more.
536             out.flush();
537             Hashtable cheaders = new Hashtable();
538             inp = readHeadersFromSocket(sockHolder, msgContext, null, cheaders);
539             int returnCode = -1;
540             Integer Irc = (Integer)msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_CODE);
541             if (null != Irc)
542             {
543                 returnCode = Irc.intValue();
544             }
545             if (100 == returnCode)
546             { // got 100 we may continue.
547                 // Need TODO a little msgContext house keeping....
548                 msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_CODE);
549                 msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE);
550             }
551             else
552             { // If no 100 Continue then we must not send anything!
553                 String statusMessage = (String)msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE);
554 
555                 AxisFault fault = new AxisFault("HTTP", "(" + returnCode + ")" + statusMessage, null, null);
556 
557                 fault.setFaultDetailString(Messages.getMessage("return01", String.valueOf(returnCode), ""));
558                 throw fault;
559             }
560         }
561         ByteArrayOutputStream baos = null;
562         if (log.isDebugEnabled())
563         {
564             log.debug(Messages.getMessage("xmlSent00"));
565             log.debug("---------------------------------------------------");
566             baos = new ByteArrayOutputStream();
567         }
568         if (httpChunkStream)
569         {
570             ChunkedOutputStream chunkedOutputStream = new ChunkedOutputStream(out);
571             out = new BufferedOutputStream(chunkedOutputStream, Constants.HTTP_TXR_BUFFER_SIZE);
572             try
573             {
574                 if (baos != null)
575                 {
576                     out = new TeeOutputStream(out, baos);
577                 }
578                 reqMessage.writeTo(out);
579             }
580             catch (SOAPException e)
581             {
582                 log.error(Messages.getMessage("exception00"), e);
583             }
584             out.flush();
585             chunkedOutputStream.eos();
586         }
587         else
588         {
589             out = new BufferedOutputStream(out, Constants.HTTP_TXR_BUFFER_SIZE);
590             try
591             {
592                 if (!httpContinueExpected)
593                 {
594                     out.write(header.toString().getBytes(HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING));
595                 }
596                 if (baos != null)
597                 {
598                     out = new TeeOutputStream(out, baos);
599                 }
600                 reqMessage.writeTo(out);
601             }
602             catch (SOAPException e)
603             {
604                 throw e;
605             }
606             finally
607             {
608                 // Flush ONLY once.
609                 out.flush();
610             }
611 
612         }
613 
614         if (log.isDebugEnabled() && baos != null)
615         {
616             log.debug(header + new String(baos.toByteArray()));
617         }
618 
619         return inp;
620     }
621 
622     private InputStream readHeadersFromSocket(SocketHolder sockHolder,
623                                               MessageContext msgContext,
624                                               InputStream inp,
625                                               Hashtable headers) throws IOException
626     {
627         byte b = 0;
628         int len = 0;
629         int colonIndex = -1;
630         String name, value;
631         int returnCode = 0;
632         if (null == inp)
633         {
634             inp = new BufferedInputStream(sockHolder.getSocket().getInputStream());
635         }
636 
637         if (headers == null)
638         {
639             headers = new Hashtable();
640         }
641 
642         // Should help performance. Temporary fix only till its all stream
643         // oriented.
644         // Need to add logic for getting the version # and the return code
645         // but that's for tomorrow!
646 
647         /* Logic to read HTTP response headers */
648         boolean readTooMuch = false;
649 
650         for (ByteArrayOutputStream buf = new ByteArrayOutputStream(4097);;)
651         {
652             if (!readTooMuch)
653             {
654                 b = (byte)inp.read();
655             }
656             if (b == -1)
657             {
658                 break;
659             }
660             readTooMuch = false;
661             if ((b != '\r') && (b != '\n'))
662             {
663                 if ((b == ':') && (colonIndex == -1))
664                 {
665                     colonIndex = len;
666                 }
667                 len++;
668                 buf.write(b);
669             }
670             else if (b == '\r')
671             {
672                 continue;
673             }
674             else
675             { // b== '\n'
676                 if (len == 0)
677                 {
678                     break;
679                 }
680                 b = (byte)inp.read();
681                 readTooMuch = true;
682 
683                 // A space or tab at the begining of a line means the header
684                 // continues.
685                 if ((b == ' ') || (b == '\t'))
686                 {
687                     continue;
688                 }
689                 buf.close();
690                 byte[] hdata = buf.toByteArray();
691                 buf.reset();
692                 if (colonIndex != -1)
693                 {
694                     name = new String(hdata, 0, colonIndex, HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING);
695                     value = new String(hdata, colonIndex + 1, len - 1 - colonIndex,
696                         HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING);
697                     colonIndex = -1;
698                 }
699                 else
700                 {
701 
702                     name = new String(hdata, 0, len, HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING);
703                     value = "";
704                 }
705                 if (log.isDebugEnabled())
706                 {
707                     log.debug(name + value);
708                 }
709                 if (msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_CODE) == null)
710                 {
711 
712                     // Reader status code
713                     int start = name.indexOf(' ') + 1;
714                     String tmp = name.substring(start).trim();
715                     int end = tmp.indexOf(' ');
716 
717                     if (end != -1)
718                     {
719                         tmp = tmp.substring(0, end);
720                     }
721                     returnCode = Integer.parseInt(tmp);
722                     msgContext.setProperty(HTTPConstants.MC_HTTP_STATUS_CODE, new Integer(returnCode));
723                     msgContext.setProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE, name.substring(start + end
724                                                                                                 + 1));
725                 }
726                 else
727                 {
728                     headers.put(name.toLowerCase(), value);
729                 }
730                 len = 0;
731             }
732         }
733 
734         return inp;
735     }
736 
737     /**
738      * Reads the SOAP response back from the server
739      * 
740      * @param msgContext message context
741      * @throws IOException
742      */
743     private InputStream readFromSocket(SocketHolder socketHolder,
744                                        MessageContext msgContext,
745                                        InputStream inp,
746                                        Hashtable headers) throws IOException
747     {
748         Message outMsg = null;
749         byte b;
750 
751         Integer rc = (Integer)msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_CODE);
752         int returnCode = 0;
753         if (rc != null)
754         {
755             returnCode = rc.intValue();
756         }
757         else
758         {
759             // No return code?? Should have one by now.
760         }
761 
762         /* All HTTP headers have been read. */
763         String contentType = (String)headers.get(HEADER_CONTENT_TYPE_LC);
764 
765         contentType = (null == contentType) ? null : contentType.trim();
766 
767         String location = (String)headers.get(HEADER_LOCATION_LC);
768 
769         location = (null == location) ? null : location.trim();
770 
771         if ((returnCode > 199) && (returnCode < 300))
772         {
773             if (returnCode == 202)
774             {
775                 return inp;
776             }
777             // SOAP return is OK - so fall through
778         }
779         else if (msgContext.getSOAPConstants() == SOAPConstants.SOAP12_CONSTANTS)
780         {
781             // For now, if we're SOAP 1.2, fall through, since the range of
782             // valid result codes is much greater
783         }
784         else if ((contentType != null) && !contentType.startsWith("text/html")
785                  && ((returnCode > 499) && (returnCode < 600)))
786         {
787             // SOAP Fault should be in here - so fall through
788         }
789         else if ((location != null) && ((returnCode == 302) || (returnCode == 307)))
790         {
791             // Temporary Redirect (HTTP: 302/307)
792             // close old connection
793             inp.close();
794             socketHolder.getSocket().close();
795             // remove former result and set new target url
796             msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_CODE);
797             msgContext.setProperty(MessageContext.TRANS_URL, location);
798             // next try
799             invoke(msgContext);
800             return inp;
801         }
802         else if (returnCode == 100)
803         {
804             msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_CODE);
805             msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE);
806             readHeadersFromSocket(socketHolder, msgContext, inp, headers);
807             return readFromSocket(socketHolder, msgContext, inp, headers);
808         }
809         else
810         {
811             // Unknown return code - so wrap up the content into a
812             // SOAP Fault.
813             ByteArrayOutputStream buf = new ByteArrayOutputStream(4097);
814 
815             while (-1 != (b = (byte)inp.read()))
816             {
817                 buf.write(b);
818             }
819             String statusMessage = msgContext.getStrProp(HTTPConstants.MC_HTTP_STATUS_MESSAGE);
820             AxisFault fault = new AxisFault("HTTP", "(" + returnCode + ")" + statusMessage, null, null);
821 
822             fault.setFaultDetailString(Messages.getMessage("return01", String.valueOf(returnCode), buf.toString()));
823             fault.addFaultDetail(Constants.QNAME_FAULTDETAIL_HTTPERRORCODE, Integer.toString(returnCode));
824             throw fault;
825         }
826 
827         String contentLocation = (String)headers.get(HEADER_CONTENT_LOCATION_LC);
828 
829         contentLocation = (null == contentLocation) ? null : contentLocation.trim();
830 
831         String contentLength = (String)headers.get(HEADER_CONTENT_LENGTH_LC);
832 
833         contentLength = (null == contentLength) ? null : contentLength.trim();
834 
835         String transferEncoding = (String)headers.get(HEADER_TRANSFER_ENCODING_LC);
836 
837         if (null != transferEncoding)
838         {
839             transferEncoding = transferEncoding.trim().toLowerCase();
840             if (transferEncoding.equals(HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED))
841             {
842                 inp = new ChunkedInputStream(inp);
843             }
844         }
845 
846         outMsg = new Message(new SocketInputStream(inp, socketHolder.getSocket()), false, contentType,
847             contentLocation);
848         // Transfer HTTP headers of HTTP message to MIME headers of SOAP message
849         MimeHeaders mimeHeaders = outMsg.getMimeHeaders();
850         for (Enumeration e = headers.keys(); e.hasMoreElements();)
851         {
852             String key = (String)e.nextElement();
853             mimeHeaders.addHeader(key, ((String)headers.get(key)).trim());
854         }
855         outMsg.setMessageType(Message.RESPONSE);
856         msgContext.setResponseMessage(outMsg);
857         if (log.isDebugEnabled())
858         {
859             if (null == contentLength)
860             {
861                 log.debug(SystemUtils.LINE_SEPARATOR + Messages.getMessage("no00", "Content-Length"));
862             }
863             log.debug(SystemUtils.LINE_SEPARATOR + Messages.getMessage("xmlRecd00"));
864             log.debug("-----------------------------------------------");
865             log.debug(outMsg.getSOAPEnvelope().toString());
866         }
867 
868         // if we are maintaining session state,
869         // handle cookies (if any)
870         if (msgContext.getMaintainSession())
871         {
872             handleCookie(HTTPConstants.HEADER_COOKIE, HTTPConstants.HEADER_SET_COOKIE, headers, msgContext);
873             handleCookie(HTTPConstants.HEADER_COOKIE2, HTTPConstants.HEADER_SET_COOKIE2, headers, msgContext);
874         }
875         return inp;
876     }
877 
878     /**
879      * little helper function for cookies
880      * 
881      * @param cookieName
882      * @param setCookieName
883      * @param headers
884      * @param msgContext
885      */
886     public void handleCookie(String cookieName,
887                              String setCookieName,
888                              Hashtable headers,
889                              MessageContext msgContext)
890     {
891 
892         if (headers.containsKey(setCookieName.toLowerCase()))
893         {
894             String cookie = (String)headers.get(setCookieName.toLowerCase());
895             cookie = cookie.trim();
896 
897             // chop after first ; a la Apache SOAP (see HTTPUtils.java there)
898             int index = cookie.indexOf(';');
899 
900             if (index != -1)
901             {
902                 cookie = cookie.substring(0, index);
903             }
904             msgContext.setProperty(cookieName, cookie);
905         }
906     }
907 }