# HG changeset patch # User dfuchs # Date 1502191961 -3600 # Node ID 5982afcbf9dce1d2fa4f64c143af8734710d91fb # Parent 14df107500cc3b8ab238c3e4ad2c74e12bfe6067 8185852: HttpConnection should resolve addresses before SocketChannel.connect() is called Summary: HttpConnection checks whether the proxy address is resolved and if not attempts to resolve it before creating the underlying connection that connects to the proxy. Reviewed-by: chegar diff -r 14df107500cc -r 5982afcbf9dc jdk/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpConnection.java --- a/jdk/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpConnection.java Thu Aug 24 16:34:44 2017 +0200 +++ b/jdk/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpConnection.java Tue Aug 08 12:32:41 2017 +0100 @@ -154,6 +154,12 @@ { HttpConnection c = null; InetSocketAddress proxy = request.proxy(client); + if (proxy != null && proxy.isUnresolved()) { + // The default proxy selector may select a proxy whose + // address is unresolved. We must resolve the address + // before using it to connect. + proxy = new InetSocketAddress(proxy.getHostString(), proxy.getPort()); + } boolean secure = request.secure(); ConnectionPool pool = client.connectionPool(); String[] alpn = null; diff -r 14df107500cc -r 5982afcbf9dc jdk/test/java/net/httpclient/ProxyTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/net/httpclient/ProxyTest.java Tue Aug 08 12:32:41 2017 +0100 @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2017, 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. + * + * 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. + */ + +import com.sun.net.httpserver.HttpContext; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; +import com.sun.net.httpserver.HttpsConfigurator; +import com.sun.net.httpserver.HttpsParameters; +import com.sun.net.httpserver.HttpsServer; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Writer; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import jdk.incubator.http.HttpClient; +import jdk.incubator.http.HttpRequest; +import jdk.incubator.http.HttpResponse; +import jdk.testlibrary.SimpleSSLContext; + +/** + * @test + * @bug 8185852 + * @summary verifies that passing a proxy with an unresolved address does + * not cause java.nio.channels.UnresolvedAddressException + * @modules jdk.incubator.httpclient + * @library /lib/testlibrary/ + * @build jdk.testlibrary.SimpleSSLContext ProxyTest + * @run main/othervm ProxyTest + * @author danielfuchs + */ +public class ProxyTest { + + static { + try { + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + SSLContext.setDefault(new SimpleSSLContext().get()); + } catch (IOException ex) { + throw new ExceptionInInitializerError(ex); + } + } + + static final String RESPONSE = "
Hello World!";
+ static final String PATH = "/foo/";
+
+ static HttpServer createHttpsServer() throws IOException, NoSuchAlgorithmException {
+ HttpsServer server = com.sun.net.httpserver.HttpsServer.create();
+ HttpContext context = server.createContext(PATH);
+ context.setHandler(new HttpHandler() {
+ @Override
+ public void handle(HttpExchange he) throws IOException {
+ he.getResponseHeaders().add("encoding", "UTF-8");
+ he.sendResponseHeaders(200, RESPONSE.length());
+ he.getResponseBody().write(RESPONSE.getBytes(StandardCharsets.UTF_8));
+ he.close();
+ }
+ });
+
+ server.setHttpsConfigurator(new Configurator(SSLContext.getDefault()));
+ server.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
+ return server;
+ }
+
+ public static void main(String[] args)
+ throws IOException,
+ URISyntaxException,
+ NoSuchAlgorithmException,
+ InterruptedException
+ {
+ HttpServer server = createHttpsServer();
+ server.start();
+ try {
+ test(server, HttpClient.Version.HTTP_1_1);
+ // test(server, HttpClient.Version.HTTP_2);
+ } finally {
+ server.stop(0);
+ System.out.println("Server stopped");
+ }
+ }
+
+ public static void test(HttpServer server, HttpClient.Version version)
+ throws IOException,
+ URISyntaxException,
+ NoSuchAlgorithmException,
+ InterruptedException
+ {
+ System.out.println("Server is: " + server.getAddress().toString());
+ System.out.println("Verifying communication with server");
+ URI uri = new URI("https:/" + server.getAddress().toString() + PATH + "x");
+ try (InputStream is = uri.toURL().openConnection().getInputStream()) {
+ String resp = new String(is.readAllBytes(), StandardCharsets.UTF_8);
+ System.out.println(resp);
+ if (!RESPONSE.equals(resp)) {
+ throw new AssertionError("Unexpected response from server");
+ }
+ }
+ System.out.println("Communication with server OK");
+
+ TunnelingProxy proxy = new TunnelingProxy(server);
+ proxy.start();
+ try {
+ System.out.println("Proxy started");
+ Proxy p = new Proxy(Proxy.Type.HTTP,
+ InetSocketAddress.createUnresolved("localhost", proxy.getAddress().getPort()));
+ System.out.println("Verifying communication with proxy");
+ HttpURLConnection conn = (HttpURLConnection)uri.toURL().openConnection(p);
+ try (InputStream is = conn.getInputStream()) {
+ String resp = new String(is.readAllBytes(), StandardCharsets.UTF_8);
+ System.out.println(resp);
+ if (!RESPONSE.equals(resp)) {
+ throw new AssertionError("Unexpected response from proxy");
+ }
+ }
+ System.out.println("Communication with proxy OK");
+ System.out.println("\nReal test begins here.");
+ System.out.println("Setting up request with HttpClient for version: "
+ + version.name());
+ ProxySelector ps = ProxySelector.of(
+ InetSocketAddress.createUnresolved("localhost", proxy.getAddress().getPort()));
+ HttpClient client = HttpClient.newBuilder()
+ .version(version)
+ .proxy(ps)
+ .build();
+ HttpRequest request = HttpRequest.newBuilder()
+ .uri(uri)
+ .GET()
+ .build();
+
+ System.out.println("Sending request with HttpClient");
+ HttpResponse