View Javadoc

1   /*
2    * $Id: HttpResponse.java 19191 2010-08-25 21:05:23Z tcarlson $
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.RequestContext;
14  import org.mule.api.MuleEvent;
15  import org.mule.api.MuleMessage;
16  import org.mule.api.transport.OutputHandler;
17  import org.mule.transformer.types.DataTypeFactory;
18  import org.mule.transport.NullPayload;
19  
20  import java.io.ByteArrayOutputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.io.UnsupportedEncodingException;
25  import java.util.Iterator;
26  
27  import org.apache.commons.httpclient.ChunkedInputStream;
28  import org.apache.commons.httpclient.ContentLengthInputStream;
29  import org.apache.commons.httpclient.Header;
30  import org.apache.commons.httpclient.HeaderElement;
31  import org.apache.commons.httpclient.HeaderGroup;
32  import org.apache.commons.httpclient.HttpStatus;
33  import org.apache.commons.httpclient.HttpVersion;
34  import org.apache.commons.httpclient.NameValuePair;
35  import org.apache.commons.httpclient.StatusLine;
36  
37  /**
38   * A generic HTTP response wrapper.
39   */
40  public class HttpResponse
41  {
42  
43      public static final String DEFAULT_CONTENT_CHARSET = "ISO-8859-1";
44  
45      private HttpVersion ver = HttpVersion.HTTP_1_1;
46      private int statusCode = HttpStatus.SC_OK;
47      private String phrase = HttpStatus.getStatusText(HttpStatus.SC_OK);
48      private HeaderGroup headers = new HeaderGroup();
49      private boolean keepAlive = false;
50      private boolean disableKeepAlive = false;
51      private String fallbackCharset = DEFAULT_CONTENT_CHARSET;
52      private OutputHandler outputHandler;
53  
54      public HttpResponse()
55      {
56          super();
57      }
58  
59      public HttpResponse(final StatusLine statusline, final Header[] headers, final InputStream content)
60          throws IOException
61      {
62          super();
63          if (statusline == null)
64          {
65              throw new IllegalArgumentException("Status line may not be null");
66          }
67          setStatusLine(HttpVersion.parse(statusline.getHttpVersion()), statusline.getStatusCode(),
68              statusline.getReasonPhrase());
69          setHeaders(headers);
70          if (content != null)
71          {
72              InputStream in = content;
73              Header contentLength = this.headers.getFirstHeader(HttpConstants.HEADER_CONTENT_LENGTH);
74              Header transferEncoding = this.headers.getFirstHeader(HttpConstants.HEADER_TRANSFER_ENCODING);
75  
76              if (transferEncoding != null)
77              {
78                  if (transferEncoding.getValue().indexOf(HttpConstants.TRANSFER_ENCODING_CHUNKED) != -1)
79                  {
80                      in = new ChunkedInputStream(in);
81                  }
82              }
83              else if (contentLength != null)
84              {
85                  long len = getContentLength();
86                  if (len >= 0)
87                  {
88                      in = new ContentLengthInputStream(in, len);
89                  }
90              }
91          }
92      }
93  
94      public void setStatusLine(final HttpVersion ver, int statuscode, final String phrase)
95      {
96          if (ver == null)
97          {
98              throw new IllegalArgumentException("HTTP version may not be null");
99          }
100         if (statuscode <= 0)
101         {
102             throw new IllegalArgumentException("Status code may not be negative or zero");
103         }
104         this.ver = ver;
105         this.statusCode = statuscode;
106         if (phrase != null)
107         {
108             this.phrase = phrase;
109         }
110         else
111         {
112             this.phrase = HttpStatus.getStatusText(statuscode);
113         }
114     }
115 
116     public void setStatusLine(final HttpVersion ver, int statuscode)
117     {
118         setStatusLine(ver, statuscode, null);
119     }
120 
121     public String getPhrase()
122     {
123         return this.phrase;
124     }
125 
126     /**
127      * @deprecated use {@link #getStatusCode()} instead
128      * @return HTTP status code
129      */
130     public int getStatuscode()
131     {
132         return this.getStatusCode();
133     }
134 
135     public int getStatusCode()
136     {
137         return this.statusCode;
138     }
139 
140     public HttpVersion getHttpVersion()
141     {
142         return this.ver;
143     }
144 
145     public String getStatusLine()
146     {
147         StringBuffer buffer = new StringBuffer(64);
148         buffer.append(this.ver);
149         buffer.append(' ');
150         buffer.append(this.statusCode);
151         if (this.phrase != null)
152         {
153             buffer.append(' ');
154             buffer.append(this.phrase);
155         }
156         return buffer.toString();
157     }
158 
159     public boolean containsHeader(final String name)
160     {
161         return this.headers.containsHeader(name);
162     }
163 
164     public Header[] getHeaders()
165     {
166         return this.headers.getAllHeaders();
167     }
168 
169     public Header getFirstHeader(final String name)
170     {
171         return this.headers.getFirstHeader(name);
172     }
173 
174     public void removeHeaders(final String s)
175     {
176         if (s == null)
177         {
178             return;
179         }
180         Header[] headers = this.headers.getHeaders(s);
181         for (int i = 0; i < headers.length; i++)
182         {
183             this.headers.removeHeader(headers[i]);
184         }
185     }
186 
187     public void addHeader(final Header header)
188     {
189         if (header == null)
190         {
191             return;
192         }
193         this.headers.addHeader(header);
194     }
195 
196     public void setHeader(final Header header)
197     {
198         if (header == null)
199         {
200             return;
201         }
202         removeHeaders(header.getName());
203         addHeader(header);
204     }
205 
206     public void setHeaders(final Header[] headers)
207     {
208         if (headers == null)
209         {
210             return;
211         }
212         this.headers.setHeaders(headers);
213     }
214 
215     public Iterator getHeaderIterator()
216     {
217         return this.headers.getIterator();
218     }
219 
220     public String getCharset()
221     {
222         String charset = getFallbackCharset();
223         Header contenttype = this.headers.getFirstHeader(HttpConstants.HEADER_CONTENT_TYPE);
224         if (contenttype != null)
225         {
226             HeaderElement values[] = contenttype.getElements();
227             if (values.length == 1)
228             {
229                 NameValuePair param = values[0].getParameterByName("charset");
230                 if (param != null)
231                 {
232                     charset = param.getValue();
233                 }
234             }
235         }
236         return charset;
237     }
238 
239     public long getContentLength()
240     {
241         Header contentLength = this.headers.getFirstHeader(HttpConstants.HEADER_CONTENT_LENGTH);
242         if (contentLength != null)
243         {
244             try
245             {
246                 return Long.parseLong(contentLength.getValue());
247             }
248             catch (NumberFormatException e)
249             {
250                 return -1;
251             }
252         }
253         else
254         {
255             return -1;
256         }
257     }
258 
259     public boolean hasBody()
260     {
261         return outputHandler != null;
262     }
263 
264     public OutputHandler getBody() throws IOException
265     {
266         return outputHandler; 
267     }
268     
269     public void setBody(MuleMessage msg) throws Exception
270     {
271         if (msg == null) return;
272 
273         //TODO MULE-5005 response attachments
274 //        if(msg.getOutboundAttachmentNames().size() > 0)
275 //        {
276 //            setBody(createMultipart());
277 //            setHeader(new Header(HttpConstants.HEADER_CONTENT_TYPE, MimeTypes.MULTIPART_MIXED));
278 //            return;
279 //        }
280         
281         Object payload = msg.getPayload();
282         if (payload instanceof String)
283         {
284             setBody(payload.toString());
285         }
286         else if (payload instanceof NullPayload) 
287         {
288             return;
289         }
290         else if (payload instanceof byte[]) 
291         {
292             setBody((byte[]) payload);
293         }
294         else 
295         {
296             setBody(msg.getPayload(DataTypeFactory.create(OutputHandler.class)));
297         }
298     }
299     
300     public void setBody(OutputHandler outputHandler) 
301     {
302         this.outputHandler = outputHandler;
303     }
304     
305     public void setBody(final String string)
306     {
307         byte[] raw;
308         try
309         {
310             raw = string.getBytes(getCharset());
311         }
312         catch (UnsupportedEncodingException e)
313         {
314             raw = string.getBytes();
315         }
316         setBody(raw);
317     }
318 
319     private void setBody(final byte[] raw)
320     {
321         if (!containsHeader(HttpConstants.HEADER_CONTENT_TYPE))
322         {
323             setHeader(new Header(HttpConstants.HEADER_CONTENT_TYPE, HttpConstants.DEFAULT_CONTENT_TYPE));
324         }
325         if (!containsHeader(HttpConstants.HEADER_TRANSFER_ENCODING))
326         {
327             setHeader(new Header(HttpConstants.HEADER_CONTENT_LENGTH, Long.toString(raw.length)));
328         }        
329         
330         this.outputHandler = new OutputHandler() {
331 
332             public void write(MuleEvent event, OutputStream out) throws IOException
333             {
334                 out.write(raw);
335             }
336             
337         };
338     }
339     
340     public String getBodyAsString() throws IOException 
341     {
342         if (!hasBody()) return "";
343         
344         ByteArrayOutputStream out = new ByteArrayOutputStream();
345         
346         outputHandler.write(RequestContext.getEvent(), out);
347         
348         try
349         {
350             return new String(out.toByteArray(), getCharset());
351         }
352         catch (UnsupportedEncodingException e)
353         {
354             return new String(out.toByteArray());
355         }
356     }
357     
358     public boolean isKeepAlive()
359     {
360         return !disableKeepAlive && keepAlive;
361     }
362 
363     public void setKeepAlive(boolean keepAlive)
364     {
365         this.keepAlive = keepAlive;
366     }
367     
368     /**
369      * The HTTTP spec suggests that for HTTP 1.1 persistent connections should be used, 
370      * for HTTP 1.0 the connection should not be kept alive. This method sets up the keepAlive flag
371      * according to the <code>version</code> that was passed in.
372      */
373     protected void setupKeepAliveFromRequestVersion(HttpVersion version)
374     {
375         setKeepAlive(version.equals(HttpVersion.HTTP_1_1));
376     }
377 
378     public void disableKeepAlive(boolean keepalive)
379     {
380         disableKeepAlive = keepalive;
381     }
382 
383     public String getFallbackCharset()
384     {
385         return fallbackCharset;
386     }
387 
388     public void setFallbackCharset(String overrideCharset)
389     {
390         this.fallbackCharset = overrideCharset;
391     }
392 
393       //TODO MULE-5005 response attachments
394 //    protected OutputHandler createMultipart() throws Exception
395 //    {
396 //
397 //        return new OutputHandler() {
398 //            public void write(MuleEvent event, OutputStream out) throws IOException
399 //            {
400 //                MultiPartOutputStream partStream = new MultiPartOutputStream(out, event.getEncoding());
401 //                try
402 //                {
403 //                    MuleMessage msg = event.getMessage();
404 //                    if (!(msg.getPayload() instanceof NullPayload))
405 //                    {
406 //                        String contentType = msg.getOutboundProperty(HttpConstants.HEADER_CONTENT_TYPE, MimeTypes.BINARY);
407 //                        partStream.startPart(contentType);
408 //                        try
409 //                        {
410 //                            partStream.getOut().write(msg.getPayloadAsBytes());
411 //                        }
412 //                        catch (Exception e)
413 //                        {
414 //                            throw new IOException(e);
415 //                        }
416 //                    }
417 //                    //Write attachments
418 //                    for (String name : event.getMessage().getOutboundAttachmentNames())
419 //                    {
420 //                        DataHandler dh = event.getMessage().getOutboundAttachment(name);
421 //                        partStream.startPart(dh.getContentType());
422 //                        partStream.getOut().write(IOUtils.toByteArray(dh.getInputStream()));
423 //                    }
424 //                }
425 //                finally
426 //                {
427 //                    partStream.close();
428 //                }
429 //            }
430 //        };
431 //
432 //    }
433 
434 }