< prev index next >
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
26 import java.io.Closeable;
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 */
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;
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;
64 this.buffer = emptyBuf;
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) {
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);
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;
120 buffer = emptyBuf;
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,
150 InetSocketAddress proxy, HttpRequestImpl request,
151 String[] alpn, Http2Connection http2) {
152 HttpClientImpl client = request.client();
153 if (proxy != null) {
154 return new SSLTunnelConnection(addr,
155 client,
156 proxy,
157 request.getAccessControlContext());
158 } else if (http2 == null) {
159 return new SSLConnection(addr, client, alpn);
160 } else {
161 return new AsyncSSLConnection(addr, client, alpn);
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,
170 HttpRequestImpl request, Http2Connection http2) {
171
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 {
196 return getSSLConnection(addr, proxy, request, alpn, http2);
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
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);
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 */
277 @Override
278 public abstract void close();
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
338 public final ByteBuffer getBuffer(int n) {
339 return client.getBuffer(n);
340 }
341
342 @Override
343 public final void returnBuffer(ByteBuffer buffer) {
344 client.returnBuffer(buffer);
345 }
346
347 @Override
348 public final void setMinBufferSize(int n) {
349 client.setMinBufferSize(n);
350 }
351 }
< prev index next >