1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.impl.nio;
29
30 import java.io.IOException;
31 import java.nio.channels.SelectionKey;
32
33 import org.apache.http.HttpEntity;
34 import org.apache.http.HttpEntityEnclosingRequest;
35 import org.apache.http.HttpException;
36 import org.apache.http.HttpRequest;
37 import org.apache.http.HttpRequestFactory;
38 import org.apache.http.HttpResponse;
39 import org.apache.http.annotation.NotThreadSafe;
40 import org.apache.http.entity.ContentLengthStrategy;
41 import org.apache.http.impl.entity.DisallowIdentityContentLengthStrategy;
42 import org.apache.http.impl.entity.LaxContentLengthStrategy;
43 import org.apache.http.impl.nio.codecs.DefaultHttpRequestParser;
44 import org.apache.http.impl.nio.codecs.DefaultHttpResponseWriter;
45 import org.apache.http.nio.NHttpMessageParser;
46 import org.apache.http.nio.NHttpMessageWriter;
47 import org.apache.http.nio.NHttpServerConnection;
48 import org.apache.http.nio.NHttpServerIOTarget;
49 import org.apache.http.nio.NHttpServerEventHandler;
50 import org.apache.http.nio.NHttpServiceHandler;
51 import org.apache.http.nio.reactor.EventMask;
52 import org.apache.http.nio.reactor.IOSession;
53 import org.apache.http.nio.reactor.SessionInputBuffer;
54 import org.apache.http.nio.reactor.SessionOutputBuffer;
55 import org.apache.http.nio.util.ByteBufferAllocator;
56 import org.apache.http.params.HttpParams;
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 @SuppressWarnings("deprecation")
73 @NotThreadSafe
74 public class DefaultNHttpServerConnection
75 extends NHttpConnectionBase implements NHttpServerIOTarget {
76
77 protected final NHttpMessageParser<HttpRequest> requestParser;
78 protected final NHttpMessageWriter<HttpResponse> responseWriter;
79
80
81
82
83
84
85
86
87
88 public DefaultNHttpServerConnection(
89 final IOSession session,
90 final HttpRequestFactory requestFactory,
91 final ByteBufferAllocator allocator,
92 final HttpParams params) {
93 super(session, allocator, params);
94 if (requestFactory == null) {
95 throw new IllegalArgumentException("Request factory may not be null");
96 }
97 this.requestParser = createRequestParser(this.inbuf, requestFactory, params);
98 this.responseWriter = createResponseWriter(this.outbuf, params);
99 }
100
101 @Override
102 protected ContentLengthStrategy createIncomingContentStrategy() {
103 return new DisallowIdentityContentLengthStrategy(new LaxContentLengthStrategy(0));
104 }
105
106
107
108
109
110
111
112
113
114
115 protected NHttpMessageParser<HttpRequest> createRequestParser(
116 final SessionInputBuffer buffer,
117 final HttpRequestFactory requestFactory,
118 final HttpParams params) {
119
120 return new DefaultHttpRequestParser(buffer, null, requestFactory, params);
121 }
122
123
124
125
126
127
128
129
130
131
132
133 protected NHttpMessageWriter<HttpResponse> createResponseWriter(
134 final SessionOutputBuffer buffer,
135 final HttpParams params) {
136
137 return new DefaultHttpResponseWriter(buffer, null, params);
138 }
139
140
141
142
143 protected void onRequestReceived(final HttpRequest request) {
144 }
145
146
147
148
149 protected void onResponseSubmitted(final HttpResponse response) {
150 }
151
152 public void resetInput() {
153 this.request = null;
154 this.contentDecoder = null;
155 this.requestParser.reset();
156 }
157
158 public void resetOutput() {
159 this.response = null;
160 this.contentEncoder = null;
161 this.responseWriter.reset();
162 }
163
164 public void consumeInput(final NHttpServerEventHandler handler) {
165 if (this.status != ACTIVE) {
166 this.session.clearEvent(EventMask.READ);
167 return;
168 }
169 try {
170 if (this.request == null) {
171 int bytesRead;
172 do {
173 bytesRead = this.requestParser.fillBuffer(this.session.channel());
174 if (bytesRead > 0) {
175 this.inTransportMetrics.incrementBytesTransferred(bytesRead);
176 }
177 this.request = this.requestParser.parse();
178 } while (bytesRead > 0 && this.request == null);
179 if (this.request != null) {
180 if (this.request instanceof HttpEntityEnclosingRequest) {
181
182 HttpEntity entity = prepareDecoder(this.request);
183 ((HttpEntityEnclosingRequest)this.request).setEntity(entity);
184 }
185 this.connMetrics.incrementRequestCount();
186 onRequestReceived(this.request);
187 handler.requestReceived(this);
188 if (this.contentDecoder == null) {
189
190
191 resetInput();
192 }
193 }
194 if (bytesRead == -1) {
195 handler.endOfInput(this);
196 }
197 }
198 if (this.contentDecoder != null && (this.session.getEventMask() & SelectionKey.OP_READ) > 0) {
199 handler.inputReady(this, this.contentDecoder);
200 if (this.contentDecoder.isCompleted()) {
201
202
203 resetInput();
204 }
205 }
206 } catch (HttpException ex) {
207 resetInput();
208 handler.exception(this, ex);
209 } catch (Exception ex) {
210 handler.exception(this, ex);
211 } finally {
212
213 this.hasBufferedInput = this.inbuf.hasData();
214 }
215 }
216
217 public void produceOutput(final NHttpServerEventHandler handler) {
218 try {
219 if (this.outbuf.hasData()) {
220 int bytesWritten = this.outbuf.flush(this.session.channel());
221 if (bytesWritten > 0) {
222 this.outTransportMetrics.incrementBytesTransferred(bytesWritten);
223 }
224 }
225 if (!this.outbuf.hasData()) {
226 if (this.status == CLOSING) {
227 this.session.close();
228 this.status = CLOSED;
229 resetOutput();
230 return;
231 } else {
232 if (this.contentEncoder != null) {
233 handler.outputReady(this, this.contentEncoder);
234 if (this.contentEncoder.isCompleted()) {
235 resetOutput();
236 }
237 }
238 }
239
240 if (this.contentEncoder == null && !this.outbuf.hasData()) {
241 if (this.status == CLOSING) {
242 this.session.close();
243 this.status = CLOSED;
244 }
245 if (this.status != CLOSED) {
246 this.session.clearEvent(EventMask.WRITE);
247 handler.responseReady(this);
248 }
249 }
250 }
251 } catch (Exception ex) {
252 handler.exception(this, ex);
253 } finally {
254
255 this.hasBufferedOutput = this.outbuf.hasData();
256 }
257 }
258
259 public void submitResponse(final HttpResponse response) throws IOException, HttpException {
260 if (response == null) {
261 throw new IllegalArgumentException("HTTP response may not be null");
262 }
263 assertNotClosed();
264 if (this.response != null) {
265 throw new HttpException("Response already submitted");
266 }
267 onResponseSubmitted(response);
268 this.responseWriter.write(response);
269 this.hasBufferedOutput = this.outbuf.hasData();
270
271 if (response.getStatusLine().getStatusCode() >= 200) {
272 this.connMetrics.incrementResponseCount();
273 if (response.getEntity() != null) {
274 this.response = response;
275 prepareEncoder(response);
276 }
277 }
278
279 this.session.setEvent(EventMask.WRITE);
280 }
281
282 public boolean isResponseSubmitted() {
283 return this.response != null;
284 }
285
286 public void consumeInput(final NHttpServiceHandler handler) {
287 consumeInput(new NHttpServerEventHandlerAdaptor(handler));
288 }
289
290 public void produceOutput(NHttpServiceHandler handler) {
291 produceOutput(new NHttpServerEventHandlerAdaptor(handler));
292 }
293
294 }