1 /*
2 * ====================================================================
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 * ====================================================================
20 *
21 * This software consists of voluntary contributions made by many
22 * individuals on behalf of the Apache Software Foundation. For more
23 * information on the Apache Software Foundation, please see
24 * <http://www.apache.org/>.
25 *
26 */
27
28 package org.apache.http.impl;
29
30 import java.io.IOException;
31
32 import org.apache.http.HttpConnectionMetrics;
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.HttpServerConnection;
40 import org.apache.http.annotation.NotThreadSafe;
41 import org.apache.http.entity.ContentLengthStrategy;
42 import org.apache.http.impl.entity.DisallowIdentityContentLengthStrategy;
43 import org.apache.http.impl.entity.EntityDeserializer;
44 import org.apache.http.impl.entity.EntitySerializer;
45 import org.apache.http.impl.entity.LaxContentLengthStrategy;
46 import org.apache.http.impl.entity.StrictContentLengthStrategy;
47 import org.apache.http.impl.io.DefaultHttpRequestParser;
48 import org.apache.http.impl.io.HttpResponseWriter;
49 import org.apache.http.io.EofSensor;
50 import org.apache.http.io.HttpMessageParser;
51 import org.apache.http.io.HttpMessageWriter;
52 import org.apache.http.io.HttpTransportMetrics;
53 import org.apache.http.io.SessionInputBuffer;
54 import org.apache.http.io.SessionOutputBuffer;
55 import org.apache.http.message.LineFormatter;
56 import org.apache.http.message.LineParser;
57 import org.apache.http.params.HttpParams;
58 import org.apache.http.util.Args;
59
60 /**
61 * Abstract server-side HTTP connection capable of transmitting and receiving
62 * data using arbitrary {@link SessionInputBuffer} and
63 * {@link SessionOutputBuffer} implementations.
64 * <p>
65 * The following parameters can be used to customize the behavior of this
66 * class:
67 * <ul>
68 * <li>{@link org.apache.http.params.CoreProtocolPNames#STRICT_TRANSFER_ENCODING}</li>
69 * <li>{@link org.apache.http.params.CoreConnectionPNames#MAX_HEADER_COUNT}</li>
70 * <li>{@link org.apache.http.params.CoreConnectionPNames#MAX_LINE_LENGTH}</li>
71 * </ul>
72 *
73 * @since 4.0
74 *
75 * @deprecated (4.3) use {@link DefaultBHttpServerConnection}
76 */
77 @NotThreadSafe
78 @Deprecated
79 public abstract class AbstractHttpServerConnection implements HttpServerConnection {
80
81 private final EntitySerializer entityserializer;
82 private final EntityDeserializer entitydeserializer;
83
84 private SessionInputBuffer inbuffer = null;
85 private SessionOutputBuffer outbuffer = null;
86 private EofSensor eofSensor = null;
87 private HttpMessageParser<HttpRequest> requestParser = null;
88 private HttpMessageWriter<HttpResponse> responseWriter = null;
89 private HttpConnectionMetricsImpl metrics = null;
90
91 /**
92 * Creates an instance of this class.
93 * <p>
94 * This constructor will invoke {@link #createEntityDeserializer()}
95 * and {@link #createEntitySerializer()} methods in order to initialize
96 * HTTP entity serializer and deserializer implementations for this
97 * connection.
98 */
99 public AbstractHttpServerConnection() {
100 super();
101 this.entityserializer = createEntitySerializer();
102 this.entitydeserializer = createEntityDeserializer();
103 }
104
105 /**
106 * Asserts if the connection is open.
107 *
108 * @throws IllegalStateException if the connection is not open.
109 */
110 protected abstract void assertOpen() throws IllegalStateException;
111
112 /**
113 * Creates an instance of {@link EntityDeserializer} with the
114 * {@link LaxContentLengthStrategy} implementation to be used for
115 * de-serializing entities received over this connection.
116 * <p>
117 * This method can be overridden in a super class in order to create
118 * instances of {@link EntityDeserializer} using a custom
119 * {@link ContentLengthStrategy}.
120 *
121 * @return HTTP entity deserializer
122 */
123 protected EntityDeserializer createEntityDeserializer() {
124 return new EntityDeserializer(new DisallowIdentityContentLengthStrategy(
125 new LaxContentLengthStrategy(0)));
126 }
127
128 /**
129 * Creates an instance of {@link EntitySerializer} with the
130 * {@link StrictContentLengthStrategy} implementation to be used for
131 * serializing HTTP entities sent over this connection.
132 * <p>
133 * This method can be overridden in a super class in order to create
134 * instances of {@link EntitySerializer} using a custom
135 * {@link ContentLengthStrategy}.
136 *
137 * @return HTTP entity serialzier.
138 */
139 protected EntitySerializer createEntitySerializer() {
140 return new EntitySerializer(new StrictContentLengthStrategy());
141 }
142
143 /**
144 * Creates an instance of {@link DefaultHttpRequestFactory} to be used
145 * for creating {@link HttpRequest} objects received by over this
146 * connection.
147 * <p>
148 * This method can be overridden in a super class in order to provide
149 * a different implementation of the {@link HttpRequestFactory} interface.
150 *
151 * @return HTTP request factory.
152 */
153 protected HttpRequestFactory createHttpRequestFactory() {
154 return DefaultHttpRequestFactory.INSTANCE;
155 }
156
157 /**
158 * Creates an instance of {@link HttpMessageParser} to be used for parsing
159 * HTTP requests received over this connection.
160 * <p>
161 * This method can be overridden in a super class in order to provide
162 * a different implementation of the {@link HttpMessageParser} interface or
163 * to pass a different implementation of the {@link LineParser} to the
164 * the {@link DefaultHttpRequestParser} constructor.
165 *
166 * @param buffer the session input buffer.
167 * @param requestFactory the HTTP request factory.
168 * @param params HTTP parameters.
169 * @return HTTP message parser.
170 */
171 protected HttpMessageParser<HttpRequest> createRequestParser(
172 final SessionInputBuffer buffer,
173 final HttpRequestFactory requestFactory,
174 final HttpParams params) {
175 return new DefaultHttpRequestParser(buffer, null, requestFactory, params);
176 }
177
178 /**
179 * Creates an instance of {@link HttpMessageWriter} to be used for
180 * writing out HTTP responses sent over this connection.
181 * <p>
182 * This method can be overridden in a super class in order to provide
183 * a different implementation of the {@link HttpMessageWriter} interface or
184 * to pass a different implementation of {@link LineFormatter} to the
185 * the default implementation {@link HttpResponseWriter}.
186 *
187 * @param buffer the session output buffer
188 * @param params HTTP parameters
189 * @return HTTP message writer
190 */
191 protected HttpMessageWriter<HttpResponse> createResponseWriter(
192 final SessionOutputBuffer buffer,
193 final HttpParams params) {
194 return new HttpResponseWriter(buffer, null, params);
195 }
196
197 /**
198 * @since 4.1
199 */
200 protected HttpConnectionMetricsImpl createConnectionMetrics(
201 final HttpTransportMetrics inTransportMetric,
202 final HttpTransportMetrics outTransportMetric) {
203 return new HttpConnectionMetricsImpl(inTransportMetric, outTransportMetric);
204 }
205
206 /**
207 * Initializes this connection object with {@link SessionInputBuffer} and
208 * {@link SessionOutputBuffer} instances to be used for sending and
209 * receiving data. These session buffers can be bound to any arbitrary
210 * physical output medium.
211 * <p>
212 * This method will invoke {@link #createHttpRequestFactory},
213 * {@link #createRequestParser(SessionInputBuffer, HttpRequestFactory, HttpParams)}
214 * and {@link #createResponseWriter(SessionOutputBuffer, HttpParams)}
215 * methods to initialize HTTP request parser and response writer for this
216 * connection.
217 *
218 * @param inbuffer the session input buffer.
219 * @param outbuffer the session output buffer.
220 * @param params HTTP parameters.
221 */
222 protected void init(
223 final SessionInputBuffer inbuffer,
224 final SessionOutputBuffer outbuffer,
225 final HttpParams params) {
226 this.inbuffer = Args.notNull(inbuffer, "Input session buffer");
227 this.outbuffer = Args.notNull(outbuffer, "Output session buffer");
228 if (inbuffer instanceof EofSensor) {
229 this.eofSensor = (EofSensor) inbuffer;
230 }
231 this.requestParser = createRequestParser(
232 inbuffer,
233 createHttpRequestFactory(),
234 params);
235 this.responseWriter = createResponseWriter(
236 outbuffer, params);
237 this.metrics = createConnectionMetrics(
238 inbuffer.getMetrics(),
239 outbuffer.getMetrics());
240 }
241
242 public HttpRequest receiveRequestHeader()
243 throws HttpException, IOException {
244 assertOpen();
245 final HttpRequest request = this.requestParser.parse();
246 this.metrics.incrementRequestCount();
247 return request;
248 }
249
250 public void receiveRequestEntity(final HttpEntityEnclosingRequest request)
251 throws HttpException, IOException {
252 Args.notNull(request, "HTTP request");
253 assertOpen();
254 final HttpEntity entity = this.entitydeserializer.deserialize(this.inbuffer, request);
255 request.setEntity(entity);
256 }
257
258 protected void doFlush() throws IOException {
259 this.outbuffer.flush();
260 }
261
262 public void flush() throws IOException {
263 assertOpen();
264 doFlush();
265 }
266
267 public void sendResponseHeader(final HttpResponse response)
268 throws HttpException, IOException {
269 Args.notNull(response, "HTTP response");
270 assertOpen();
271 this.responseWriter.write(response);
272 if (response.getStatusLine().getStatusCode() >= 200) {
273 this.metrics.incrementResponseCount();
274 }
275 }
276
277 public void sendResponseEntity(final HttpResponse response)
278 throws HttpException, IOException {
279 if (response.getEntity() == null) {
280 return;
281 }
282 this.entityserializer.serialize(
283 this.outbuffer,
284 response,
285 response.getEntity());
286 }
287
288 protected boolean isEof() {
289 return this.eofSensor != null && this.eofSensor.isEof();
290 }
291
292 public boolean isStale() {
293 if (!isOpen()) {
294 return true;
295 }
296 if (isEof()) {
297 return true;
298 }
299 try {
300 this.inbuffer.isDataAvailable(1);
301 return isEof();
302 } catch (final IOException ex) {
303 return true;
304 }
305 }
306
307 public HttpConnectionMetrics getMetrics() {
308 return this.metrics;
309 }
310
311 }