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