8345625: Better HTTP connections

Reviewed-by: skoivu, rhalade, ahgross, dfuchs, jpai, aefimov
This commit is contained in:
Volkan Yazici 2025-02-06 11:49:15 +00:00 committed by Jaikiran Pai
parent 7aa3f31724
commit d1ea951d39
10 changed files with 109 additions and 49 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,8 +24,6 @@
*/
package sun.net.ftp.impl;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
@ -61,6 +59,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import sun.net.ftp.FtpDirEntry;
import sun.net.ftp.FtpDirParser;
import sun.net.ftp.FtpProtocolException;
@ -68,6 +67,7 @@ import sun.net.ftp.FtpReplyCode;
import sun.net.util.IPAddressUtil;
import sun.util.logging.PlatformLogger;
import static sun.net.util.ProxyUtil.copyProxy;
public class FtpClient extends sun.net.ftp.FtpClient {
@ -954,7 +954,7 @@ public class FtpClient extends sun.net.ftp.FtpClient {
}
public sun.net.ftp.FtpClient setProxy(Proxy p) {
proxy = p;
proxy = copyProxy(p);
return this;
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.util;
import sun.net.ApplicationProxy;
import java.net.Proxy;
public final class ProxyUtil {
private ProxyUtil() {}
/**
* Creates a new {@link Proxy} instance for the given proxy iff it is
* neither null, {@link Proxy#NO_PROXY Proxy.NO_PROXY}, an
* {@link ApplicationProxy} instance, nor already a {@code Proxy} instance.
*/
public static Proxy copyProxy(Proxy proxy) {
return proxy == null
|| proxy.getClass() == Proxy.class
|| proxy instanceof ApplicationProxy
? proxy
: new Proxy(proxy.type(), proxy.address());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -41,6 +41,8 @@ import sun.net.www.ParseUtil;
import sun.net.www.protocol.http.AuthCacheImpl;
import sun.net.www.protocol.http.HttpURLConnection;
import sun.util.logging.PlatformLogger;
import static sun.net.util.ProxyUtil.copyProxy;
import static sun.net.www.protocol.http.HttpURLConnection.TunnelState.*;
/**
@ -261,7 +263,7 @@ public class HttpClient extends NetworkClient {
}
protected HttpClient(URL url, Proxy p, int to) throws IOException {
proxy = (p == null) ? Proxy.NO_PROXY : p;
proxy = p == null ? Proxy.NO_PROXY : copyProxy(p);
this.host = url.getHost();
this.url = url;
port = url.getPort();
@ -326,9 +328,7 @@ public class HttpClient extends NetworkClient {
public static HttpClient New(URL url, Proxy p, int to, boolean useCache,
HttpURLConnection httpuc) throws IOException
{
if (p == null) {
p = Proxy.NO_PROXY;
}
p = p == null ? Proxy.NO_PROXY : copyProxy(p);
HttpClient ret = null;
/* see if one's already around */
if (useCache) {

View File

@ -43,6 +43,7 @@ import java.net.ProxySelector;
import java.util.List;
import java.util.StringTokenizer;
import java.security.Permission;
import sun.net.NetworkClient;
import sun.net.util.IPAddressUtil;
import sun.net.www.MessageHeader;
@ -53,6 +54,7 @@ import sun.net.ftp.FtpClient;
import sun.net.ftp.FtpProtocolException;
import sun.net.www.ParseUtil;
import static sun.net.util.ProxyUtil.copyProxy;
/**
* This class Opens an FTP input (or output) stream given a URL.
@ -234,7 +236,7 @@ public class FtpURLConnection extends URLConnection {
throw new IOException("Failed to select a proxy", iae);
}
for (Proxy proxy : proxies) {
p = proxy;
p = copyProxy(proxy);
if (p == null || p == Proxy.NO_PROXY ||
p.type() == Proxy.Type.SOCKS) {
break;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,11 +33,9 @@ import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.Proxy;
import java.util.Map;
import java.util.HashMap;
import java.util.Objects;
import sun.net.ftp.FtpClient;
import sun.net.www.protocol.http.HttpURLConnection;
import static sun.net.util.ProxyUtil.copyProxy;
/** open an ftp connection given a URL */
public class Handler extends java.net.URLStreamHandler {
@ -57,11 +55,11 @@ public class Handler extends java.net.URLStreamHandler {
return openConnection(u, null);
}
protected java.net.URLConnection openConnection(URL u, Proxy p)
protected java.net.URLConnection openConnection(URL u, Proxy proxy)
throws IOException {
FtpURLConnection connection = null;
FtpURLConnection connection;
try {
connection = new FtpURLConnection(u, p);
connection = new FtpURLConnection(u, copyProxy(proxy));
} catch (IllegalArgumentException e) {
var mfue = new MalformedURLException(e.getMessage());
mfue.initCause(e);

View File

@ -77,6 +77,7 @@ import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
import static sun.net.util.ProxyUtil.copyProxy;
import static sun.net.www.protocol.http.AuthScheme.BASIC;
import static sun.net.www.protocol.http.AuthScheme.DIGEST;
import static sun.net.www.protocol.http.AuthScheme.NTLM;
@ -854,7 +855,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
responses = new MessageHeader(maxHeaderSize);
userHeaders = new MessageHeader();
this.handler = handler;
instProxy = p;
instProxy = copyProxy(p);
cookieHandler = CookieHandler.getDefault();
cacheHandler = ResponseCache.getDefault();
}
@ -956,7 +957,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
final Iterator<Proxy> it = proxies.iterator();
Proxy p;
while (it.hasNext()) {
p = it.next();
p = copyProxy(it.next());
try {
if (!failedOnce) {
http = getNewHttpClient(url, p, connectTimeout);

View File

@ -1636,11 +1636,6 @@ final class HttpClientImpl extends HttpClient implements Trackable {
return Optional.ofNullable(userProxySelector);
}
// Return the effective proxy that this client uses.
ProxySelector proxySelector() {
return proxySelector;
}
@Override
public WebSocket.Builder newWebSocketBuilder() {
// Make sure to pass the HttpClientFacade to the WebSocket builder.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -45,10 +45,10 @@ import jdk.internal.net.http.common.HttpHeadersBuilder;
import jdk.internal.net.http.common.Utils;
import jdk.internal.net.http.websocket.WebSocketRequest;
import static java.net.Authenticator.RequestorType.PROXY;
import static java.net.Authenticator.RequestorType.SERVER;
import static jdk.internal.net.http.common.Utils.ALLOWED_HEADERS;
import static jdk.internal.net.http.common.Utils.ProxyHeaders;
import static jdk.internal.net.http.common.Utils.copyProxy;
public class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
@ -127,15 +127,7 @@ public class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
this.systemHeadersBuilder.setHeader("User-Agent", USER_AGENT);
}
this.uri = requestURI;
if (isWebSocket) {
// WebSocket determines and sets the proxy itself
this.proxy = ((HttpRequestImpl) request).proxy;
} else {
if (ps != null)
this.proxy = retrieveProxy(ps, uri);
else
this.proxy = null;
}
this.proxy = retrieveProxy(request, ps, uri);
this.expectContinue = request.expectContinue();
this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
this.requestPublisher = request.bodyPublisher().orElse(null);
@ -292,16 +284,27 @@ public class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
@Override
public boolean expectContinue() { return expectContinue; }
/** Retrieves the proxy, from the given ProxySelector, if there is one. */
private static Proxy retrieveProxy(ProxySelector ps, URI uri) {
Proxy proxy = null;
List<Proxy> pl = ps.select(uri);
if (!pl.isEmpty()) {
Proxy p = pl.get(0);
if (p.type() == Proxy.Type.HTTP)
proxy = p;
/** Retrieves a copy of the proxy either from the given {@link HttpRequest} or {@link ProxySelector}, if there is one. */
private static Proxy retrieveProxy(HttpRequest request, ProxySelector ps, URI uri) {
// WebSocket determines and sets the proxy itself
if (request instanceof HttpRequestImpl requestImpl && requestImpl.isWebSocket) {
return requestImpl.proxy;
}
return proxy;
// Try to find a matching one from the `ProxySelector`
if (ps != null) {
List<Proxy> pl = ps.select(uri);
if (!pl.isEmpty()) {
Proxy p = pl.getFirst();
if (p.type() == Proxy.Type.HTTP) {
return copyProxy(p);
}
}
}
return null;
}
InetSocketAddress proxy() {
@ -317,7 +320,7 @@ public class HttpRequestImpl extends HttpRequest implements WebSocketRequest {
@Override
public void setProxy(Proxy proxy) {
assert isWebSocket;
this.proxy = proxy;
this.proxy = copyProxy(proxy);
}
@Override

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -38,6 +38,7 @@ import java.io.UncheckedIOException;
import java.lang.System.Logger.Level;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URI;
import java.net.http.HttpHeaders;
import java.net.http.HttpTimeoutException;
@ -78,7 +79,6 @@ import sun.net.www.HeaderParser;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.US_ASCII;
import static java.util.stream.Collectors.joining;
import static java.net.Authenticator.RequestorType.PROXY;
import static java.net.Authenticator.RequestorType.SERVER;
@ -309,6 +309,17 @@ public final class Utils {
: ! PROXY_AUTH_DISABLED_SCHEMES.isEmpty();
}
/**
* Creates a new {@link Proxy} instance for the given proxy iff it is
* neither null, {@link Proxy#NO_PROXY Proxy.NO_PROXY}, nor already a
* {@code Proxy} instance.
*/
public static Proxy copyProxy(Proxy proxy) {
return proxy == null || proxy.getClass() == Proxy.class
? proxy
: new Proxy(proxy.type(), proxy.address());
}
// WebSocket connection Upgrade headers
private static final String HEADER_CONNECTION = "Connection";
private static final String HEADER_UPGRADE = "Upgrade";

View File

@ -59,6 +59,7 @@ import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import static java.lang.String.format;
import static jdk.internal.net.http.common.Utils.copyProxy;
import static jdk.internal.net.http.common.Utils.isValidName;
import static jdk.internal.net.http.common.Utils.stringOf;
import static jdk.internal.util.Exceptions.filterNonSocketInfo;
@ -369,7 +370,7 @@ public class OpeningHandshake {
if (proxy.type() != Proxy.Type.HTTP) {
return null;
}
return proxy;
return copyProxy(proxy);
}
}