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 } finally {
320 socket.close();
321 }
322 }
323 }
324
325 private int fillInputBuffer(final int timeout) throws IOException {
326 final Socket socket = this.socketHolder.get();
327 final int oldtimeout = socket.getSoTimeout();
328 try {
329 socket.setSoTimeout(timeout);
330 return this.inBuffer.fillBuffer();
331 } finally {
332 socket.setSoTimeout(oldtimeout);
333 }
334 }
335
336 protected boolean awaitInput(final int timeout) throws IOException {
337 if (this.inBuffer.hasBufferedData()) {
338 return true;
339 }
340 fillInputBuffer(timeout);
341 return this.inBuffer.hasBufferedData();
342 }
343
344 @Override
345 public boolean isStale() {
346 if (!isOpen()) {
347 return true;
348 }
349 try {
350 final int bytesRead = fillInputBuffer(1);
351 return bytesRead < 0;
352 } catch (final SocketTimeoutException ex) {
353 return false;
354 } catch (final IOException ex) {
355 return true;
356 }
357 }
358
359 protected void incrementRequestCount() {
360 this.connMetrics.incrementRequestCount();
361 }
362
363 protected void incrementResponseCount() {
364 this.connMetrics.incrementResponseCount();
365 }
366
367 @Override
368 public HttpConnectionMetrics getMetrics() {
369 return this.connMetrics;
370 }
371
372 @Override
373 public String toString() {
374 final Socket socket = this.socketHolder.get();
375 if (socket != null) {
376 final StringBuilder buffer = new StringBuilder();
377 final SocketAddress remoteAddress = socket.getRemoteSocketAddress();
378 final SocketAddress localAddress = socket.getLocalSocketAddress();
379 if (remoteAddress != null && localAddress != null) {
380 NetUtils.formatAddress(buffer, localAddress);
381 buffer.append("<->");
382 NetUtils.formatAddress(buffer, remoteAddress);
383 }
384 return buffer.toString();
385 }
386 return "[Not bound]";
387 }
388
389 }