Coverage Report - org.mule.transport.http.HttpMuleMessageFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
HttpMuleMessageFactory
0%
0/146
0%
0/78
0
 
 1  
 /*
 2  
  * $Id: HttpMuleMessageFactory.java 19519 2010-09-09 21:36:07Z dzapata $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 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  
             // This should never happen because of the supported type checking
 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  
             //We need to store this so that the headers for the part can be read
 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  
             // If http method is GET we use the request uri as the payload.
 114  0
             if (body == null)
 115  
             {
 116  0
                 body = httpRequest.getRequestLine().getUri();
 117  
             }
 118  
             else
 119  
             {
 120  
                 // If we are running async we need to read stream into a byte[].
 121  
                 // Passing along the InputStream doesn't work because the
 122  
                 // HttpConnection gets closed and closes the InputStream, often
 123  
                 // before it can be read.
 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  
                 //Attachments are the last thing to get processed
 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  
             // This should never happen because of the supported type checking in our superclass
 202  0
             throw new MessageTypeNotSupportedException(transportMessage, getClass());
 203  
         }
 204  
 
 205  0
         rewriteConnectionAndKeepAliveHeaders(headers);
 206  
 
 207  0
         headers = processIncomingHeaders(headers);
 208  
 
 209  
         //Make any URI params available ans inbound message headers
 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  
         // The encoding is stored as message property. To avoid overriding it from the message
 228  
         // properties, it must be initialized last
 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  
             // fix Mule headers?
 241  0
             if (headerName.startsWith("X-MULE"))
 242  
             {
 243  0
                 headerName = headerName.substring(2);
 244  
             }
 245  
 
 246  
             // accept header & value
 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  
             // Cookies are a special case because there may be more than one
 261  
             // cookie.
 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  
                         // concat
 278  0
                         headersMap.put(header.getName(),
 279  
                             headersMap.get(header.getName()) + "," + header.getValue());
 280  
                     }
 281  
                     else
 282  
                     {
 283  
                         // override
 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  
             // use HttpClient classes to parse the charset part from the Content-Type
 334  
             // header (e.g. "text/html; charset=UTF-16BE")
 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  
         // rewrite Connection and Keep-Alive headers based on HTTP version
 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  
 }