1 | |
|
2 | |
|
3 | |
|
4 | |
|
5 | |
|
6 | |
|
7 | |
|
8 | |
|
9 | |
|
10 | |
|
11 | |
package org.mule.providers.http; |
12 | |
|
13 | |
import org.mule.impl.MuleMessage; |
14 | |
import org.mule.impl.message.ExceptionPayload; |
15 | |
import org.mule.providers.AbstractMessageDispatcher; |
16 | |
import org.mule.providers.http.i18n.HttpMessages; |
17 | |
import org.mule.providers.http.transformers.HttpClientMethodResponseToObject; |
18 | |
import org.mule.providers.http.transformers.ObjectToHttpClientMethodRequest; |
19 | |
import org.mule.providers.streaming.StreamMessageAdapter; |
20 | |
import org.mule.umo.UMOEvent; |
21 | |
import org.mule.umo.UMOMessage; |
22 | |
import org.mule.umo.endpoint.UMOImmutableEndpoint; |
23 | |
import org.mule.umo.provider.DispatchException; |
24 | |
import org.mule.umo.provider.ReceiveException; |
25 | |
import org.mule.umo.provider.UMOMessageAdapter; |
26 | |
import org.mule.umo.provider.UMOStreamMessageAdapter; |
27 | |
import org.mule.umo.transformer.TransformerException; |
28 | |
import org.mule.umo.transformer.UMOTransformer; |
29 | |
import org.mule.util.StringUtils; |
30 | |
|
31 | |
import java.io.IOException; |
32 | |
import java.io.OutputStream; |
33 | |
import java.net.URI; |
34 | |
import java.net.URISyntaxException; |
35 | |
import java.util.Iterator; |
36 | |
import java.util.Map; |
37 | |
import java.util.Properties; |
38 | |
|
39 | |
import org.apache.commons.codec.binary.Base64; |
40 | |
import org.apache.commons.httpclient.Cookie; |
41 | |
import org.apache.commons.httpclient.Header; |
42 | |
import org.apache.commons.httpclient.HostConfiguration; |
43 | |
import org.apache.commons.httpclient.HttpClient; |
44 | |
import org.apache.commons.httpclient.HttpMethod; |
45 | |
import org.apache.commons.httpclient.HttpState; |
46 | |
import org.apache.commons.httpclient.HttpStatus; |
47 | |
import org.apache.commons.httpclient.UsernamePasswordCredentials; |
48 | |
import org.apache.commons.httpclient.auth.AuthScope; |
49 | |
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; |
50 | |
import org.apache.commons.httpclient.methods.DeleteMethod; |
51 | |
import org.apache.commons.httpclient.methods.EntityEnclosingMethod; |
52 | |
import org.apache.commons.httpclient.methods.GetMethod; |
53 | |
import org.apache.commons.httpclient.methods.HeadMethod; |
54 | |
import org.apache.commons.httpclient.methods.OptionsMethod; |
55 | |
import org.apache.commons.httpclient.methods.PostMethod; |
56 | |
import org.apache.commons.httpclient.methods.PutMethod; |
57 | |
import org.apache.commons.httpclient.methods.RequestEntity; |
58 | |
import org.apache.commons.httpclient.methods.TraceMethod; |
59 | |
import org.apache.commons.httpclient.params.HttpMethodParams; |
60 | |
import org.apache.commons.httpclient.protocol.Protocol; |
61 | |
import org.apache.commons.io.IOUtils; |
62 | |
|
63 | |
|
64 | |
|
65 | |
|
66 | |
public class HttpClientMessageDispatcher extends AbstractMessageDispatcher |
67 | |
{ |
68 | |
|
69 | |
|
70 | |
|
71 | |
public static final int ERROR_STATUS_CODE_RANGE_START = 400; |
72 | |
private final HttpConnector connector; |
73 | 46 | private volatile HttpClient client = null; |
74 | |
private final UMOTransformer receiveTransformer; |
75 | |
|
76 | |
public HttpClientMessageDispatcher(UMOImmutableEndpoint endpoint) |
77 | |
{ |
78 | 46 | super(endpoint); |
79 | 46 | this.connector = (HttpConnector) endpoint.getConnector(); |
80 | 46 | this.receiveTransformer = new HttpClientMethodResponseToObject(); |
81 | 46 | } |
82 | |
|
83 | |
protected void doConnect() throws Exception |
84 | |
{ |
85 | 46 | if (client == null) |
86 | |
{ |
87 | 46 | HttpState state = new HttpState(); |
88 | |
|
89 | 46 | if (connector.getProxyUsername() != null) |
90 | |
{ |
91 | 0 | state.setProxyCredentials(new AuthScope(null, -1, null, null), |
92 | |
new UsernamePasswordCredentials(connector.getProxyUsername(), |
93 | |
connector.getProxyPassword())); |
94 | |
} |
95 | |
|
96 | 46 | client = new HttpClient(); |
97 | 46 | client.setState(state); |
98 | 46 | client.setHttpConnectionManager(connector.getClientConnectionManager()); |
99 | |
} |
100 | |
|
101 | 46 | } |
102 | |
|
103 | |
protected void doDisconnect() throws Exception |
104 | |
{ |
105 | 46 | client = null; |
106 | 46 | } |
107 | |
|
108 | |
protected void doDispatch(UMOEvent event) throws Exception |
109 | |
{ |
110 | 0 | HttpMethod httpMethod = getMethod(event); |
111 | 0 | execute(event, httpMethod, true); |
112 | 0 | if (httpMethod.getStatusCode() >= ERROR_STATUS_CODE_RANGE_START) |
113 | |
{ |
114 | 0 | logger.error(httpMethod.getResponseBodyAsString()); |
115 | 0 | throw new DispatchException(event.getMessage(), event.getEndpoint(), new Exception( |
116 | |
"Http call returned a status of: " + httpMethod.getStatusCode() + " " |
117 | |
+ httpMethod.getStatusText())); |
118 | |
} |
119 | 0 | } |
120 | |
|
121 | |
|
122 | |
|
123 | |
|
124 | |
|
125 | |
|
126 | |
|
127 | |
|
128 | |
|
129 | |
|
130 | |
|
131 | |
|
132 | |
protected UMOMessage doReceive(long timeout) throws Exception |
133 | |
{ |
134 | 0 | HttpMethod httpMethod = new GetMethod(endpoint.getEndpointURI().getAddress()); |
135 | 0 | httpMethod.setDoAuthentication(true); |
136 | 0 | if (endpoint.getEndpointURI().getUserInfo() != null |
137 | |
&& endpoint.getProperty(HttpConstants.HEADER_AUTHORIZATION) == null) |
138 | |
{ |
139 | |
|
140 | 0 | StringBuffer header = new StringBuffer(128); |
141 | 0 | header.append("Basic "); |
142 | 0 | header.append(new String(Base64.encodeBase64(endpoint.getEndpointURI().getUserInfo().getBytes( |
143 | |
endpoint.getEncoding())))); |
144 | 0 | httpMethod.addRequestHeader(HttpConstants.HEADER_AUTHORIZATION, header.toString()); |
145 | |
} |
146 | |
try |
147 | |
{ |
148 | 0 | HttpClient client = new HttpClient(); |
149 | 0 | client.executeMethod(httpMethod); |
150 | |
|
151 | 0 | if (httpMethod.getStatusCode() == HttpStatus.SC_OK) |
152 | |
{ |
153 | 0 | return (UMOMessage) receiveTransformer.transform(httpMethod); |
154 | |
} |
155 | |
else |
156 | |
{ |
157 | 0 | throw new ReceiveException( |
158 | |
HttpMessages.requestFailedWithStatus(httpMethod.getStatusLine().toString()), |
159 | |
endpoint, timeout); |
160 | |
} |
161 | |
} |
162 | 0 | catch (ReceiveException e) |
163 | |
{ |
164 | 0 | throw e; |
165 | |
} |
166 | 0 | catch (Exception e) |
167 | |
{ |
168 | 0 | throw new ReceiveException(endpoint, timeout, e); |
169 | |
} |
170 | |
finally |
171 | |
{ |
172 | 0 | httpMethod.releaseConnection(); |
173 | |
} |
174 | |
} |
175 | |
|
176 | |
protected HttpMethod execute(UMOEvent event, HttpMethod httpMethod, boolean closeConnection) |
177 | |
throws Exception |
178 | |
{ |
179 | |
|
180 | |
try |
181 | |
{ |
182 | 126 | URI uri = event.getEndpoint().getEndpointURI().getUri(); |
183 | |
|
184 | 126 | this.processCookies(event); |
185 | |
|
186 | |
|
187 | 126 | client.executeMethod(getHostConfig(uri), httpMethod); |
188 | |
|
189 | 126 | return httpMethod; |
190 | |
} |
191 | 0 | catch (IOException e) |
192 | |
{ |
193 | |
|
194 | 0 | throw new DispatchException(event.getMessage(), event.getEndpoint(), e); |
195 | |
} |
196 | 0 | catch (Exception e) |
197 | |
{ |
198 | 0 | throw new DispatchException(event.getMessage(), event.getEndpoint(), e); |
199 | |
} |
200 | |
finally |
201 | |
{ |
202 | 126 | if (httpMethod != null && closeConnection) |
203 | |
{ |
204 | 0 | httpMethod.releaseConnection(); |
205 | |
} |
206 | |
} |
207 | |
} |
208 | |
|
209 | |
protected void processCookies(UMOEvent event) |
210 | |
{ |
211 | 126 | UMOMessage msg = event.getMessage(); |
212 | 126 | Cookie[] cookies = (Cookie[]) msg.removeProperty(HttpConnector.HTTP_COOKIES_PROPERTY); |
213 | 126 | if (cookies != null && cookies.length > 0) |
214 | |
{ |
215 | 12 | String policy = (String) msg.removeProperty(HttpConnector.HTTP_COOKIE_SPEC_PROPERTY); |
216 | 12 | client.getParams().setCookiePolicy(CookieHelper.getCookiePolicy(policy)); |
217 | 12 | client.getState().addCookies(cookies); |
218 | |
} |
219 | 126 | } |
220 | |
|
221 | |
protected HttpMethod getMethod(UMOEvent event) throws TransformerException |
222 | |
{ |
223 | 126 | UMOMessage msg = event.getMessage(); |
224 | 126 | String method = msg.getStringProperty(HttpConnector.HTTP_METHOD_PROPERTY, HttpConstants.METHOD_POST); |
225 | 126 | URI uri = event.getEndpoint().getEndpointURI().getUri(); |
226 | |
HttpMethod httpMethod; |
227 | 126 | Object body = event.getTransformedMessage(); |
228 | |
|
229 | 126 | if (body instanceof HttpMethod) |
230 | |
{ |
231 | 126 | httpMethod = (HttpMethod)body; |
232 | |
} |
233 | 0 | else if (HttpConstants.METHOD_GET.equalsIgnoreCase(method)) |
234 | |
{ |
235 | 0 | httpMethod = new GetMethod(uri.toString()); |
236 | |
} |
237 | 0 | else if (HttpConstants.METHOD_PUT.equalsIgnoreCase(method)) |
238 | |
{ |
239 | 0 | PutMethod postMethod = new PutMethod(uri.toString()); |
240 | |
|
241 | 0 | httpMethod = createEntityMethod(event, body, postMethod); |
242 | 0 | } |
243 | 0 | else if (HttpConstants.METHOD_POST.equalsIgnoreCase(method)) |
244 | |
{ |
245 | 0 | PostMethod postMethod = new PostMethod(uri.toString()); |
246 | |
|
247 | 0 | httpMethod = createEntityMethod(event, body, postMethod); |
248 | 0 | } |
249 | 0 | else if (HttpConstants.METHOD_DELETE.equalsIgnoreCase(method)) |
250 | |
{ |
251 | 0 | httpMethod = new DeleteMethod(uri.toString()); |
252 | |
} |
253 | 0 | else if (HttpConstants.METHOD_HEAD.equalsIgnoreCase(method)) |
254 | |
{ |
255 | 0 | httpMethod = new HeadMethod(uri.toString()); |
256 | |
} |
257 | 0 | else if (HttpConstants.METHOD_OPTIONS.equalsIgnoreCase(method)) |
258 | |
{ |
259 | 0 | httpMethod = new OptionsMethod(uri.toString()); |
260 | |
} |
261 | 0 | else if (HttpConstants.METHOD_TRACE.equalsIgnoreCase(method)) |
262 | |
{ |
263 | 0 | httpMethod = new TraceMethod(uri.toString()); |
264 | |
} |
265 | |
else |
266 | |
{ |
267 | 0 | throw new TransformerException(HttpMessages.unsupportedMethod(method)); |
268 | |
} |
269 | |
|
270 | 126 | httpMethod.setDoAuthentication(true); |
271 | 126 | if (event.getCredentials() != null) |
272 | |
{ |
273 | 0 | String authScopeHost = msg.getStringProperty("http.auth.scope.host", null); |
274 | 0 | int authScopePort = msg.getIntProperty("http.auth.scope.port", -1); |
275 | 0 | String authScopeRealm = msg.getStringProperty("http.auth.scope.realm", null); |
276 | 0 | String authScopeScheme = msg.getStringProperty("http.auth.scope.scheme", null); |
277 | 0 | client.getState().setCredentials( |
278 | |
new AuthScope(authScopeHost, authScopePort, authScopeRealm, authScopeScheme), |
279 | |
new UsernamePasswordCredentials(event.getCredentials().getUsername(), new String( |
280 | |
event.getCredentials().getPassword()))); |
281 | 0 | client.getParams().setAuthenticationPreemptive(true); |
282 | 0 | } |
283 | |
else |
284 | |
{ |
285 | |
|
286 | 126 | client.getParams().setAuthenticationPreemptive(false); |
287 | |
} |
288 | 126 | return httpMethod; |
289 | |
} |
290 | |
|
291 | |
protected HttpMethod createEntityMethod(UMOEvent event, Object body, EntityEnclosingMethod postMethod) |
292 | |
throws TransformerException |
293 | |
{ |
294 | |
HttpMethod httpMethod; |
295 | 0 | if (body instanceof String) |
296 | |
{ |
297 | 0 | ObjectToHttpClientMethodRequest trans = new ObjectToHttpClientMethodRequest(); |
298 | 0 | httpMethod = (HttpMethod)trans.transform(body.toString()); |
299 | 0 | } |
300 | 0 | else if (body instanceof UMOStreamMessageAdapter) |
301 | |
{ |
302 | 0 | UMOStreamMessageAdapter sma = (UMOStreamMessageAdapter)body; |
303 | 0 | Map headers = sma.getOutputHandler().getHeaders(event); |
304 | 0 | for (Iterator iterator = headers.entrySet().iterator(); iterator.hasNext();) |
305 | |
{ |
306 | 0 | Map.Entry entry = (Map.Entry)iterator.next(); |
307 | 0 | postMethod.addRequestHeader((String)entry.getKey(), (String)entry.getValue()); |
308 | 0 | } |
309 | 0 | postMethod.setRequestEntity(new StreamPayloadRequestEntity((StreamMessageAdapter)body, event)); |
310 | 0 | postMethod.setContentChunked(true); |
311 | 0 | httpMethod = postMethod; |
312 | 0 | } |
313 | |
else |
314 | |
{ |
315 | 0 | byte[] buffer = event.getTransformedMessageAsBytes(); |
316 | 0 | postMethod.setRequestEntity(new ByteArrayRequestEntity(buffer, event.getEncoding())); |
317 | 0 | httpMethod = postMethod; |
318 | |
} |
319 | 0 | return httpMethod; |
320 | |
} |
321 | |
|
322 | |
|
323 | |
|
324 | |
|
325 | |
|
326 | |
|
327 | |
protected UMOMessage doSend(UMOEvent event) throws Exception |
328 | |
{ |
329 | 126 | HttpMethod httpMethod = getMethod(event); |
330 | 126 | httpMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new MuleHttpMethodRetryHandler()); |
331 | |
|
332 | 126 | httpMethod = execute(event, httpMethod, false); |
333 | |
|
334 | |
try |
335 | |
{ |
336 | 126 | Properties h = new Properties(); |
337 | 126 | Header[] headers = httpMethod.getResponseHeaders(); |
338 | 786 | for (int i = 0; i < headers.length; i++) |
339 | |
{ |
340 | 660 | h.setProperty(headers[i].getName(), headers[i].getValue()); |
341 | |
} |
342 | |
|
343 | 126 | String status = String.valueOf(httpMethod.getStatusCode()); |
344 | |
|
345 | 126 | h.setProperty(HttpConnector.HTTP_STATUS_PROPERTY, status); |
346 | 126 | if (logger.isDebugEnabled()) |
347 | |
{ |
348 | 0 | logger.debug("Http response is: " + status); |
349 | |
} |
350 | 126 | ExceptionPayload ep = null; |
351 | 126 | if (httpMethod.getStatusCode() >= ERROR_STATUS_CODE_RANGE_START) |
352 | |
{ |
353 | 6 | ep = new ExceptionPayload(new DispatchException(event.getMessage(), event.getEndpoint(), |
354 | |
new Exception("Http call returned a status of: " + httpMethod.getStatusCode() + " " |
355 | |
+ httpMethod.getStatusText()))); |
356 | |
} |
357 | |
UMOMessage m; |
358 | |
|
359 | 126 | Header header = httpMethod.getResponseHeader(HttpConstants.HEADER_CONTENT_TYPE); |
360 | 126 | if ((header != null) && event.isStreaming()) |
361 | |
{ |
362 | 0 | HttpStreamMessageAdapter sp = (HttpStreamMessageAdapter)connector.getStreamMessageAdapter( |
363 | |
httpMethod.getResponseBodyAsStream(), null); |
364 | 0 | sp.setHttpMethod(httpMethod); |
365 | 0 | m = new MuleMessage(sp, h); |
366 | 0 | } |
367 | |
else |
368 | |
{ |
369 | 126 | Object body = IOUtils.toByteArray(httpMethod.getResponseBodyAsStream()); |
370 | 126 | if (body == null) |
371 | |
{ |
372 | 0 | body = StringUtils.EMPTY; |
373 | |
} |
374 | 126 | UMOMessageAdapter adapter = connector.getMessageAdapter(new Object[]{body, h}); |
375 | 126 | m = new MuleMessage(adapter); |
376 | |
} |
377 | 126 | m.setExceptionPayload(ep); |
378 | 126 | return m; |
379 | |
} |
380 | 0 | catch (Exception e) |
381 | |
{ |
382 | 0 | throw new DispatchException(event.getMessage(), event.getEndpoint(), e); |
383 | |
} |
384 | |
finally |
385 | |
{ |
386 | 126 | if (httpMethod != null && !event.isStreaming()) |
387 | |
{ |
388 | 126 | httpMethod.releaseConnection(); |
389 | |
} |
390 | |
} |
391 | |
} |
392 | |
|
393 | |
protected HostConfiguration getHostConfig(URI uri) throws URISyntaxException |
394 | |
{ |
395 | 126 | Protocol protocol = Protocol.getProtocol(uri.getScheme().toLowerCase()); |
396 | |
|
397 | 126 | String host = uri.getHost(); |
398 | 126 | int port = uri.getPort(); |
399 | 126 | HostConfiguration config = new HostConfiguration(); |
400 | 126 | config.setHost(host, port, protocol); |
401 | 126 | if (StringUtils.isNotBlank(connector.getProxyHostname())) |
402 | |
{ |
403 | |
|
404 | 0 | config.setProxy(connector.getProxyHostname(), connector.getProxyPort()); |
405 | |
} |
406 | 126 | return config; |
407 | |
} |
408 | |
|
409 | |
protected void doDispose() |
410 | |
{ |
411 | |
|
412 | 46 | } |
413 | |
|
414 | |
protected class StreamPayloadRequestEntity implements RequestEntity |
415 | |
{ |
416 | |
private UMOStreamMessageAdapter messageAdapter; |
417 | |
private UMOEvent event; |
418 | |
|
419 | |
public StreamPayloadRequestEntity(UMOStreamMessageAdapter messageAdapter, UMOEvent event) |
420 | 0 | { |
421 | 0 | this.messageAdapter = messageAdapter; |
422 | 0 | this.event = event; |
423 | 0 | } |
424 | |
|
425 | |
public boolean isRepeatable() |
426 | |
{ |
427 | 0 | return true; |
428 | |
} |
429 | |
|
430 | |
public void writeRequest(OutputStream outputStream) throws IOException |
431 | |
{ |
432 | 0 | messageAdapter.getOutputHandler().write(event, outputStream); |
433 | 0 | } |
434 | |
|
435 | |
public long getContentLength() |
436 | |
{ |
437 | 0 | return -1L; |
438 | |
} |
439 | |
|
440 | |
public String getContentType() |
441 | |
{ |
442 | 0 | return event.getMessage().getStringProperty(HttpConstants.HEADER_CONTENT_TYPE, null); |
443 | |
} |
444 | |
} |
445 | |
|
446 | |
} |