1
2
3
4
5
6
7
8
9
10
11 package org.mule.providers.http;
12
13 import org.mule.config.MuleProperties;
14 import org.mule.impl.MuleEvent;
15 import org.mule.impl.MuleMessage;
16 import org.mule.impl.MuleSession;
17 import org.mule.impl.NullSessionHandler;
18 import org.mule.impl.OptimizedRequestContext;
19 import org.mule.impl.RequestContext;
20 import org.mule.providers.ConnectException;
21 import org.mule.providers.NullPayload;
22 import org.mule.providers.http.i18n.HttpMessages;
23 import org.mule.providers.tcp.TcpMessageReceiver;
24 import org.mule.umo.MessagingException;
25 import org.mule.umo.UMOComponent;
26 import org.mule.umo.UMOEvent;
27 import org.mule.umo.UMOException;
28 import org.mule.umo.UMOMessage;
29 import org.mule.umo.endpoint.UMOEndpoint;
30 import org.mule.umo.endpoint.UMOEndpointURI;
31 import org.mule.umo.lifecycle.InitialisationException;
32 import org.mule.umo.provider.UMOConnector;
33 import org.mule.umo.provider.UMOMessageAdapter;
34 import org.mule.umo.provider.UMOMessageReceiver;
35 import org.mule.umo.transformer.TransformerException;
36 import org.mule.util.MapUtils;
37 import org.mule.util.ObjectUtils;
38
39 import java.io.IOException;
40 import java.net.Socket;
41 import java.net.SocketAddress;
42 import java.util.HashMap;
43 import java.util.Iterator;
44 import java.util.Map;
45
46 import javax.resource.spi.work.Work;
47
48 import org.apache.commons.httpclient.Cookie;
49 import org.apache.commons.httpclient.Header;
50 import org.apache.commons.httpclient.cookie.MalformedCookieException;
51
52
53
54
55
56 public class HttpMessageReceiver extends TcpMessageReceiver
57 {
58
59 public HttpMessageReceiver(UMOConnector connector, UMOComponent component, UMOEndpoint endpoint)
60 throws InitialisationException
61 {
62 super(connector, component, endpoint);
63 }
64
65
66 protected Work createWork(Socket socket) throws IOException
67 {
68 return new HttpWorker(socket);
69 }
70
71
72 protected void doConnect() throws ConnectException
73 {
74
75
76 if (this.shouldConnect())
77 {
78 super.doConnect();
79 }
80 }
81
82 protected boolean shouldConnect()
83 {
84 StringBuffer requestUri = new StringBuffer(80);
85 requestUri.append(endpoint.getProtocol()).append("://");
86 requestUri.append(endpoint.getEndpointURI().getHost());
87 requestUri.append(':').append(endpoint.getEndpointURI().getPort());
88 requestUri.append('*');
89
90 UMOMessageReceiver[] receivers = connector.getReceivers(requestUri.toString());
91 for (int i = 0; i < receivers.length; i++)
92 {
93 if (receivers[i].isConnected())
94 {
95 return false;
96 }
97 }
98
99 return true;
100 }
101
102
103
104 protected UMOMessage handleUnacceptedFilter(UMOMessage message)
105 {
106 if(logger.isDebugEnabled())
107 {
108 logger.debug("Message request '" + message.getProperty(HttpConnector.HTTP_REQUEST_PROPERTY)
109 + "' is being rejected since it does not match the filter on this endpoint: " + endpoint);
110 }
111 message.setProperty(HttpConnector.HTTP_STATUS_PROPERTY, String.valueOf(HttpConstants.SC_NOT_ACCEPTABLE));
112 return message;
113 }
114
115 protected class HttpWorker implements Work
116 {
117 private HttpServerConnection conn;
118 private String cookieSpec;
119 private boolean enableCookies;
120 private String remoteClientAddress;
121
122 public HttpWorker(Socket socket) throws IOException
123 {
124 if (endpoint.getEncoding() != null)
125 {
126 conn = new HttpServerConnection(socket, endpoint.getEncoding());
127 }
128 else
129 {
130 conn = new HttpServerConnection(socket);
131 }
132
133 cookieSpec =
134 MapUtils.getString(endpoint.getProperties(), HttpConnector.HTTP_COOKIE_SPEC_PROPERTY,
135 ((HttpConnector)connector).getCookieSpec());
136 enableCookies =
137 MapUtils.getBooleanValue(endpoint.getProperties(), HttpConnector.HTTP_ENABLE_COOKIES_PROPERTY,
138 ((HttpConnector)connector).isEnableCookies());
139
140 final SocketAddress clientAddress = socket.getRemoteSocketAddress();
141 if (clientAddress != null)
142 {
143 remoteClientAddress = clientAddress.toString();
144 }
145 }
146
147 public void run()
148 {
149 try
150 {
151 do
152 {
153 conn.setKeepAlive(false);
154 HttpRequest request = conn.readRequest();
155 if (request == null)
156 {
157 break;
158 }
159 conn.writeResponse(processRequest(request));
160 }
161 while (conn.isKeepAlive());
162 }
163 catch (Exception e)
164 {
165 handleException(e);
166 }
167 finally
168 {
169 conn.close();
170 conn = null;
171 }
172 }
173
174 protected HttpResponse processRequest(HttpRequest request) throws UMOException, IOException
175 {
176 RequestLine requestLine = request.getRequestLine();
177 String method = requestLine.getMethod();
178
179 if (method.equals(HttpConstants.METHOD_HEAD))
180 {
181 return doHead(requestLine);
182 }
183 else if (method.equals(HttpConstants.METHOD_GET)
184 || method.equals(HttpConstants.METHOD_POST)
185 || method.equals(HttpConstants.METHOD_OPTIONS)
186 || method.equals(HttpConstants.METHOD_PUT)
187 || method.equals(HttpConstants.METHOD_DELETE)
188 || method.equals(HttpConstants.METHOD_TRACE)
189 || method.equals(HttpConstants.METHOD_CONNECT))
190 {
191 return doRequest(request, requestLine);
192 }
193 else
194 {
195 return doBad(requestLine);
196 }
197 }
198
199 protected HttpResponse doHead(RequestLine requestLine) throws UMOException
200 {
201 UMOMessage message = new MuleMessage(NullPayload.getInstance());
202 UMOEvent event = new MuleEvent(message, endpoint, new MuleSession(message, new NullSessionHandler()), true);
203 OptimizedRequestContext.unsafeSetEvent(event);
204 HttpResponse response = new HttpResponse();
205 response.setStatusLine(requestLine.getHttpVersion(), HttpConstants.SC_OK);
206 response = (HttpResponse)connector.getDefaultResponseTransformer().transform(response);
207 return response;
208 }
209
210 protected HttpResponse doRequest(HttpRequest request, RequestLine requestLine) throws IOException, UMOException
211 {
212 Map headers = parseHeaders(request);
213
214
215 UMOMessageAdapter adapter;
216 if (endpoint.isStreaming() && request.getBody() != null)
217 {
218 adapter = buildStreamingAdapter(request, headers);
219 }
220 else
221 {
222 adapter = buildStandardAdapter(request, headers);
223 }
224 UMOMessage message = new MuleMessage(adapter);
225
226 if (logger.isDebugEnabled())
227 {
228 logger.debug(message.getProperty(HttpConnector.HTTP_REQUEST_PROPERTY));
229 }
230
231
232 UMOMessageReceiver receiver = getTargetReceiver(message, endpoint);
233
234 HttpResponse response;
235
236
237 if (receiver != null)
238 {
239 preRouteMessage(message);
240 UMOMessage returnMessage = receiver.routeMessage(message, endpoint.isSynchronous(), null);
241
242 Object tempResponse;
243 if (returnMessage != null)
244 {
245 tempResponse = returnMessage.getPayload();
246 }
247 else
248 {
249 tempResponse = NullPayload.getInstance();
250 }
251
252
253 if (tempResponse instanceof HttpResponse)
254 {
255 response = (HttpResponse)tempResponse;
256 }
257 else
258 {
259 response = (HttpResponse)connector.getDefaultResponseTransformer().transform(tempResponse);
260 }
261 response.disableKeepAlive(!((HttpConnector)connector).isKeepAlive());
262 }
263 else
264 {
265 response = buildFailureResponse(requestLine, message);
266 }
267 return response;
268 }
269
270 protected HttpResponse doOtherValid(RequestLine requestLine, String method) throws UMOException
271 {
272 UMOMessage message = new MuleMessage(NullPayload.getInstance());
273 UMOEvent event = new MuleEvent(message, endpoint, new MuleSession(message, new NullSessionHandler()), true);
274 OptimizedRequestContext.unsafeSetEvent(event);
275 HttpResponse response = new HttpResponse();
276 response.setStatusLine(requestLine.getHttpVersion(), HttpConstants.SC_METHOD_NOT_ALLOWED);
277 response.setBodyString(HttpMessages.methodNotAllowed(method).toString() + HttpConstants.CRLF);
278 response = (HttpResponse)connector.getDefaultResponseTransformer().transform(response);
279 return response;
280 }
281
282 protected HttpResponse doBad(RequestLine requestLine) throws UMOException
283 {
284 UMOMessage message = new MuleMessage(NullPayload.getInstance());
285 UMOEvent event = new MuleEvent(message, endpoint, new MuleSession(message, new NullSessionHandler()), true);
286 OptimizedRequestContext.unsafeSetEvent(event);
287 HttpResponse response = new HttpResponse();
288 response.setStatusLine(requestLine.getHttpVersion(), HttpConstants.SC_BAD_REQUEST);
289 response.setBodyString(HttpMessages.malformedSyntax().toString() + HttpConstants.CRLF);
290 response = (HttpResponse)connector.getDefaultResponseTransformer().transform(response);
291 return response;
292 }
293
294 protected UMOMessageAdapter buildStreamingAdapter(HttpRequest request, Map headers) throws MessagingException
295 {
296 UMOMessageAdapter adapter = connector.getStreamMessageAdapter(request.getBody(), conn.getOutputStream());
297 for (Iterator iterator = headers.entrySet().iterator(); iterator.hasNext();)
298 {
299 Map.Entry entry = (Map.Entry)iterator.next();
300 adapter.setProperty((String)entry.getKey(), entry.getValue());
301 }
302 return adapter;
303 }
304
305 protected UMOMessageAdapter buildStandardAdapter(HttpRequest request, Map headers) throws MessagingException, TransformerException, IOException
306 {
307 RequestLine requestLine = request.getRequestLine();
308
309
310
311
312 if (HttpConstants.HTTP11.equals(headers.get(HttpConnector.HTTP_VERSION_PROPERTY)))
313 {
314
315
316 String expectHeaderValue = ObjectUtils.toString(
317 headers.get(HttpConstants.HEADER_EXPECT)).toLowerCase();
318 if (HttpConstants.HEADER_EXPECT_CONTINUE_REQUEST_VALUE.equals(expectHeaderValue))
319 {
320 HttpResponse expected = new HttpResponse();
321 expected.setStatusLine(requestLine.getHttpVersion(), HttpConstants.SC_CONTINUE);
322 final MuleEvent event = new MuleEvent(new MuleMessage(expected), endpoint,
323 new MuleSession(component), true);
324 RequestContext.setEvent(event);
325 expected = (HttpResponse)connector.getDefaultResponseTransformer().transform(
326 expected);
327 conn.writeResponse(expected);
328 }
329 }
330
331 Object body = request.getBodyBytes();
332 if (body == null)
333 {
334 body = requestLine.getUri();
335 }
336 return connector.getMessageAdapter(new Object[]{body, headers});
337 }
338
339 protected HttpResponse buildFailureResponse(RequestLine requestLine, UMOMessage message) throws TransformerException
340 {
341 UMOEndpointURI uri = endpoint.getEndpointURI();
342 String failedPath = uri.getScheme() + "://" + uri.getHost() + ":" + uri.getPort()
343 + getRequestPath(message);
344
345 if (logger.isDebugEnabled())
346 {
347 logger.debug("Failed to bind to " + failedPath);
348 }
349
350 HttpResponse response = new HttpResponse();
351 response.setStatusLine(requestLine.getHttpVersion(), HttpConstants.SC_NOT_FOUND);
352 response.setBodyString(HttpMessages.cannotBindToAddress(failedPath).toString());
353 RequestContext.setEvent(new MuleEvent(new MuleMessage(response), endpoint,
354 new MuleSession(component), true));
355
356 return (HttpResponse)connector.getDefaultResponseTransformer().transform(response);
357 }
358
359 protected Map parseHeaders(HttpRequest request) throws MalformedCookieException
360 {
361 RequestLine requestLine = request.getRequestLine();
362 Map headers = new HashMap();
363
364 for (Iterator rhi = request.getHeaderIterator(); rhi.hasNext();)
365 {
366 Header header = (Header)rhi.next();
367 String headerName = header.getName();
368 Object headerValue = header.getValue();
369
370
371 if (headerName.startsWith("X-MULE"))
372 {
373 headerName = headerName.substring(2);
374 }
375
376 else if (headerName.equals(HttpConnector.HTTP_COOKIES_PROPERTY))
377 {
378 if (enableCookies)
379 {
380 Cookie[] cookies = CookieHelper.parseCookies(header, cookieSpec);
381 if (cookies.length > 0)
382 {
383
384 headerValue = cookies;
385 }
386 else
387 {
388
389 continue;
390 }
391 }
392 else
393 {
394
395 continue;
396 }
397 }
398
399
400 headers.put(headerName, headerValue);
401 }
402
403 headers.put(HttpConnector.HTTP_METHOD_PROPERTY, requestLine.getMethod());
404 headers.put(HttpConnector.HTTP_REQUEST_PROPERTY, requestLine.getUri());
405 headers.put(HttpConnector.HTTP_VERSION_PROPERTY, requestLine.getHttpVersion().toString());
406 headers.put(HttpConnector.HTTP_COOKIE_SPEC_PROPERTY, cookieSpec);
407 return headers;
408 }
409
410 protected void preRouteMessage(UMOMessage message)
411 {
412 message.setProperty(MuleProperties.MULE_REMOTE_CLIENT_ADDRESS, remoteClientAddress);
413 }
414
415 public void release()
416 {
417 conn.close();
418 conn = null;
419 }
420
421 }
422
423 protected String getRequestPath(UMOMessage message)
424 {
425 String path = (String)message.getProperty(HttpConnector.HTTP_REQUEST_PROPERTY);
426 int i = path.indexOf('?');
427 if (i > -1)
428 {
429 path = path.substring(0, i);
430 }
431 return path;
432 }
433
434 protected UMOMessageReceiver getTargetReceiver(UMOMessage message, UMOEndpoint endpoint)
435 throws ConnectException
436 {
437 String path = (String)message.getProperty(HttpConnector.HTTP_REQUEST_PROPERTY);
438 int i = path.indexOf('?');
439 if (i > -1)
440 {
441 path = path.substring(0, i);
442 }
443
444 StringBuffer requestUri = new StringBuffer(80);
445 if (path.indexOf("://")==-1)
446 {
447 requestUri.append(endpoint.getProtocol()).append("://");
448 requestUri.append(endpoint.getEndpointURI().getHost());
449 requestUri.append(':').append(endpoint.getEndpointURI().getPort());
450 }
451
452 if (logger.isTraceEnabled())
453 {
454 logger.trace("Looking up receiver on connector: " + connector.getName() + " with URI key: "
455 + requestUri.toString());
456 }
457
458 UMOMessageReceiver receiver = connector.lookupReceiver(requestUri.toString());
459
460
461
462 if (receiver == null && !"/".equals(path))
463 {
464
465 int x = path.lastIndexOf('/');
466 if (x > 1 && path.indexOf('.') > x)
467 {
468 requestUri.append(path.substring(0, x));
469 }
470 else
471 {
472 requestUri.append(path);
473 }
474
475 if (logger.isDebugEnabled())
476 {
477 logger.debug("Secondary lookup of receiver on connector: " + connector.getName()
478 + " with URI key: " + requestUri.toString());
479 }
480
481
482 String uriStr = requestUri.toString();
483 receiver = connector.lookupReceiver(uriStr);
484
485 if (receiver == null)
486 {
487 receiver = findReceiverByStem(connector.getReceivers(), uriStr);
488 }
489
490 if (receiver == null && logger.isWarnEnabled())
491 {
492 logger.warn("No receiver found with secondary lookup on connector: " + connector.getName()
493 + " with URI key: " + requestUri.toString());
494 logger.warn("Receivers on connector are: "
495 + MapUtils.toString(connector.getReceivers(), true));
496 }
497 }
498
499 return receiver;
500 }
501
502 public static UMOMessageReceiver findReceiverByStem(Map receivers, String uriStr)
503 {
504 int match = 0;
505 UMOMessageReceiver receiver = null;
506 for (Iterator itr = receivers.entrySet().iterator(); itr.hasNext();)
507 {
508 Map.Entry e = (Map.Entry)itr.next();
509 String key = (String)e.getKey();
510 UMOMessageReceiver candidate = (UMOMessageReceiver)e.getValue();
511 if (uriStr.startsWith(key) && match < key.length())
512 {
513 match = key.length();
514 receiver = candidate;
515 }
516 }
517 return receiver;
518 }
519
520 }