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