View Javadoc

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