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.entity.ContentLengthStrategy;
44 import org.apache.http.impl.entity.EntityDeserializer;
45 import org.apache.http.impl.entity.EntitySerializer;
46 import org.apache.http.impl.entity.LaxContentLengthStrategy;
47 import org.apache.http.impl.entity.StrictContentLengthStrategy;
48 import org.apache.http.impl.io.DefaultHttpResponseParser;
49 import org.apache.http.impl.io.HttpRequestWriter;
50 import org.apache.http.io.EofSensor;
51 import org.apache.http.io.HttpMessageParser;
52 import org.apache.http.io.HttpMessageWriter;
53 import org.apache.http.io.HttpTransportMetrics;
54 import org.apache.http.io.SessionInputBuffer;
55 import org.apache.http.io.SessionOutputBuffer;
56 import org.apache.http.message.LineFormatter;
57 import org.apache.http.message.LineParser;
58 import org.apache.http.params.HttpParams;
59 import org.apache.http.util.Args;
60
61 /**
62 * Abstract client-side HTTP connection capable of transmitting and receiving
63 * data using arbitrary {@link SessionInputBuffer} and
64 * {@link SessionOutputBuffer} implementations.
65 * <p>
66 * The following parameters can be used to customize the behavior of this
67 * class:
68 * <ul>
69 * <li>{@link org.apache.http.params.CoreProtocolPNames#STRICT_TRANSFER_ENCODING}</li>
70 * <li>{@link org.apache.http.params.CoreConnectionPNames#MAX_HEADER_COUNT}</li>
71 * <li>{@link org.apache.http.params.CoreConnectionPNames#MAX_LINE_LENGTH}</li>
72 * </ul>
73 *
74 * @since 4.0
75 *
76 * @deprecated (4.3) use {@link DefaultBHttpClientConnection}
77 */
78 @NotThreadSafe
79 @Deprecated
80 public abstract class AbstractHttpClientConnection implements HttpClientConnection {
81
82 private final EntitySerializer entityserializer;
83 private final EntityDeserializer entitydeserializer;
84
85 private SessionInputBuffer inbuffer = null;
86 private SessionOutputBuffer outbuffer = null;
87 private EofSensor eofSensor = null;
88 private HttpMessageParser<HttpResponse> responseParser = null;
89 private HttpMessageWriter<HttpRequest> requestWriter = null;
90 private HttpConnectionMetricsImpl metrics = null;
91
92 /**
93 * Creates an instance of this class.
94 * <p>
95 * This constructor will invoke {@link #createEntityDeserializer()}
96 * and {@link #createEntitySerializer()} methods in order to initialize
97 * HTTP entity serializer and deserializer implementations for this
98 * connection.
99 */
100 public AbstractHttpClientConnection() {
101 super();
102 this.entityserializer = createEntitySerializer();
103 this.entitydeserializer = createEntityDeserializer();
104 }
105
106 /**
107 * Asserts if the connection is open.
108 *
109 * @throws IllegalStateException if the connection is not open.
110 */
111 protected abstract void assertOpen() throws IllegalStateException;
112
113 /**
114 * Creates an instance of {@link EntityDeserializer} with the
115 * {@link LaxContentLengthStrategy} implementation to be used for
116 * de-serializing entities received over this connection.
117 * <p>
118 * This method can be overridden in a super class in order to create
119 * instances of {@link EntityDeserializer} using a custom
120 * {@link ContentLengthStrategy}.
121 *
122 * @return HTTP entity deserializer
123 */
124 protected EntityDeserializer createEntityDeserializer() {
125 return new EntityDeserializer(new LaxContentLengthStrategy());
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 DefaultHttpResponseFactory} to be used
145 * for creating {@link HttpResponse} 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 HttpResponseFactory} interface.
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 {@link LineParser} to the
164 * the {@link DefaultHttpResponseParser} constructor.
165 *
166 * @param buffer the session input buffer.
167 * @param responseFactory the HTTP response factory.
168 * @param params HTTP parameters.
169 * @return HTTP message parser.
170 */
171 protected HttpMessageParser<HttpResponse> createResponseParser(
172 final SessionInputBuffer buffer,
173 final HttpResponseFactory responseFactory,
174 final HttpParams params) {
175 return new DefaultHttpResponseParser(buffer, null, responseFactory, params);
176 }
177
178 /**
179 * Creates an instance of {@link HttpMessageWriter} to be used for
180 * writing out HTTP requests 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 HttpRequestWriter}.
186 *
187 * @param buffer the session output buffer
188 * @param params HTTP parameters
189 * @return HTTP message writer
190 */
191 protected HttpMessageWriter<HttpRequest> createRequestWriter(
192 final SessionOutputBuffer buffer,
193 final HttpParams params) {
194 return new HttpRequestWriter(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 #createHttpResponseFactory()},
213 * {@link #createRequestWriter(SessionOutputBuffer, HttpParams)}
214 * and {@link #createResponseParser(SessionInputBuffer, HttpResponseFactory, HttpParams)}
215 * methods to initialize HTTP request writer and response parser 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.responseParser = createResponseParser(
232 inbuffer,
233 createHttpResponseFactory(),
234 params);
235 this.requestWriter = createRequestWriter(
236 outbuffer, params);
237 this.metrics = createConnectionMetrics(
238 inbuffer.getMetrics(),
239 outbuffer.getMetrics());
240 }
241
242 public boolean isResponseAvailable(final int timeout) throws IOException {
243 assertOpen();
244 try {
245 return this.inbuffer.isDataAvailable(timeout);
246 } catch (final SocketTimeoutException ex) {
247 return false;
248 }
249 }
250
251 public void sendRequestHeader(final HttpRequest request)
252 throws HttpException, IOException {
253 Args.notNull(request, "HTTP request");
254 assertOpen();
255 this.requestWriter.write(request);
256 this.metrics.incrementRequestCount();
257 }
258
259 public void sendRequestEntity(final HttpEntityEnclosingRequest request)
260 throws HttpException, IOException {
261 Args.notNull(request, "HTTP request");
262 assertOpen();
263 if (request.getEntity() == null) {
264 return;
265 }
266 this.entityserializer.serialize(
267 this.outbuffer,
268 request,
269 request.getEntity());
270 }
271
272 protected void doFlush() throws IOException {
273 this.outbuffer.flush();
274 }
275
276 public void flush() throws IOException {
277 assertOpen();
278 doFlush();
279 }
280
281 public HttpResponse receiveResponseHeader()
282 throws HttpException, IOException {
283 assertOpen();
284 final HttpResponse response = this.responseParser.parse();
285 if (response.getStatusLine().getStatusCode() >= HttpStatus.SC_OK) {
286 this.metrics.incrementResponseCount();
287 }
288 return response;
289 }
290
291 public void receiveResponseEntity(final HttpResponse response)
292 throws HttpException, IOException {
293 Args.notNull(response, "HTTP response");
294 assertOpen();
295 final HttpEntity entity = this.entitydeserializer.deserialize(this.inbuffer, response);
296 response.setEntity(entity);
297 }
298
299 protected boolean isEof() {
300 return this.eofSensor != null && this.eofSensor.isEof();
301 }
302
303 public boolean isStale() {
304 if (!isOpen()) {
305 return true;
306 }
307 if (isEof()) {
308 return true;
309 }
310 try {
311 this.inbuffer.isDataAvailable(1);
312 return isEof();
313 } catch (final SocketTimeoutException ex) {
314 return false;
315 } catch (final IOException ex) {
316 return true;
317 }
318 }
319
320 public HttpConnectionMetrics getMetrics() {
321 return this.metrics;
322 }
323
324 }