|
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 ch.boye.httpclientandroidlib.impl.conn; |
|
29 |
|
30 import java.io.IOException; |
|
31 import java.net.Socket; |
|
32 import java.util.HashMap; |
|
33 import java.util.Map; |
|
34 |
|
35 import ch.boye.httpclientandroidlib.annotation.NotThreadSafe; |
|
36 |
|
37 import ch.boye.httpclientandroidlib.androidextra.HttpClientAndroidLog; |
|
38 /* LogFactory removed by HttpClient for Android script. */ |
|
39 import ch.boye.httpclientandroidlib.Header; |
|
40 import ch.boye.httpclientandroidlib.HttpException; |
|
41 import ch.boye.httpclientandroidlib.HttpHost; |
|
42 import ch.boye.httpclientandroidlib.HttpRequest; |
|
43 import ch.boye.httpclientandroidlib.HttpResponse; |
|
44 import ch.boye.httpclientandroidlib.HttpResponseFactory; |
|
45 import ch.boye.httpclientandroidlib.params.HttpParams; |
|
46 import ch.boye.httpclientandroidlib.params.HttpProtocolParams; |
|
47 import ch.boye.httpclientandroidlib.protocol.HttpContext; |
|
48 import ch.boye.httpclientandroidlib.impl.SocketHttpClientConnection; |
|
49 import ch.boye.httpclientandroidlib.io.HttpMessageParser; |
|
50 import ch.boye.httpclientandroidlib.io.SessionInputBuffer; |
|
51 import ch.boye.httpclientandroidlib.io.SessionOutputBuffer; |
|
52 |
|
53 import ch.boye.httpclientandroidlib.conn.OperatedClientConnection; |
|
54 |
|
55 /** |
|
56 * Default implementation of an operated client connection. |
|
57 * <p> |
|
58 * The following parameters can be used to customize the behavior of this |
|
59 * class: |
|
60 * <ul> |
|
61 * <li>{@link ch.boye.httpclientandroidlib.params.CoreProtocolPNames#STRICT_TRANSFER_ENCODING}</li> |
|
62 * <li>{@link ch.boye.httpclientandroidlib.params.CoreProtocolPNames#HTTP_ELEMENT_CHARSET}</li> |
|
63 * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#SOCKET_BUFFER_SIZE}</li> |
|
64 * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_LINE_LENGTH}</li> |
|
65 * <li>{@link ch.boye.httpclientandroidlib.params.CoreConnectionPNames#MAX_HEADER_COUNT}</li> |
|
66 * </ul> |
|
67 * |
|
68 * @since 4.0 |
|
69 */ |
|
70 @NotThreadSafe // connSecure, targetHost |
|
71 public class DefaultClientConnection extends SocketHttpClientConnection |
|
72 implements OperatedClientConnection, HttpContext { |
|
73 |
|
74 public HttpClientAndroidLog log = new HttpClientAndroidLog(getClass()); |
|
75 public HttpClientAndroidLog headerLog = new HttpClientAndroidLog("ch.boye.httpclientandroidlib.headers"); |
|
76 public HttpClientAndroidLog wireLog = new HttpClientAndroidLog("ch.boye.httpclientandroidlib.wire"); |
|
77 |
|
78 /** The unconnected socket */ |
|
79 private volatile Socket socket; |
|
80 |
|
81 /** The target host of this connection. */ |
|
82 private HttpHost targetHost; |
|
83 |
|
84 /** Whether this connection is secure. */ |
|
85 private boolean connSecure; |
|
86 |
|
87 /** True if this connection was shutdown. */ |
|
88 private volatile boolean shutdown; |
|
89 |
|
90 /** connection specific attributes */ |
|
91 private final Map<String, Object> attributes; |
|
92 |
|
93 public DefaultClientConnection() { |
|
94 super(); |
|
95 this.attributes = new HashMap<String, Object>(); |
|
96 } |
|
97 |
|
98 public final HttpHost getTargetHost() { |
|
99 return this.targetHost; |
|
100 } |
|
101 |
|
102 public final boolean isSecure() { |
|
103 return this.connSecure; |
|
104 } |
|
105 |
|
106 @Override |
|
107 public final Socket getSocket() { |
|
108 return this.socket; |
|
109 } |
|
110 |
|
111 public void opening(Socket sock, HttpHost target) throws IOException { |
|
112 assertNotOpen(); |
|
113 this.socket = sock; |
|
114 this.targetHost = target; |
|
115 |
|
116 // Check for shutdown after assigning socket, so that |
|
117 if (this.shutdown) { |
|
118 sock.close(); // allow this to throw... |
|
119 // ...but if it doesn't, explicitly throw one ourselves. |
|
120 throw new IOException("Connection already shutdown"); |
|
121 } |
|
122 } |
|
123 |
|
124 public void openCompleted(boolean secure, HttpParams params) throws IOException { |
|
125 assertNotOpen(); |
|
126 if (params == null) { |
|
127 throw new IllegalArgumentException |
|
128 ("Parameters must not be null."); |
|
129 } |
|
130 this.connSecure = secure; |
|
131 bind(this.socket, params); |
|
132 } |
|
133 |
|
134 /** |
|
135 * Force-closes this connection. |
|
136 * If the connection is still in the process of being open (the method |
|
137 * {@link #opening opening} was already called but |
|
138 * {@link #openCompleted openCompleted} was not), the associated |
|
139 * socket that is being connected to a remote address will be closed. |
|
140 * That will interrupt a thread that is blocked on connecting |
|
141 * the socket. |
|
142 * If the connection is not yet open, this will prevent the connection |
|
143 * from being opened. |
|
144 * |
|
145 * @throws IOException in case of a problem |
|
146 */ |
|
147 @Override |
|
148 public void shutdown() throws IOException { |
|
149 shutdown = true; |
|
150 try { |
|
151 super.shutdown(); |
|
152 log.debug("Connection shut down"); |
|
153 Socket sock = this.socket; // copy volatile attribute |
|
154 if (sock != null) |
|
155 sock.close(); |
|
156 } catch (IOException ex) { |
|
157 log.debug("I/O error shutting down connection", ex); |
|
158 } |
|
159 } |
|
160 |
|
161 @Override |
|
162 public void close() throws IOException { |
|
163 try { |
|
164 super.close(); |
|
165 log.debug("Connection closed"); |
|
166 } catch (IOException ex) { |
|
167 log.debug("I/O error closing connection", ex); |
|
168 } |
|
169 } |
|
170 |
|
171 @Override |
|
172 protected SessionInputBuffer createSessionInputBuffer( |
|
173 final Socket socket, |
|
174 int buffersize, |
|
175 final HttpParams params) throws IOException { |
|
176 if (buffersize == -1) { |
|
177 buffersize = 8192; |
|
178 } |
|
179 SessionInputBuffer inbuffer = super.createSessionInputBuffer( |
|
180 socket, |
|
181 buffersize, |
|
182 params); |
|
183 if (wireLog.isDebugEnabled()) { |
|
184 inbuffer = new LoggingSessionInputBuffer( |
|
185 inbuffer, |
|
186 new Wire(wireLog), |
|
187 HttpProtocolParams.getHttpElementCharset(params)); |
|
188 } |
|
189 return inbuffer; |
|
190 } |
|
191 |
|
192 @Override |
|
193 protected SessionOutputBuffer createSessionOutputBuffer( |
|
194 final Socket socket, |
|
195 int buffersize, |
|
196 final HttpParams params) throws IOException { |
|
197 if (buffersize == -1) { |
|
198 buffersize = 8192; |
|
199 } |
|
200 SessionOutputBuffer outbuffer = super.createSessionOutputBuffer( |
|
201 socket, |
|
202 buffersize, |
|
203 params); |
|
204 if (wireLog.isDebugEnabled()) { |
|
205 outbuffer = new LoggingSessionOutputBuffer( |
|
206 outbuffer, |
|
207 new Wire(wireLog), |
|
208 HttpProtocolParams.getHttpElementCharset(params)); |
|
209 } |
|
210 return outbuffer; |
|
211 } |
|
212 |
|
213 @Override |
|
214 protected HttpMessageParser createResponseParser( |
|
215 final SessionInputBuffer buffer, |
|
216 final HttpResponseFactory responseFactory, |
|
217 final HttpParams params) { |
|
218 // override in derived class to specify a line parser |
|
219 return new DefaultResponseParser |
|
220 (buffer, null, responseFactory, params); |
|
221 } |
|
222 |
|
223 public void update(Socket sock, HttpHost target, |
|
224 boolean secure, HttpParams params) |
|
225 throws IOException { |
|
226 |
|
227 assertOpen(); |
|
228 if (target == null) { |
|
229 throw new IllegalArgumentException |
|
230 ("Target host must not be null."); |
|
231 } |
|
232 if (params == null) { |
|
233 throw new IllegalArgumentException |
|
234 ("Parameters must not be null."); |
|
235 } |
|
236 |
|
237 if (sock != null) { |
|
238 this.socket = sock; |
|
239 bind(sock, params); |
|
240 } |
|
241 targetHost = target; |
|
242 connSecure = secure; |
|
243 } |
|
244 |
|
245 @Override |
|
246 public HttpResponse receiveResponseHeader() throws HttpException, IOException { |
|
247 HttpResponse response = super.receiveResponseHeader(); |
|
248 if (log.isDebugEnabled()) { |
|
249 log.debug("Receiving response: " + response.getStatusLine()); |
|
250 } |
|
251 if (headerLog.isDebugEnabled()) { |
|
252 headerLog.debug("<< " + response.getStatusLine().toString()); |
|
253 Header[] headers = response.getAllHeaders(); |
|
254 for (Header header : headers) { |
|
255 headerLog.debug("<< " + header.toString()); |
|
256 } |
|
257 } |
|
258 return response; |
|
259 } |
|
260 |
|
261 @Override |
|
262 public void sendRequestHeader(HttpRequest request) throws HttpException, IOException { |
|
263 if (log.isDebugEnabled()) { |
|
264 log.debug("Sending request: " + request.getRequestLine()); |
|
265 } |
|
266 super.sendRequestHeader(request); |
|
267 if (headerLog.isDebugEnabled()) { |
|
268 headerLog.debug(">> " + request.getRequestLine().toString()); |
|
269 Header[] headers = request.getAllHeaders(); |
|
270 for (Header header : headers) { |
|
271 headerLog.debug(">> " + header.toString()); |
|
272 } |
|
273 } |
|
274 } |
|
275 |
|
276 public Object getAttribute(final String id) { |
|
277 return this.attributes.get(id); |
|
278 } |
|
279 |
|
280 public Object removeAttribute(final String id) { |
|
281 return this.attributes.remove(id); |
|
282 } |
|
283 |
|
284 public void setAttribute(final String id, final Object obj) { |
|
285 this.attributes.put(id, obj); |
|
286 } |
|
287 |
|
288 } |