KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > transport > http > HTTPSender


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.axis.transport.http;
17
18 import org.apache.axis.AxisFault;
19 import org.apache.axis.Message;
20 import org.apache.axis.MessageContext;
21 import org.apache.axis.Constants;
22 import org.apache.axis.components.logger.LogFactory;
23 import org.apache.axis.components.net.BooleanHolder;
24 import org.apache.axis.components.net.SocketFactory;
25 import org.apache.axis.components.net.SocketFactoryFactory;
26 import org.apache.axis.components.net.DefaultSocketFactory;
27 import org.apache.axis.encoding.Base64;
28 import org.apache.axis.handlers.BasicHandler;
29 import org.apache.axis.soap.SOAP12Constants;
30 import org.apache.axis.soap.SOAPConstants;
31 import org.apache.axis.utils.Messages;
32 import org.apache.axis.utils.TeeOutputStream;
33 import org.apache.commons.logging.Log;
34
35 import javax.xml.soap.MimeHeader JavaDoc;
36 import javax.xml.soap.MimeHeaders JavaDoc;
37 import javax.xml.soap.SOAPException JavaDoc;
38 import java.io.BufferedInputStream JavaDoc;
39 import java.io.BufferedOutputStream JavaDoc;
40 import java.io.ByteArrayOutputStream JavaDoc;
41 import java.io.IOException JavaDoc;
42 import java.io.InputStream JavaDoc;
43 import java.io.OutputStream JavaDoc;
44 import java.net.Socket JavaDoc;
45 import java.net.URL JavaDoc;
46 import java.util.Enumeration JavaDoc;
47 import java.util.Hashtable JavaDoc;
48 import java.util.Iterator JavaDoc;
49 import java.util.ArrayList JavaDoc;
50 import java.util.Collection JavaDoc;
51
52 /**
53  * This is meant to be used on a SOAP Client to call a SOAP server.
54  *
55  * @author Doug Davis (dug@us.ibm.com)
56  * @author Davanum Srinivas (dims@yahoo.com)
57  */

