Skip to content

Commit 5fc18f5

Browse files
Volkan Yazicijaikiran
Volkan Yazici
authored andcommitted
8350279: HttpClient: Add a new HttpResponse method to identify connections
Reviewed-by: dfuchs, jpai
1 parent 03fd43f commit 5fc18f5

File tree

12 files changed

+600
-35
lines changed

12 files changed

+600
-35
lines changed

src/java.net.http/share/classes/java/net/http/HttpResponse.java

+22
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,28 @@ public interface HttpResponse<T> {
9999
*/
100100
public int statusCode();
101101

102+
/**
103+
* {@return if present, a label identifying the connection on which the
104+
* response was received}
105+
* <p>
106+
* The format of the string is opaque, but the value is fixed and unique
107+
* for any connection in the scope of the associated {@link HttpClient}
108+
* instance.
109+
*
110+
* @implSpec
111+
* The default implementation of this method returns
112+
* {@link Optional#empty() Optional.empty()}.
113+
*
114+
* @implNote
115+
* Instances of {@code HttpResponse} returned by the JDK built-in
116+
* implementation of {@code HttpClient} always return a non-empty value.
117+
*
118+
* @since 25
119+
*/
120+
default Optional<String> connectionLabel() {
121+
return Optional.empty();
122+
}
123+
102124
/**
103125
* Returns the {@link HttpRequest} corresponding to this response.
104126
*

src/java.net.http/share/classes/jdk/internal/net/http/AbstractAsyncSSLConnection.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ abstract class AbstractAsyncSSLConnection extends HttpConnection
7474
AbstractAsyncSSLConnection(InetSocketAddress addr,
7575
HttpClientImpl client,
7676
ServerName serverName, int port,
77-
String[] alpn) {
78-
super(addr, client);
77+
String[] alpn,
78+
String label) {
79+
super(addr, client, label);
7980
this.sniServerNames = formSNIServerNames(serverName, client);
8081
SSLContext context = client.theSSLContext();
8182
sslParameters = createSSLParameters(client, this.sniServerNames, alpn);

src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLConnection.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ class AsyncSSLConnection extends AbstractAsyncSSLConnection {
4444

4545
AsyncSSLConnection(InetSocketAddress addr,
4646
HttpClientImpl client,
47-
String[] alpn) {
48-
super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn);
49-
plainConnection = new PlainHttpConnection(addr, client);
47+
String[] alpn,
48+
String label) {
49+
super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn, label);
50+
plainConnection = new PlainHttpConnection(addr, client, label);
5051
writePublisher = new PlainHttpPublisher();
5152
}
5253

src/java.net.http/share/classes/jdk/internal/net/http/AsyncSSLTunnelConnection.java

+4-3
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,11 @@ class AsyncSSLTunnelConnection extends AbstractAsyncSSLConnection {
4747
HttpClientImpl client,
4848
String[] alpn,
4949
InetSocketAddress proxy,
50-
ProxyHeaders proxyHeaders)
50+
ProxyHeaders proxyHeaders,
51+
String label)
5152
{
52-
super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn);
53-
this.plainConnection = new PlainTunnelingConnection(addr, proxy, client, proxyHeaders);
53+
super(addr, client, Utils.getServerName(addr), addr.getPort(), alpn, label);
54+
this.plainConnection = new PlainTunnelingConnection(addr, proxy, client, proxyHeaders, label);
5455
this.writePublisher = new PlainHttpPublisher();
5556
}
5657

src/java.net.http/share/classes/jdk/internal/net/http/HttpConnection.java

+42-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,7 @@
2828
import java.io.Closeable;
2929
import java.io.IOException;
3030
import java.net.InetSocketAddress;
31+
import java.net.http.HttpResponse;
3132
import java.nio.ByteBuffer;
3233
import java.nio.channels.SocketChannel;
3334
import java.util.Arrays;
@@ -39,6 +40,7 @@
3940
import java.util.concurrent.CompletionStage;
4041
import java.util.concurrent.ConcurrentLinkedDeque;
4142
import java.util.concurrent.Flow;
43+
import java.util.concurrent.atomic.AtomicLong;
4244
import java.util.function.BiPredicate;
4345
import java.util.function.Predicate;
4446
import java.net.http.HttpClient;
@@ -76,17 +78,46 @@ abstract class HttpConnection implements Closeable {
7678
public static final Comparator<HttpConnection> COMPARE_BY_ID
7779
= Comparator.comparing(HttpConnection::id);
7880

81+
private static final AtomicLong LABEL_COUNTER = new AtomicLong();
82+
7983
/** The address this connection is connected to. Could be a server or a proxy. */
8084
final InetSocketAddress address;
8185
private final HttpClientImpl client;
8286
private final TrailingOperations trailingOperations;
87+
88+
/**
89+
* A unique identifier that provides a total order among instances.
90+
*/
8391
private final long id;
8492

85-
HttpConnection(InetSocketAddress address, HttpClientImpl client) {
93+
/**
94+
* A label to identify the connection.
95+
* <p>
96+
* This label helps with associating multiple components participating in a
97+
* connection. For instance, an {@link AsyncSSLConnection} and the
98+
* {@link PlainHttpConnection} it wraps will share the same label.
99+
* </p>
100+
*/
101+
private final String label;
102+
103+
HttpConnection(InetSocketAddress address, HttpClientImpl client, String label) {
86104
this.address = address;
87105
this.client = client;
88106
trailingOperations = new TrailingOperations();
89107
this.id = newConnectionId(client);
108+
this.label = label;
109+
}
110+
111+
private static String nextLabel() {
112+
return "" + LABEL_COUNTER.incrementAndGet();
113+
}
114+
115+
/**
116+
* {@return a label identifying the connection to facilitate
117+
* {@link HttpResponse#connectionLabel() HttpResponse::connectionLabel}}
118+
*/
119+
public final String label() {
120+
return label;
90121
}
91122

92123
// This is overridden in tests
@@ -303,11 +334,13 @@ private static HttpConnection getSSLConnection(InetSocketAddress addr,
303334
String[] alpn,
304335
HttpRequestImpl request,
305336
HttpClientImpl client) {
337+
String label = nextLabel();
306338
if (proxy != null)
307339
return new AsyncSSLTunnelConnection(addr, client, alpn, proxy,
308-
proxyTunnelHeaders(request));
340+
proxyTunnelHeaders(request),
341+
label);
309342
else
310-
return new AsyncSSLConnection(addr, client, alpn);
343+
return new AsyncSSLConnection(addr, client, alpn, label);
311344
}
312345

313346
/**
@@ -381,14 +414,16 @@ private static HttpConnection getPlainConnection(InetSocketAddress addr,
381414
InetSocketAddress proxy,
382415
HttpRequestImpl request,
383416
HttpClientImpl client) {
417+
String label = nextLabel();
384418
if (request.isWebSocket() && proxy != null)
385419
return new PlainTunnelingConnection(addr, proxy, client,
386-
proxyTunnelHeaders(request));
420+
proxyTunnelHeaders(request),
421+
label);
387422

388423
if (proxy == null)
389-
return new PlainHttpConnection(addr, client);
424+
return new PlainHttpConnection(addr, client, label);
390425
else
391-
return new PlainProxyConnection(proxy, client);
426+
return new PlainProxyConnection(proxy, client, label);
392427
}
393428

394429
void closeOrReturnToCache(HttpHeaders hdrs) {

src/java.net.http/share/classes/jdk/internal/net/http/HttpResponseImpl.java

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -44,6 +44,7 @@
4444
class HttpResponseImpl<T> implements HttpResponse<T>, RawChannel.Provider {
4545

4646
final int responseCode;
47+
private final String connectionLabel;
4748
final HttpRequest initialRequest;
4849
final Optional<HttpResponse<T>> previousResponse;
4950
final HttpHeaders headers;
@@ -59,6 +60,7 @@ public HttpResponseImpl(HttpRequest initialRequest,
5960
T body,
6061
Exchange<T> exch) {
6162
this.responseCode = response.statusCode();
63+
this.connectionLabel = connectionLabel(exch).orElse(null);
6264
this.initialRequest = initialRequest;
6365
this.previousResponse = Optional.ofNullable(previousResponse);
6466
this.headers = response.headers();
@@ -70,11 +72,23 @@ public HttpResponseImpl(HttpRequest initialRequest,
7072
this.body = body;
7173
}
7274

75+
private static Optional<String> connectionLabel(Exchange<?> exchange) {
76+
return Optional.ofNullable(exchange)
77+
.map(e -> e.exchImpl)
78+
.map(ExchangeImpl::connection)
79+
.map(HttpConnection::label);
80+
}
81+
7382
@Override
7483
public int statusCode() {
7584
return responseCode;
7685
}
7786

87+
@Override
88+
public Optional<String> connectionLabel() {
89+
return Optional.ofNullable(connectionLabel);
90+
}
91+
7892
@Override
7993
public HttpRequest request() {
8094
return initialRequest;

src/java.net.http/share/classes/jdk/internal/net/http/PlainHttpConnection.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,8 @@ final FlowTube getConnectionFlow() {
310310
return tube;
311311
}
312312

313-
PlainHttpConnection(InetSocketAddress addr, HttpClientImpl client) {
314-
super(addr, client);
313+
PlainHttpConnection(InetSocketAddress addr, HttpClientImpl client, String label) {
314+
super(addr, client, label);
315315
try {
316316
this.chan = SocketChannel.open();
317317
chan.configureBlocking(false);
@@ -335,7 +335,7 @@ final FlowTube getConnectionFlow() {
335335
}
336336
chan.setOption(StandardSocketOptions.TCP_NODELAY, true);
337337
// wrap the channel in a Tube for async reading and writing
338-
tube = new SocketTube(client(), chan, Utils::getBuffer);
338+
tube = new SocketTube(client(), chan, Utils::getBuffer, label);
339339
} catch (IOException e) {
340340
throw new InternalError(e);
341341
}

src/java.net.http/share/classes/jdk/internal/net/http/PlainProxyConnection.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -29,8 +29,8 @@
2929

3030
class PlainProxyConnection extends PlainHttpConnection {
3131

32-
PlainProxyConnection(InetSocketAddress proxy, HttpClientImpl client) {
33-
super(proxy, client);
32+
PlainProxyConnection(InetSocketAddress proxy, HttpClientImpl client, String label) {
33+
super(proxy, client, label);
3434
}
3535

3636
@Override

src/java.net.http/share/classes/jdk/internal/net/http/PlainTunnelingConnection.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -54,11 +54,12 @@ final class PlainTunnelingConnection extends HttpConnection {
5454
protected PlainTunnelingConnection(InetSocketAddress addr,
5555
InetSocketAddress proxy,
5656
HttpClientImpl client,
57-
ProxyHeaders proxyHeaders) {
58-
super(addr, client);
57+
ProxyHeaders proxyHeaders,
58+
String label) {
59+
super(addr, client, label);
5960
this.proxyAddr = proxy;
6061
this.proxyHeaders = proxyHeaders;
61-
delegate = new PlainHttpConnection(proxy, client);
62+
delegate = new PlainHttpConnection(proxy, client, label);
6263
}
6364

6465
@Override

src/java.net.http/share/classes/jdk/internal/net/http/SocketTube.java

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,6 @@
3131
import java.util.Objects;
3232
import java.util.concurrent.ConcurrentLinkedQueue;
3333
import java.util.concurrent.Flow;
34-
import java.util.concurrent.atomic.AtomicLong;
3534
import java.util.concurrent.atomic.AtomicReference;
3635
import java.nio.channels.SelectableChannel;
3736
import java.nio.channels.SelectionKey;
@@ -59,7 +58,6 @@
5958
final class SocketTube implements FlowTube {
6059

6160
final Logger debug = Utils.getDebugLogger(this::dbgString, Utils.DEBUG);
62-
static final AtomicLong IDS = new AtomicLong();
6361

6462
private final HttpClientImpl client;
6563
private final SocketChannel channel;
@@ -68,14 +66,15 @@ final class SocketTube implements FlowTube {
6866
private final AtomicReference<Throwable> errorRef = new AtomicReference<>();
6967
private final InternalReadPublisher readPublisher;
7068
private final InternalWriteSubscriber writeSubscriber;
71-
private final long id = IDS.incrementAndGet();
69+
private final String connectionLabel;
7270

7371
public SocketTube(HttpClientImpl client, SocketChannel channel,
74-
Supplier<ByteBuffer> buffersFactory) {
72+
Supplier<ByteBuffer> buffersFactory,
73+
String connectionLabel) {
7574
this.client = client;
7675
this.channel = channel;
7776
this.sliceBuffersSource = new SliceBufferSource(buffersFactory);
78-
77+
this.connectionLabel = connectionLabel;
7978
this.readPublisher = new InternalReadPublisher();
8079
this.writeSubscriber = new InternalWriteSubscriber();
8180
}
@@ -1343,7 +1342,7 @@ public String toString() {
13431342
}
13441343

13451344
final String dbgString() {
1346-
return "SocketTube("+id+")";
1345+
return "SocketTube("+ connectionLabel +")";
13471346
}
13481347

13491348
final String channelDescr() {

0 commit comments

Comments
 (0)