36131
|
1 |
/*
|
|
2 |
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
|
3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
4 |
*
|
|
5 |
* This code is free software; you can redistribute it and/or modify it
|
|
6 |
* under the terms of the GNU General Public License version 2 only, as
|
|
7 |
* published by the Free Software Foundation. Oracle designates this
|
|
8 |
* particular file as subject to the "Classpath" exception as provided
|
|
9 |
* by Oracle in the LICENSE file that accompanied this code.
|
|
10 |
*
|
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that
|
|
15 |
* accompanied this code).
|
|
16 |
*
|
|
17 |
* You should have received a copy of the GNU General Public License version
|
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
20 |
*
|
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
22 |
* or visit www.oracle.com if you need additional information or have any
|
|
23 |
*/
|
|
24 |
package java.net.http;
|
|
25 |
|
37720
|
26 |
import java.io.Closeable;
|
36131
|
27 |
import java.io.IOException;
|
|
28 |
import java.net.InetSocketAddress;
|
|
29 |
import java.nio.ByteBuffer;
|
|
30 |
import java.nio.channels.SocketChannel;
|
|
31 |
import java.util.concurrent.CompletableFuture;
|
|
32 |
import javax.net.ssl.SSLParameters;
|
|
33 |
|
|
34 |
/**
|
|
35 |
* Wraps socket channel layer and takes care of SSL also.
|
|
36 |
*
|
|
37 |
* Subtypes are:
|
|
38 |
* PlainHttpConnection: regular direct TCP connection to server
|
|
39 |
* PlainProxyConnection: plain text proxy connection
|
|
40 |
* PlainTunnelingConnection: opens plain text (CONNECT) tunnel to server
|
|
41 |
* SSLConnection: TLS channel direct to server
|
|
42 |
* SSLTunnelConnection: TLS channel via (CONNECT) proxy tunnel
|
|
43 |
*/
|
37720
|
44 |
abstract class HttpConnection implements BufferHandler, Closeable {
|
|
45 |
|
|
46 |
protected final static ByteBuffer emptyBuf = Utils.EMPTY_BYTEBUFFER;
|
|
47 |
|
|
48 |
enum Mode {
|
|
49 |
BLOCKING,
|
|
50 |
NON_BLOCKING,
|
|
51 |
ASYNC
|
|
52 |
}
|
|
53 |
|
|
54 |
protected Mode mode;
|
36131
|
55 |
|
|
56 |
// address we are connected to. Could be a server or a proxy
|
|
57 |
final InetSocketAddress address;
|
|
58 |
final HttpClientImpl client;
|
|
59 |
protected volatile ByteBuffer buffer;
|
|
60 |
|
|
61 |
HttpConnection(InetSocketAddress address, HttpClientImpl client) {
|
|
62 |
this.address = address;
|
|
63 |
this.client = client;
|
37720
|
64 |
this.buffer = emptyBuf;
|
36131
|
65 |
}
|
|
66 |
|
|
67 |
/**
|
|
68 |
* Public API to this class. addr is the ultimate destination. Any proxies
|
|
69 |
* etc are figured out from the request. Returns an instance of one of the
|
|
70 |
* following
|
|
71 |
* PlainHttpConnection
|
|
72 |
* PlainTunnelingConnection
|
|
73 |
* SSLConnection
|
|
74 |
* SSLTunnelConnection
|
|
75 |
*
|
|
76 |
* When object returned, connect() or connectAsync() must be called, which
|
|
77 |
* when it returns/completes, the connection is usable for requests.
|
|
78 |
*/
|
|
79 |
public static HttpConnection getConnection(InetSocketAddress addr,
|
|
80 |
HttpRequestImpl request) {
|
37720
|
81 |
return getConnectionImpl(addr, request, null);
|
|
82 |
}
|
|
83 |
|
|
84 |
/**
|
|
85 |
* Called specifically to get an async connection for HTTP/2 over SSL.
|
|
86 |
*
|
|
87 |
* @param addr
|
|
88 |
* @param request
|
|
89 |
* @param http2
|
|
90 |
* @return
|
|
91 |
*/
|
|
92 |
public static HttpConnection getConnection(InetSocketAddress addr,
|
|
93 |
HttpRequestImpl request, Http2Connection http2) {
|
|
94 |
|
|
95 |
return getConnectionImpl(addr, request, http2);
|
36131
|
96 |
}
|
|
97 |
|
|
98 |
public abstract void connect() throws IOException, InterruptedException;
|
|
99 |
|
|
100 |
public abstract CompletableFuture<Void> connectAsync();
|
|
101 |
|
|
102 |
/**
|
|
103 |
* Returns whether this connection is connected to its destination
|
|
104 |
*/
|
|
105 |
abstract boolean connected();
|
|
106 |
|
|
107 |
abstract boolean isSecure();
|
|
108 |
|
|
109 |
abstract boolean isProxied();
|
|
110 |
|
|
111 |
/**
|
|
112 |
* Completes when the first byte of the response is available to be read.
|
|
113 |
*/
|
|
114 |
abstract CompletableFuture<Void> whenReceivingResponse();
|
|
115 |
|
|
116 |
// must be called before reading any data off connection
|
|
117 |
// at beginning of response.
|
|
118 |
ByteBuffer getRemaining() {
|
|
119 |
ByteBuffer b = buffer;
|
37720
|
120 |
buffer = emptyBuf;
|
36131
|
121 |
return b;
|
|
122 |
}
|
|
123 |
|
|
124 |
final boolean isOpen() {
|
|
125 |
return channel().isOpen();
|
|
126 |
}
|
|
127 |
|
|
128 |
/* Returns either a plain HTTP connection or a plain tunnelling connection
|
|
129 |
* for proxied websockets */
|
|
130 |
private static HttpConnection getPlainConnection(InetSocketAddress addr,
|
|
131 |
InetSocketAddress proxy,
|
|
132 |
HttpRequestImpl request) {
|
|
133 |
HttpClientImpl client = request.client();
|
|
134 |
|
|
135 |
if (request.isWebSocket() && proxy != null) {
|
|
136 |
return new PlainTunnelingConnection(addr,
|
|
137 |
proxy,
|
|
138 |
client,
|
|
139 |
request.getAccessControlContext());
|
|
140 |
} else {
|
|
141 |
if (proxy == null) {
|
|
142 |
return new PlainHttpConnection(addr, client);
|
|
143 |
} else {
|
|
144 |
return new PlainProxyConnection(proxy, client);
|
|
145 |
}
|
|
146 |
}
|
|
147 |
}
|
|
148 |
|
|
149 |
private static HttpConnection getSSLConnection(InetSocketAddress addr,
|
37720
|
150 |
InetSocketAddress proxy, HttpRequestImpl request,
|
|
151 |
String[] alpn, Http2Connection http2) {
|
36131
|
152 |
HttpClientImpl client = request.client();
|
|
153 |
if (proxy != null) {
|
|
154 |
return new SSLTunnelConnection(addr,
|
|
155 |
client,
|
|
156 |
proxy,
|
|
157 |
request.getAccessControlContext());
|
37720
|
158 |
} else if (http2 == null) {
|
|
159 |
return new SSLConnection(addr, client, alpn);
|
36131
|
160 |
} else {
|
37720
|
161 |
return new AsyncSSLConnection(addr, client, alpn);
|
36131
|
162 |
}
|
|
163 |
}
|
|
164 |
|
|
165 |
/**
|
|
166 |
* Main factory method. Gets a HttpConnection, either cached or new if
|
|
167 |
* none available.
|
|
168 |
*/
|
|
169 |
private static HttpConnection getConnectionImpl(InetSocketAddress addr,
|
37720
|
170 |
HttpRequestImpl request, Http2Connection http2) {
|
|
171 |
|
36131
|
172 |
HttpConnection c;
|
|
173 |
HttpClientImpl client = request.client();
|
|
174 |
InetSocketAddress proxy = request.proxy();
|
|
175 |
boolean secure = request.secure();
|
|
176 |
ConnectionPool pool = client.connectionPool();
|
|
177 |
String[] alpn = null;
|
|
178 |
|
|
179 |
if (secure && request.requestHttp2()) {
|
|
180 |
alpn = new String[1];
|
|
181 |
alpn[0] = "h2";
|
|
182 |
}
|
|
183 |
|
|
184 |
if (!secure) {
|
|
185 |
c = pool.getConnection(false, addr, proxy);
|
|
186 |
if (c != null) {
|
|
187 |
return c;
|
|
188 |
} else {
|
|
189 |
return getPlainConnection(addr, proxy, request);
|
|
190 |
}
|
|
191 |
} else {
|
|
192 |
c = pool.getConnection(true, addr, proxy);
|
|
193 |
if (c != null) {
|
|
194 |
return c;
|
|
195 |
} else {
|
37720
|
196 |
return getSSLConnection(addr, proxy, request, alpn, http2);
|
36131
|
197 |
}
|
|
198 |
}
|
|
199 |
}
|
|
200 |
|
|
201 |
void returnToCache(HttpHeaders hdrs) {
|
|
202 |
if (hdrs == null) {
|
|
203 |
// the connection was closed by server
|
|
204 |
close();
|
|
205 |
return;
|
|
206 |
}
|
|
207 |
if (!isOpen()) {
|
|
208 |
return;
|
|
209 |
}
|
|
210 |
ConnectionPool pool = client.connectionPool();
|
|
211 |
boolean keepAlive = hdrs.firstValue("Connection")
|
|
212 |
.map((s) -> !s.equalsIgnoreCase("close"))
|
|
213 |
.orElse(true);
|
|
214 |
|
|
215 |
if (keepAlive) {
|
|
216 |
pool.returnToPool(this);
|
|
217 |
} else {
|
|
218 |
close();
|
|
219 |
}
|
|
220 |
}
|
|
221 |
|
|
222 |
/**
|
|
223 |
* Also check that the number of bytes written is what was expected. This
|
|
224 |
* could be different if the buffer is user-supplied and its internal
|
|
225 |
* pointers were manipulated in a race condition.
|
|
226 |
*/
|
|
227 |
final void checkWrite(long expected, ByteBuffer buffer) throws IOException {
|
|
228 |
long written = write(buffer);
|
|
229 |
if (written != expected) {
|
|
230 |
throw new IOException("incorrect number of bytes written");
|
|
231 |
}
|
|
232 |
}
|
|
233 |
|
|
234 |
final void checkWrite(long expected,
|
|
235 |
ByteBuffer[] buffers,
|
|
236 |
int start,
|
|
237 |
int length)
|
|
238 |
throws IOException
|
|
239 |
{
|
|
240 |
long written = write(buffers, start, length);
|
|
241 |
if (written != expected) {
|
|
242 |
throw new IOException("incorrect number of bytes written");
|
|
243 |
}
|
|
244 |
}
|
|
245 |
|
|
246 |
abstract SocketChannel channel();
|
|
247 |
|
|
248 |
final InetSocketAddress address() {
|
|
249 |
return address;
|
|
250 |
}
|
|
251 |
|
37720
|
252 |
synchronized void configureMode(Mode mode) throws IOException {
|
|
253 |
this.mode = mode;
|
|
254 |
if (mode == Mode.BLOCKING)
|
|
255 |
channel().configureBlocking(true);
|
|
256 |
else
|
|
257 |
channel().configureBlocking(false);
|
36131
|
258 |
}
|
|
259 |
|
|
260 |
abstract ConnectionPool.CacheKey cacheKey();
|
|
261 |
|
|
262 |
// overridden in SSL only
|
|
263 |
SSLParameters sslParameters() {
|
|
264 |
return null;
|
|
265 |
}
|
|
266 |
|
|
267 |
// Methods to be implemented for Plain TCP and SSL
|
|
268 |
|
|
269 |
abstract long write(ByteBuffer[] buffers, int start, int number)
|
|
270 |
throws IOException;
|
|
271 |
|
|
272 |
abstract long write(ByteBuffer buffer) throws IOException;
|
|
273 |
|
|
274 |
/**
|
|
275 |
* Closes this connection, by returning the socket to its connection pool.
|
|
276 |
*/
|
37720
|
277 |
@Override
|
|
278 |
public abstract void close();
|
36131
|
279 |
|
|
280 |
/**
|
|
281 |
* Returns a ByteBuffer with data, or null if EOF.
|
|
282 |
*/
|
|
283 |
final ByteBuffer read() throws IOException {
|
|
284 |
return read(-1);
|
|
285 |
}
|
|
286 |
|
|
287 |
/**
|
|
288 |
* Puts position to limit and limit to capacity so we can resume reading
|
|
289 |
* into this buffer, but if required > 0 then limit may be reduced so that
|
|
290 |
* no more than required bytes are read next time.
|
|
291 |
*/
|
|
292 |
static void resumeChannelRead(ByteBuffer buf, int required) {
|
|
293 |
int limit = buf.limit();
|
|
294 |
buf.position(limit);
|
|
295 |
int capacity = buf.capacity() - limit;
|
|
296 |
if (required > 0 && required < capacity) {
|
|
297 |
buf.limit(limit + required);
|
|
298 |
} else {
|
|
299 |
buf.limit(buf.capacity());
|
|
300 |
}
|
|
301 |
}
|
|
302 |
|
|
303 |
/**
|
|
304 |
* Blocks ands return requested amount.
|
|
305 |
*/
|
|
306 |
final ByteBuffer read(int length) throws IOException {
|
|
307 |
if (length <= 0) {
|
|
308 |
buffer = readImpl(length);
|
|
309 |
return buffer;
|
|
310 |
}
|
|
311 |
buffer = readImpl(length);
|
|
312 |
int required = length - buffer.remaining();
|
|
313 |
while (buffer.remaining() < length) {
|
|
314 |
resumeChannelRead(buffer, required);
|
|
315 |
int n = readImpl(buffer);
|
|
316 |
required -= n;
|
|
317 |
}
|
|
318 |
return buffer;
|
|
319 |
}
|
|
320 |
|
|
321 |
final int read(ByteBuffer buffer) throws IOException {
|
|
322 |
int n = readImpl(buffer);
|
|
323 |
return n;
|
|
324 |
}
|
|
325 |
|
|
326 |
/** Reads up to length bytes. */
|
|
327 |
protected abstract ByteBuffer readImpl(int length) throws IOException;
|
|
328 |
|
|
329 |
/** Reads as much as possible into given buffer and returns amount read. */
|
|
330 |
protected abstract int readImpl(ByteBuffer buffer) throws IOException;
|
|
331 |
|
|
332 |
@Override
|
|
333 |
public String toString() {
|
|
334 |
return "HttpConnection: " + channel().toString();
|
|
335 |
}
|
|
336 |
|
|
337 |
@Override
|
37720
|
338 |
public final ByteBuffer getBuffer(int n) {
|
|
339 |
return client.getBuffer(n);
|
36131
|
340 |
}
|
|
341 |
|
|
342 |
@Override
|
|
343 |
public final void returnBuffer(ByteBuffer buffer) {
|
|
344 |
client.returnBuffer(buffer);
|
|
345 |
}
|
37720
|
346 |
|
|
347 |
@Override
|
|
348 |
public final void setMinBufferSize(int n) {
|
|
349 |
client.setMinBufferSize(n);
|
|
350 |
}
|
36131
|
351 |
}
|