58 public class HTTPSender extends BasicHandler {
59
60     protected static Log log = LogFactory.getLog(HTTPSender.class.getName());
61
62     private static final String JavaDoc ACCEPT_HEADERS =
63         HTTPConstants.HEADER_ACCEPT + //Limit to the types that are meaningful to us.
64
": " +
65         HTTPConstants.HEADER_ACCEPT_APPL_SOAP +
66         ", " +
67         HTTPConstants.HEADER_ACCEPT_APPLICATION_DIME +
68         ", " +
69         HTTPConstants.HEADER_ACCEPT_MULTIPART_RELATED +
70         ", " +
71         HTTPConstants.HEADER_ACCEPT_TEXT_ALL +
72         "\r\n" +
73         HTTPConstants.HEADER_USER_AGENT + //Tell who we are.
74
": " +
75         Messages.getMessage("axisUserAgent") +
76         "\r\n";
77
78     private static final String JavaDoc CACHE_HEADERS =
79         HTTPConstants.HEADER_CACHE_CONTROL + //Stop caching proxies from caching SOAP reqeuest.
80
": " +
81         HTTPConstants.HEADER_CACHE_CONTROL_NOCACHE +
82         "\r\n" +
83         HTTPConstants.HEADER_PRAGMA +
84         ": " +
85         HTTPConstants.HEADER_CACHE_CONTROL_NOCACHE +
86         "\r\n";
87
88     private static final String JavaDoc CHUNKED_HEADER =
89         HTTPConstants.HEADER_TRANSFER_ENCODING +
90         ": " +
91         HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED +
92         "\r\n";
93
94     private static final String JavaDoc HEADER_CONTENT_TYPE_LC =
95         HTTPConstants.HEADER_CONTENT_TYPE.toLowerCase();
96     
97     private static final String JavaDoc HEADER_LOCATION_LC =
98         HTTPConstants.HEADER_LOCATION.toLowerCase();
99     
100     private static final String JavaDoc HEADER_CONTENT_LOCATION_LC =
101         HTTPConstants.HEADER_CONTENT_LOCATION.toLowerCase();
102     
103     private static final String JavaDoc HEADER_CONTENT_LENGTH_LC =
104         HTTPConstants.HEADER_CONTENT_LENGTH.toLowerCase();
105     
106     private static final String JavaDoc HEADER_TRANSFER_ENCODING_LC =
107         HTTPConstants.HEADER_TRANSFER_ENCODING.toLowerCase();
108
109     /**
110      * the url; used for error reporting
111      */

112     URL JavaDoc targetURL;
113     
114     /**
115      * invoke creates a socket connection, sends the request SOAP message and then
116      * reads the response SOAP message back from the SOAP server
117      *
118      * @param msgContext the messsage context
119      *
120      * @throws AxisFault
121      */

122     public void invoke(MessageContext msgContext) throws AxisFault {
123
124         if (log.isDebugEnabled()) {
125             log.debug(Messages.getMessage("enter00", "HTTPSender::invoke"));
126         }
127
128         SocketHolder socketHolder = new SocketHolder(null);
129
130         try {
131             BooleanHolder useFullURL = new BooleanHolder(false);
132             StringBuffer JavaDoc otherHeaders = new StringBuffer JavaDoc();
133             targetURL = new URL JavaDoc(msgContext.getStrProp(MessageContext.TRANS_URL));
134             String JavaDoc host = targetURL.getHost();
135             int port = targetURL.getPort();
136             
137             // Send the SOAP request to the server
138
InputStream JavaDoc inp = writeToSocket(socketHolder, msgContext, targetURL,
139                         otherHeaders, host, port, msgContext.getTimeout(), useFullURL);
140
141             // Read the response back from the server
142
Hashtable JavaDoc headers = new Hashtable JavaDoc();
143             inp = readHeadersFromSocket(socketHolder, msgContext, inp, headers);
144             readFromSocket(socketHolder, msgContext, inp, headers);
145         } catch (Exception JavaDoc e) {
146             log.debug(e);
147             try {
148                 if (socketHolder.getSocket() != null ) {
149                     socketHolder.getSocket().close();
150                 }
151             } catch (IOException JavaDoc ie) {
152                 // we shouldn't get here.
153
}
154             throw AxisFault.makeFault(e);
155         }
156         if (log.isDebugEnabled()) {
157             log.debug(Messages.getMessage("exit00",
158                     "HTTPDispatchHandler::invoke"));
159         }
160     }
161
162     /**
163      * Creates a socket connection to the SOAP server
164      *
165      * @param protocol "http" for standard, "https" for ssl.
166      * @param host host name
167      * @param port port to connect to
168      * @param otherHeaders buffer for storing additional headers that need to be sent
169      * @param useFullURL flag to indicate if the complete URL has to be sent
170      *
171      * @throws IOException
172      */

173     protected void getSocket(SocketHolder sockHolder,
174                              MessageContext msgContext,
175                              String JavaDoc protocol,
176                              String JavaDoc host, int port, int timeout,
177                              StringBuffer JavaDoc otherHeaders,
178                              BooleanHolder useFullURL)
179         throws Exception JavaDoc {
180         Hashtable JavaDoc options = getOptions();
181         if(timeout > 0) {
182             if(options == null) {
183                 options = new Hashtable JavaDoc();
184             }
185             options.put(DefaultSocketFactory.CONNECT_TIMEOUT,Integer.toString(timeout));
186         }
187         SocketFactory factory = SocketFactoryFactory.getFactory(protocol, options);
188         if (factory == null) {
189             throw new IOException JavaDoc(Messages.getMessage("noSocketFactory", protocol));
190         }
191         Socket JavaDoc sock = factory.create(host, port, otherHeaders, useFullURL);
192         if(timeout > 0) {
193             sock.setSoTimeout(timeout);
194         }
195         sockHolder.setSocket(sock);
196     }
197
198     /**
199      * Send the soap request message to the server
200      *
201      * @param msgContext message context
202      * @param tmpURL url to connect to
203      * @param otherHeaders other headers if any
204      * @param host host name
205      * @param port port
206      * @param useFullURL flag to indicate if the whole url needs to be sent
207      *
208      * @throws IOException
209      */

210     private InputStream JavaDoc writeToSocket(SocketHolder sockHolder,
211             MessageContext msgContext, URL JavaDoc tmpURL,
212             StringBuffer JavaDoc otherHeaders, String JavaDoc host, int port, int timeout,
213             BooleanHolder useFullURL)
214             throws Exception JavaDoc {
215
216         String JavaDoc userID = msgContext.getUsername();
217         String JavaDoc passwd = msgContext.getPassword();
218
219         // Get SOAPAction, default to ""
220
String JavaDoc action = msgContext.useSOAPAction()
221                 ? msgContext.getSOAPActionURI()
222                 : "";
223
224         if (action == null) {
225             action = "";
226         }
227
228         // if UserID is not part of the context, but is in the URL, use
229
// the one in the URL.
230
if ((userID == null) && (tmpURL.getUserInfo() != null)) {
231             String JavaDoc info = tmpURL.getUserInfo();
232             int sep = info.indexOf(':');
233
234             if ((sep >= 0) && (sep + 1 < info.length())) {
235                 userID = info.substring(0, sep);
236                 passwd = info.substring(sep + 1);
237             } else {
238                 userID = info;
239             }
240         }
241         if (userID != null) {
242             StringBuffer JavaDoc tmpBuf = new StringBuffer JavaDoc();
243
244             tmpBuf.append(userID).append(":").append((passwd == null)
245                     ? ""
246                     : passwd);
247             otherHeaders.append(HTTPConstants.HEADER_AUTHORIZATION)
248                     .append(": Basic ")
249                     .append(Base64.encode(tmpBuf.toString().getBytes()))
250                     .append("\r\n");
251         }
252
253         // don't forget the cookies!
254
// mmm... cookies
255
if (msgContext.getMaintainSession()) {
256             fillHeaders(msgContext, HTTPConstants.HEADER_COOKIE, otherHeaders);
257             fillHeaders(msgContext, HTTPConstants.HEADER_COOKIE2, otherHeaders);
258         }
259
260         StringBuffer JavaDoc header2 = new StringBuffer JavaDoc();
261
262         String JavaDoc webMethod = null;
263         boolean posting = true;
264
265         Message reqMessage = msgContext.getRequestMessage();
266
267         boolean http10 = true; //True if this is to use HTTP 1.0 / false HTTP 1.1
268
boolean httpChunkStream = false; //Use HTTP chunking or not.
269
boolean httpContinueExpected = false; //Under HTTP 1.1 if false you *MAY* need to wait for a 100 rc,
270
// if true the server MUST reply with 100 continue.
271
String JavaDoc httpConnection = null;
272
273         String JavaDoc httpver = msgContext.getStrProp(MessageContext.HTTP_TRANSPORT_VERSION);
274         if (null == httpver) {
275             httpver = HTTPConstants.HEADER_PROTOCOL_V10;
276         }
277         httpver = httpver.trim();
278         if (httpver.equals(HTTPConstants.HEADER_PROTOCOL_V11)) {
279             http10 = false;
280         }
281
282         //process user defined headers for information.
283
Hashtable JavaDoc userHeaderTable = (Hashtable JavaDoc) msgContext.
284                 getProperty(HTTPConstants.REQUEST_HEADERS);
285
286         if (userHeaderTable != null) {
287             if (null == otherHeaders) {
288                 otherHeaders = new StringBuffer JavaDoc(1024);
289             }
290
291             for (java.util.Iterator JavaDoc e = userHeaderTable.entrySet().iterator();
292                  e.hasNext();) {
293
294                 java.util.Map.Entry me = (java.util.Map.Entry) e.next();
295                 Object JavaDoc keyObj = me.getKey();
296                 if (null == keyObj) continue;
297                 String JavaDoc key = keyObj.toString().trim();
298
299                 if (key.equalsIgnoreCase(HTTPConstants.HEADER_TRANSFER_ENCODING)) {
300                     if (!http10) {
301                         String JavaDoc val = me.getValue().toString();
302                         if (null != val && val.trim().equalsIgnoreCase(HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED))
303                             httpChunkStream = true;
304                     }
305                 } else if (key.equalsIgnoreCase(HTTPConstants.HEADER_CONNECTION)) {
306                     if (!http10) {
307                         String JavaDoc val = me.getValue().toString();
308                         if (val.trim().equalsIgnoreCase(HTTPConstants.HEADER_CONNECTION_CLOSE))
309                             httpConnection = HTTPConstants.HEADER_CONNECTION_CLOSE;
310                     }
311                     //HTTP 1.0 will always close.
312
//HTTP 1.1 will use persistent. //no need to specify
313
} else {
314                     if( !http10 && key.equalsIgnoreCase(HTTPConstants.HEADER_EXPECT)) {
315                         String JavaDoc val = me.getValue().toString();
316                         if (null != val && val.trim().equalsIgnoreCase(HTTPConstants.HEADER_EXPECT_100_Continue))
317                             httpContinueExpected = true;
318                     }
319
320                     otherHeaders.append(key).append(": ").append(me.getValue()).append("\r\n");
321                 }
322             }
323         }
324
325         if (!http10) {
326             //Force close for now.
327
//TODO HTTP/1.1
328
httpConnection = HTTPConstants.HEADER_CONNECTION_CLOSE;
329         }
330
331         header2.append(" ");
332         header2.append(http10 ? HTTPConstants.HEADER_PROTOCOL_10 :
333                 HTTPConstants.HEADER_PROTOCOL_11)
334                 .append("\r\n");
335         MimeHeaders JavaDoc mimeHeaders = reqMessage.getMimeHeaders();
336
337         if (posting) {
338             String JavaDoc contentType;
339             final String JavaDoc[] header = mimeHeaders.getHeader(HTTPConstants.HEADER_CONTENT_TYPE);
340             if (header != null && header.length > 0) {
341                 contentType = mimeHeaders.getHeader(HTTPConstants.HEADER_CONTENT_TYPE)[0];
342             } else {
343                 contentType = reqMessage.getContentType(msgContext.getSOAPConstants());
344             }
345             
346             //fix for AXIS-2027
347
if (contentType == null || contentType.equals("")) {
348                 throw new Exception JavaDoc(Messages.getMessage("missingContentType"));
349             }
350             header2.append(HTTPConstants.HEADER_CONTENT_TYPE)
351                     .append(": ")
352                     .append(contentType)
353                     .append("\r\n");
354         }
355
356         header2.append(ACCEPT_HEADERS)
357                 .append(HTTPConstants.HEADER_HOST) //used for virtual connections
358
.append(": ")
359                 .append(host)
360                 .append((port == -1)?(""):(":" + port))
361                 .append("\r\n")
362                 .append(CACHE_HEADERS)
363                 .append(HTTPConstants.HEADER_SOAP_ACTION) //The SOAP action.
364
.append(": \"")
365                 .append(action)
366                 .append("\"\r\n");
367
368         if (posting) {
369             if (!httpChunkStream) {
370                 //Content length MUST be sent on HTTP 1.0 requests.
371
header2.append(HTTPConstants.HEADER_CONTENT_LENGTH)
372                         .append(": ")
373                         .append(reqMessage.getContentLength())
374                         .append("\r\n");
375             } else {
376                 //Do http chunking.
377
header2.append(CHUNKED_HEADER);
378             }
379         }
380
381         // Transfer MIME headers of SOAPMessage to HTTP headers.
382
if (mimeHeaders != null) {
383             for (Iterator JavaDoc i = mimeHeaders.getAllHeaders(); i.hasNext(); ) {
384                 MimeHeader JavaDoc mimeHeader = (MimeHeader JavaDoc) i.next();
385                 String JavaDoc headerName = mimeHeader.getName();
386                 if (headerName.equals(HTTPConstants.HEADER_CONTENT_TYPE)
387                         || headerName.equals(HTTPConstants.HEADER_SOAP_ACTION)) {
388                         continue;
389                 }
390                 header2.append(mimeHeader.getName())
391                 .append(": ")
392                 .append(mimeHeader.getValue())
393                 .append("\r\n");
394             }
395         }
396
397         if (null != httpConnection) {
398             header2.append(HTTPConstants.HEADER_CONNECTION);
399             header2.append(": ");
400             header2.append(httpConnection);
401             header2.append("\r\n");
402         }
403
404         getSocket(sockHolder, msgContext, targetURL.getProtocol(),
405                   host, port, timeout, otherHeaders, useFullURL);
406         
407         if (null != otherHeaders) {
408             //Add other headers to the end.
409
//for pre java1.4 support, we have to turn the string buffer argument into
410
//a string before appending.
411
header2.append(otherHeaders.toString());
412         }
413
414         header2.append("\r\n"); //The empty line to start the BODY.
415

416         StringBuffer JavaDoc header = new StringBuffer JavaDoc();
417         
418         // If we're SOAP 1.2, allow the web method to be set from the
419
// MessageContext.
420
if (msgContext.getSOAPConstants() == SOAPConstants.SOAP12_CONSTANTS) {
421             webMethod = msgContext.getStrProp(SOAP12Constants.PROP_WEBMETHOD);
422         }
423         if (webMethod == null) {
424             webMethod = HTTPConstants.HEADER_POST;
425         } else {
426             posting = webMethod.equals(HTTPConstants.HEADER_POST);
427         }
428
429         header.append(webMethod).append(" ");
430         if (useFullURL.value) {
431             header.append(tmpURL.toExternalForm());
432         } else {
433             header.append((((tmpURL.getFile() == null)
434                     || tmpURL.getFile().equals(""))
435                     ? "/"
436                     : tmpURL.getFile()));
437         }
438         header.append(header2.toString());
439
440         OutputStream out = sockHolder.getSocket().getOutputStream();
441
442         if (!posting) {
443             out.write(header.toString()
444                     .getBytes(HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING));
445             out.flush();
446             return null;
447         }
448
449         InputStream JavaDoc inp = null;
450
451         if (httpChunkStream || httpContinueExpected) {
452             out.write(header.toString()
453                     .getBytes(HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING));
454         }
455
456         if(httpContinueExpected ){ //We need to get a reply from the server as to whether
457
// it wants us send anything more.
458
out.flush();
459             Hashtable JavaDoc cheaders= new Hashtable JavaDoc ();
460             inp = readHeadersFromSocket(sockHolder, msgContext, null, cheaders);
461             int returnCode= -1;
462             Integer JavaDoc Irc= (Integer JavaDoc)msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_CODE);
463             if(null != Irc) {
464                 returnCode= Irc.intValue();
465             }
466             if(100 == returnCode){ // got 100 we may continue.
467
//Need todo a little msgContext house keeping....
468
msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_CODE);
469                 msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE);
470             }
471             else{ //If no 100 Continue then we must not send anything!
472
String JavaDoc statusMessage= (String JavaDoc)
473                         msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE);
474
475                 AxisFault fault = new AxisFault("HTTP", "(" + returnCode+ ")" + statusMessage, null, null);
476
477                 fault.setFaultDetailString(Messages.getMessage("return01",
478                                                                "" + returnCode, ""));
479                 throw fault;
480             }
481         }
482         ByteArrayOutputStream JavaDoc baos = null;
483         if (log.isDebugEnabled()) {
484             log.debug(Messages.getMessage("xmlSent00"));
485             log.debug("---------------------------------------------------");
486             baos = new ByteArrayOutputStream JavaDoc();
487         }
488         if (httpChunkStream) {
489             ChunkedOutputStream chunkedOutputStream = new ChunkedOutputStream(out);
490             out = new BufferedOutputStream JavaDoc(chunkedOutputStream, Constants.HTTP_TXR_BUFFER_SIZE);
491             try {
492                 if(baos != null) {
493                     out = new TeeOutputStream(out, baos);
494                 }
495                 reqMessage.writeTo(out);
496             } catch (SOAPException JavaDoc e) {
497                 log.error(Messages.getMessage("exception00"), e);
498             }
499             out.flush();
500             chunkedOutputStream.eos();
501         } else {
502             out = new BufferedOutputStream JavaDoc(out, Constants.HTTP_TXR_BUFFER_SIZE);
503             try {
504                 if (!httpContinueExpected) {
505                     out.write(header.toString()
506                             .getBytes(HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING));
507                 }
508                 if(baos != null) {
509                     out = new TeeOutputStream(out, baos);
510                 }
511                 reqMessage.writeTo(out);
512             } catch (SOAPException JavaDoc e) {
513                 log.error(Messages.getMessage("exception00"), e);
514             }
515             // Flush ONLY once.
516
out.flush();
517         }
518         if (log.isDebugEnabled()) {
519             log.debug(header + new String JavaDoc(baos.toByteArray()));
520         }
521
522         return inp;
523     }
524
525     /**
526      * Get cookies from message context and add it to the headers
527      * @param msgContext
528      * @param header
529      * @param otherHeaders
530      */

