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