View Javadoc

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