View Javadoc

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