1
2
3
4
5
6
7 package org.mule.transport.http;
8
9 import org.mule.RequestContext;
10 import org.mule.api.transformer.TransformerException;
11 import org.mule.api.transport.Connector;
12 import org.mule.api.transport.OutputHandler;
13 import org.mule.util.SystemUtils;
14
15 import java.io.DataOutputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.OutputStream;
19 import java.io.UnsupportedEncodingException;
20 import java.net.Socket;
21 import java.net.SocketException;
22 import java.util.Iterator;
23
24 import org.apache.commons.httpclient.ChunkedOutputStream;
25 import org.apache.commons.httpclient.Header;
26 import org.apache.commons.httpclient.HttpParser;
27 import org.apache.commons.httpclient.StatusLine;
28 import org.apache.commons.io.IOUtils;
29 import org.apache.commons.logging.Log;
30 import org.apache.commons.logging.LogFactory;
31
32
33 public class HttpServerConnection
34 {
35 private static final Log logger = LogFactory.getLog(HttpServerConnection.class);
36
37 private Socket socket;
38 private final InputStream in;
39 private final OutputStream out;
40
41 private boolean keepAlive = false;
42 private final String encoding;
43
44 public HttpServerConnection(final Socket socket, String encoding, HttpConnector connector) throws IOException
45 {
46 super();
47
48 if (socket == null)
49 {
50 throw new IllegalArgumentException("Socket may not be null");
51 }
52
53 this.socket = socket;
54 setSocketTcpNoDelay(connector.isSendTcpNoDelay());
55 this.socket.setKeepAlive(connector.isKeepAlive());
56
57 if (connector.getReceiveBufferSize() != Connector.INT_VALUE_NOT_SET
58 && socket.getReceiveBufferSize() != connector.getReceiveBufferSize())
59 {
60 socket.setReceiveBufferSize(connector.getReceiveBufferSize());
61 }
62 if (connector.getServerSoTimeout() != Connector.INT_VALUE_NOT_SET
63 && socket.getSoTimeout() != connector.getServerSoTimeout())
64 {
65 socket.setSoTimeout(connector.getServerSoTimeout());
66 }
67
68 this.in = socket.getInputStream();
69 this.out = new DataOutputStream(socket.getOutputStream());
70 this.encoding = encoding;
71 }
72
73 private void setSocketTcpNoDelay(boolean tcpNoDelay) throws IOException
74 {
75 try
76 {
77 socket.setTcpNoDelay(tcpNoDelay);
78 }
79 catch (SocketException se)
80 {
81 if (SystemUtils.IS_OS_SOLARIS || SystemUtils.IS_OS_SUN_OS)
82 {
83
84
85
86 if (logger.isDebugEnabled())
87 {
88 logger.debug("Failed to set tcpNoDelay on socket", se);
89 }
90 }
91 else
92 {
93 throw se;
94 }
95 }
96 }
97
98 public synchronized void close()
99 {
100 try
101 {
102 if (socket != null)
103 {
104 if (logger.isDebugEnabled())
105 {
106 logger.debug("Closing: " + socket);
107 }
108
109 try
110 {
111 socket.shutdownOutput();
112 }
113 catch (UnsupportedOperationException e)
114 {
115
116 }
117
118 if (in != null)
119 {
120 in.close();
121 }
122 if (out != null)
123 {
124 out.close();
125 }
126 socket.close();
127 }
128 }
129 catch (IOException e)
130 {
131 if (logger.isDebugEnabled())
132 {
133 logger.debug("(Ignored) Error closing the socket: " + e.getMessage());
134 }
135 }
136 finally
137 {
138 socket = null;
139 }
140 }
141
142 public synchronized boolean isOpen()
143 {
144 return this.socket != null;
145 }
146
147 public void setKeepAlive(boolean b)
148 {
149 this.keepAlive = b;
150 }
151
152 public boolean isKeepAlive()
153 {
154 return this.keepAlive;
155 }
156
157 public InputStream getInputStream()
158 {
159 return this.in;
160 }
161
162 public OutputStream getOutputStream()
163 {
164 return this.out;
165 }
166
167
168
169
170
171
172 public ResponseWriter getWriter() throws UnsupportedEncodingException
173 {
174 return new ResponseWriter(out);
175 }
176
177 public HttpRequest readRequest() throws IOException
178 {
179 try
180 {
181 String line = readLine();
182 if (line == null)
183 {
184 return null;
185 }
186 return new HttpRequest(RequestLine.parseLine(line), HttpParser.parseHeaders(this.in, encoding), this.in, encoding);
187 }
188 catch (IOException e)
189 {
190 close();
191 throw e;
192 }
193 }
194
195 public HttpResponse readResponse() throws IOException
196 {
197 try
198 {
199 String line = readLine();
200 return new HttpResponse(new StatusLine(line), HttpParser.parseHeaders(this.in, encoding), this.in);
201 }
202 catch (IOException e)
203 {
204 close();
205 throw e;
206 }
207 }
208
209 private String readLine() throws IOException
210 {
211 String line;
212
213 do
214 {
215 line = HttpParser.readLine(in, encoding);
216 }
217 while (line != null && line.length() == 0);
218
219 if (line == null)
220 {
221 setKeepAlive(false);
222 return null;
223 }
224
225 return line;
226 }
227
228 public void writeRequest(final HttpRequest request) throws IOException
229 {
230 if (request == null)
231 {
232 return;
233 }
234 ResponseWriter writer = new ResponseWriter(this.out, encoding);
235 writer.println(request.getRequestLine().toString());
236 Iterator item = request.getHeaderIterator();
237 while (item.hasNext())
238 {
239 Header header = (Header) item.next();
240 writer.print(header.toExternalForm());
241 }
242 writer.println();
243 writer.flush();
244
245 OutputStream outstream = this.out;
246 InputStream content = request.getBody();
247 if (content != null)
248 {
249 Header transferenc = request.getFirstHeader(HttpConstants.HEADER_TRANSFER_ENCODING);
250 if (transferenc != null)
251 {
252 request.removeHeaders(HttpConstants.HEADER_CONTENT_LENGTH);
253 if (transferenc.getValue().indexOf(HttpConstants.TRANSFER_ENCODING_CHUNKED) != -1)
254 {
255 outstream = new ChunkedOutputStream(outstream);
256 }
257 }
258
259 IOUtils.copy(content, outstream);
260
261 if (outstream instanceof ChunkedOutputStream)
262 {
263 ((ChunkedOutputStream) outstream).finish();
264 }
265 }
266
267 outstream.flush();
268 }
269
270 public void writeResponse(final HttpResponse response) throws IOException, TransformerException
271 {
272 if (response == null)
273 {
274 return;
275 }
276
277 if (!response.isKeepAlive())
278 {
279 Header header = new Header(HttpConstants.HEADER_CONNECTION, "close");
280 response.setHeader(header);
281 }
282
283 setKeepAlive(response.isKeepAlive());
284
285 ResponseWriter writer = new ResponseWriter(this.out, encoding);
286 OutputStream outstream = this.out;
287
288 writer.println(response.getStatusLine());
289 Iterator item = response.getHeaderIterator();
290 while (item.hasNext())
291 {
292 Header header = (Header) item.next();
293 writer.print(header.toExternalForm());
294 }
295 writer.println();
296 writer.flush();
297
298 OutputHandler content = response.getBody();
299 if (content != null)
300 {
301 Header transferenc = response.getFirstHeader(HttpConstants.HEADER_TRANSFER_ENCODING);
302 if (transferenc != null)
303 {
304 response.removeHeaders(HttpConstants.HEADER_CONTENT_LENGTH);
305 if (transferenc.getValue().indexOf(HttpConstants.TRANSFER_ENCODING_CHUNKED) != -1)
306 {
307 outstream = new ChunkedOutputStream(outstream);
308 }
309 }
310
311 content.write(RequestContext.getEvent(), outstream);
312
313 if (outstream instanceof ChunkedOutputStream)
314 {
315 ((ChunkedOutputStream) outstream).finish();
316 }
317 }
318
319 outstream.flush();
320 }
321
322
323
324
325
326
327
328 public int getSocketTimeout() throws SocketException
329 {
330 return socket.getSoTimeout();
331 }
332
333 public void setSocketTimeout(int timeout) throws SocketException
334 {
335 socket.setSoTimeout(timeout);
336 }
337
338
339
340
341
342
343
344 public boolean isSocketKeepAlive() throws SocketException
345 {
346 return socket.getKeepAlive();
347 }
348
349
350
351
352
353
354
355 public boolean isSocketTcpNoDelay() throws SocketException
356 {
357 return socket.getTcpNoDelay();
358 }
359
360
361
362
363
364
365
366 public int getSocketReceiveBufferSize() throws SocketException
367 {
368 return socket.getReceiveBufferSize();
369 }
370 }