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