|
|
d5c0b6 |
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java
|
|
|
d5c0b6 |
--- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java
|
|
|
d5c0b6 |
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java
|
|
|
d5c0b6 |
@@ -157,6 +157,7 @@
|
|
|
d5c0b6 |
return true;
|
|
|
d5c0b6 |
};
|
|
|
d5c0b6 |
|
|
|
d5c0b6 |
+ private static final Predicate<String> IS_HOST = "host"::equalsIgnoreCase;
|
|
|
d5c0b6 |
private static final Predicate<String> IS_PROXY_HEADER = (k) ->
|
|
|
d5c0b6 |
k != null && k.length() > 6 && "proxy-".equalsIgnoreCase(k.substring(0,6));
|
|
|
d5c0b6 |
private static final Predicate<String> NO_PROXY_HEADER =
|
|
|
d5c0b6 |
@@ -228,7 +229,8 @@
|
|
|
d5c0b6 |
|
|
|
d5c0b6 |
public static final BiPredicate<String, String> PROXY_TUNNEL_FILTER =
|
|
|
d5c0b6 |
(s,v) -> isAllowedForProxy(s, v, PROXY_AUTH_TUNNEL_DISABLED_SCHEMES,
|
|
|
d5c0b6 |
- IS_PROXY_HEADER);
|
|
|
d5c0b6 |
+ // Allows Proxy-* and Host headers when establishing the tunnel.
|
|
|
d5c0b6 |
+ IS_PROXY_HEADER.or(IS_HOST));
|
|
|
d5c0b6 |
public static final BiPredicate<String, String> PROXY_FILTER =
|
|
|
d5c0b6 |
(s,v) -> isAllowedForProxy(s, v, PROXY_AUTH_DISABLED_SCHEMES,
|
|
|
d5c0b6 |
ALL_HEADERS);
|
|
|
d5c0b6 |
diff --git a/test/jdk/java/net/httpclient/DigestEchoServer.java b/test/jdk/java/net/httpclient/DigestEchoServer.java
|
|
|
d5c0b6 |
--- a/test/jdk/java/net/httpclient/DigestEchoServer.java
|
|
|
d5c0b6 |
+++ b/test/jdk/java/net/httpclient/DigestEchoServer.java
|
|
|
d5c0b6 |
@@ -82,6 +82,8 @@
|
|
|
d5c0b6 |
Boolean.parseBoolean(System.getProperty("test.debug", "false"));
|
|
|
d5c0b6 |
public static final boolean NO_LINGER =
|
|
|
d5c0b6 |
Boolean.parseBoolean(System.getProperty("test.nolinger", "false"));
|
|
|
d5c0b6 |
+ public static final boolean TUNNEL_REQUIRES_HOST =
|
|
|
d5c0b6 |
+ Boolean.parseBoolean(System.getProperty("test.requiresHost", "false"));
|
|
|
d5c0b6 |
public enum HttpAuthType {
|
|
|
d5c0b6 |
SERVER, PROXY, SERVER307, PROXY305
|
|
|
d5c0b6 |
/* add PROXY_AND_SERVER and SERVER_PROXY_NONE */
|
|
|
d5c0b6 |
@@ -1524,6 +1526,36 @@
|
|
|
d5c0b6 |
}
|
|
|
d5c0b6 |
}
|
|
|
d5c0b6 |
|
|
|
d5c0b6 |
+ boolean badRequest(StringBuilder response, String hostport, List<String> hosts) {
|
|
|
d5c0b6 |
+ String message = null;
|
|
|
d5c0b6 |
+ if (hosts.isEmpty()) {
|
|
|
d5c0b6 |
+ message = "No host header provided\r\n";
|
|
|
d5c0b6 |
+ } else if (hosts.size() > 1) {
|
|
|
d5c0b6 |
+ message = "Multiple host headers provided\r\n";
|
|
|
d5c0b6 |
+ for (String h : hosts) {
|
|
|
d5c0b6 |
+ message = message + "host: " + h + "\r\n";
|
|
|
d5c0b6 |
+ }
|
|
|
d5c0b6 |
+ } else {
|
|
|
d5c0b6 |
+ String h = hosts.get(0);
|
|
|
d5c0b6 |
+ if (!hostport.equalsIgnoreCase(h)
|
|
|
d5c0b6 |
+ && !hostport.equalsIgnoreCase(h + ":80")
|
|
|
d5c0b6 |
+ && !hostport.equalsIgnoreCase(h + ":443")) {
|
|
|
d5c0b6 |
+ message = "Bad host provided: [" + h
|
|
|
d5c0b6 |
+ + "] doesnot match [" + hostport + "]\r\n";
|
|
|
d5c0b6 |
+ }
|
|
|
d5c0b6 |
+ }
|
|
|
d5c0b6 |
+ if (message != null) {
|
|
|
d5c0b6 |
+ int length = message.getBytes(StandardCharsets.UTF_8).length;
|
|
|
d5c0b6 |
+ response.append("HTTP/1.1 400 BadRequest\r\n")
|
|
|
d5c0b6 |
+ .append("Content-Length: " + length)
|
|
|
d5c0b6 |
+ .append("\r\n\r\n")
|
|
|
d5c0b6 |
+ .append(message);
|
|
|
d5c0b6 |
+ return true;
|
|
|
d5c0b6 |
+ }
|
|
|
d5c0b6 |
+
|
|
|
d5c0b6 |
+ return false;
|
|
|
d5c0b6 |
+ }
|
|
|
d5c0b6 |
+
|
|
|
d5c0b6 |
boolean authorize(StringBuilder response, String requestLine, String headers) {
|
|
|
d5c0b6 |
if (authorization != null) {
|
|
|
d5c0b6 |
return authorization.authorize(response, requestLine, headers);
|
|
|
d5c0b6 |
@@ -1637,6 +1669,7 @@
|
|
|
d5c0b6 |
assert connect.equalsIgnoreCase("connect");
|
|
|
d5c0b6 |
String hostport = tokenizer.nextToken();
|
|
|
d5c0b6 |
InetSocketAddress targetAddress;
|
|
|
d5c0b6 |
+ List<String> hosts = new ArrayList<>();
|
|
|
d5c0b6 |
try {
|
|
|
d5c0b6 |
URI uri = new URI("https", hostport, "/", null, null);
|
|
|
d5c0b6 |
int port = uri.getPort();
|
|
|
d5c0b6 |
@@ -1661,9 +1694,30 @@
|
|
|
d5c0b6 |
System.out.println(now() + "Tunnel: Reading header: "
|
|
|
d5c0b6 |
+ (line = readLine(ccis)));
|
|
|
d5c0b6 |
headers.append(line).append("\r\n");
|
|
|
d5c0b6 |
+ int index = line.indexOf(':');
|
|
|
d5c0b6 |
+ if (index >= 0) {
|
|
|
d5c0b6 |
+ String key = line.substring(0, index).trim();
|
|
|
d5c0b6 |
+ if (key.equalsIgnoreCase("host")) {
|
|
|
d5c0b6 |
+ hosts.add(line.substring(index+1).trim());
|
|
|
d5c0b6 |
+ }
|
|
|
d5c0b6 |
+ }
|
|
|
d5c0b6 |
+ }
|
|
|
d5c0b6 |
+ StringBuilder response = new StringBuilder();
|
|
|
d5c0b6 |
+ if (TUNNEL_REQUIRES_HOST) {
|
|
|
d5c0b6 |
+ if (badRequest(response, hostport, hosts)) {
|
|
|
d5c0b6 |
+ System.out.println(now() + "Tunnel: Sending " + response);
|
|
|
d5c0b6 |
+ // send the 400 response
|
|
|
d5c0b6 |
+ pw.print(response.toString());
|
|
|
d5c0b6 |
+ pw.flush();
|
|
|
d5c0b6 |
+ toClose.close();
|
|
|
d5c0b6 |
+ continue;
|
|
|
d5c0b6 |
+ } else {
|
|
|
d5c0b6 |
+ assert hosts.size() == 1;
|
|
|
d5c0b6 |
+ System.out.println(now()
|
|
|
d5c0b6 |
+ + "Tunnel: Host header verified " + hosts);
|
|
|
d5c0b6 |
+ }
|
|
|
d5c0b6 |
}
|
|
|
d5c0b6 |
|
|
|
d5c0b6 |
- StringBuilder response = new StringBuilder();
|
|
|
d5c0b6 |
final boolean authorize = authorize(response, requestLine, headers.toString());
|
|
|
d5c0b6 |
if (!authorize) {
|
|
|
d5c0b6 |
System.out.println(now() + "Tunnel: Sending "
|
|
|
d5c0b6 |
diff --git a/test/jdk/java/net/httpclient/HttpsTunnelTest.java b/test/jdk/java/net/httpclient/HttpsTunnelTest.java
|
|
|
d5c0b6 |
--- a/test/jdk/java/net/httpclient/HttpsTunnelTest.java
|
|
|
d5c0b6 |
+++ b/test/jdk/java/net/httpclient/HttpsTunnelTest.java
|
|
|
d5c0b6 |
@@ -1,5 +1,5 @@
|
|
|
d5c0b6 |
/*
|
|
|
d5c0b6 |
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
|
|
d5c0b6 |
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
d5c0b6 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
d5c0b6 |
*
|
|
|
d5c0b6 |
* This code is free software; you can redistribute it and/or modify it
|
|
|
d5c0b6 |
@@ -47,8 +47,9 @@
|
|
|
d5c0b6 |
* proxy P is downgraded to HTTP/1.1, then a new h2 request
|
|
|
d5c0b6 |
* going to a different host through the same proxy will not
|
|
|
d5c0b6 |
* be preemptively downgraded. That, is the stack should attempt
|
|
|
d5c0b6 |
- * a new h2 connection to the new host.
|
|
|
d5c0b6 |
- * @bug 8196967
|
|
|
d5c0b6 |
+ * a new h2 connection to the new host. It also verifies that
|
|
|
d5c0b6 |
+ * the stack sends the appropriate "host" header to the proxy.
|
|
|
d5c0b6 |
+ * @bug 8196967 8222527
|
|
|
d5c0b6 |
* @library /lib/testlibrary http2/server
|
|
|
d5c0b6 |
* @build jdk.testlibrary.SimpleSSLContext HttpServerAdapters DigestEchoServer HttpsTunnelTest
|
|
|
d5c0b6 |
* @modules java.net.http/jdk.internal.net.http.common
|
|
|
d5c0b6 |
@@ -58,7 +59,10 @@
|
|
|
d5c0b6 |
* java.base/sun.net.www.http
|
|
|
d5c0b6 |
* java.base/sun.net.www
|
|
|
d5c0b6 |
* java.base/sun.net
|
|
|
d5c0b6 |
- * @run main/othervm -Djdk.internal.httpclient.debug=true HttpsTunnelTest
|
|
|
d5c0b6 |
+ * @run main/othervm -Dtest.requiresHost=true
|
|
|
d5c0b6 |
+ * -Djdk.httpclient.HttpClient.log=headers
|
|
|
d5c0b6 |
+ * -Djdk.internal.httpclient.debug=true HttpsTunnelTest
|
|
|
d5c0b6 |
+ *
|
|
|
d5c0b6 |
*/
|
|
|
d5c0b6 |
|
|
|
d5c0b6 |
public class HttpsTunnelTest implements HttpServerAdapters {
|
|
|
d5c0b6 |
@@ -145,6 +149,7 @@
|
|
|
d5c0b6 |
if (!lines.equals(respLines)) {
|
|
|
d5c0b6 |
throw new RuntimeException("Unexpected response 1: " + respLines);
|
|
|
d5c0b6 |
}
|
|
|
d5c0b6 |
+
|
|
|
d5c0b6 |
HttpRequest.BodyPublisher reqBody2 = HttpRequest.BodyPublishers.ofString(body);
|
|
|
d5c0b6 |
HttpRequest req2 = HttpRequest
|
|
|
d5c0b6 |
.newBuilder(uri2)
|
|
|
d5c0b6 |
diff --git a/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java b/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java
|
|
|
d5c0b6 |
--- a/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java
|
|
|
d5c0b6 |
+++ b/test/jdk/java/net/httpclient/ProxyAuthDisabledSchemesSSL.java
|
|
|
d5c0b6 |
@@ -1,5 +1,5 @@
|
|
|
d5c0b6 |
/*
|
|
|
d5c0b6 |
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
|
|
d5c0b6 |
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
d5c0b6 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
d5c0b6 |
*
|
|
|
d5c0b6 |
* This code is free software; you can redistribute it and/or modify it
|
|
|
d5c0b6 |
@@ -23,7 +23,7 @@
|
|
|
d5c0b6 |
|
|
|
d5c0b6 |
/**
|
|
|
d5c0b6 |
* @test
|
|
|
d5c0b6 |
- * @bug 8087112
|
|
|
d5c0b6 |
+ * @bug 8087112 8222527
|
|
|
d5c0b6 |
* @summary this test verifies that a client may provides authorization
|
|
|
d5c0b6 |
* headers directly when connecting with a server over SSL, and
|
|
|
d5c0b6 |
* it verifies that the client honor the jdk.http.auth.*.disabledSchemes
|
|
|
d5c0b6 |
@@ -43,9 +43,11 @@
|
|
|
d5c0b6 |
* ProxyAuthDisabledSchemesSSL SSL
|
|
|
d5c0b6 |
* @run main/othervm -Djdk.http.auth.proxying.disabledSchemes=Basic
|
|
|
d5c0b6 |
* -Djdk.http.auth.tunneling.disabledSchemes=Basic
|
|
|
d5c0b6 |
+ * -Dtest.requiresHost=true
|
|
|
d5c0b6 |
* ProxyAuthDisabledSchemesSSL SSL PROXY
|
|
|
d5c0b6 |
* @run main/othervm -Djdk.http.auth.proxying.disabledSchemes=Digest
|
|
|
d5c0b6 |
* -Djdk.http.auth.tunneling.disabledSchemes=Digest
|
|
|
d5c0b6 |
+ * -Dtest.requiresHost=true
|
|
|
d5c0b6 |
* ProxyAuthDisabledSchemesSSL SSL PROXY
|
|
|
d5c0b6 |
*/
|
|
|
d5c0b6 |
|