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