1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 package org.apache.http.impl;
29
30 import java.io.IOException;
31 import java.io.InputStream;
32 import java.io.OutputStream;
33 import java.net.InetAddress;
34 import java.net.Socket;
35 import java.net.SocketAddress;
36 import java.net.SocketException;
37 import java.net.SocketTimeoutException;
38 import java.nio.charset.CharsetDecoder;
39 import java.nio.charset.CharsetEncoder;
40 import java.util.concurrent.atomic.AtomicReference;
41
42 import org.apache.http.ConnectionClosedException;
43 import org.apache.http.Header;
44 import org.apache.http.HttpConnectionMetrics;
45 import org.apache.http.HttpEntity;
46 import org.apache.http.HttpException;
47 import org.apache.http.HttpInetConnection;
48 import org.apache.http.HttpMessage;
49 import org.apache.http.config.MessageConstraints;
50 import org.apache.http.entity.BasicHttpEntity;
51 import org.apache.http.entity.ContentLengthStrategy;
52 import org.apache.http.impl.entity.LaxContentLengthStrategy;
53 import org.apache.http.impl.entity.StrictContentLengthStrategy;
54 import org.apache.http.impl.io.ChunkedInputStream;
55 import org.apache.http.impl.io.ChunkedOutputStream;
56 import org.apache.http.impl.io.ContentLengthInputStream;
57 import org.apache.http.impl.io.ContentLengthOutputStream;
58 import org.apache.http.impl.io.EmptyInputStream;
59 import org.apache.http.impl.io.HttpTransportMetricsImpl;
60 import org.apache.http.impl.io.IdentityInputStream;
61 import org.apache.http.impl.io.IdentityOutputStream;
62 import org.apache.http.impl.io.SessionInputBufferImpl;
63 import org.apache.http.impl.io.SessionOutputBufferImpl;
64 import org.apache.http.io.SessionInputBuffer;
65 import org.apache.http.io.SessionOutputBuffer;
66 import org.apache.http.protocol.HTTP;
67 import org.apache.http.util.Args;
68 import org.apache.http.util.NetUtils;
69
70
71
72
73
74
75
76 public class BHttpConnectionBase implements HttpInetConnection {
77
78 private final SessionInputBufferImpl inBuffer;
79 private final SessionOutputBufferImpl outbuffer;
80 private final MessageConstraints messageConstraints;
81 private final HttpConnectionMetricsImpl connMetrics;
82 private final ContentLengthStrategy incomingContentStrategy;
83 private final ContentLengthStrategy outgoingContentStrategy;
84 private final AtomicReference<Socket> socketHolder;
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102 protected BHttpConnectionBase(
103 final int bufferSize,
104 final int fragmentSizeHint,
105 final CharsetDecoder charDecoder,
106 final CharsetEncoder charEncoder,
107 final MessageConstraints messageConstraints,
108 final ContentLengthStrategy incomingContentStrategy,
109 final ContentLengthStrategy outgoingContentStrategy) {
110 super();
111 Args.positive(bufferSize, "Buffer size");
112 final HttpTransportMetricsImplTransportMetricsImpl">HttpTransportMetricsImpl inTransportMetrics = new HttpTransportMetricsImpl();
113 final HttpTransportMetricsImplransportMetricsImpl">HttpTransportMetricsImpl outTransportMetrics = new HttpTransportMetricsImpl();
114 this.inBuffer = new SessionInputBufferImpl(inTransportMetrics, bufferSize, -1,
115 messageConstraints != null ? messageConstraints : MessageConstraints.DEFAULT, charDecoder);
116 this.outbuffer = new SessionOutputBufferImpl(outTransportMetrics, bufferSize, fragmentSizeHint,
117 charEncoder);
118 this.messageConstraints = messageConstraints;
119 this.connMetrics = new HttpConnectionMetricsImpl(inTransportMetrics, outTransportMetrics);
120 this.incomingContentStrategy = incomingContentStrategy != null ? incomingContentStrategy :
121 LaxContentLengthStrategy.INSTANCE;
122 this.outgoingContentStrategy = outgoingContentStrategy != null ? outgoingContentStrategy :
123 StrictContentLengthStrategy.INSTANCE;
124 this.socketHolder = new AtomicReference<Socket>();
125 }
126
127 protected void ensureOpen() throws IOException {
128 final Socket socket = this.socketHolder.get();
129 if (socket == null) {
130 throw new ConnectionClosedException();
131 }
132 if (!this.inBuffer.isBound()) {
133 this.inBuffer.bind(getSocketInputStream(socket));
134 }
135 if (!this.outbuffer.isBound()) {
136 this.outbuffer.bind(getSocketOutputStream(socket));
137 }
138 }
139
140 protected InputStream getSocketInputStream(final Socket socket) throws IOException {
141 return socket.getInputStream();
142 }
143
144 protected OutputStream getSocketOutputStream(final Socket socket) throws IOException {
145 return socket.getOutputStream();
146 }
147
148
149
150
151
152
153
154
155
156
157
158 protected void bind(final Socket socket) throws IOException {
159 Args.notNull(socket, "Socket");
160 this.socketHolder.set(socket);
161 this.inBuffer.bind(null);
162 this.outbuffer.bind(null);
163 }
164
165 protected SessionInputBuffer getSessionInputBuffer() {
166 return this.inBuffer;
167 }
168
169 protected SessionOutputBuffer getSessionOutputBuffer() {
170 return this.outbuffer;
171 }
172
173 protected void doFlush() throws IOException {
174 this.outbuffer.flush();
175 }
176
177 @Override
178 public boolean isOpen() {
179 return this.socketHolder.get() != null;
180 }
181
182 protected Socket getSocket() {
183 return this.socketHolder.get();
184 }
185
186 protected OutputStream createOutputStream(
187 final long len,
188 final SessionOutputBuffer outbuffer) {
189 if (len == ContentLengthStrategy.CHUNKED) {
190 return new ChunkedOutputStream(2048, outbuffer);
191 } else if (len == ContentLengthStrategy.IDENTITY) {
192 return new IdentityOutputStream(outbuffer);
193 } else {
194 return new ContentLengthOutputStream(outbuffer, len);
195 }
196 }
197
198 protected OutputStream prepareOutput(final HttpMessage message) throws HttpException {
199 final long len = this.outgoingContentStrategy.determineLength(message);
200 return createOutputStream(len, this.outbuffer);
201 }
202
203 protected InputStream createInputStream(
204 final long len,
205 final SessionInputBuffer inBuffer) {
206 if (len == ContentLengthStrategy.CHUNKED) {
207 return new ChunkedInputStream(inBuffer, this.messageConstraints);
208 } else if (len == ContentLengthStrategy.IDENTITY) {
209 return new IdentityInputStream(inBuffer);
210 } else if (len == 0L) {
211 return EmptyInputStream.INSTANCE;
212 } else {
213 return new ContentLengthInputStream(inBuffer, len);
214 }
215 }
216
217 protected HttpEntity prepareInput(final HttpMessage message) throws HttpException {
218 final BasicHttpEntityy.html#BasicHttpEntity">BasicHttpEntity entity = new BasicHttpEntity();
219
220 final long len = this.incomingContentStrategy.determineLength(message);
221 final InputStream inStream = createInputStream(len, this.inBuffer);
222 if (len == ContentLengthStrategy.CHUNKED) {
223 entity.setChunked(true);
224 entity.setContentLength(-1);
225 entity.setContent(inStream);
226 } else if (len == ContentLengthStrategy.IDENTITY) {
227 entity.setChunked(false);
228 entity.setContentLength(-1);
229 entity.setContent(inStream);
230 } else {
231 entity.setChunked(false);
232 entity.setContentLength(len);
233 entity.setContent(inStream);
234 }
235
236 final Header contentTypeHeader = message.getFirstHeader(HTTP.CONTENT_TYPE);
237 if (contentTypeHeader != null) {
238 entity.setContentType(contentTypeHeader);
239 }
240 final Header contentEncodingHeader = message.getFirstHeader(HTTP.CONTENT_ENCODING);
241 if (contentEncodingHeader != null) {
242 entity.setContentEncoding(contentEncodingHeader);
243 }
244 return entity;
245 }
246
247 @Override
248 public InetAddress getLocalAddress() {
249 final Socket socket = this.socketHolder.get();
250 return socket != null ? socket.getLocalAddress() : null;
251 }
252
253 @Override
254 public int getLocalPort() {
255 final Socket socket = this.socketHolder.get();
256 return socket != null ? socket.getLocalPort() : -1;
257 }
258
259 @Override
260 public InetAddress getRemoteAddress() {
261 final Socket socket = this.socketHolder.get();
262 return socket != null ? socket.getInetAddress() : null;
263 }
264
265 @Override
266 public int getRemotePort() {
267 final Socket socket = this.socketHolder.get();
268 return socket != null ? socket.getPort() : -1;
269 }
270
271 @Override
272 public void setSocketTimeout(final int timeout) {
273 final Socket socket = this.socketHolder.get();
274 if (socket != null) {
275 try {
276 socket.setSoTimeout(timeout);
277 } catch (final SocketException ignore) {
278
279
280
281 }
282 }
283 }
284
285 @Override
286 public int getSocketTimeout() {
287 final Socket socket = this.socketHolder.get();
288 if (socket != null) {
289 try {
290 return socket.getSoTimeout();
291 } catch (final SocketException ignore) {
292
293 }
294 }
295 return -1;
296 }
297
298 @Override
299 public void shutdown() throws IOException {
300 final Socket socket = this.socketHolder.getAndSet(null);
301 if (socket != null) {
302
303 try {
304 socket.setSoLinger(true, 0);
305 } catch (final IOException ex) {
306 } finally {
307 socket.close();
308 }
309 }
310 }
311
312 @Override
313 public void close() throws IOException {
314 final Socket socket = this.socketHolder.getAndSet(null);
315 if (socket != null) {
316 try {
317 this.inBuffer.clear();
318 this.outbuffer.flush();
319 try {
320 try {
321 socket.shutdownOutput();
322 } catch (final IOException ignore) {
323 }
324 try {
325 socket.shutdownInput();
326 } catch (final IOException ignore) {
327 }
328 } catch (final UnsupportedOperationException ignore) {
329
330 }
331 } finally {
332 socket.close();
333 }
334 }
335 }
336
337 private int fillInputBuffer(final int timeout) throws IOException {
338 final Socket socket = this.socketHolder.get();
339 final int oldtimeout = socket.getSoTimeout();
340 try {
341 socket.setSoTimeout(timeout);
342 return this.inBuffer.fillBuffer();
343 } finally {
344 socket.setSoTimeout(oldtimeout);
345 }
346 }
347
348 protected boolean awaitInput(final int timeout) throws IOException {
349 if (this.inBuffer.hasBufferedData()) {
350 return true;
351 }
352 fillInputBuffer(timeout);
353 return this.inBuffer.hasBufferedData();
354 }
355
356 @Override
357 public boolean isStale() {
358 if (!isOpen()) {
359 return true;
360 }
361 try {
362 final int bytesRead = fillInputBuffer(1);
363 return bytesRead < 0;
364 } catch (final SocketTimeoutException ex) {
365 return false;
366 } catch (final IOException ex) {
367 return true;
368 }
369 }
370
371 protected void incrementRequestCount() {
372 this.connMetrics.incrementRequestCount();
373 }
374
375 protected void incrementResponseCount() {
376 this.connMetrics.incrementResponseCount();
377 }
378
379 @Override
380 public HttpConnectionMetrics getMetrics() {
381 return this.connMetrics;
382 }
383
384 @Override
385 public String toString() {
386 final Socket socket = this.socketHolder.get();
387 if (socket != null) {
388 final StringBuilder buffer = new StringBuilder();
389 final SocketAddress remoteAddress = socket.getRemoteSocketAddress();
390 final SocketAddress localAddress = socket.getLocalSocketAddress();
391 if (remoteAddress != null && localAddress != null) {
392 NetUtils.formatAddress(buffer, localAddress);
393 buffer.append("<->");
394 NetUtils.formatAddress(buffer, remoteAddress);
395 }
396 return buffer.toString();
397 }
398 return "[Not bound]";
399 }
400
401 }