View Javadoc

1   /*
2    * $Id: HttpConnector.java 10961 2008-02-22 19:01:02Z dfeist $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.transport.http;
12  
13  import org.mule.api.MuleEvent;
14  import org.mule.api.MuleMessage;
15  import org.mule.api.endpoint.ImmutableEndpoint;
16  import org.mule.api.endpoint.InboundEndpoint;
17  import org.mule.api.lifecycle.InitialisationException;
18  import org.mule.api.service.Service;
19  import org.mule.api.transport.Connector;
20  import org.mule.api.transport.MessageReceiver;
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.Iterator;
27  import java.util.Map;
28  
29  import org.apache.commons.codec.binary.Base64;
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.UsernamePasswordCredentials;
36  import org.apache.commons.httpclient.auth.AuthScope;
37  import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
38  
39  import sun.rmi.transport.Endpoint;
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      public static final String HTTP_CUSTOM_HEADERS_MAP_PROPERTY = HTTP_PREFIX + "custom.headers";
71      public static final String HTTP_METHOD_PROPERTY = HTTP_PREFIX + "method";
72      public static final String HTTP_REQUEST_PROPERTY = HTTP_PREFIX + "request";
73  
74      /**
75       * Allows the user to set a {@link org.apache.commons.httpclient.params.HttpMethodParams} object in the client
76       * request to be set on the HttpMethod request object
77       */
78      public static final String HTTP_PARAMS_PROPERTY = HTTP_PREFIX + "params";
79      public static final String HTTP_GET_BODY_PARAM_PROPERTY = HTTP_PREFIX + "get.body.param";
80      public static final String DEFAULT_HTTP_GET_BODY_PARAM_PROPERTY = "body";
81      public static final String HTTP_POST_BODY_PARAM_PROPERTY = HTTP_PREFIX + "post.body.param";
82  
83      public static final String HTTP_COOKIE_SPEC_PROPERTY = "cookieSpec";
84      public static final String HTTP_COOKIES_PROPERTY = "cookies";
85      public static final String HTTP_ENABLE_COOKIES_PROPERTY = "enableCookies";
86  
87      public static final String COOKIE_SPEC_NETSCAPE = "netscape";
88      public static final String COOKIE_SPEC_RFC2109 = "rcf2109";
89  
90      private String proxyHostname = null;
91  
92      private int proxyPort = HttpConstants.DEFAULT_HTTP_PORT;
93  
94      private String proxyUsername = null;
95  
96      private String proxyPassword = null;
97  
98      private String cookieSpec;
99  
100     private boolean enableCookies = false;
101 
102     protected HttpConnectionManager clientConnectionManager;
103 
104 
105     //@Override
106     protected void doInitialise() throws InitialisationException
107     {
108         super.doInitialise();
109         if (clientConnectionManager == null)
110         {
111             clientConnectionManager = new MultiThreadedHttpConnectionManager();
112             HttpConnectionManagerParams params = new HttpConnectionManagerParams();
113             if (getSendBufferSize() != INT_VALUE_NOT_SET)
114             {
115                 params.setSendBufferSize(getSendBufferSize());
116             }
117             if (getReceiveBufferSize() != INT_VALUE_NOT_SET)
118             {
119                 params.setReceiveBufferSize(getReceiveBufferSize());
120             }
121             if (getClientSoTimeout() != INT_VALUE_NOT_SET)
122             {
123                 params.setSoTimeout(getClientSoTimeout());
124             }
125             if (getSocketSoLinger() != INT_VALUE_NOT_SET)
126             {
127                 params.setLinger(getSocketSoLinger());
128             }
129 
130             params.setTcpNoDelay(isSendTcpNoDelay());
131             params.setMaxTotalConnections(getDispatcherThreadingProfile().getMaxThreadsActive());
132             params.setDefaultMaxConnectionsPerHost(getDispatcherThreadingProfile().getMaxThreadsActive());
133 
134             clientConnectionManager.setParams(params);
135         }
136     }
137 
138     /**
139      * @see Connector#registerListener(Service, Endpoint)
140      */
141     public MessageReceiver registerListener(Service service, InboundEndpoint endpoint) throws Exception
142     {
143         if (endpoint != null)
144         {
145             Map endpointProperties = endpoint.getProperties();
146             if (endpointProperties != null)
147             {
148                 // normalize properties for HTTP
149                 Map newProperties = new HashMap(endpointProperties.size());
150                 for (Iterator entries = endpointProperties.entrySet().iterator(); entries.hasNext();)
151                 {
152                     Map.Entry entry = (Map.Entry)entries.next();
153                     Object key = entry.getKey();
154                     Object normalizedKey = HttpConstants.ALL_HEADER_NAMES.get(key);
155                     if (normalizedKey != null)
156                     {
157                         // normalized property exists
158                         key = normalizedKey;
159                     }
160                     newProperties.put(key, entry.getValue());
161                 }
162                 // set normalized properties back on the endpoint
163                 endpoint.getProperties().clear();
164                 endpoint.getProperties().putAll(newProperties);
165             }
166         }
167         // proceed as usual
168         return super.registerListener(service, endpoint);
169     }
170 
171     /**
172      * The method determines the key used to store the receiver against.
173      *
174      * @param service the service for which the endpoint is being registered
175      * @param endpoint the endpoint being registered for the service
176      * @return the key to store the newly created receiver against
177      */
178     protected Object getReceiverKey(Service service, InboundEndpoint endpoint)
179     {
180         String key = endpoint.getEndpointURI().toString();
181         int i = key.indexOf('?');
182         if (i > -1)
183         {
184             key = key.substring(0, i);
185         }
186         return key;
187     }
188 
189     /**
190      * @see org.mule.api.transport.Connector#getProtocol()
191      */
192     public String getProtocol()
193     {
194         return HTTP;
195     }
196 
197     /**
198      * @return
199      */
200     public String getProxyHostname()
201     {
202         return proxyHostname;
203     }
204 
205     /**
206      * @return
207      */
208     public String getProxyPassword()
209     {
210         return proxyPassword;
211     }
212 
213     /**
214      * @return
215      */
216     public int getProxyPort()
217     {
218         return proxyPort;
219     }
220 
221     /**
222      * @return
223      */
224     public String getProxyUsername()
225     {
226         return proxyUsername;
227     }
228 
229     /**
230      * @param host
231      */
232     public void setProxyHostname(String host)
233     {
234         proxyHostname = host;
235     }
236 
237     /**
238      * @param string
239      */
240     public void setProxyPassword(String string)
241     {
242         proxyPassword = string;
243     }
244 
245     /**
246      * @param port
247      */
248     public void setProxyPort(int port)
249     {
250         proxyPort = port;
251     }
252 
253     /**
254      * @param string
255      */
256     public void setProxyUsername(String string)
257     {
258         proxyUsername = string;
259     }
260 
261     public Map getReceivers()
262     {
263         return this.receivers;
264     }
265 
266     public String getCookieSpec()
267     {
268         return cookieSpec;
269     }
270 
271     public void setCookieSpec(String cookieSpec)
272     {
273         if (!(COOKIE_SPEC_NETSCAPE.equalsIgnoreCase(cookieSpec) || COOKIE_SPEC_RFC2109.equalsIgnoreCase(cookieSpec)))
274         {
275             throw new IllegalArgumentException(
276                 CoreMessages.propertyHasInvalidValue("cookieSpec", cookieSpec).toString());
277         }
278         this.cookieSpec = cookieSpec;
279     }
280 
281     public boolean isEnableCookies()
282     {
283         return enableCookies;
284     }
285 
286     public void setEnableCookies(boolean enableCookies)
287     {
288         this.enableCookies = enableCookies;
289     }
290 
291 
292     public HttpConnectionManager getClientConnectionManager()
293     {
294         return clientConnectionManager;
295     }
296 
297     public void setClientConnectionManager(HttpConnectionManager clientConnectionManager)
298     {
299         this.clientConnectionManager = clientConnectionManager;
300     }
301 
302     protected HttpClient doClientConnect() throws Exception
303     {
304         HttpState state = new HttpState();
305 
306         if (getProxyUsername() != null)
307         {
308             state.setProxyCredentials(
309                     new AuthScope(null, -1, null, null),
310                     new UsernamePasswordCredentials(getProxyUsername(), getProxyPassword()));
311         }
312 
313         HttpClient client = new HttpClient();
314         client.setState(state);
315         client.setHttpConnectionManager(getClientConnectionManager());
316 
317         return client;
318     }
319 
320     protected void setupClientAuthorization(MuleEvent event, HttpMethod httpMethod,
321                                             HttpClient client, ImmutableEndpoint endpoint)
322             throws UnsupportedEncodingException
323     {
324         httpMethod.setDoAuthentication(true);
325         if (event != null && event.getCredentials() != null)
326         {
327             MuleMessage msg = event.getMessage();
328             String authScopeHost = msg.getStringProperty(HTTP_PREFIX + "auth.scope.host", null);
329             int authScopePort = msg.getIntProperty(HTTP_PREFIX + "auth.scope.port", -1);
330             String authScopeRealm = msg.getStringProperty(HTTP_PREFIX + "auth.scope.realm", null);
331             String authScopeScheme = msg.getStringProperty(HTTP_PREFIX + "auth.scope.scheme", null);
332             client.getState().setCredentials(
333                 new AuthScope(authScopeHost, authScopePort, authScopeRealm, authScopeScheme),
334                 new UsernamePasswordCredentials(event.getCredentials().getUsername(), new String(
335                     event.getCredentials().getPassword())));
336             client.getParams().setAuthenticationPreemptive(true);
337         }
338         else if (endpoint.getEndpointURI().getUserInfo() != null
339             && endpoint.getProperty(HttpConstants.HEADER_AUTHORIZATION) == null)
340         {
341             // Add User Creds
342             StringBuffer header = new StringBuffer(128);
343             header.append("Basic ");
344             header.append(new String(Base64.encodeBase64(endpoint.getEndpointURI().getUserInfo().getBytes(
345                 endpoint.getEncoding()))));
346             httpMethod.addRequestHeader(HttpConstants.HEADER_AUTHORIZATION, header.toString());
347         }
348         else
349         {
350             // don't use preemptive if there are no credentials to send
351             client.getParams().setAuthenticationPreemptive(false);
352         }
353 
354     }
355 
356 }