531     private void fillHeaders(MessageContext msgContext, String JavaDoc header, StringBuffer JavaDoc otherHeaders) {
532         Object JavaDoc ck1 = msgContext.getProperty(header);
533         if (ck1 != null) {
534             if (ck1 instanceof String JavaDoc[]) {
535                 String JavaDoc [] cookies = (String JavaDoc[]) ck1;
536                 for (int i = 0; i < cookies.length; i++) {
537                     addCookie(otherHeaders, header, cookies[i]);
538                 }
539             } else {
540                 addCookie(otherHeaders, header, (String JavaDoc) ck1);
541             }
542         }
543     }
544
545     /**
546      * add cookie to headers
547      * @param otherHeaders
548      * @param header
549      * @param cookie
550      */

551     private void addCookie(StringBuffer JavaDoc otherHeaders, String JavaDoc header, String JavaDoc cookie) {
552         otherHeaders.append(header).append(": ")
553                 .append(cookie).append("\r\n");
554     }
555
556     private InputStream JavaDoc readHeadersFromSocket(SocketHolder sockHolder,
557                                               MessageContext msgContext,
558                                               InputStream JavaDoc inp,
559                                               Hashtable JavaDoc headers)
560             throws IOException JavaDoc {
561         byte b = 0;
562         int len = 0;
563         int colonIndex = -1;
564         String JavaDoc name, value;
565         int returnCode = 0;
566         if(null == inp) {
567             inp = new BufferedInputStream JavaDoc(sockHolder.getSocket().getInputStream());
568         }
569
570         if (headers == null) {
571             headers = new Hashtable JavaDoc();
572         }
573
574         // Should help performance. Temporary fix only till its all stream oriented.
575
// Need to add logic for getting the version # and the return code
576
// but that's for tomorrow!
577

578         /* Logic to read HTTP response headers */
579         boolean readTooMuch = false;
580
581         for (ByteArrayOutputStream JavaDoc buf = new ByteArrayOutputStream JavaDoc(4097); ;) {
582             if (!readTooMuch) {
583                 b = (byte) inp.read();
584             }
585             if (b == -1) {
586                 break;
587             }
588             readTooMuch = false;
589             if ((b != '\r') && (b != '\n')) {
590                 if ((b == ':') && (colonIndex == -1)) {
591                     colonIndex = len;
592                 }
593                 len++;
594                 buf.write(b);
595             } else if (b == '\r') {
596                 continue;
597             } else { // b== '\n'
598
if (len == 0) {
599                     break;
600                 }
601                 b = (byte) inp.read();
602                 readTooMuch = true;
603
604                 // A space or tab at the begining of a line means the header continues.
605
if ((b == ' ') || (b == '\t')) {
606                     continue;
607                 }
608                 buf.close();
609                 byte[] hdata = buf.toByteArray();
610                 buf.reset();
611                 if (colonIndex != -1) {
612                     name =
613                             new String JavaDoc(hdata, 0, colonIndex,
614                                     HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING);
615                     value =
616                             new String JavaDoc(hdata, colonIndex + 1, len - 1 - colonIndex,
617                                     HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING);
618                     colonIndex = -1;
619                 } else {
620
621                     name =
622                             new String JavaDoc(hdata, 0, len,
623                                     HTTPConstants.HEADER_DEFAULT_CHAR_ENCODING);
624                     value = "";
625                 }
626                 if (log.isDebugEnabled()) {
627                     log.debug(name + value);
628                 }
629                 if (msgContext.getProperty(HTTPConstants.MC_HTTP_STATUS_CODE)
630                         == null) {
631
632                     // Reader status code
633
int start = name.indexOf(' ') + 1;
634                     String JavaDoc tmp = name.substring(start).trim();
635                     int end = tmp.indexOf(' ');
636
637                     if (end != -1) {
638                         tmp = tmp.substring(0, end);
639                     }
640                     returnCode = Integer.parseInt(tmp);
641                     msgContext.setProperty(HTTPConstants.MC_HTTP_STATUS_CODE,
642                             new Integer JavaDoc(returnCode));
643                     msgContext.setProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE,
644                             name.substring(start + end + 1));
645                 } else {
646                     // if we are maintaining session state,
647
// handle cookies (if any)
648
if (msgContext.getMaintainSession()) {
649                         final String JavaDoc nameLowerCase = name.toLowerCase();
650                         if (nameLowerCase.equalsIgnoreCase(HTTPConstants.HEADER_SET_COOKIE)) {
651                             handleCookie(HTTPConstants.HEADER_COOKIE, null, value, msgContext);
652                         } else if (nameLowerCase.equalsIgnoreCase(HTTPConstants.HEADER_SET_COOKIE2)) {
653                             handleCookie(HTTPConstants.HEADER_COOKIE2, null, value, msgContext);
654                         } else {
655                             headers.put(name.toLowerCase(), value);
656                         }
657                     } else {
658                         headers.put(name.toLowerCase(), value);
659                     }
660                 }
661                 len = 0;
662             }
663         }
664
665         return inp;
666     }
667
668     /**
669      * Reads the SOAP response back from the server
670      *
671      * @param msgContext message context
672      *
673      * @throws IOException
674      */

