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