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   * <ul>
65   *  <li>{@link org.apache.http.params.CoreProtocolPNames#STRICT_TRANSFER_ENCODING}</li>
66   *  <li>{@link org.apache.http.params.CoreConnectionPNames#MAX_HEADER_COUNT}</li>
67   *  <li>{@link org.apache.http.params.CoreConnectionPNames#MAX_LINE_LENGTH}</li>
68   * </ul>
69   *
70   * @since 4.0
71   *
72   * @deprecated (4.3) use {@link DefaultBHttpClientConnection}
73   */
74  @Deprecated
75  public abstract class AbstractHttpClientConnection implements HttpClientConnection {
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<HttpResponse> responseParser = null;
84      private HttpMessageWriter<HttpRequest> requestWriter = 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 AbstractHttpClientConnection() {
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 org.apache.http.entity.ContentLengthStrategy}.
116      *
117      * @return HTTP entity deserializer
118      */
119     protected EntityDeserializer createEntityDeserializer() {
120         return new EntityDeserializer(new LaxContentLengthStrategy());
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 DefaultHttpResponseFactory} to be used
140      * for creating {@link HttpResponse} 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 HttpResponseFactory} interface.
145      *
146      * @return HTTP response factory.
147      */
148     protected HttpResponseFactory createHttpResponseFactory() {
149         return DefaultHttpResponseFactory.INSTANCE;
150     }
151 
152     /**
153      * Creates an instance of {@link HttpMessageParser} to be used for parsing
154      * HTTP responses 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 the
160      * {@link DefaultHttpResponseParser} constructor.
161      *
162      * @param buffer the session input buffer.
163      * @param responseFactory the HTTP response factory.
164      * @param params HTTP parameters.
165      * @return HTTP message parser.
166      */
167     protected HttpMessageParser<HttpResponse> createResponseParser(
168             final SessionInputBuffer buffer,
169             final HttpResponseFactory responseFactory,
170             final HttpParams params) {
171         return new DefaultHttpResponseParser(buffer, null, responseFactory, params);
172     }
173 
174     /**
175      * Creates an instance of {@link HttpMessageWriter} to be used for
176      * writing out HTTP requests 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 implementation
182      * {@link HttpRequestWriter}.
183      *
184      * @param buffer the session output buffer
185      * @param params HTTP parameters
186      * @return HTTP message writer
187      */
188     protected HttpMessageWriter<HttpRequest> createRequestWriter(
189             final SessionOutputBuffer buffer,
190             final HttpParams params) {
191         return new HttpRequestWriter(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 #createHttpResponseFactory()},
210      * {@link #createRequestWriter(SessionOutputBuffer, HttpParams)}
211      * and {@link #createResponseParser(SessionInputBuffer, HttpResponseFactory, HttpParams)}
212      * methods to initialize HTTP request writer and response parser 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.responseParser = createResponseParser(
229                 inbuffer,
230                 createHttpResponseFactory(),
231                 params);
232         this.requestWriter = createRequestWriter(
233                 outbuffer, params);
234         this.metrics = createConnectionMetrics(
235                 inbuffer.getMetrics(),
236                 outbuffer.getMetrics());
237     }
238 
239     public boolean isResponseAvailable(final int timeout) throws IOException {
240         assertOpen();
241         try {
242             return this.inbuffer.isDataAvailable(timeout);
243         } catch (final SocketTimeoutException ex) {
244             return false;
245         }
246     }
247 
248     public void sendRequestHeader(final HttpRequest request)
249             throws HttpException, IOException {
250         Args.notNull(request, "HTTP request");
251         assertOpen();
252         this.requestWriter.write(request);
253         this.metrics.incrementRequestCount();
254     }
255 
256     public void sendRequestEntity(final HttpEntityEnclosingRequest request)
257             throws HttpException, IOException {
258         Args.notNull(request, "HTTP request");
259         assertOpen();
260         if (request.getEntity() == null) {
261             return;
262         }
263         this.entityserializer.serialize(
264                 this.outbuffer,
265                 request,
266                 request.getEntity());
267     }
268 
269     protected void doFlush() throws IOException {
270         this.outbuffer.flush();
271     }
272 
273     public void flush() throws IOException {
274         assertOpen();
275         doFlush();
276     }
277 
278     public HttpResponse receiveResponseHeader()
279             throws HttpException, IOException {
280         assertOpen();
281         final HttpResponse response = this.responseParser.parse();
282         if (response.getStatusLine().getStatusCode() >= HttpStatus.SC_OK) {
283             this.metrics.incrementResponseCount();
284         }
285         return response;
286     }
287 
288     public void receiveResponseEntity(final HttpResponse response)
289             throws HttpException, IOException {
290         Args.notNull(response, "HTTP response");
291         assertOpen();
292         final HttpEntity entity = this.entitydeserializer.deserialize(this.inbuffer, response);
293         response.setEntity(entity);
294     }
295 
296     protected boolean isEof() {
297         return this.eofSensor != null && this.eofSensor.isEof();
298     }
299 
300     public boolean isStale() {
301         if (!isOpen()) {
302             return true;
303         }
304         if (isEof()) {
305             return true;
306         }
307         try {
308             this.inbuffer.isDataAvailable(1);
309             return isEof();
310         } catch (final SocketTimeoutException ex) {
311             return false;
312         } catch (final IOException ex) {
313             return true;
314         }
315     }
316 
317     public HttpConnectionMetrics getMetrics() {
318         return this.metrics;
319     }
320 
321 }