8203850: java.net.http HTTP client should allow specifying Origin and Referer headers
authormichaelm
Fri, 12 Oct 2018 11:12:51 +0100
changeset 52106 76d526565453
parent 52105 537dbfcef4a7
child 52107 0c1e44da019c
8203850: java.net.http HTTP client should allow specifying Origin and Referer headers Reviewed-by: chegar, dfuchs
src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java
test/jdk/java/net/httpclient/RequestBuilderTest.java
test/jdk/java/net/httpclient/SpecialHeadersTest.java
--- a/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java	Fri Oct 12 03:51:02 2018 -0400
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/Utils.java	Fri Oct 12 11:12:51 2018 +0100
@@ -133,9 +133,7 @@
         // A case insensitive TreeSet of strings.
         TreeSet<String> treeSet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
         treeSet.addAll(Set.of("connection", "content-length",
-                "date", "expect", "from", "host", "origin",
-                "referer", "upgrade",
-                "via", "warning"));
+                "date", "expect", "from", "host", "upgrade", "via", "warning"));
         DISALLOWED_HEADERS_SET = Collections.unmodifiableSet(treeSet);
     }
 
--- a/test/jdk/java/net/httpclient/RequestBuilderTest.java	Fri Oct 12 03:51:02 2018 -0400
+++ b/test/jdk/java/net/httpclient/RequestBuilderTest.java	Fri Oct 12 11:12:51 2018 +0100
@@ -337,15 +337,31 @@
         }
     }
 
+    // headers that are allowed now, but weren't before
+    private static final Set<String> FORMERLY_RESTRICTED = Set.of("referer", "origin",
+            "OriGin", "Referer");
+
+    @Test
+    public void testFormerlyRestricted()  throws URISyntaxException {
+        URI uri = new URI("http://localhost:80/test/");
+        URI otherURI = new URI("http://www.foo.com/test/");
+        for (String header : FORMERLY_RESTRICTED) {
+            HttpRequest req = HttpRequest.newBuilder(uri)
+                .header(header, otherURI.toString())
+                .GET()
+                .build();
+        }
+    }
+
     private static final Set<String> RESTRICTED = Set.of("connection", "content-length",
-            "date", "expect", "from", "host", "origin",
-            "referer", "upgrade", "via", "warning",
+            "date", "expect", "from", "host",
+            "upgrade", "via", "warning",
             "Connection", "Content-Length",
-            "DATE", "eXpect", "frOm", "hosT", "origIN",
-            "ReFerer", "upgradE", "vIa", "Warning",
+            "DATE", "eXpect", "frOm", "hosT",
+            "upgradE", "vIa", "Warning",
             "CONNection", "CONTENT-LENGTH",
-            "Date", "EXPECT", "From", "Host", "Origin",
-            "Referer", "Upgrade", "Via", "WARNING");
+            "Date", "EXPECT", "From", "Host",
+            "Upgrade", "Via", "WARNING");
 
     interface WithHeader {
         HttpRequest.Builder withHeader(HttpRequest.Builder builder, String name, String value);
--- a/test/jdk/java/net/httpclient/SpecialHeadersTest.java	Fri Oct 12 03:51:02 2018 -0400
+++ b/test/jdk/java/net/httpclient/SpecialHeadersTest.java	Fri Oct 12 11:12:51 2018 +0100
@@ -57,21 +57,25 @@
 import java.net.InetSocketAddress;
 import java.net.URI;
 import java.net.http.HttpClient;
+import java.net.http.HttpHeaders;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse;
 import java.net.http.HttpResponse.BodyHandlers;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Optional;
 
 import static java.lang.System.err;
 import static java.lang.System.out;
 import static java.net.http.HttpClient.Builder.NO_PROXY;
 import static java.nio.charset.StandardCharsets.US_ASCII;
+import org.testng.Assert;
 import static org.testng.Assert.assertEquals;
 
 public class SpecialHeadersTest implements HttpServerAdapters {
@@ -91,6 +95,13 @@
             {"User-Agent: camel-cased"},
             {"user-agent: all-lower-case"},
             {"user-Agent: mixed"},
+            // headers which were restricted before and are now allowable
+            {"referer: lower"},
+            {"Referer: normal"},
+            {"REFERER: upper"},
+            {"origin: lower"},
+            {"Origin: normal"},
+            {"ORIGIN: upper"},
     };
 
     @DataProvider(name = "variants")
@@ -169,6 +180,50 @@
     }
 
     @Test(dataProvider = "variants")
+    void testHomeMadeIllegalHeader(String uriString, String headerNameAndValue, boolean sameClient) throws Exception {
+        out.println("\n--- Starting ");
+        final URI uri = URI.create(uriString);
+
+        HttpClient client = HttpClient.newBuilder()
+                .proxy(NO_PROXY)
+                .sslContext(sslContext)
+                .build();
+
+        // Test a request which contains an illegal header created
+        HttpRequest req = new HttpRequest() {
+            @Override public Optional<BodyPublisher> bodyPublisher() {
+                return Optional.of(BodyPublishers.noBody());
+            }
+            @Override public String method() {
+                return "GET";
+            }
+            @Override public Optional<Duration> timeout() {
+                return Optional.empty();
+            }
+            @Override public boolean expectContinue() {
+                return false;
+            }
+            @Override public URI uri() {
+                return uri;
+            }
+            @Override public Optional<HttpClient.Version> version() {
+                return Optional.empty();
+            }
+            @Override public HttpHeaders headers() {
+                Map<String, List<String>> map = Map.of("via", List.of("http://foo.com"));
+                return HttpHeaders.of(map, (x, y) -> true);
+            }
+        };
+
+        try {
+            HttpResponse<String> response = client.send(req, BodyHandlers.ofString());
+            Assert.fail("Unexpected reply: " + response);
+        } catch (IllegalArgumentException ee) {
+            out.println("Got IAE as expected");
+        }
+    }
+
+    @Test(dataProvider = "variants")
     void testAsync(String uriString, String headerNameAndValue, boolean sameClient) {
         out.println("\n--- Starting ");
         int index = headerNameAndValue.indexOf(":");
@@ -259,7 +314,10 @@
         https2TestServer.stop();
     }
 
-    /** A handler that returns, as its body, the exact received request URI. */
+    /** A handler that returns, as its body, the exact received request URI.
+     *  The header whose name is in the URI query and is set in the request is
+     *  returned in the response with its name prefixed by X-
+     */
     static class HttpUriStringHandler implements HttpTestHandler {
         @Override
         public void handle(HttpTestExchange t) throws IOException {