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