# HG changeset patch # User dfuchs # Date 1520362510 0 # Node ID 4b2272dfe7209ceeb26f8e17403aa736fc1b36f5 # Parent 875dbf6234f2b7c957d62080401e563a50505f7a http-client-branch: 8199135: Validate that method names are tokens diff -r 875dbf6234f2 -r 4b2272dfe720 src/java.net.http/share/classes/java/net/http/HttpRequest.java --- a/src/java.net.http/share/classes/java/net/http/HttpRequest.java Tue Mar 06 18:43:27 2018 +0000 +++ b/src/java.net.http/share/classes/java/net/http/HttpRequest.java Tue Mar 06 18:55:10 2018 +0000 @@ -272,7 +272,10 @@ * @param method the method to use * @param bodyPublisher the body publisher * @return this builder - * @throws IllegalArgumentException if the method is restricted + * @throws IllegalArgumentException if the method name is not + * valid, see + * RFC 7230 section-3.1.1, or the method is restricted by the + * implementation. */ public Builder method(String method, BodyPublisher bodyPublisher); diff -r 875dbf6234f2 -r 4b2272dfe720 src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java Tue Mar 06 18:43:27 2018 +0000 +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java Tue Mar 06 18:55:10 2018 +0000 @@ -195,6 +195,12 @@ throw newIAE("illegal method "); if (method.equals("CONNECT")) throw newIAE("method CONNECT is not supported"); + if (!Utils.isValidName(method)) + throw newIAE("illegal method \"" + + method.replace("\n","\\n") + .replace("\r", "\\r") + .replace("\t", "\\t") + + "\""); return method0(method, requireNonNull(body)); } diff -r 875dbf6234f2 -r 4b2272dfe720 src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java --- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java Tue Mar 06 18:43:27 2018 +0000 +++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestImpl.java Tue Mar 06 18:55:10 2018 +0000 @@ -41,6 +41,7 @@ import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import jdk.internal.net.http.common.HttpHeadersImpl; +import jdk.internal.net.http.common.Utils; import jdk.internal.net.http.websocket.WebSocketRequest; import static jdk.internal.net.http.common.Utils.ALLOWED_HEADERS; @@ -94,8 +95,14 @@ */ public HttpRequestImpl(HttpRequest request, ProxySelector ps) { String method = request.method(); + if (method != null && !Utils.isValidName(method)) + throw new IllegalArgumentException("illegal method \"" + + method.replace("\n","\\n") + .replace("\r", "\\r") + .replace("\t", "\\t") + + "\""); this.method = method == null ? "GET" : method; - this.userHeaders = request.headers(); + this.userHeaders = ImmutableHeaders.of(request.headers()); if (request instanceof HttpRequestImpl) { // all cases exception WebSocket should have a new system headers this.isWebSocket = ((HttpRequestImpl) request).isWebSocket; @@ -145,6 +152,7 @@ private HttpRequestImpl(URI uri, String method, HttpRequestImpl other) { + assert method == null || Utils.isValidName(method); this.method = method == null? "GET" : method; this.userHeaders = other.userHeaders; this.isWebSocket = other.isWebSocket; diff -r 875dbf6234f2 -r 4b2272dfe720 test/jdk/java/net/httpclient/MethodsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/net/httpclient/MethodsTest.java Tue Mar 06 18:55:10 2018 +0000 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2018, 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 jdk.internal.net.http.common.HttpHeadersImpl; + +import java.io.IOException; +import java.net.http.HttpClient; +import java.net.http.HttpHeaders; +import java.net.http.HttpRequest; +import java.net.URI; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.Optional; + +/** + * @test + * @bug 8199135 + * @modules java.net.http/jdk.internal.net.http.common + * @summary Basic test for method names + */ +public class MethodsTest { + + static final URI TEST_URI = URI.create("http://www.foo.com/"); + static final String FORBIDDEN = "()<>@,;:\\\"/[]?={} \t\r\n"; + + static void bad(String name) throws IOException, InterruptedException { + HttpRequest.Builder builder = HttpRequest.newBuilder(TEST_URI); + try { + builder.method(name, HttpRequest.BodyPublishers.noBody()); + throw new RuntimeException("Expected IAE for method:" + name); + } catch (IllegalArgumentException expected) { + System.out.println("Got expected IAE: " + expected); + } + try { + HttpRequest req = new HttpRequest() { + @Override public Optional bodyPublisher() { + return Optional.of(BodyPublishers.noBody()); + } + @Override public String method() { + return name; + } + @Override public Optional timeout() { + return Optional.empty(); + } + @Override public boolean expectContinue() { + return false; + } + @Override public URI uri() { + return TEST_URI; + } + @Override public Optional version() { + return Optional.empty(); + } + @Override public HttpHeaders headers() { + return new HttpHeadersImpl(); + } + }; + HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString()); + throw new RuntimeException("Expected IAE for method:" + name); + } catch (IllegalArgumentException expected) { + System.out.println("Got expected IAE: " + expected); + } + } + + static void good(String name) { + HttpRequest.Builder builder = HttpRequest.newBuilder(TEST_URI); + try { + builder.method(name, HttpRequest.BodyPublishers.noBody()); + } catch (IllegalArgumentException e) { + throw new RuntimeException("Unexpected IAE for header:" + name); + } + } + + public static void main(String[] args) throws Exception { + bad("bad:method"); + bad("Foo\n"); + good("X-Foo!"); + good("Bar~"); + good("x"); + bad(" "); + bad("x y"); + bad("x\t"); + bad("Bar\r\n"); + good("Hello#world"); + good("Qwer#ert"); + bad("m\u00e9thode"); + for (char c =0; c < 256 ; c++) { + if (c < 32 || FORBIDDEN.indexOf(c) > -1 || c >= 127) { + bad("me" + c + "thod"); + bad(c + "thod"); + bad("me" + c); + } else { + good("me" + c + "thod"); + good(c + "thod"); + good("me" + c); + } + } + } +}