Coverage Report - org.mule.transport.http.HttpConnector
 
Classes in this File Line Coverage Branch Coverage Complexity
HttpConnector
0%
0/117
0%
0/44
0
 
 1  
 /*
 2  
  * $Id: HttpConnector.java 19191 2010-08-25 21:05:23Z tcarlson $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 
 11  
 package org.mule.transport.http;
 12  
 
 13  
 import org.mule.api.MuleContext;
 14  
 import org.mule.api.MuleEvent;
 15  
 import org.mule.api.MuleMessage;
 16  
 import org.mule.api.construct.FlowConstruct;
 17  
 import org.mule.api.endpoint.ImmutableEndpoint;
 18  
 import org.mule.api.endpoint.InboundEndpoint;
 19  
 import org.mule.api.lifecycle.InitialisationException;
 20  
 import org.mule.api.processor.MessageProcessor;
 21  
 import org.mule.config.i18n.CoreMessages;
 22  
 import org.mule.transport.tcp.TcpConnector;
 23  
 
 24  
 import java.io.UnsupportedEncodingException;
 25  
 import java.util.HashMap;
 26  
 import java.util.HashSet;
 27  
 import java.util.Iterator;
 28  
 import java.util.Map;
 29  
 import java.util.Set;
 30  
 
 31  
 import org.apache.commons.codec.binary.Base64;
 32  
 import org.apache.commons.httpclient.HttpClient;
 33  
 import org.apache.commons.httpclient.HttpConnectionManager;
 34  
 import org.apache.commons.httpclient.HttpMethod;
 35  
 import org.apache.commons.httpclient.HttpState;
 36  
 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
 37  
 import org.apache.commons.httpclient.UsernamePasswordCredentials;
 38  
 import org.apache.commons.httpclient.auth.AuthScope;
 39  
 import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
 40  
 
 41  
 /**
 42  
  * <code>HttpConnector</code> provides a way of receiving and sending http requests
 43  
  * and responses. The Connector itself handles dispatching http requests. The
 44  
  * <code>HttpMessageReceiver</code> handles the receiving requests and processing
 45  
  * of headers This endpoint recognises the following properties - <p/>
 46  
  * <ul>
 47  
  * <li>hostname - The hostname to send and receive http requests</li>
 48  
  * <li>port - The port to listen on. The industry standard is 80 and if this propert
 49  
  * is not set it will default to 80</li>
 50  
  * <li>proxyHostname - If you access the web through a proxy, this holds the server
 51  
  * address</li>
 52  
  * <li>proxyPort - The port the proxy is configured on</li>
 53  
  * <li>proxyUsername - If the proxy requires authentication supply a username</li>
 54  
  * <li>proxyPassword - If the proxy requires authentication supply a password</li>
 55  
  * </ul>
 56  
  * 
 57  
  */
 58  
 
 59  
 public class HttpConnector extends TcpConnector
 60  
 {
 61  
 
 62  
     public static final String HTTP = "http";
 63  
     public static final String HTTP_PREFIX = "http.";
 64  
     
 65  
     /**
 66  
      * MuleEvent property to pass back the status for the response
 67  
      */
 68  
     public static final String HTTP_STATUS_PROPERTY = HTTP_PREFIX + "status";
 69  
     public static final String HTTP_VERSION_PROPERTY = HTTP_PREFIX + "version";
 70  
     
 71  
     /**
 72  
      * @deprecated Instead users can now add properties to the outgoing request using the OUTBOUND property scope on the message.
 73  
      */
 74  
     @Deprecated
 75  
     public static final String HTTP_CUSTOM_HEADERS_MAP_PROPERTY = HTTP_PREFIX + "custom.headers";
 76  
 
 77  
     public static final String HTTP_METHOD_PROPERTY = HTTP_PREFIX + "method";
 78  
     
 79  
     /**
 80  
      * The path and query portions of the URL being accessed. 
 81  
      */
 82  
     public static final String HTTP_REQUEST_PROPERTY = HTTP_PREFIX + "request";
 83  
     
 84  
     /**
 85  
      * The path portion of the URL being accessed. No query string is included.
 86  
      */
 87  
     public static final String HTTP_REQUEST_PATH_PROPERTY = HTTP_PREFIX + "request.path";
 88  
     
 89  
     /**
 90  
      * The context path of the endpoint being accessed. This is the path that the 
 91  
      * HTTP endpoint is listening on.
 92  
      */
 93  
     public static final String HTTP_CONTEXT_PATH_PROPERTY = HTTP_PREFIX + "context.path";
 94  
 
 95  
     /**
 96  
      * Allows the user to set a {@link org.apache.commons.httpclient.params.HttpMethodParams} object in the client
 97  
      * request to be set on the HttpMethod request object
 98  
      */
 99  
     public static final String HTTP_PARAMS_PROPERTY = HTTP_PREFIX + "params";
 100  
     public static final String HTTP_GET_BODY_PARAM_PROPERTY = HTTP_PREFIX + "get.body.param";
 101  
     public static final String DEFAULT_HTTP_GET_BODY_PARAM_PROPERTY = "body";
 102  
     public static final String HTTP_POST_BODY_PARAM_PROPERTY = HTTP_PREFIX + "post.body.param";
 103  
 
 104  
     public static final String HTTP_DISABLE_STATUS_CODE_EXCEPTION_CHECK = HTTP_PREFIX + "disable.status.code.exception.check";
 105  
     public static final String HTTP_ENCODE_PARAMVALUE = HTTP_PREFIX + "encode.paramvalue";
 106  
     
 107  
     public static final Set<String> HTTP_INBOUND_PROPERTIES;
 108  
     
 109  
     static 
 110  
     {
 111  0
         Set<String> props = new HashSet<String>();
 112  0
         props.add(HTTP_CONTEXT_PATH_PROPERTY);
 113  0
         props.add(HTTP_GET_BODY_PARAM_PROPERTY);
 114  0
         props.add(HTTP_METHOD_PROPERTY);
 115  0
         props.add(HTTP_PARAMS_PROPERTY);
 116  0
         props.add(HTTP_POST_BODY_PARAM_PROPERTY);
 117  0
         props.add(HTTP_REQUEST_PROPERTY);
 118  0
         props.add(HTTP_REQUEST_PATH_PROPERTY);
 119  0
         props.add(HTTP_STATUS_PROPERTY);
 120  0
         props.add(HTTP_VERSION_PROPERTY);
 121  0
         props.add(HTTP_ENCODE_PARAMVALUE);
 122  0
         HTTP_INBOUND_PROPERTIES = props;
 123  0
     }
 124  
     
 125  
     public static final String HTTP_COOKIE_SPEC_PROPERTY = "cookieSpec";
 126  
     public static final String HTTP_COOKIES_PROPERTY = "cookies";
 127  
     public static final String HTTP_ENABLE_COOKIES_PROPERTY = "enableCookies";
 128  
 
 129  
     public static final String COOKIE_SPEC_NETSCAPE = "netscape";
 130  
     public static final String COOKIE_SPEC_RFC2109 = "rcf2109";
 131  
 
 132  0
     private String proxyHostname = null;
 133  
 
 134  0
     private int proxyPort = HttpConstants.DEFAULT_HTTP_PORT;
 135  
 
 136  0
     private String proxyUsername = null;
 137  
 
 138  0
     private String proxyPassword = null;
 139  
 
 140  
     private String cookieSpec;
 141  
 
 142  0
     private boolean enableCookies = false;
 143  
 
 144  
     protected HttpConnectionManager clientConnectionManager;
 145  
 
 146  
     public HttpConnector(MuleContext context)
 147  
     {
 148  0
         super(context);
 149  0
     }
 150  
     
 151  
     @Override
 152  
     protected void doInitialise() throws InitialisationException
 153  
     {
 154  0
         super.doInitialise();
 155  0
         if (clientConnectionManager == null)
 156  
         {
 157  0
             clientConnectionManager = new MultiThreadedHttpConnectionManager();
 158  0
             HttpConnectionManagerParams params = new HttpConnectionManagerParams();
 159  0
             if (getSendBufferSize() != INT_VALUE_NOT_SET)
 160  
             {
 161  0
                 params.setSendBufferSize(getSendBufferSize());
 162  
             }
 163  0
             if (getReceiveBufferSize() != INT_VALUE_NOT_SET)
 164  
             {
 165  0
                 params.setReceiveBufferSize(getReceiveBufferSize());
 166  
             }
 167  0
             if (getClientSoTimeout() != INT_VALUE_NOT_SET)
 168  
             {
 169  0
                 params.setSoTimeout(getClientSoTimeout());
 170  
             }
 171  0
             if (getSocketSoLinger() != INT_VALUE_NOT_SET)
 172  
             {
 173  0
                 params.setLinger(getSocketSoLinger());
 174  
             }
 175  
 
 176  0
             params.setTcpNoDelay(isSendTcpNoDelay());
 177  0
             params.setMaxTotalConnections(dispatchers.getMaxTotal());
 178  0
             params.setDefaultMaxConnectionsPerHost(dispatchers.getMaxTotal());
 179  0
             clientConnectionManager.setParams(params);
 180  
         }
 181  0
     }
 182  
 
 183  
     @Override
 184  
     public void registerListener(InboundEndpoint endpoint, MessageProcessor listener, FlowConstruct flowConstruct) throws Exception
 185  
     {
 186  0
         if (endpoint != null)
 187  
         {
 188  0
             Map endpointProperties = endpoint.getProperties();
 189  0
             if (endpointProperties != null)
 190  
             {
 191  
                 // normalize properties for HTTP
 192  0
                 Map newProperties = new HashMap(endpointProperties.size());
 193  0
                 for (Iterator entries = endpointProperties.entrySet().iterator(); entries.hasNext();)
 194  
                 {
 195  0
                     Map.Entry entry = (Map.Entry) entries.next();
 196  0
                     Object key = entry.getKey();
 197  0
                     Object normalizedKey = HttpConstants.ALL_HEADER_NAMES.get(key);
 198  0
                     if (normalizedKey != null)
 199  
                     {
 200  
                         // normalized property exists
 201  0
                         key = normalizedKey;
 202  
                     }
 203  0
                     newProperties.put(key, entry.getValue());
 204  0
                 }
 205  
                 // set normalized properties back on the endpoint
 206  0
                 endpoint.getProperties().clear();
 207  0
                 endpoint.getProperties().putAll(newProperties);
 208  
             }
 209  
         }
 210  
         // proceed as usual
 211  0
         super.registerListener(endpoint, listener, flowConstruct);
 212  0
     }
 213  
 
 214  
     /**
 215  
      * The method determines the key used to store the receiver against.
 216  
      *
 217  
      * @param endpoint the endpoint being registered for the service
 218  
      * @return the key to store the newly created receiver against
 219  
      */
 220  
     @Override
 221  
     protected Object getReceiverKey(FlowConstruct flowConstruct, InboundEndpoint endpoint)
 222  
     {
 223  0
         String key = endpoint.getEndpointURI().toString();
 224  0
         int i = key.indexOf('?');
 225  0
         if (i > -1)
 226  
         {
 227  0
             key = key.substring(0, i);
 228  
         }
 229  0
         return key;
 230  
     }
 231  
 
 232  
     /**
 233  
      * @see org.mule.api.transport.Connector#getProtocol()
 234  
      */
 235  
     @Override
 236  
     public String getProtocol()
 237  
     {
 238  0
         return HTTP;
 239  
     }
 240  
 
 241  
     public String getProxyHostname()
 242  
     {
 243  0
         return proxyHostname;
 244  
     }
 245  
 
 246  
     public String getProxyPassword()
 247  
     {
 248  0
         return proxyPassword;
 249  
     }
 250  
 
 251  
     public int getProxyPort()
 252  
     {
 253  0
         return proxyPort;
 254  
     }
 255  
 
 256  
     public String getProxyUsername()
 257  
     {
 258  0
         return proxyUsername;
 259  
     }
 260  
 
 261  
     public void setProxyHostname(String host)
 262  
     {
 263  0
         proxyHostname = host;
 264  0
     }
 265  
 
 266  
     public void setProxyPassword(String string)
 267  
     {
 268  0
         proxyPassword = string;
 269  0
     }
 270  
 
 271  
     public void setProxyPort(int port)
 272  
     {
 273  0
         proxyPort = port;
 274  0
     }
 275  
 
 276  
     public void setProxyUsername(String string)
 277  
     {
 278  0
         proxyUsername = string;
 279  0
     }
 280  
 
 281  
     @Override
 282  
     public Map getReceivers()
 283  
     {
 284  0
         return this.receivers;
 285  
     }
 286  
 
 287  
     public String getCookieSpec()
 288  
     {
 289  0
         return cookieSpec;
 290  
     }
 291  
 
 292  
     public void setCookieSpec(String cookieSpec)
 293  
     {
 294  0
         if (!(COOKIE_SPEC_NETSCAPE.equalsIgnoreCase(cookieSpec) || COOKIE_SPEC_RFC2109.equalsIgnoreCase(cookieSpec)))
 295  
         {
 296  0
             throw new IllegalArgumentException(
 297  
                 CoreMessages.propertyHasInvalidValue("cookieSpec", cookieSpec).toString());
 298  
         }
 299  0
         this.cookieSpec = cookieSpec;
 300  0
     }
 301  
 
 302  
     public boolean isEnableCookies()
 303  
     {
 304  0
         return enableCookies;
 305  
     }
 306  
 
 307  
     public void setEnableCookies(boolean enableCookies)
 308  
     {
 309  0
         this.enableCookies = enableCookies;
 310  0
     }
 311  
 
 312  
 
 313  
     public HttpConnectionManager getClientConnectionManager()
 314  
     {
 315  0
         return clientConnectionManager;
 316  
     }
 317  
 
 318  
     public void setClientConnectionManager(HttpConnectionManager clientConnectionManager)
 319  
     {
 320  0
         this.clientConnectionManager = clientConnectionManager;
 321  0
     }
 322  
 
 323  
     protected HttpClient doClientConnect() throws Exception
 324  
     {
 325  0
         HttpState state = new HttpState();
 326  
 
 327  0
         if (getProxyUsername() != null)
 328  
         {
 329  0
             state.setProxyCredentials(
 330  
                     new AuthScope(null, -1, null, null),
 331  
                     new UsernamePasswordCredentials(getProxyUsername(), getProxyPassword()));
 332  
         }
 333  
 
 334  0
         HttpClient client = new HttpClient();
 335  0
         client.setState(state);
 336  0
         client.setHttpConnectionManager(getClientConnectionManager());
 337  
 
 338  0
         return client;
 339  
     }
 340  
 
 341  
     protected void setupClientAuthorization(MuleEvent event, HttpMethod httpMethod,
 342  
                                             HttpClient client, ImmutableEndpoint endpoint)
 343  
             throws UnsupportedEncodingException
 344  
     {
 345  0
         httpMethod.setDoAuthentication(true);
 346  0
         client.getParams().setAuthenticationPreemptive(true);
 347  
 
 348  0
         if (event != null && event.getCredentials() != null)
 349  
         {
 350  0
             MuleMessage msg = event.getMessage();
 351  0
             String authScopeHost = msg.getOutboundProperty(HTTP_PREFIX + "auth.scope.host", event.getEndpoint().getEndpointURI().getHost());
 352  0
             int authScopePort = msg.getOutboundProperty(HTTP_PREFIX + "auth.scope.port", event.getEndpoint().getEndpointURI().getPort());
 353  0
             String authScopeRealm = msg.getOutboundProperty(HTTP_PREFIX + "auth.scope.realm", AuthScope.ANY_REALM);
 354  0
             String authScopeScheme = msg.getOutboundProperty(HTTP_PREFIX + "auth.scope.scheme", AuthScope.ANY_SCHEME);
 355  0
             client.getState().setCredentials(
 356  
                 new AuthScope(authScopeHost, authScopePort, authScopeRealm, authScopeScheme),
 357  
                 new UsernamePasswordCredentials(event.getCredentials().getUsername(), new String(
 358  
                     event.getCredentials().getPassword())));
 359  0
         }
 360  0
         else if (endpoint.getEndpointURI().getUserInfo() != null
 361  
             && endpoint.getProperty(HttpConstants.HEADER_AUTHORIZATION) == null)
 362  
         {
 363  
             // Add User Creds
 364  0
             StringBuffer header = new StringBuffer(128);
 365  0
             header.append("Basic ");
 366  0
             header.append(new String(Base64.encodeBase64(endpoint.getEndpointURI().getUserInfo().getBytes(
 367  
                 endpoint.getEncoding()))));
 368  0
             httpMethod.addRequestHeader(HttpConstants.HEADER_AUTHORIZATION, header.toString());
 369  0
         }
 370  
         //TODO MULE-4501 this sohuld be removed and handled only in the ObjectToHttpRequest transformer
 371  0
         else if (event!=null && event.getMessage().getOutboundProperty(HttpConstants.HEADER_AUTHORIZATION) != null &&
 372  
                 httpMethod.getRequestHeader(HttpConstants.HEADER_AUTHORIZATION)==null)
 373  
         {
 374  0
             String auth = event.getMessage().getOutboundProperty(HttpConstants.HEADER_AUTHORIZATION);
 375  0
             httpMethod.addRequestHeader(HttpConstants.HEADER_AUTHORIZATION, auth);
 376  0
         }
 377  
         else
 378  
         {
 379  
             // don't use preemptive if there are no credentials to send
 380  0
             client.getParams().setAuthenticationPreemptive(false);
 381  
         }
 382  0
     }
 383  
 
 384  
     /**
 385  
      * Ensures that the supplied URL starts with a '/'.
 386  
      */
 387  
     public static String normalizeUrl(String url)
 388  
     {
 389  0
         if (url == null) 
 390  
         {
 391  0
             url = "/";
 392  
         } 
 393  0
         else if (!url.startsWith("/")) 
 394  
         {
 395  0
             url = "/" + url;
 396  
         }
 397  0
         return url;
 398  
     }
 399  
 }