You are viewing a plain text version of this content. The canonical link for it is here.
Posted to java-dev@axis.apache.org by di...@apache.org on 2003/06/28 21:15:16 UTC

cvs commit: xml-axis/java/src/org/apache/axis/transport/http CommonsHTTPSender.java

dims        2003/06/28 12:15:16

  Modified:    java/src/org/apache/axis/transport/http
                        CommonsHTTPSender.java
  Log:
  Fix from "Chandra Talluri" <ct...@netnumber.com> for maintaining sessions and do multiple requests without closing the stream.
  See http://marc.theaimsgroup.com/?l=axis-user&m=105681087530198&w=2 for details.
  
  Revision  Changes    Path
  1.16      +145 -132  xml-axis/java/src/org/apache/axis/transport/http/CommonsHTTPSender.java
  
  Index: CommonsHTTPSender.java
  ===================================================================
  RCS file: /home/cvs/xml-axis/java/src/org/apache/axis/transport/http/CommonsHTTPSender.java,v
  retrieving revision 1.15
  retrieving revision 1.16
  diff -u -r1.15 -r1.16
  --- CommonsHTTPSender.java	22 Apr 2003 19:35:51 -0000	1.15
  +++ CommonsHTTPSender.java	28 Jun 2003 19:15:16 -0000	1.16
  @@ -57,29 +57,31 @@
   import org.apache.axis.AxisFault;
   import org.apache.axis.Message;
   import org.apache.axis.MessageContext;
  -import org.apache.axis.soap.SOAPConstants;
  -import org.apache.axis.soap.SOAP12Constants;
   import org.apache.axis.components.logger.LogFactory;
   import org.apache.axis.components.net.TransportClientProperties;
   import org.apache.axis.components.net.TransportClientPropertiesFactory;
   import org.apache.axis.encoding.Base64;
   import org.apache.axis.handlers.BasicHandler;
  +import org.apache.axis.soap.SOAP12Constants;
  +import org.apache.axis.soap.SOAPConstants;
   import org.apache.axis.utils.Messages;
  +import org.apache.commons.httpclient.Cookie;
   import org.apache.commons.httpclient.Credentials;
   import org.apache.commons.httpclient.Header;
   import org.apache.commons.httpclient.HostConfiguration;
   import org.apache.commons.httpclient.HttpClient;
   import org.apache.commons.httpclient.HttpConnectionManager;
  +import org.apache.commons.httpclient.HttpMethodBase;
  +import org.apache.commons.httpclient.HttpState;
   import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
   import org.apache.commons.httpclient.UsernamePasswordCredentials;
  -import org.apache.commons.httpclient.HttpMethodBase;
  -import org.apache.commons.httpclient.methods.PostMethod;
  +import org.apache.commons.httpclient.cookie.CookiePolicy;
   import org.apache.commons.httpclient.methods.GetMethod;
  +import org.apache.commons.httpclient.methods.PostMethod;
   import org.apache.commons.logging.Log;
   
  -import java.io.ByteArrayOutputStream;
  -import java.io.UnsupportedEncodingException;
   import java.io.ByteArrayInputStream;
  +import java.io.ByteArrayOutputStream;
   import java.net.URL;
   import java.util.Hashtable;
   import java.util.StringTokenizer;
  @@ -88,13 +90,19 @@
    * This class uses Jakarta Commons's HttpClient to call a SOAP server.
    *
    * @author Davanum Srinivas (dims@yahoo.com)
  + * History: By Chandra Talluri
  + * Modifications done for maintaining sessions. Cookies needed to be set on
  + * HttpState not on MessageContext, since ttpMethodBase overwrites the cookies 
  + * from HttpState. Also we need to setCookiePolicy on HttpState to 
  + * CookiePolicy.COMPATIBILITY else it is defaulting to RFC2109Spec and adding 
  + * Version information to it and tomcat server not recognizing it
    */
   public class CommonsHTTPSender extends BasicHandler {
  -
  +    
       /** Field log           */
       protected static Log log =
  -        LogFactory.getLog(CommonsHTTPSender.class.getName());
  -
  +    LogFactory.getLog(CommonsHTTPSender.class.getName());
  +    
       private HttpConnectionManager connectionManager;
       
       public CommonsHTTPSender() {
  @@ -102,7 +110,7 @@
           // declarative configuration
           connectionManager = new MultiThreadedHttpConnectionManager();
       }
  -
  +    
       /**
        * invoke creates a socket connection, sends the request SOAP message and then
        * reads the response SOAP message back from the SOAP server
  @@ -113,26 +121,25 @@
        */
       public void invoke(MessageContext msgContext) throws AxisFault {
           HttpMethodBase method = null;
  -        
           if (log.isDebugEnabled()) {
               log.debug(Messages.getMessage("enter00",
  -                                          "CommonsHTTPSender::invoke"));
  +            "CommonsHTTPSender::invoke"));
           }
           try {
               URL targetURL =
  -                new URL(msgContext.getStrProp(MessageContext.TRANS_URL));
  -
  +            new URL(msgContext.getStrProp(MessageContext.TRANS_URL));
  +            
               // no need to retain these, as the cookies/credentials are
               // stored in the message context across multiple requests.
               // the underlying connection manager, however, is retained
               // so sockets get recycled when possible.
               HttpClient httpClient = new HttpClient(connectionManager);
  -
  +            
               HostConfiguration hostConfiguration = getHostConfiguration(httpClient, targetURL);
  -
  +            
               String webMethod = null;
               boolean posting = true;
  -
  +            
               // If we're SOAP 1.2, allow the web method to be set from the
               // MessageContext.
               if (msgContext.getSOAPConstants() == SOAPConstants.SOAP12_CONSTANTS) {
  @@ -154,54 +161,74 @@
                   method = new GetMethod(targetURL.toString());
                   addContextInfo(method, httpClient, msgContext, targetURL);
               }
  -
  +           // don't forget the cookies!
  +           // Cookies need to be set on HttpState, since HttpMethodBase 
  +           // overwrites the cookies from HttpState
  +           if (msgContext.getMaintainSession()) {
  +                HttpState state = httpClient.getState();
  +                state.setCookiePolicy(CookiePolicy.COMPATIBILITY);
  +                String host = hostConfiguration.getHost();
  +                String path = targetURL.getPath();
  +                boolean secure = hostConfiguration.getProtocol().isSecure();
  +                String ck1 = (String)msgContext.getProperty(HTTPConstants.HEADER_COOKIE);
  +                
  +                String ck2 = (String)msgContext.getProperty(HTTPConstants.HEADER_COOKIE2);
  +                if (ck1 != null) {
  +                    int index = ck1.indexOf('=');
  +                    state.addCookie(new Cookie(host,ck1.substring(0, index),ck1.substring(index+1),path,null,secure));
  +                }
  +                if (ck2 != null) {
  +                    int index = ck2.indexOf('=');
  +                    state.addCookie(new Cookie(host,ck2.substring(0, index),ck2.substring(index+1),path,null,secure));
  +                }
  +                httpClient.setState(state);
  +            }
               int returnCode = httpClient.executeMethod(method);
               String contentType = null;
               String contentLocation = null;
               String contentLength = null;
  -
               if (method.getResponseHeader(HTTPConstants.HEADER_CONTENT_TYPE)
  -                != null) {
  +            != null) {
                   contentType = method.getResponseHeader(
  -                    HTTPConstants.HEADER_CONTENT_TYPE).getValue();
  +                HTTPConstants.HEADER_CONTENT_TYPE).getValue();
               }
               if (method.getResponseHeader(HTTPConstants.HEADER_CONTENT_LOCATION)
  -                != null) {
  +            != null) {
                   contentLocation = method.getResponseHeader(
  -                    HTTPConstants.HEADER_CONTENT_LOCATION).getValue();
  +                HTTPConstants.HEADER_CONTENT_LOCATION).getValue();
               }
               if (method.getResponseHeader(HTTPConstants.HEADER_CONTENT_LENGTH)
  -                != null) {
  +            != null) {
                   contentLength = method.getResponseHeader(
  -                    HTTPConstants.HEADER_CONTENT_LENGTH).getValue();
  +                HTTPConstants.HEADER_CONTENT_LENGTH).getValue();
               }
               contentType = (null == contentType)
  -                ? null
  -                : contentType.trim();
  +            ? null
  +            : contentType.trim();
               if ((returnCode > 199) && (returnCode < 300)) {
  -
  +                
                   // SOAP return is OK - so fall through
               } else if (msgContext.getSOAPConstants() ==
  -                    SOAPConstants.SOAP12_CONSTANTS) {
  +            SOAPConstants.SOAP12_CONSTANTS) {
                   // For now, if we're SOAP 1.2, fall through, since the range of
                   // valid result codes is much greater
               } else if ((contentType != null) && !contentType.equals("text/html")
  -                       && ((returnCode > 499) && (returnCode < 600))) {
  -
  +            && ((returnCode > 499) && (returnCode < 600))) {
  +                
                   // SOAP Fault should be in here - so fall through
               } else {
                   String statusMessage = method.getStatusText();
                   AxisFault fault = new AxisFault("HTTP",
  -                                                "(" + returnCode + ")"
  -                                                + statusMessage, null,
  -                                                null);
  -
  +                "(" + returnCode + ")"
  +                + statusMessage, null,
  +                null);
  +                
                   fault.setFaultDetailString(Messages.getMessage("return01",
  -                                                               "" + returnCode, method.getResponseBodyAsString()));
  +                "" + returnCode, method.getResponseBodyAsString()));
                   throw fault;
               }
               Message outMsg = new Message(method.getResponseBodyAsStream(),
  -                                         false, contentType, contentLocation);
  +            false, contentType, contentLocation);
               // no need to invoke method.releaseConnection here, as that will
               // happen automatically when the response body is read.
               // issue: what if the stream is never closed?  Are we certain
  @@ -211,13 +238,13 @@
               if (log.isDebugEnabled()) {
                   if (null == contentLength) {
                       log.debug("\n"
  -                              + Messages.getMessage("no00", "Content-Length"));
  +                    + Messages.getMessage("no00", "Content-Length"));
                   }
                   log.debug("\n" + Messages.getMessage("xmlRecd00"));
                   log.debug("-----------------------------------------------");
  -                log.debug((String) outMsg.getSOAPPartAsString());
  +                log.debug(outMsg.getSOAPPartAsString());
               }
  -
  +            
               // if we are maintaining session state,
               // handle cookies (if any)
               if (msgContext.getMaintainSession()) {
  @@ -228,7 +255,9 @@
                       else if (headers[i].getName().equalsIgnoreCase(HTTPConstants.HEADER_SET_COOKIE2))
                           msgContext.setProperty(HTTPConstants.HEADER_COOKIE2, cleanupCookie(headers[i].getValue()));
                   }
  +                
               }
  +            
           } catch (Exception e) {
               log.debug(e);
               throw AxisFault.makeFault(e);
  @@ -236,10 +265,10 @@
           
           if (log.isDebugEnabled()) {
               log.debug(Messages.getMessage("exit00",
  -                                          "CommonsHTTPSender::invoke"));
  +            "CommonsHTTPSender::invoke"));
           }
       }
  -
  +    
       /**
        * cleanup the cookie value.
        *
  @@ -251,34 +280,33 @@
           cookie = cookie.trim();
           // chop after first ; a la Apache SOAP (see HTTPUtils.java there)
           int index = cookie.indexOf(';');
  -
  +        
           if (index != -1) {
               cookie = cookie.substring(0, index);
           }
           return cookie;
       }
  -
  +    
       private HostConfiguration getHostConfiguration(HttpClient client, URL targetURL) {
  -        boolean isSecure = targetURL.getProtocol().equalsIgnoreCase("http");
           TransportClientProperties tcp = TransportClientPropertiesFactory.create(targetURL.getProtocol()); // http or https
           int port = targetURL.getPort();
           boolean hostInNonProxyList =
  -            isHostInNonProxyList(targetURL.getHost(), tcp.getNonProxyHosts());
  -
  +        isHostInNonProxyList(targetURL.getHost(), tcp.getNonProxyHosts());
  +        
           HostConfiguration config = new HostConfiguration();
           
           if (port == -1) {
               port = 80;          // even for https
           }
           if (tcp.getProxyHost().length() == 0 ||
  -            tcp.getProxyPort().length() == 0 ||
  -            hostInNonProxyList) {
  +        tcp.getProxyPort().length() == 0 ||
  +        hostInNonProxyList) {
               config.setHost(targetURL.getHost(), port, targetURL.getProtocol());
           } else {
               if (tcp.getProxyUser().length() != 0) {
                   Credentials proxyCred =
  -                    new UsernamePasswordCredentials(tcp.getProxyUser(),
  -                                                    tcp.getProxyPassword());
  +                new UsernamePasswordCredentials(tcp.getProxyUser(),
  +                tcp.getProxyPassword());
                   client.getState().setProxyCredentials(null, proxyCred);
               }
               int proxyPort = new Integer(tcp.getProxyPort()).intValue();
  @@ -286,7 +314,7 @@
           }
           return config;
       }
  -
  +    
       /**
        * Extracts info from message context.
        *
  @@ -298,37 +326,37 @@
        * @throws Exception
        */
       private void addContextInfo(
  -        HttpMethodBase method, HttpClient httpClient, MessageContext msgContext, URL tmpURL)
  -        throws Exception {
  -
  +    HttpMethodBase method, HttpClient httpClient, MessageContext msgContext, URL tmpURL)
  +    throws Exception {
  +        
           // optionally set a timeout for the request
           if (msgContext.getTimeout() != 0) {
               httpClient.setTimeout(msgContext.getTimeout());
           }
  -
  +        
           // Get SOAPAction, default to ""
           String action = msgContext.useSOAPAction()
  -            ? msgContext.getSOAPActionURI()
  -            : "";
  -
  +        ? msgContext.getSOAPActionURI()
  +        : "";
  +        
           if (action == null) {
               action = "";
           }
           Message msg = msgContext.getRequestMessage();
           if (msg != null){
               method.setRequestHeader(new Header(HTTPConstants.HEADER_CONTENT_TYPE,
  -                                               msg.getContentType(msgContext.getSOAPConstants())));
  +            msg.getContentType(msgContext.getSOAPConstants())));
           }
           method.setRequestHeader(new Header(HTTPConstants.HEADER_SOAP_ACTION, "\"" + action + "\""));
           String userID = msgContext.getUsername();
           String passwd = msgContext.getPassword();
  -
  +        
           // if UserID is not part of the context, but is in the URL, use
           // the one in the URL.
           if ((userID == null) && (tmpURL.getUserInfo() != null)) {
               String info = tmpURL.getUserInfo();
               int sep = info.indexOf(':');
  -
  +            
               if ((sep >= 0) && (sep + 1 < info.length())) {
                   userID = info.substring(0, sep);
                   passwd = info.substring(sep + 1);
  @@ -339,50 +367,35 @@
           if (userID != null) {
               Credentials cred = new UsernamePasswordCredentials(userID, passwd);
               httpClient.getState().setCredentials(null, cred);
  -
  +            
               // The following 3 lines should NOT be required. But Our SimpleAxisServer fails
               // during all-tests if this is missing.
               StringBuffer tmpBuf = new StringBuffer();
               tmpBuf.append(userID).append(":").append((passwd == null) ? "" : passwd);
               method.addRequestHeader(HTTPConstants.HEADER_AUTHORIZATION, "Basic " + Base64.encode(tmpBuf.toString().getBytes()));
           }
  -
  -        // don't forget the cookies!
  -        if (msgContext.getMaintainSession()) {
  -            String cookie =
  -                (String) msgContext.getProperty(HTTPConstants.HEADER_COOKIE);
  -            String cookie2 =
  -                (String) msgContext.getProperty(HTTPConstants.HEADER_COOKIE2);
  -
  -            if (cookie != null) {
  -                method.addRequestHeader(HTTPConstants.HEADER_COOKIE, cookie);
  -            }
  -            if (cookie2 != null) {
  -                method.addRequestHeader(HTTPConstants.HEADER_COOKIE2, cookie2);
  -            }
  -        }
  -
  +        
           // process user defined headers for information.
           Hashtable userHeaderTable =
  -            (Hashtable) msgContext.getProperty(HTTPConstants.REQUEST_HEADERS);
  -
  +        (Hashtable) msgContext.getProperty(HTTPConstants.REQUEST_HEADERS);
  +        
           if (userHeaderTable != null) {
               for (java.util.Iterator e = userHeaderTable.entrySet().iterator();
  -                 e.hasNext();) {
  +            e.hasNext();) {
                   java.util.Map.Entry me = (java.util.Map.Entry) e.next();
                   Object keyObj = me.getKey();
  -
  +                
                   if (null == keyObj) {
                       continue;
                   }
                   String key = keyObj.toString().trim();
                   String value = me.getValue().toString().trim();
  -
  +                
                   method.addRequestHeader(key, value);
               }
           }
       }
  -
  +    
       /**
        * Check if the specified host is in the list of non proxy hosts.
        *
  @@ -392,25 +405,25 @@
        * @return true/false
        */
       protected boolean isHostInNonProxyList(String host, String nonProxyHosts) {
  -
  +        
           if ((nonProxyHosts == null) || (host == null)) {
               return false;
           }
  -
  +        
           /*
            * The http.nonProxyHosts system property is a list enclosed in
            * double quotes with items separated by a vertical bar.
            */
           StringTokenizer tokenizer = new StringTokenizer(nonProxyHosts, "|\"");
  -
  +        
           while (tokenizer.hasMoreTokens()) {
               String pattern = tokenizer.nextToken();
  -
  +            
               if (log.isDebugEnabled()) {
                   log.debug(Messages.getMessage("match00",
  -                                              new String[]{"HTTPSender",
  -                                                           host,
  -                                                           pattern}));
  +                new String[]{"HTTPSender",
  +                host,
  +                pattern}));
               }
               if (match(pattern, host, false)) {
                   return true;
  @@ -418,7 +431,7 @@
           }
           return false;
       }
  -
  +    
       /**
        * Matches a string against a pattern. The pattern contains two special
        * characters:
  @@ -433,8 +446,8 @@
        *         <code>false</code> otherwise.
        */
       protected static boolean match(String pattern, String str,
  -                                   boolean isCaseSensitive) {
  -
  +    boolean isCaseSensitive) {
  +        
           char[] patArr = pattern.toCharArray();
           char[] strArr = str.toCharArray();
           int patIdxStart = 0;
  @@ -443,7 +456,7 @@
           int strIdxEnd = strArr.length - 1;
           char ch;
           boolean containsStar = false;
  -
  +        
           for (int i = 0; i < patArr.length; i++) {
               if (patArr[i] == '*') {
                   containsStar = true;
  @@ -451,7 +464,7 @@
               }
           }
           if (!containsStar) {
  -
  +            
               // No '*'s, so we make a shortcut
               if (patIdxEnd != strIdxEnd) {
                   return false;        // Pattern and string do not have the same size
  @@ -462,8 +475,8 @@
                       return false;    // Character mismatch
                   }
                   if (!isCaseSensitive
  -                    && (Character.toUpperCase(ch)
  -                        != Character.toUpperCase(strArr[i]))) {
  +                && (Character.toUpperCase(ch)
  +                != Character.toUpperCase(strArr[i]))) {
                       return false;    // Character mismatch
                   }
               }
  @@ -472,23 +485,23 @@
           if (patIdxEnd == 0) {
               return true;    // Pattern contains only '*', which matches anything
           }
  -
  +        
           // Process characters before first star
           while ((ch = patArr[patIdxStart]) != '*'
  -               && (strIdxStart <= strIdxEnd)) {
  +        && (strIdxStart <= strIdxEnd)) {
               if (isCaseSensitive && (ch != strArr[strIdxStart])) {
                   return false;    // Character mismatch
               }
               if (!isCaseSensitive
  -                && (Character.toUpperCase(ch)
  -                    != Character.toUpperCase(strArr[strIdxStart]))) {
  +            && (Character.toUpperCase(ch)
  +            != Character.toUpperCase(strArr[strIdxStart]))) {
                   return false;    // Character mismatch
               }
               patIdxStart++;
               strIdxStart++;
           }
           if (strIdxStart > strIdxEnd) {
  -
  +            
               // All characters in the string are used. Check if only '*'s are
               // left in the pattern. If so, we succeeded. Otherwise failure.
               for (int i = patIdxStart; i <= patIdxEnd; i++) {
  @@ -498,22 +511,22 @@
               }
               return true;
           }
  -
  +        
           // Process characters after last star
           while ((ch = patArr[patIdxEnd]) != '*' && (strIdxStart <= strIdxEnd)) {
               if (isCaseSensitive && (ch != strArr[strIdxEnd])) {
                   return false;    // Character mismatch
               }
               if (!isCaseSensitive
  -                && (Character.toUpperCase(ch)
  -                    != Character.toUpperCase(strArr[strIdxEnd]))) {
  +            && (Character.toUpperCase(ch)
  +            != Character.toUpperCase(strArr[strIdxEnd]))) {
                   return false;    // Character mismatch
               }
               patIdxEnd--;
               strIdxEnd--;
           }
           if (strIdxStart > strIdxEnd) {
  -
  +            
               // All characters in the string are used. Check if only '*'s are
               // left in the pattern. If so, we succeeded. Otherwise failure.
               for (int i = patIdxStart; i <= patIdxEnd; i++) {
  @@ -523,12 +536,12 @@
               }
               return true;
           }
  -
  +        
           // process pattern between stars. padIdxStart and patIdxEnd point
           // always to a '*'.
           while ((patIdxStart != patIdxEnd) && (strIdxStart <= strIdxEnd)) {
               int patIdxTmp = -1;
  -
  +            
               for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
                   if (patArr[i] == '*') {
                       patIdxTmp = i;
  @@ -536,42 +549,42 @@
                   }
               }
               if (patIdxTmp == patIdxStart + 1) {
  -
  +                
                   // Two stars next to each other, skip the first one.
                   patIdxStart++;
                   continue;
               }
  -
  +            
               // Find the pattern between padIdxStart & padIdxTmp in str between
               // strIdxStart & strIdxEnd
               int patLength = (patIdxTmp - patIdxStart - 1);
               int strLength = (strIdxEnd - strIdxStart + 1);
               int foundIdx = -1;
  -
  +            
               strLoop:
  -            for (int i = 0; i <= strLength - patLength; i++) {
  -                for (int j = 0; j < patLength; j++) {
  -                    ch = patArr[patIdxStart + j + 1];
  -                    if (isCaseSensitive
  +                for (int i = 0; i <= strLength - patLength; i++) {
  +                    for (int j = 0; j < patLength; j++) {
  +                        ch = patArr[patIdxStart + j + 1];
  +                        if (isCaseSensitive
                           && (ch != strArr[strIdxStart + i + j])) {
  -                        continue strLoop;
  -                    }
  -                    if (!isCaseSensitive && (Character
  -                                             .toUpperCase(ch) != Character
  -                                             .toUpperCase(strArr[strIdxStart + i + j]))) {
  -                        continue strLoop;
  +                            continue strLoop;
  +                        }
  +                        if (!isCaseSensitive && (Character
  +                        .toUpperCase(ch) != Character
  +                        .toUpperCase(strArr[strIdxStart + i + j]))) {
  +                            continue strLoop;
  +                        }
                       }
  +                    foundIdx = strIdxStart + i;
  +                    break;
                   }
  -                foundIdx = strIdxStart + i;
  -                break;
  -            }
  -            if (foundIdx == -1) {
  -                return false;
  -            }
  -            patIdxStart = patIdxTmp;
  -            strIdxStart = foundIdx + patLength;
  +                if (foundIdx == -1) {
  +                    return false;
  +                }
  +                patIdxStart = patIdxTmp;
  +                strIdxStart = foundIdx + patLength;
           }
  -
  +        
           // All characters in the string are used. Check if only '*'s are left
           // in the pattern. If so, we succeeded. Otherwise failure.
           for (int i = patIdxStart; i <= patIdxEnd; i++) {