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
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
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
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
145
146
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 }