675     private InputStream JavaDoc readFromSocket(SocketHolder socketHolder,
676                                        MessageContext msgContext,
677                                        InputStream JavaDoc inp,
678                                        Hashtable JavaDoc headers)
679             throws IOException JavaDoc {
680         Message outMsg = null;
681         byte b;
682
683         Integer JavaDoc rc = (Integer JavaDoc)msgContext.getProperty(
684                                             HTTPConstants.MC_HTTP_STATUS_CODE);
685         int returnCode = 0;
686         if (rc != null) {
687             returnCode = rc.intValue();
688         } else {
689             // No return code?? Should have one by now.
690
}
691
692         /* All HTTP headers have been read. */
693         String JavaDoc contentType = (String JavaDoc) headers.get(HEADER_CONTENT_TYPE_LC);
694                         
695         contentType = (null == contentType)
696                 ? null
697                 : contentType.trim();
698                 
699         String JavaDoc location = (String JavaDoc) headers.get(HEADER_LOCATION_LC);
700
701         location = (null == location)
702                 ? null
703                 : location.trim();
704                 
705         if ((returnCode > 199) && (returnCode < 300)) {
706             if (returnCode == 202) {
707                 return inp;
708             }
709             // SOAP return is OK - so fall through
710
} else if (msgContext.getSOAPConstants() ==
711                 SOAPConstants.SOAP12_CONSTANTS) {
712             // For now, if we're SOAP 1.2, fall through, since the range of
713
// valid result codes is much greater
714
} else if ((contentType != null) && !contentType.startsWith("text/html")
715                 && ((returnCode > 499) && (returnCode < 600))) {
716             // SOAP Fault should be in here - so fall through
717
} else if ((location != null) &&
718                 ((returnCode == 302) || (returnCode == 307))) {
719             // Temporary Redirect (HTTP: 302/307)
720
// close old connection
721
inp.close();
722                 socketHolder.getSocket().close();
723             // remove former result and set new target url
724
msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_CODE);
725                 msgContext.setProperty(MessageContext.TRANS_URL, location);
726             // next try
727
invoke(msgContext);
728                 return inp;
729         } else if (returnCode == 100) {
730             msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_CODE);
731             msgContext.removeProperty(HTTPConstants.MC_HTTP_STATUS_MESSAGE);
732             readHeadersFromSocket(socketHolder, msgContext, inp, headers);
733             return readFromSocket(socketHolder, msgContext, inp, headers);
734         } else {
735             // Unknown return code - so wrap up the content into a
736
// SOAP Fault.
737
ByteArrayOutputStream JavaDoc buf = new ByteArrayOutputStream JavaDoc(4097);
738
739             while (-1 != (b = (byte) inp.read())) {
740                 buf.write(b);
741             }
742             String JavaDoc statusMessage = msgContext.getStrProp(
743                                         HTTPConstants.MC_HTTP_STATUS_MESSAGE);
744             AxisFault fault = new AxisFault("HTTP", "(" + returnCode + ")" +
745                                                     statusMessage, null, null);
746
747             fault.setFaultDetailString(Messages.getMessage("return01",
748                     "" + returnCode, buf.toString()));
749             fault.addFaultDetail(Constants.QNAME_FAULTDETAIL_HTTPERRORCODE,
750                     Integer.toString(returnCode));
751             throw fault;
752         }
753
754         String JavaDoc contentLocation =
755             (String JavaDoc) headers.get(HEADER_CONTENT_LOCATION_LC);
756
757         contentLocation = (null == contentLocation)
758                 ? null
759                 : contentLocation.trim();
760
761         String JavaDoc contentLength =
762             (String JavaDoc) headers.get(HEADER_CONTENT_LENGTH_LC);
763
764         contentLength = (null == contentLength)
765                 ? null
766                 : contentLength.trim();
767
768         String JavaDoc transferEncoding =
769             (String JavaDoc) headers.get(HEADER_TRANSFER_ENCODING_LC);
770
771         if (null != transferEncoding) {
772             transferEncoding = transferEncoding.trim().toLowerCase();
773             if (transferEncoding.equals(
774                    HTTPConstants.HEADER_TRANSFER_ENCODING_CHUNKED)) {
775                 inp = new ChunkedInputStream(inp);
776             }
777         }
778
779         outMsg = new Message( new SocketInputStream(inp, socketHolder.getSocket()), false,
780                               contentType, contentLocation);
781         // Transfer HTTP headers of HTTP message to MIME headers of SOAP message
782
MimeHeaders JavaDoc mimeHeaders = outMsg.getMimeHeaders();
783         for (Enumeration JavaDoc e = headers.keys(); e.hasMoreElements(); ) {
784             String JavaDoc key = (String JavaDoc) e.nextElement();
785             mimeHeaders.addHeader(key, ((String JavaDoc) headers.get(key)).trim());
786         }
787         outMsg.setMessageType(Message.RESPONSE);
788         msgContext.setResponseMessage(outMsg);
789         if (log.isDebugEnabled()) {
790             if (null == contentLength) {
791                 log.debug("\n"
792                           + Messages.getMessage("no00", "Content-Length"));
793             }
794             log.debug("\n" + Messages.getMessage("xmlRecd00"));
795             log.debug("-----------------------------------------------");
796             log.debug(outMsg.getSOAPEnvelope().toString());
797         }
798
799         return inp;
800     }
801
802     /**
803      * little helper function for cookies. fills up the message context with
804      * a string or an array of strings (if there are more than one Set-Cookie)
805      *
806      * @param cookieName
807      * @param setCookieName
808      * @param cookie
809      * @param msgContext
810      */

