1
2
3
4
5
6
7
8
9
10
11 package org.mule.transport.http;
12
13 import org.mule.DefaultMuleMessage;
14 import org.mule.MessageExchangePattern;
15 import org.mule.api.MuleContext;
16 import org.mule.api.MuleMessage;
17 import org.mule.api.transport.MessageTypeNotSupportedException;
18 import org.mule.transport.AbstractMuleMessageFactory;
19 import org.mule.transport.http.multipart.MultiPartInputStream;
20 import org.mule.transport.http.multipart.Part;
21 import org.mule.transport.http.multipart.PartDataSource;
22 import org.mule.util.CaseInsensitiveHashMap;
23 import org.mule.util.IOUtils;
24 import org.mule.util.PropertiesUtils;
25 import org.mule.util.StringUtils;
26
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.net.URI;
30 import java.net.URISyntaxException;
31 import java.util.Collection;
32 import java.util.HashMap;
33 import java.util.Map;
34
35 import javax.activation.DataHandler;
36
37 import org.apache.commons.httpclient.Cookie;
38 import org.apache.commons.httpclient.Header;
39 import org.apache.commons.httpclient.HeaderElement;
40 import org.apache.commons.httpclient.HttpMethod;
41 import org.apache.commons.httpclient.HttpVersion;
42 import org.apache.commons.httpclient.NameValuePair;
43 import org.apache.commons.httpclient.cookie.MalformedCookieException;
44 import org.apache.commons.logging.Log;
45 import org.apache.commons.logging.LogFactory;
46
47 public class HttpMuleMessageFactory extends AbstractMuleMessageFactory
48 {
49 private static Log log = LogFactory.getLog(HttpMuleMessageFactory.class);
50
51 private boolean enableCookies = false;
52 private String cookieSpec;
53 private MessageExchangePattern exchangePattern = MessageExchangePattern.REQUEST_RESPONSE;
54 private Collection<Part> parts;
55
56 public HttpMuleMessageFactory(MuleContext context)
57 {
58 super(context);
59 }
60
61 @Override
62 protected Class<?>[] getSupportedTransportMessageTypes()
63 {
64 return new Class[]{HttpRequest.class, HttpMethod.class};
65 }
66
67 @Override
68 protected Object extractPayload(Object transportMessage, String encoding) throws Exception
69 {
70 if (transportMessage instanceof HttpRequest)
71 {
72 return extractPayloadFromHttpRequest((HttpRequest) transportMessage);
73 }
74 else if (transportMessage instanceof HttpMethod)
75 {
76 return extractPayloadFromHttpMethod((HttpMethod) transportMessage);
77 }
78 else
79 {
80
81 throw new MessageTypeNotSupportedException(transportMessage, getClass());
82 }
83 }
84
85 protected Object extractPayloadFromHttpRequest(HttpRequest httpRequest) throws IOException
86 {
87 Object body = null;
88
89 if (httpRequest.getContentType().contains("multipart/form-data"))
90 {
91 MultiPartInputStream in = new MultiPartInputStream(httpRequest.getBody(), httpRequest.getContentType(), null);
92
93
94 parts = in.getParts();
95 for (Part part : parts)
96 {
97 if (part.getName().equals("payload"))
98 {
99 body = part.getInputStream();
100 break;
101 }
102 }
103 if (body == null)
104 {
105 throw new IllegalArgumentException("todo");
106 }
107 }
108 else
109 {
110
111 body = httpRequest.getBody();
112
113
114 if (body == null)
115 {
116 body = httpRequest.getRequestLine().getUri();
117 }
118 else
119 {
120
121
122
123
124 if (!exchangePattern.hasResponse())
125 {
126 log.debug("Reading HTTP POST InputStream into byte[] for asynchronous messaging.");
127 body = IOUtils.toByteArray((InputStream) body);
128 }
129 }
130 }
131
132 return body;
133 }
134
135 @Override
136 protected void addAttachments(DefaultMuleMessage message, Object transportMessage) throws Exception
137 {
138 if (parts != null)
139 {
140 try
141 {
142 for (Part part : parts)
143 {
144 if (!part.getName().equals("payload"))
145 {
146 message.addInboundAttachment(part.getName(), new DataHandler(new PartDataSource(part)));
147 }
148 }
149 }
150 finally
151 {
152
153 parts.clear();
154 parts = null;
155 }
156 }
157 }
158
159 protected Object extractPayloadFromHttpMethod(HttpMethod httpMethod) throws IOException
160 {
161 InputStream body = httpMethod.getResponseBodyAsStream();
162 if (body != null)
163 {
164 return new ReleasingInputStream(body, httpMethod);
165 }
166 else
167 {
168 return StringUtils.EMPTY;
169 }
170 }
171
172 @Override
173 protected void addProperties(DefaultMuleMessage message, Object transportMessage) throws Exception
174 {
175 String method;
176 HttpVersion httpVersion;
177 String uri;
178 String statusCode = null;
179 Map<String, Object> headers;
180
181 if (transportMessage instanceof HttpRequest)
182 {
183 HttpRequest httpRequest = (HttpRequest) transportMessage;
184 method = httpRequest.getRequestLine().getMethod();
185 httpVersion = httpRequest.getRequestLine().getHttpVersion();
186 uri = httpRequest.getRequestLine().getUri();
187 headers = convertHeadersToMap(httpRequest.getHeaders(), uri);
188 convertMultiPartHeaders(headers);
189 }
190 else if (transportMessage instanceof HttpMethod)
191 {
192 HttpMethod httpMethod = (HttpMethod) transportMessage;
193 method = httpMethod.getName();
194 httpVersion = HttpVersion.parse(httpMethod.getStatusLine().getHttpVersion());
195 uri = httpMethod.getURI().toString();
196 statusCode = String.valueOf(httpMethod.getStatusCode());
197 headers = convertHeadersToMap(httpMethod.getResponseHeaders(), uri);
198 }
199 else
200 {
201
202 throw new MessageTypeNotSupportedException(transportMessage, getClass());
203 }
204
205 rewriteConnectionAndKeepAliveHeaders(headers);
206
207 headers = processIncomingHeaders(headers);
208
209
210 addUriParamsAsHeaders(headers, uri);
211
212 headers.put(HttpConnector.HTTP_METHOD_PROPERTY, method);
213 headers.put(HttpConnector.HTTP_REQUEST_PROPERTY, uri);
214 headers.put(HttpConnector.HTTP_VERSION_PROPERTY, httpVersion.toString());
215 if (enableCookies)
216 {
217 headers.put(HttpConnector.HTTP_COOKIE_SPEC_PROPERTY, cookieSpec);
218 }
219
220 if (statusCode != null)
221 {
222 headers.put(HttpConnector.HTTP_STATUS_PROPERTY, statusCode);
223 }
224
225 message.addInboundProperties(headers);
226
227
228
229 initEncoding(message, headers);
230 }
231
232 protected Map<String, Object> processIncomingHeaders(Map<String, Object> headers) throws Exception
233 {
234 Map<String, Object> outHeaders = new HashMap<String, Object>();
235
236 for (String headerName : headers.keySet())
237 {
238 Object headerValue = headers.get(headerName);
239
240
241 if (headerName.startsWith("X-MULE"))
242 {
243 headerName = headerName.substring(2);
244 }
245
246
247 outHeaders.put(headerName, headerValue);
248 }
249
250 return outHeaders;
251 }
252
253 Map<String, Object> convertHeadersToMap(Header[] headersArray, String uri)
254 throws URISyntaxException
255 {
256 Map<String, Object> headersMap = new CaseInsensitiveHashMap();
257 for (int i = 0; i < headersArray.length; i++)
258 {
259 final Header header = headersArray[i];
260
261
262 if (HttpConnector.HTTP_COOKIES_PROPERTY.equals(header.getName())
263 || HttpConstants.HEADER_COOKIE.equals(header.getName()))
264 {
265 putCookieHeaderInMapAsAServer(headersMap, header, uri);
266 }
267 else if (HttpConstants.HEADER_COOKIE_SET.equals(header.getName()))
268 {
269 putCookieHeaderInMapAsAClient(headersMap, header, uri);
270 }
271 else
272 {
273 if (headersMap.containsKey(header.getName()))
274 {
275 if (headersMap.get(header.getName()) instanceof String)
276 {
277
278 headersMap.put(header.getName(),
279 headersMap.get(header.getName()) + "," + header.getValue());
280 }
281 else
282 {
283
284 headersMap.put(header.getName(), header.getValue());
285 }
286 }
287 else
288 {
289 headersMap.put(header.getName(), header.getValue());
290 }
291 }
292 }
293 return headersMap;
294 }
295
296 private void putCookieHeaderInMapAsAClient(Map<String, Object> headersMap, final Header header, String uri)
297 throws URISyntaxException
298 {
299 try
300 {
301 final Cookie[] newCookies = CookieHelper.parseCookiesAsAClient(header.getValue(), cookieSpec,
302 new URI(uri));
303 final Object preExistentCookies = headersMap.get(HttpConstants.HEADER_COOKIE_SET);
304 final Object mergedCookie = CookieHelper.putAndMergeCookie(preExistentCookies, newCookies);
305 headersMap.put(HttpConstants.HEADER_COOKIE_SET, mergedCookie);
306 }
307 catch (MalformedCookieException e)
308 {
309 log.warn("Received an invalid cookie: " + header, e);
310 }
311 }
312
313 private void putCookieHeaderInMapAsAServer(Map<String, Object> headersMap, final Header header, String uri)
314 throws URISyntaxException
315 {
316 if (enableCookies)
317 {
318 Cookie[] newCookies = CookieHelper.parseCookiesAsAServer(header.getValue(), new URI(uri));
319 if (newCookies.length > 0)
320 {
321 Object oldCookies = headersMap.get(HttpConnector.HTTP_COOKIES_PROPERTY);
322 Object mergedCookies = CookieHelper.putAndMergeCookie(oldCookies, newCookies);
323 headersMap.put(HttpConnector.HTTP_COOKIES_PROPERTY, mergedCookies);
324 }
325 }
326 }
327
328 private void initEncoding(MuleMessage message, Map<String, Object> headers)
329 {
330 Object contentType = headers.get(HttpConstants.HEADER_CONTENT_TYPE);
331 if (contentType != null)
332 {
333
334
335 Header contentTypeHeader = new Header(HttpConstants.HEADER_CONTENT_TYPE,
336 contentType.toString());
337 HeaderElement values[] = contentTypeHeader.getElements();
338 if (values.length == 1)
339 {
340 NameValuePair param = values[0].getParameterByName("charset");
341 if (param != null)
342 {
343 message.setEncoding(param.getValue());
344 }
345 }
346 }
347 }
348
349 private void rewriteConnectionAndKeepAliveHeaders(Map<String, Object> headers)
350 {
351
352 String headerValue;
353 if (!isHttp11(headers))
354 {
355 String connection = (String) headers.get(HttpConstants.HEADER_CONNECTION);
356 if ((connection != null) && connection.equalsIgnoreCase("close"))
357 {
358 headerValue = Boolean.FALSE.toString();
359 }
360 else
361 {
362 headerValue = Boolean.TRUE.toString();
363 }
364 }
365 else
366 {
367 headerValue = (headers.get(HttpConstants.HEADER_CONNECTION) != null
368 ? Boolean.TRUE.toString()
369 : Boolean.FALSE.toString());
370 }
371
372 headers.put(HttpConstants.HEADER_CONNECTION, headerValue);
373 headers.put(HttpConstants.HEADER_KEEP_ALIVE, headerValue);
374 }
375
376 private boolean isHttp11(Map<String, Object> headers)
377 {
378 String httpVersion = (String) headers.get(HttpConnector.HTTP_VERSION_PROPERTY);
379 return !HttpConstants.HTTP10.equalsIgnoreCase(httpVersion);
380 }
381
382 protected void addUriParamsAsHeaders(Map headers, String uri)
383 {
384 int i = uri.indexOf("?");
385 if (i > -1)
386 {
387 headers.putAll(PropertiesUtils.getPropertiesFromQueryString(uri.substring(i + 1)));
388 }
389 }
390
391 protected void convertMultiPartHeaders(Map headers)
392 {
393 if (parts != null)
394 {
395 for (Part part : parts)
396 {
397 if (part.getName().equals("payload"))
398 {
399 for (String name : part.getHeaderNames())
400 {
401 headers.put(name, part.getHeader(name));
402 }
403 break;
404 }
405 }
406
407 }
408
409 }
410
411 public void setEnableCookies(boolean enableCookies)
412 {
413 this.enableCookies = enableCookies;
414 }
415
416 public void setCookieSpec(String cookieSpec)
417 {
418 this.cookieSpec = cookieSpec;
419 }
420
421 public void setExchangePattern(MessageExchangePattern mep)
422 {
423 exchangePattern = mep;
424 }
425 }