Source code: org/apache/http/impl/DefaultHttpClientConnection.java
1 /*
2 * $HeadURL: https://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha2/src/java/org/apache/http/impl/DefaultHttpClientConnection.java $
3 * $Revision: 411100 $
4 * $Date: 2006-06-02 11:12:04 +0200 (Fri, 02 Jun 2006) $
5 *
6 * ====================================================================
7 *
8 * Copyright 1999-2006 The Apache Software Foundation
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 * ====================================================================
22 *
23 * This software consists of voluntary contributions made by many
24 * individuals on behalf of the Apache Software Foundation. For more
25 * information on the Apache Software Foundation, please see
26 * <http://www.apache.org/>.
27 *
28 */
29
30 package org.apache.http.impl;
31
32 import java.io.IOException;
33 import java.net.InetAddress;
34 import java.net.Socket;
35
36 import org.apache.http.Header;
37 import org.apache.http.HttpClientConnection;
38 import org.apache.http.HttpEntity;
39 import org.apache.http.HttpEntityEnclosingRequest;
40 import org.apache.http.HttpException;
41 import org.apache.http.HttpHost;
42 import org.apache.http.HttpRequest;
43 import org.apache.http.HttpResponse;
44 import org.apache.http.HttpResponseFactory;
45 import org.apache.http.NoHttpResponseException;
46 import org.apache.http.ProtocolException;
47 import org.apache.http.RequestLine;
48 import org.apache.http.StatusLine;
49 import org.apache.http.entity.EntityDeserializer;
50 import org.apache.http.entity.EntitySerializer;
51 import org.apache.http.impl.entity.DefaultEntitySerializer;
52 import org.apache.http.impl.entity.DefaultEntityDeserializer;
53 import org.apache.http.io.CharArrayBuffer;
54 import org.apache.http.io.SocketFactory;
55 import org.apache.http.params.HttpConnectionParams;
56 import org.apache.http.params.HttpParams;
57 import org.apache.http.params.HttpProtocolParams;
58 import org.apache.http.protocol.HTTP;
59 import org.apache.http.util.HeaderUtils;
60
61 /**
62 * Default implementation of a client-side HTTP connection.
63 *
64 * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
65 *
66 * @version $Revision: 411100 $
67 *
68 * @since 4.0
69 */
70 public class DefaultHttpClientConnection
71 extends AbstractHttpConnection implements HttpClientConnection {
72
73 private HttpHost targethost = null;
74 private InetAddress localAddress = null;
75 private int maxHeaderCount = -1;
76
77 private final CharArrayBuffer buffer;
78
79 /*
80 * Dependent interfaces
81 */
82 private HttpResponseFactory responsefactory = null;
83 private EntitySerializer entityserializer = null;
84 private EntityDeserializer entitydeserializer = null;
85
86 public DefaultHttpClientConnection(final HttpHost targethost, final InetAddress localAddress) {
87 super();
88 this.targethost = targethost;
89 this.localAddress = localAddress;
90 this.buffer = new CharArrayBuffer(128);
91 this.responsefactory = new DefaultHttpResponseFactory();
92 this.entityserializer = new DefaultEntitySerializer();
93 this.entitydeserializer = new DefaultEntityDeserializer();
94 }
95
96 public DefaultHttpClientConnection(final HttpHost targethost) {
97 this(targethost, null);
98 }
99
100 public DefaultHttpClientConnection() {
101 this(null, null);
102 }
103
104 public void setResponseFactory(final HttpResponseFactory responsefactory) {
105 if (responsefactory == null) {
106 throw new IllegalArgumentException("Factory may not be null");
107 }
108 this.responsefactory = responsefactory;
109 }
110
111 public void setEntityDeserializer(final EntityDeserializer entitydeserializer) {
112 if (entitydeserializer == null) {
113 throw new IllegalArgumentException("Entity deserializer may not be null");
114 }
115 this.entitydeserializer = entitydeserializer;
116 }
117
118 public void setEntitySerializer(final EntitySerializer entityserializer) {
119 if (entityserializer == null) {
120 throw new IllegalArgumentException("Entity serializer may not be null");
121 }
122 this.entityserializer = entityserializer;
123 }
124
125 public void open(final HttpParams params) throws IOException {
126 if (params == null) {
127 throw new IllegalArgumentException("HTTP parameters may not be null");
128 }
129 assertNotOpen();
130 if (this.targethost == null) {
131 throw new IllegalStateException("Target host not specified");
132 }
133 SocketFactory socketfactory = this.targethost.getScheme().getSocketFactory();
134 Socket socket = socketfactory.createSocket(
135 this.targethost.getHostName(), this.targethost.getPort(),
136 this.localAddress, 0,
137 params);
138 bind(socket, params);
139 this.maxHeaderCount = params.getIntParameter(HttpConnectionParams.MAX_HEADER_COUNT, -1);
140 }
141
142 public HttpHost getTargetHost() {
143 return this.targethost;
144 }
145
146 public InetAddress getLocalAddress() {
147 return this.localAddress;
148 }
149
150 public void setTargetHost(final HttpHost targethost) {
151 if (targethost == null) {
152 throw new IllegalArgumentException("Target host may not be null");
153 }
154 assertNotOpen();
155 this.targethost = targethost;
156 }
157
158 public void setLocalAddress(final InetAddress localAddress) {
159 assertNotOpen();
160 this.localAddress = localAddress;
161 }
162
163 public boolean isResponseAvailable(int timeout) throws IOException {
164 assertOpen();
165 return this.datareceiver.isDataAvailable(timeout);
166 }
167
168 public void sendRequestHeader(final HttpRequest request)
169 throws HttpException, IOException {
170 if (request == null) {
171 throw new IllegalArgumentException("HTTP request may not be null");
172 }
173 assertOpen();
174 sendRequestLine(request);
175 sendRequestHeaders(request);
176 }
177
178 public void sendRequestEntity(final HttpEntityEnclosingRequest request)
179 throws HttpException, IOException {
180 if (request == null) {
181 throw new IllegalArgumentException("HTTP request may not be null");
182 }
183 assertOpen();
184 if (request.getEntity() == null) {
185 return;
186 }
187 this.entityserializer.serialize(
188 this.datatransmitter,
189 request,
190 request.getEntity());
191 }
192
193 public void flush() throws IOException {
194 this.datatransmitter.flush();
195 }
196
197 protected void sendRequestLine(final HttpRequest request)
198 throws HttpException, IOException {
199 this.buffer.clear();
200 RequestLine.format(this.buffer, request.getRequestLine());
201 this.datatransmitter.writeLine(this.buffer);
202 }
203
204 protected void sendRequestHeaders(final HttpRequest request)
205 throws HttpException, IOException {
206 Header[] headers = request.getAllHeaders();
207 for (int i = 0; i < headers.length; i++) {
208 this.buffer.clear();
209 Header.format(this.buffer, headers[i]);
210 this.datatransmitter.writeLine(this.buffer);
211 }
212 this.buffer.clear();
213 this.datatransmitter.writeLine(this.buffer);
214 }
215
216 public HttpResponse receiveResponseHeader(final HttpParams params)
217 throws HttpException, IOException {
218 if (params == null) {
219 throw new IllegalArgumentException("HTTP parameters may not be null");
220 }
221 assertOpen();
222 HttpResponse response = readResponseStatusLine(params);
223 readResponseHeaders(response);
224 return response;
225 }
226
227 public void receiveResponseEntity(final HttpResponse response)
228 throws HttpException, IOException {
229 if (response == null) {
230 throw new IllegalArgumentException("HTTP response may not be null");
231 }
232 assertOpen();
233 HttpEntity entity = this.entitydeserializer.deserialize(this.datareceiver, response);
234 response.setEntity(entity);
235 }
236
237 /**
238 * Tests if the string starts with 'HTTP' signature.
239 * @param buffer buffer to test
240 * @return <tt>true</tt> if the line starts with 'HTTP'
241 * signature, <tt>false</tt> otherwise.
242 */
243 private static boolean startsWithHTTP(final CharArrayBuffer buffer) {
244 try {
245 int i = 0;
246 while (HTTP.isWhitespace(buffer.charAt(i))) {
247 ++i;
248 }
249 return buffer.charAt(i) == 'H'
250 && buffer.charAt(i + 1) == 'T'
251 && buffer.charAt(i + 2) == 'T'
252 && buffer.charAt(i + 3) == 'P';
253 } catch (IndexOutOfBoundsException e) {
254 return false;
255 }
256 }
257
258 protected HttpResponse readResponseStatusLine(final HttpParams params)
259 throws HttpException, IOException {
260 // clear the buffer
261 this.buffer.clear();
262 //read out the HTTP status string
263 int maxGarbageLines = params.getIntParameter(
264 HttpProtocolParams.STATUS_LINE_GARBAGE_LIMIT, Integer.MAX_VALUE);
265 int count = 0;
266 do {
267 int i = this.datareceiver.readLine(this.buffer);
268 if (i == -1 && count == 0) {
269 // The server just dropped connection on us
270 throw new NoHttpResponseException("The server " +
271 this.targethost.getHostName() + " failed to respond");
272 }
273 if (startsWithHTTP(this.buffer)) {
274 // Got one
275 break;
276 } else if (i == -1 || count >= maxGarbageLines) {
277 // Giving up
278 throw new ProtocolException("The server " + this.targethost.getHostName() +
279 " failed to respond with a valid HTTP response");
280 }
281 count++;
282 } while(true);
283 //create the status line from the status string
284 StatusLine statusline = StatusLine.parse(this.buffer, 0, this.buffer.length());
285 HttpResponse response = this.responsefactory.newHttpResponse(statusline);
286 response.getParams().setDefaults(params);
287 return response;
288 }
289
290 protected void readResponseHeaders(final HttpResponse response)
291 throws HttpException, IOException {
292 Header[] headers = HeaderUtils.parseHeaders(this.datareceiver, this.maxHeaderCount);
293 for (int i = 0; i < headers.length; i++) {
294 response.addHeader(headers[i]);
295 }
296 }
297
298 }