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