001: /*
002: * $Id: HttpConnector.java 10961 2008-02-22 19:01:02Z dfeist $
003: * --------------------------------------------------------------------------------------
004: * Copyright (c) MuleSource, Inc. All rights reserved. http://www.mulesource.com
005: *
006: * The software in this package is published under the terms of the CPAL v1.0
007: * license, a copy of which has been included with this distribution in the
008: * LICENSE.txt file.
009: */
010:
011: package org.mule.transport.http;
012:
013: import org.mule.api.MuleEvent;
014: import org.mule.api.MuleMessage;
015: import org.mule.api.endpoint.ImmutableEndpoint;
016: import org.mule.api.endpoint.InboundEndpoint;
017: import org.mule.api.lifecycle.InitialisationException;
018: import org.mule.api.service.Service;
019: import org.mule.api.transport.Connector;
020: import org.mule.api.transport.MessageReceiver;
021: import org.mule.config.i18n.CoreMessages;
022: import org.mule.transport.tcp.TcpConnector;
023:
024: import java.io.UnsupportedEncodingException;
025: import java.util.HashMap;
026: import java.util.Iterator;
027: import java.util.Map;
028:
029: import org.apache.commons.codec.binary.Base64;
030: import org.apache.commons.httpclient.HttpClient;
031: import org.apache.commons.httpclient.HttpConnectionManager;
032: import org.apache.commons.httpclient.HttpMethod;
033: import org.apache.commons.httpclient.HttpState;
034: import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
035: import org.apache.commons.httpclient.UsernamePasswordCredentials;
036: import org.apache.commons.httpclient.auth.AuthScope;
037: import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
038:
039: import sun.rmi.transport.Endpoint;
040:
041: /**
042: * <code>HttpConnector</code> provides a way of receiving and sending http requests
043: * and responses. The Connector itself handles dispatching http requests. The
044: * <code>HttpMessageReceiver</code> handles the receiving requests and processing
045: * of headers This endpoint recognises the following properties - <p/>
046: * <ul>
047: * <li>hostname - The hostname to send and receive http requests</li>
048: * <li>port - The port to listen on. The industry standard is 80 and if this propert
049: * is not set it will default to 80</li>
050: * <li>proxyHostname - If you access the web through a proxy, this holds the server
051: * address</li>
052: * <li>proxyPort - The port the proxy is configured on</li>
053: * <li>proxyUsername - If the proxy requires authentication supply a username</li>
054: * <li>proxyPassword - If the proxy requires authentication supply a password</li>
055: * </ul>
056: *
057: */
058:
059: public class HttpConnector extends TcpConnector {
060:
061: public static final String HTTP = "http";
062: public static final String HTTP_PREFIX = "http.";
063:
064: /**
065: * MuleEvent property to pass back the status for the response
066: */
067: public static final String HTTP_STATUS_PROPERTY = HTTP_PREFIX
068: + "status";
069: public static final String HTTP_VERSION_PROPERTY = HTTP_PREFIX
070: + "version";
071: public static final String HTTP_CUSTOM_HEADERS_MAP_PROPERTY = HTTP_PREFIX
072: + "custom.headers";
073: public static final String HTTP_METHOD_PROPERTY = HTTP_PREFIX
074: + "method";
075: public static final String HTTP_REQUEST_PROPERTY = HTTP_PREFIX
076: + "request";
077:
078: /**
079: * Allows the user to set a {@link org.apache.commons.httpclient.params.HttpMethodParams} object in the client
080: * request to be set on the HttpMethod request object
081: */
082: public static final String HTTP_PARAMS_PROPERTY = HTTP_PREFIX
083: + "params";
084: public static final String HTTP_GET_BODY_PARAM_PROPERTY = HTTP_PREFIX
085: + "get.body.param";
086: public static final String DEFAULT_HTTP_GET_BODY_PARAM_PROPERTY = "body";
087: public static final String HTTP_POST_BODY_PARAM_PROPERTY = HTTP_PREFIX
088: + "post.body.param";
089:
090: public static final String HTTP_COOKIE_SPEC_PROPERTY = "cookieSpec";
091: public static final String HTTP_COOKIES_PROPERTY = "cookies";
092: public static final String HTTP_ENABLE_COOKIES_PROPERTY = "enableCookies";
093:
094: public static final String COOKIE_SPEC_NETSCAPE = "netscape";
095: public static final String COOKIE_SPEC_RFC2109 = "rcf2109";
096:
097: private String proxyHostname = null;
098:
099: private int proxyPort = HttpConstants.DEFAULT_HTTP_PORT;
100:
101: private String proxyUsername = null;
102:
103: private String proxyPassword = null;
104:
105: private String cookieSpec;
106:
107: private boolean enableCookies = false;
108:
109: protected HttpConnectionManager clientConnectionManager;
110:
111: //@Override
112: protected void doInitialise() throws InitialisationException {
113: super .doInitialise();
114: if (clientConnectionManager == null) {
115: clientConnectionManager = new MultiThreadedHttpConnectionManager();
116: HttpConnectionManagerParams params = new HttpConnectionManagerParams();
117: if (getSendBufferSize() != INT_VALUE_NOT_SET) {
118: params.setSendBufferSize(getSendBufferSize());
119: }
120: if (getReceiveBufferSize() != INT_VALUE_NOT_SET) {
121: params.setReceiveBufferSize(getReceiveBufferSize());
122: }
123: if (getClientSoTimeout() != INT_VALUE_NOT_SET) {
124: params.setSoTimeout(getClientSoTimeout());
125: }
126: if (getSocketSoLinger() != INT_VALUE_NOT_SET) {
127: params.setLinger(getSocketSoLinger());
128: }
129:
130: params.setTcpNoDelay(isSendTcpNoDelay());
131: params
132: .setMaxTotalConnections(getDispatcherThreadingProfile()
133: .getMaxThreadsActive());
134: params
135: .setDefaultMaxConnectionsPerHost(getDispatcherThreadingProfile()
136: .getMaxThreadsActive());
137:
138: clientConnectionManager.setParams(params);
139: }
140: }
141:
142: /**
143: * @see Connector#registerListener(Service, Endpoint)
144: */
145: public MessageReceiver registerListener(Service service,
146: InboundEndpoint endpoint) throws Exception {
147: if (endpoint != null) {
148: Map endpointProperties = endpoint.getProperties();
149: if (endpointProperties != null) {
150: // normalize properties for HTTP
151: Map newProperties = new HashMap(endpointProperties
152: .size());
153: for (Iterator entries = endpointProperties.entrySet()
154: .iterator(); entries.hasNext();) {
155: Map.Entry entry = (Map.Entry) entries.next();
156: Object key = entry.getKey();
157: Object normalizedKey = HttpConstants.ALL_HEADER_NAMES
158: .get(key);
159: if (normalizedKey != null) {
160: // normalized property exists
161: key = normalizedKey;
162: }
163: newProperties.put(key, entry.getValue());
164: }
165: // set normalized properties back on the endpoint
166: endpoint.getProperties().clear();
167: endpoint.getProperties().putAll(newProperties);
168: }
169: }
170: // proceed as usual
171: return super .registerListener(service, endpoint);
172: }
173:
174: /**
175: * The method determines the key used to store the receiver against.
176: *
177: * @param service the service for which the endpoint is being registered
178: * @param endpoint the endpoint being registered for the service
179: * @return the key to store the newly created receiver against
180: */
181: protected Object getReceiverKey(Service service,
182: InboundEndpoint endpoint) {
183: String key = endpoint.getEndpointURI().toString();
184: int i = key.indexOf('?');
185: if (i > -1) {
186: key = key.substring(0, i);
187: }
188: return key;
189: }
190:
191: /**
192: * @see org.mule.api.transport.Connector#getProtocol()
193: */
194: public String getProtocol() {
195: return HTTP;
196: }
197:
198: /**
199: * @return
200: */
201: public String getProxyHostname() {
202: return proxyHostname;
203: }
204:
205: /**
206: * @return
207: */
208: public String getProxyPassword() {
209: return proxyPassword;
210: }
211:
212: /**
213: * @return
214: */
215: public int getProxyPort() {
216: return proxyPort;
217: }
218:
219: /**
220: * @return
221: */
222: public String getProxyUsername() {
223: return proxyUsername;
224: }
225:
226: /**
227: * @param host
228: */
229: public void setProxyHostname(String host) {
230: proxyHostname = host;
231: }
232:
233: /**
234: * @param string
235: */
236: public void setProxyPassword(String string) {
237: proxyPassword = string;
238: }
239:
240: /**
241: * @param port
242: */
243: public void setProxyPort(int port) {
244: proxyPort = port;
245: }
246:
247: /**
248: * @param string
249: */
250: public void setProxyUsername(String string) {
251: proxyUsername = string;
252: }
253:
254: public Map getReceivers() {
255: return this .receivers;
256: }
257:
258: public String getCookieSpec() {
259: return cookieSpec;
260: }
261:
262: public void setCookieSpec(String cookieSpec) {
263: if (!(COOKIE_SPEC_NETSCAPE.equalsIgnoreCase(cookieSpec) || COOKIE_SPEC_RFC2109
264: .equalsIgnoreCase(cookieSpec))) {
265: throw new IllegalArgumentException(CoreMessages
266: .propertyHasInvalidValue("cookieSpec", cookieSpec)
267: .toString());
268: }
269: this .cookieSpec = cookieSpec;
270: }
271:
272: public boolean isEnableCookies() {
273: return enableCookies;
274: }
275:
276: public void setEnableCookies(boolean enableCookies) {
277: this .enableCookies = enableCookies;
278: }
279:
280: public HttpConnectionManager getClientConnectionManager() {
281: return clientConnectionManager;
282: }
283:
284: public void setClientConnectionManager(
285: HttpConnectionManager clientConnectionManager) {
286: this .clientConnectionManager = clientConnectionManager;
287: }
288:
289: protected HttpClient doClientConnect() throws Exception {
290: HttpState state = new HttpState();
291:
292: if (getProxyUsername() != null) {
293: state.setProxyCredentials(new AuthScope(null, -1, null,
294: null), new UsernamePasswordCredentials(
295: getProxyUsername(), getProxyPassword()));
296: }
297:
298: HttpClient client = new HttpClient();
299: client.setState(state);
300: client.setHttpConnectionManager(getClientConnectionManager());
301:
302: return client;
303: }
304:
305: protected void setupClientAuthorization(MuleEvent event,
306: HttpMethod httpMethod, HttpClient client,
307: ImmutableEndpoint endpoint)
308: throws UnsupportedEncodingException {
309: httpMethod.setDoAuthentication(true);
310: if (event != null && event.getCredentials() != null) {
311: MuleMessage msg = event.getMessage();
312: String authScopeHost = msg.getStringProperty(HTTP_PREFIX
313: + "auth.scope.host", null);
314: int authScopePort = msg.getIntProperty(HTTP_PREFIX
315: + "auth.scope.port", -1);
316: String authScopeRealm = msg.getStringProperty(HTTP_PREFIX
317: + "auth.scope.realm", null);
318: String authScopeScheme = msg.getStringProperty(HTTP_PREFIX
319: + "auth.scope.scheme", null);
320: client.getState().setCredentials(
321: new AuthScope(authScopeHost, authScopePort,
322: authScopeRealm, authScopeScheme),
323: new UsernamePasswordCredentials(event
324: .getCredentials().getUsername(),
325: new String(event.getCredentials()
326: .getPassword())));
327: client.getParams().setAuthenticationPreemptive(true);
328: } else if (endpoint.getEndpointURI().getUserInfo() != null
329: && endpoint
330: .getProperty(HttpConstants.HEADER_AUTHORIZATION) == null) {
331: // Add User Creds
332: StringBuffer header = new StringBuffer(128);
333: header.append("Basic ");
334: header.append(new String(Base64.encodeBase64(endpoint
335: .getEndpointURI().getUserInfo().getBytes(
336: endpoint.getEncoding()))));
337: httpMethod.addRequestHeader(
338: HttpConstants.HEADER_AUTHORIZATION, header
339: .toString());
340: } else {
341: // don't use preemptive if there are no credentials to send
342: client.getParams().setAuthenticationPreemptive(false);
343: }
344:
345: }
346:
347: }
|