811     public void handleCookie(String JavaDoc cookieName, String JavaDoc setCookieName,
812                              String JavaDoc cookie, MessageContext msgContext) {
813
814         cookie = cleanupCookie(cookie);
815         int keyIndex = cookie.indexOf("=");
816         String JavaDoc key = (keyIndex != -1) ? cookie.substring(0, keyIndex) : cookie;
817         
818         ArrayList JavaDoc cookies = new ArrayList JavaDoc();
819         Object JavaDoc oldCookies = msgContext.getProperty(cookieName);
820         boolean alreadyExist = false;
821         if(oldCookies != null) {
822             if(oldCookies instanceof String JavaDoc[]) {
823                 String JavaDoc[] oldCookiesArray = (String JavaDoc[])oldCookies;
824                 for(int i = 0; i < oldCookiesArray.length; i++) {
825                     String JavaDoc anOldCookie = oldCookiesArray[i];
826                     if (key != null && anOldCookie.indexOf(key) == 0) { // same cookie key
827
anOldCookie = cookie; // update to new one
828
alreadyExist = true;
829                     }
830                     cookies.add(anOldCookie);
831                 }
832             } else {
833                 String JavaDoc oldCookie = (String JavaDoc)oldCookies;
834                 if (key != null && oldCookie.indexOf(key) == 0) { // same cookie key
835
oldCookie = cookie; // update to new one
836
alreadyExist = true;
837                 }
838                 cookies.add(oldCookie);
839             }
840         }
841         
842         if (!alreadyExist) {
843             cookies.add(cookie);
844         }
845         
846         if(cookies.size()==1) {
847             msgContext.setProperty(cookieName, cookies.get(0));
848         } else if (cookies.size() > 1) {
849             msgContext.setProperty(cookieName, cookies.toArray(new String JavaDoc[cookies.size()]));
850         }
851     }
852     
853     /**
854      * cleanup the cookie value.
855      *
856      * @param cookie initial cookie value
857      *
858      * @return a cleaned up cookie value.
859      */

860     private String JavaDoc cleanupCookie(String JavaDoc cookie) {
861         cookie = cookie.trim();
862         // chop after first ; a la Apache SOAP (see HTTPUtils.java there)
863
int index = cookie.indexOf(';');
864         if (index != -1) {
865             cookie = cookie.substring(0, index);
866         }
867         return cookie;
868     }
869 }
870
Popular Tags