View Javadoc

1   /*
2    * $Id: HttpServerConnection.java 12117 2008-06-20 09:40:51Z dirk.olmes $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.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.transformer.TransformerException;
15  import org.mule.api.transport.Connector;
16  import org.mule.api.transport.OutputHandler;
17  
18  import java.io.DataOutputStream;
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.OutputStream;
22  import java.io.UnsupportedEncodingException;
23  import java.net.Socket;
24  import java.net.SocketException;
25  import java.util.Iterator;
26  
27  import org.apache.commons.httpclient.ChunkedOutputStream;
28  import org.apache.commons.httpclient.Header;
29  import org.apache.commons.httpclient.HttpParser;
30  import org.apache.commons.httpclient.StatusLine;
31  import org.apache.commons.io.IOUtils;
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  
35  /** A connection to the SimpleHttpServer. */
36  public class HttpServerConnection
37  {
38      private static final Log logger = LogFactory.getLog(HttpServerConnection.class);
39  
40      private Socket socket;
41      private final InputStream in;
42      private final OutputStream out;
43      private boolean keepAlive = false;
44      private final String encoding;
45  
46      public HttpServerConnection(final Socket socket, String encoding, HttpConnector connector) throws IOException
47      {
48          super();
49  
50          if (socket == null)
51          {
52              throw new IllegalArgumentException("Socket may not be null");
53          }
54  
55          this.socket = socket;
56          this.socket.setTcpNoDelay(true);
57          
58          if (connector.getReceiveBufferSize() != Connector.INT_VALUE_NOT_SET
59              && socket.getReceiveBufferSize() != connector.getReceiveBufferSize())
60          {
61              socket.setReceiveBufferSize(connector.getReceiveBufferSize());            
62          }
63          if (connector.getServerSoTimeout() != Connector.INT_VALUE_NOT_SET
64              && socket.getSoTimeout() != connector.getServerSoTimeout())
65          {
66              socket.setSoTimeout(connector.getServerSoTimeout());
67          }
68          
69          this.in = socket.getInputStream();
70          this.out = new DataOutputStream(socket.getOutputStream());
71          this.encoding = encoding;
72      }
73  
74      public synchronized void close()
75      {
76          try
77          {
78              if (socket != null)
79              {
80                  if (logger.isDebugEnabled())
81                  {
82                      logger.debug("Closing: " + socket);
83                  }
84  
85                  try
86                  {
87                      socket.shutdownOutput();
88                  }
89                  catch (UnsupportedOperationException e)
90                  {
91                      //Can't shutdown in/output on SSL sockets
92                  }
93                  
94                  if (in != null)
95                  {
96                      in.close();
97                  }
98                  if (out != null)
99                  {
100                     out.close();
101                 }
102                 socket.close();
103             }
104         }
105         catch (IOException e)
106         {
107             if (logger.isDebugEnabled())
108             {
109                 logger.debug("(Ignored) Error closing the socket: " + e.getMessage());
110             }
111         }
112         finally
113         {
114             socket = null;
115         }
116     }
117 
118     public synchronized boolean isOpen()
119     {
120         return this.socket != null;
121     }
122 
123     public void setKeepAlive(boolean b)
124     {
125         this.keepAlive = b;
126     }
127 
128     public boolean isKeepAlive()
129     {
130         return this.keepAlive;
131     }
132 
133     public InputStream getInputStream()
134     {
135         return this.in;
136     }
137 
138     public OutputStream getOutputStream()
139     {
140         return this.out;
141     }
142 
143     /**
144      * Returns the ResponseWriter used to write the output to the socket.
145      *
146      * @return This connection's ResponseWriter
147      */
148     public ResponseWriter getWriter() throws UnsupportedEncodingException
149     {
150         return new ResponseWriter(out);
151     }
152 
153     public HttpRequest readRequest() throws IOException
154     {
155         try
156         {
157             String line = readLine();
158             if (line == null)
159             {
160                 return null;
161             }
162             return new HttpRequest(RequestLine.parseLine(line), HttpParser.parseHeaders(this.in, encoding), this.in);
163         }
164         catch (IOException e)
165         {
166             close();
167             throw e;
168         }
169     }
170 
171     public HttpResponse readResponse() throws IOException
172     {
173         try
174         {
175             String line = readLine();
176             return new HttpResponse(new StatusLine(line), HttpParser.parseHeaders(this.in, encoding), this.in);
177         }
178         catch (IOException e)
179         {
180             close();
181             throw e;
182         }
183     }
184 
185     private String readLine() throws IOException
186     {
187         String line;
188 
189         do
190         {
191             line = HttpParser.readLine(in, encoding);
192         }
193         while (line != null && line.length() == 0);
194 
195         if (line == null)
196         {
197             setKeepAlive(false);
198             return null;
199         }
200 
201         return line;
202     }
203 
204     public void writeRequest(final HttpRequest request) throws IOException
205     {
206         if (request == null)
207         {
208             return;
209         }
210         ResponseWriter writer = new ResponseWriter(this.out, encoding);
211         writer.println(request.getRequestLine().toString());
212         Iterator item = request.getHeaderIterator();
213         while (item.hasNext())
214         {
215             Header header = (Header) item.next();
216             writer.print(header.toExternalForm());
217         }
218         writer.println();
219         writer.flush();
220 
221         OutputStream outstream = this.out;
222         InputStream content = request.getBody();
223         if (content != null)
224         {
225             Header transferenc = request.getFirstHeader(HttpConstants.HEADER_TRANSFER_ENCODING);
226             if (transferenc != null)
227             {
228                 request.removeHeaders(HttpConstants.HEADER_CONTENT_LENGTH);
229                 if (transferenc.getValue().indexOf(HttpConstants.TRANSFER_ENCODING_CHUNKED) != -1)
230                 {
231                     outstream = new ChunkedOutputStream(outstream);
232                 }
233             }
234 
235             IOUtils.copy(content, outstream);
236 
237             if (outstream instanceof ChunkedOutputStream)
238             {
239                 ((ChunkedOutputStream) outstream).finish();
240             }
241         }
242 
243         outstream.flush();
244     }
245 
246     public void writeResponse(final HttpResponse response) throws IOException, TransformerException
247     {
248         if (response == null)
249         {
250             return;
251         }
252 
253         setKeepAlive(response.isKeepAlive());
254         ResponseWriter writer = new ResponseWriter(this.out, encoding);
255         OutputStream outstream = this.out;
256 
257         writer.println(response.getStatusLine());
258         Iterator item = response.getHeaderIterator();
259         while (item.hasNext())
260         {
261             Header header = (Header) item.next();
262             writer.print(header.toExternalForm());
263         }
264 
265         writer.println();
266         writer.flush();
267 
268         OutputHandler content = response.getBody();
269         if (content != null)
270         {
271             Header transferenc = response.getFirstHeader(HttpConstants.HEADER_TRANSFER_ENCODING);
272             if (transferenc != null)
273             {
274                 response.removeHeaders(HttpConstants.HEADER_CONTENT_LENGTH);
275                 if (transferenc.getValue().indexOf(HttpConstants.TRANSFER_ENCODING_CHUNKED) != -1)
276                 {
277                     outstream = new ChunkedOutputStream(outstream);
278                 }
279             }
280 
281             content.write(RequestContext.getEvent(), outstream);
282 
283             if (outstream instanceof ChunkedOutputStream)
284             {
285                 ((ChunkedOutputStream) outstream).finish();
286             }
287         }
288 
289         outstream.flush();
290     }
291 
292     public int getSocketTimeout() throws SocketException
293     {
294         return this.socket.getSoTimeout();
295     }
296 
297     public void setSocketTimeout(int timeout) throws SocketException
298     {
299         this.socket.setSoTimeout(timeout);
300     }
301 }