Coverage Report - org.mule.transport.http.HttpMuleMessageFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
HttpMuleMessageFactory
0%
0/121
0%
0/56
0
 
 1  
 /*
 2  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 3  
  * The software in this package is published under the terms of the CPAL v1.0
 4  
  * license, a copy of which has been included with this distribution in the
 5  
  * LICENSE.txt file.
 6  
  */
 7  
 package org.mule.transport.http;
 8  
 
 9  
 import org.mule.DefaultMuleMessage;
 10  
 import org.mule.MessageExchangePattern;
 11  
 import org.mule.api.MuleContext;
 12  
 import org.mule.api.MuleMessage;
 13  
 import org.mule.api.transport.MessageTypeNotSupportedException;
 14  
 import org.mule.transport.AbstractMuleMessageFactory;
 15  
 import org.mule.util.CaseInsensitiveHashMap;
 16  
 import org.mule.util.IOUtils;
 17  
 import org.mule.util.PropertiesUtils;
 18  
 import org.mule.util.StringUtils;
 19  
 
 20  
 import java.io.IOException;
 21  
 import java.io.InputStream;
 22  
 import java.net.URI;
 23  
 import java.net.URISyntaxException;
 24  
 import java.util.HashMap;
 25  
 import java.util.Map;
 26  
 
 27  
 import org.apache.commons.httpclient.Cookie;
 28  
 import org.apache.commons.httpclient.Header;
 29  
 import org.apache.commons.httpclient.HeaderElement;
 30  
 import org.apache.commons.httpclient.HttpMethod;
 31  
 import org.apache.commons.httpclient.HttpVersion;
 32  
 import org.apache.commons.httpclient.NameValuePair;
 33  
 import org.apache.commons.httpclient.cookie.MalformedCookieException;
 34  
 import org.apache.commons.logging.Log;
 35  
 import org.apache.commons.logging.LogFactory;
 36  
 
 37  
 public class HttpMuleMessageFactory extends AbstractMuleMessageFactory
 38  
 {
 39  0
     private static Log log = LogFactory.getLog(HttpMuleMessageFactory.class);
 40  
 
 41  0
     private boolean enableCookies = false;
 42  
     private String cookieSpec;
 43  0
     private MessageExchangePattern exchangePattern = MessageExchangePattern.REQUEST_RESPONSE;
 44  
 
 45  
     public HttpMuleMessageFactory(MuleContext context)
 46  
     {
 47  0
         super(context);
 48  0
     }
 49  
 
 50  
     @Override
 51  
     protected Class<?>[] getSupportedTransportMessageTypes()
 52  
     {
 53  0
         return new Class[]{HttpRequest.class, HttpMethod.class};
 54  
     }
 55  
 
 56  
     @Override
 57  
     protected Object extractPayload(Object transportMessage, String encoding) throws Exception
 58  
     {
 59  0
         if (transportMessage instanceof HttpRequest)
 60  
         {
 61  0
             return extractPayloadFromHttpRequest((HttpRequest) transportMessage);
 62  
         }
 63  0
         else if (transportMessage instanceof HttpMethod)
 64  
         {
 65  0
             return extractPayloadFromHttpMethod((HttpMethod) transportMessage);
 66  
         }
 67  
         else
 68  
         {
 69  
             // This should never happen because of the supported type checking
 70  0
             throw new MessageTypeNotSupportedException(transportMessage, getClass());
 71  
         }
 72  
     }
 73  
 
 74  
     protected Object extractPayloadFromHttpRequest(HttpRequest httpRequest) throws IOException
 75  
     {
 76  0
         Object body = httpRequest.getBody();
 77  
 
 78  
         // If http method is GET we use the request uri as the payload.
 79  0
         if (body == null)
 80  
         {
 81  0
             body = httpRequest.getRequestLine().getUri();
 82  
         }
 83  
         else
 84  
         {
 85  
             // If we are running async we need to read stream into a byte[].
 86  
             // Passing along the InputStream doesn't work because the
 87  
             // HttpConnection gets closed and closes the InputStream, often
 88  
             // before it can be read.
 89  0
             if (!exchangePattern.hasResponse())
 90  
             {
 91  0
                 log.debug("Reading HTTP POST InputStream into byte[] for asynchronous messaging.");
 92  0
                 body = IOUtils.toByteArray((InputStream) body);
 93  
             }
 94  
         }
 95  
 
 96  0
         return body;
 97  
     }
 98  
 
 99  
     protected Object extractPayloadFromHttpMethod(HttpMethod httpMethod) throws IOException
 100  
     {
 101  0
         InputStream body = httpMethod.getResponseBodyAsStream();
 102  0
         if (body != null)
 103  
         {
 104  0
             return new ReleasingInputStream(body, httpMethod);
 105  
         }
 106  
         else
 107  
         {
 108  0
             return StringUtils.EMPTY;
 109  
         }
 110  
     }
 111  
 
 112  
     @Override
 113  
     protected void addProperties(DefaultMuleMessage message, Object transportMessage) throws Exception
 114  
     {
 115  
         String method;
 116  
         HttpVersion httpVersion;
 117  
         String uri;
 118  0
         String statusCode = null;
 119  
         Map<String, Object> headers;
 120  
 
 121  0
         if (transportMessage instanceof HttpRequest)
 122  
         {
 123  0
             HttpRequest httpRequest = (HttpRequest) transportMessage;
 124  0
             method = httpRequest.getRequestLine().getMethod();
 125  0
             httpVersion = httpRequest.getRequestLine().getHttpVersion();
 126  0
             uri = httpRequest.getRequestLine().getUri();
 127  0
             headers = convertHeadersToMap(httpRequest.getHeaders(), uri);
 128  0
             convertMultiPartHeaders(headers);
 129  0
         }
 130  0
         else if (transportMessage instanceof HttpMethod)
 131  
         {
 132  0
             HttpMethod httpMethod = (HttpMethod) transportMessage;
 133  0
             method = httpMethod.getName();
 134  0
             httpVersion = HttpVersion.parse(httpMethod.getStatusLine().getHttpVersion());
 135  0
             uri = httpMethod.getURI().toString();
 136  0
             statusCode = String.valueOf(httpMethod.getStatusCode());
 137  0
             headers = convertHeadersToMap(httpMethod.getResponseHeaders(), uri);
 138  0
         }
 139  
         else
 140  
         {
 141  
             // This should never happen because of the supported type checking in our superclass
 142  0
             throw new MessageTypeNotSupportedException(transportMessage, getClass());
 143  
         }
 144  
 
 145  0
         rewriteConnectionAndKeepAliveHeaders(headers);
 146  
 
 147  0
         headers = processIncomingHeaders(headers);
 148  
 
 149  
         //Make any URI params available ans inbound message headers
 150  0
         addUriParamsAsHeaders(headers, uri);
 151  
 
 152  0
         headers.put(HttpConnector.HTTP_METHOD_PROPERTY, method);
 153  0
         headers.put(HttpConnector.HTTP_REQUEST_PROPERTY, uri);
 154  0
         headers.put(HttpConnector.HTTP_VERSION_PROPERTY, httpVersion.toString());
 155  0
         if (enableCookies)
 156  
         {
 157  0
             headers.put(HttpConnector.HTTP_COOKIE_SPEC_PROPERTY, cookieSpec);
 158  
         }
 159  
 
 160  0
         if (statusCode != null)
 161  
         {
 162  0
             headers.put(HttpConnector.HTTP_STATUS_PROPERTY, statusCode);
 163  
         }
 164  
 
 165  0
         message.addInboundProperties(headers);
 166  
 
 167  
         // The encoding is stored as message property. To avoid overriding it from the message
 168  
         // properties, it must be initialized last
 169  0
         initEncoding(message, headers);
 170  0
     }
 171  
 
 172  
     protected Map<String, Object> processIncomingHeaders(Map<String, Object> headers) throws Exception
 173  
     {
 174  0
         Map<String, Object> outHeaders = new HashMap<String, Object>();
 175  
 
 176  0
         for (String headerName : headers.keySet())
 177  
         {
 178  0
             Object headerValue = headers.get(headerName);
 179  
 
 180  
             // fix Mule headers?
 181  0
             if (headerName.startsWith("X-MULE"))
 182  
             {
 183  0
                 headerName = headerName.substring(2);
 184  
             }
 185  
 
 186  
             // accept header & value
 187  0
             outHeaders.put(headerName, headerValue);
 188  0
         }
 189  
 
 190  0
         return outHeaders;
 191  
     }
 192  
 
 193  
     Map<String, Object> convertHeadersToMap(Header[] headersArray, String uri)
 194  
         throws URISyntaxException
 195  
     {
 196  0
         Map<String, Object> headersMap = new CaseInsensitiveHashMap();
 197  0
         for (int i = 0; i < headersArray.length; i++)
 198  
         {
 199  0
             final Header header = headersArray[i];
 200  
             // Cookies are a special case because there may be more than one
 201  
             // cookie.
 202  0
             if (HttpConnector.HTTP_COOKIES_PROPERTY.equals(header.getName())
 203  
                 || HttpConstants.HEADER_COOKIE.equals(header.getName()))
 204  
             {
 205  0
                 putCookieHeaderInMapAsAServer(headersMap, header, uri);
 206  
             }
 207  0
             else if (HttpConstants.HEADER_COOKIE_SET.equals(header.getName()))
 208  
             {
 209  0
                 putCookieHeaderInMapAsAClient(headersMap, header, uri);
 210  
             }
 211  
             else
 212  
             {
 213  0
                 if (headersMap.containsKey(header.getName()))
 214  
                 {
 215  0
                     if (headersMap.get(header.getName()) instanceof String)
 216  
                     {
 217  
                         // concat
 218  0
                         headersMap.put(header.getName(),
 219  
                             headersMap.get(header.getName()) + "," + header.getValue());
 220  
                     }
 221  
                     else
 222  
                     {
 223  
                         // override
 224  0
                         headersMap.put(header.getName(), header.getValue());
 225  
                     }
 226  
                 }
 227  
                 else
 228  
                 {
 229  0
                     headersMap.put(header.getName(), header.getValue());
 230  
                 }
 231  
             }
 232  
         }
 233  0
         return headersMap;
 234  
     }
 235  
 
 236  
     private void putCookieHeaderInMapAsAClient(Map<String, Object> headersMap, final Header header, String uri)
 237  
         throws URISyntaxException
 238  
     {
 239  
         try
 240  
         {
 241  0
             final Cookie[] newCookies = CookieHelper.parseCookiesAsAClient(header.getValue(), cookieSpec,
 242  
                 new URI(uri));
 243  0
             final Object preExistentCookies = headersMap.get(HttpConstants.HEADER_COOKIE_SET);
 244  0
             final Object mergedCookie = CookieHelper.putAndMergeCookie(preExistentCookies, newCookies);
 245  0
             headersMap.put(HttpConstants.HEADER_COOKIE_SET, mergedCookie);
 246  
         }
 247  0
         catch (MalformedCookieException e)
 248  
         {
 249  0
             log.warn("Received an invalid cookie: " + header, e);
 250  0
         }
 251  0
     }
 252  
 
 253  
     private void putCookieHeaderInMapAsAServer(Map<String, Object> headersMap, final Header header, String uri)
 254  
         throws URISyntaxException
 255  
     {
 256  0
         if (enableCookies)
 257  
         {
 258  0
             Cookie[] newCookies = CookieHelper.parseCookiesAsAServer(header.getValue(), new URI(uri));
 259  0
             if (newCookies.length > 0)
 260  
             {
 261  0
                 Object oldCookies = headersMap.get(HttpConnector.HTTP_COOKIES_PROPERTY);
 262  0
                 Object mergedCookies = CookieHelper.putAndMergeCookie(oldCookies, newCookies);
 263  0
                 headersMap.put(HttpConnector.HTTP_COOKIES_PROPERTY, mergedCookies);
 264  
             }
 265  
         }
 266  0
     }
 267  
 
 268  
     private void initEncoding(MuleMessage message, Map<String, Object> headers)
 269  
     {
 270  0
         Object contentType = headers.get(HttpConstants.HEADER_CONTENT_TYPE);
 271  0
         if (contentType != null)
 272  
         {
 273  
             // use HttpClient classes to parse the charset part from the Content-Type
 274  
             // header (e.g. "text/html; charset=UTF-16BE")
 275  0
             Header contentTypeHeader = new Header(HttpConstants.HEADER_CONTENT_TYPE,
 276  
                     contentType.toString());
 277  0
             HeaderElement values[] = contentTypeHeader.getElements();
 278  0
             if (values.length == 1)
 279  
             {
 280  0
                 NameValuePair param = values[0].getParameterByName("charset");
 281  0
                 if (param != null)
 282  
                 {
 283  0
                     message.setEncoding(param.getValue());
 284  
                 }
 285  
             }
 286  
         }
 287  0
     }
 288  
 
 289  
     private void rewriteConnectionAndKeepAliveHeaders(Map<String, Object> headers)
 290  
     {
 291  
         // rewrite Connection and Keep-Alive headers based on HTTP version
 292  
         String headerValue;
 293  0
         if (!isHttp11(headers))
 294  
         {
 295  0
             String connection = (String) headers.get(HttpConstants.HEADER_CONNECTION);
 296  0
             if ((connection != null) && connection.equalsIgnoreCase("close"))
 297  
             {
 298  0
                 headerValue = Boolean.FALSE.toString();
 299  
             }
 300  
             else
 301  
             {
 302  0
                 headerValue = Boolean.TRUE.toString();
 303  
             }
 304  0
         }
 305  
         else
 306  
         {
 307  0
             headerValue = (headers.get(HttpConstants.HEADER_CONNECTION) != null
 308  
                     ? Boolean.TRUE.toString()
 309  
                     : Boolean.FALSE.toString());
 310  
         }
 311  
 
 312  0
         headers.put(HttpConstants.HEADER_CONNECTION, headerValue);
 313  0
         headers.put(HttpConstants.HEADER_KEEP_ALIVE, headerValue);
 314  0
     }
 315  
 
 316  
     private boolean isHttp11(Map<String, Object> headers)
 317  
     {
 318  0
         String httpVersion = (String) headers.get(HttpConnector.HTTP_VERSION_PROPERTY);
 319  0
         return !HttpConstants.HTTP10.equalsIgnoreCase(httpVersion);
 320  
     }
 321  
 
 322  
     protected void addUriParamsAsHeaders(Map headers, String uri)
 323  
     {
 324  0
         int i = uri.indexOf("?");
 325  0
         if (i > -1)
 326  
         {
 327  0
             headers.putAll(PropertiesUtils.getPropertiesFromQueryString(uri.substring(i + 1)));
 328  
         }
 329  0
     }
 330  
 
 331  
     protected void convertMultiPartHeaders(Map<String, Object> headers)
 332  
     {
 333  
         // template method
 334  0
     }
 335  
 
 336  
     public void setEnableCookies(boolean enableCookies)
 337  
     {
 338  0
         this.enableCookies = enableCookies;
 339  0
     }
 340  
 
 341  
     public void setCookieSpec(String cookieSpec)
 342  
     {
 343  0
         this.cookieSpec = cookieSpec;
 344  0
     }
 345  
 
 346  
     public void setExchangePattern(MessageExchangePattern mep)
 347  
     {
 348  0
         exchangePattern = mep;
 349  0
     }
 350  
 }