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.hc.client5.http.impl.io;
29
30 import java.io.IOException;
31 import java.io.InterruptedIOException;
32 import java.net.Socket;
33 import java.nio.charset.CharsetDecoder;
34 import java.nio.charset.CharsetEncoder;
35 import java.util.concurrent.atomic.AtomicBoolean;
36
37 import javax.net.ssl.SSLSession;
38 import javax.net.ssl.SSLSocket;
39
40 import org.apache.hc.client5.http.io.ManagedHttpClientConnection;
41 import org.apache.hc.core5.http.ClassicHttpRequest;
42 import org.apache.hc.core5.http.ClassicHttpResponse;
43 import org.apache.hc.core5.http.ContentLengthStrategy;
44 import org.apache.hc.core5.http.Header;
45 import org.apache.hc.core5.http.config.Http1Config;
46 import org.apache.hc.core5.http.impl.io.DefaultBHttpClientConnection;
47 import org.apache.hc.core5.http.impl.io.SocketHolder;
48 import org.apache.hc.core5.http.io.HttpMessageParserFactory;
49 import org.apache.hc.core5.http.io.HttpMessageWriterFactory;
50 import org.apache.hc.core5.http.message.RequestLine;
51 import org.apache.hc.core5.http.message.StatusLine;
52 import org.apache.hc.core5.io.CloseMode;
53 import org.apache.hc.core5.util.Identifiable;
54 import org.apache.hc.core5.util.Timeout;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58 final class DefaultManagedHttpClientConnection
59 extends DefaultBHttpClientConnection implements ManagedHttpClientConnection, Identifiable {
60
61 private static final Logger LOG = LoggerFactory.getLogger(DefaultManagedHttpClientConnection.class);
62 private static final Logger HEADER_LOG = LoggerFactory.getLogger("org.apache.hc.client5.http.headers");
63 private static final Logger WIRE_LOG = LoggerFactory.getLogger("org.apache.hc.client5.http.wire");
64
65 private final String id;
66 private final AtomicBoolean closed;
67
68 private Timeout socketTimeout;
69
70 public DefaultManagedHttpClientConnection(
71 final String id,
72 final CharsetDecoder charDecoder,
73 final CharsetEncoder charEncoder,
74 final Http1Config h1Config,
75 final ContentLengthStrategy incomingContentStrategy,
76 final ContentLengthStrategy outgoingContentStrategy,
77 final HttpMessageWriterFactory<ClassicHttpRequest> requestWriterFactory,
78 final HttpMessageParserFactory<ClassicHttpResponse> responseParserFactory) {
79 super(h1Config, charDecoder, charEncoder, incomingContentStrategy, outgoingContentStrategy, requestWriterFactory, responseParserFactory);
80 this.id = id;
81 this.closed = new AtomicBoolean();
82 }
83
84 public DefaultManagedHttpClientConnection(final String id) {
85 this(id, null, null, null, null, null, null, null);
86 }
87
88 @Override
89 public String getId() {
90 return this.id;
91 }
92
93 @Override
94 public void bind(final SocketHolder socketHolder) throws IOException {
95 if (this.closed.get()) {
96 final Socket socket = socketHolder.getSocket();
97 socket.close();
98
99 throw new InterruptedIOException("Connection already shutdown");
100 }
101 super.bind(socketHolder);
102 socketTimeout = Timeout.ofMilliseconds(socketHolder.getSocket().getSoTimeout());
103 }
104
105 @Override
106 public Socket getSocket() {
107 final SocketHolder socketHolder = getSocketHolder();
108 return socketHolder != null ? socketHolder.getSocket() : null;
109 }
110
111 @Override
112 public SSLSession getSSLSession() {
113 final Socket socket = getSocket();
114 if (socket instanceof SSLSocket) {
115 return ((SSLSocket) socket).getSession();
116 } else {
117 return null;
118 }
119 }
120
121 @Override
122 public void close() throws IOException {
123 if (this.closed.compareAndSet(false, true)) {
124 if (LOG.isDebugEnabled()) {
125 LOG.debug("{}: Close connection", this.id);
126 }
127 super.close();
128 }
129 }
130
131 @Override
132 public void setSocketTimeout(final Timeout timeout) {
133 if (LOG.isDebugEnabled()) {
134 LOG.debug("{}: set socket timeout to {}", this.id, timeout);
135 }
136 super.setSocketTimeout(timeout);
137 }
138
139 @Override
140 public void close(final CloseMode closeMode) {
141 if (this.closed.compareAndSet(false, true)) {
142 if (LOG.isDebugEnabled()) {
143 LOG.debug("{}: close connection {}", this.id, closeMode);
144 }
145 super.close(closeMode);
146 }
147 }
148
149 @Override
150 public void bind(final Socket socket) throws IOException {
151 super.bind(WIRE_LOG.isDebugEnabled() ? new LoggingSocketHolder(socket, this.id, WIRE_LOG) : new SocketHolder(socket));
152 socketTimeout = Timeout.ofMilliseconds(socket.getSoTimeout());
153 }
154
155 @Override
156 protected void onResponseReceived(final ClassicHttpResponse response) {
157 if (response != null && HEADER_LOG.isDebugEnabled()) {
158 HEADER_LOG.debug("{} << {}", this.id, new StatusLine(response));
159 final Header[] headers = response.getHeaders();
160 for (final Header header : headers) {
161 HEADER_LOG.debug("{} << {}", this.id, header);
162 }
163 }
164 }
165
166 @Override
167 protected void onRequestSubmitted(final ClassicHttpRequest request) {
168 if (request != null && HEADER_LOG.isDebugEnabled()) {
169 HEADER_LOG.debug("{} >> {}", this.id, new RequestLine(request));
170 final Header[] headers = request.getHeaders();
171 for (final Header header : headers) {
172 HEADER_LOG.debug("{} >> {}", this.id, header);
173 }
174 }
175 }
176
177 @Override
178 public void passivate() {
179 super.setSocketTimeout(Timeout.ZERO_MILLISECONDS);
180 }
181
182 @Override
183 public void activate() {
184 super.setSocketTimeout(socketTimeout);
185 }
186
187 }