/*
* Copyright (c) 2017, 2021, 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.
*/
/*
* @test
* @bug 8276559
* @summary HttpRequest[.Builder] API and behaviour checks
* @run testng RequestBuilderTest
*/
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import static java.time.Duration.ofNanos;
import static java.time.Duration.ofMinutes;
import static java.time.Duration.ofSeconds;
import static java.time.Duration.ZERO;
import static java.net.http.HttpClient.Version.HTTP_1_1;
import static java.net.http.HttpClient.Version.HTTP_2;
import static java.net.http.HttpRequest.newBuilder;
import static org.testng.Assert .*;
import org.testng.annotations.Test;
public class RequestBuilderTest {
static final URI uri = URI.create("http://foo.com/ ");
static final Class <NullPointerException> NPE = NullPointerException.class ;
static final Class <IllegalArgumentException> IAE = IllegalArgumentException.class ;
static final Class <IllegalStateException> ISE = IllegalStateException.class ;
static final Class <NumberFormatException> NFE = NumberFormatException.class ;
static final Class <UnsupportedOperationException> UOE = UnsupportedOperationException.class ;
@Test
public void testDefaults() {
List<HttpRequest.Builder> builders = List.of(newBuilder().uri(uri),
newBuilder(uri),
newBuilder().copy().uri(uri),
newBuilder(uri).copy());
for (HttpRequest.Builder builder : builders) {
assertFalse(builder.build().expectContinue());
assertEquals(builder.build().method(), "GET" );
assertFalse(builder.build().bodyPublisher().isPresent());
assertFalse(builder.build().version().isPresent());
assertFalse(builder.build().timeout().isPresent());
assertTrue(builder.build().headers() != null );
assertEquals(builder.build().headers().map().size(), 0);
}
}
@Test
public void testNull() {
HttpRequest.Builder builder = newBuilder();
assertThrows(NPE, () -> newBuilder(null ).build());
assertThrows(NPE, () -> newBuilder(uri).uri(null ).build());
assertThrows(NPE, () -> builder.uri(null ));
assertThrows(NPE, () -> builder.version(null ));
assertThrows(NPE, () -> builder.header(null , null ));
assertThrows(NPE, () -> builder.header("name" , null ));
assertThrows(NPE, () -> builder.header(null , "value" ));
assertThrows(NPE, () -> builder.headers(null ));
assertThrows(NPE, () -> builder.headers(new String[] { null , null }));
assertThrows(NPE, () -> builder.headers(new String[] { "name" , null }));
assertThrows(NPE, () -> builder.headers(new String[] { null , "value" }));
assertThrows(NPE, () -> builder.method(null , null ));
assertThrows(NPE, () -> builder.method("GET" , null ));
assertThrows(NPE, () -> builder.method("POST" , null ));
assertThrows(NPE, () -> builder.method("PUT" , null ));
assertThrows(NPE, () -> builder.method("DELETE" , null ));
assertThrows(NPE, () -> builder.setHeader(null , null ));
assertThrows(NPE, () -> builder.setHeader("name" , null ));
assertThrows(NPE, () -> builder.setHeader(null , "value" ));
assertThrows(NPE, () -> builder.timeout(null ));
assertThrows(NPE, () -> builder.POST(null ));
assertThrows(NPE, () -> builder.PUT(null ));
}
@Test
public void testURI() {
assertThrows(ISE, () -> newBuilder().build());
List<URI> uris = List.of(
URI.create("ws://foo.com"),
URI.create("wss://foo.com"),
URI.create("ftp://foo.com"),
URI.create("mailto:a@b.com" ),
URI.create("scheme:example.com" ),
URI.create("scheme:example.com" ),
URI.create("scheme:example.com/path" ),
URI.create("path" ),
URI.create("/path" )
);
for (URI u : uris) {
assertThrows(IAE, () -> newBuilder(u));
assertThrows(IAE, () -> newBuilder().uri(u));
}
assertEquals(newBuilder(uri).build().uri(), uri);
assertEquals(newBuilder().uri(uri).build().uri(), uri);
URI https = URI.create("https://foo.com ");
assertEquals(newBuilder(https).build().uri(), https);
assertEquals(newBuilder().uri(https).build().uri(), https);
}
@Test
public void testMethod() {
HttpRequest request = newBuilder(uri).build();
assertEquals(request.method(), "GET" );
assertTrue(!request.bodyPublisher().isPresent());
request = newBuilder(uri).GET().build();
assertEquals(request.method(), "GET" );
assertTrue(!request.bodyPublisher().isPresent());
request = newBuilder(uri).POST(BodyPublishers.ofString("" )).GET().build();
assertEquals(request.method(), "GET" );
assertTrue(!request.bodyPublisher().isPresent());
request = newBuilder(uri).PUT(BodyPublishers.ofString("" )).GET().build();
assertEquals(request.method(), "GET" );
assertTrue(!request.bodyPublisher().isPresent());
request = newBuilder(uri).DELETE ().GET().build();
assertEquals(request.method(), "GET" );
assertTrue(!request.bodyPublisher().isPresent());
request = newBuilder(uri).POST(BodyPublishers.ofString("" )).build();
assertEquals(request.method(), "POST" );
assertTrue(request.bodyPublisher().isPresent());
request = newBuilder(uri).PUT(BodyPublishers.ofString("" )).build();
assertEquals(request.method(), "PUT" );
assertTrue(request.bodyPublisher().isPresent());
request = newBuilder(uri).DELETE ().build();
assertEquals(request.method(), "DELETE" );
assertTrue(!request.bodyPublisher().isPresent());
request = newBuilder(uri).HEAD().build();
assertEquals(request.method(), "HEAD" );
assertFalse(request.bodyPublisher().isPresent());
request = newBuilder(uri).GET().POST(BodyPublishers.ofString("" )).build();
assertEquals(request.method(), "POST" );
assertTrue(request.bodyPublisher().isPresent());
request = newBuilder(uri).GET().PUT(BodyPublishers.ofString("" )).build();
assertEquals(request.method(), "PUT" );
assertTrue(request.bodyPublisher().isPresent());
request = newBuilder(uri).GET().DELETE ().build();
assertEquals(request.method(), "DELETE" );
assertTrue(!request.bodyPublisher().isPresent());
// CONNECT is disallowed in the implementation, since it is used for
// tunneling, and is handled separately for security checks.
assertThrows(IAE, () -> newBuilder(uri).method("CONNECT" , BodyPublishers.noBody()).build());
request = newBuilder(uri).method("GET" , BodyPublishers.noBody()).build();
assertEquals(request.method(), "GET" );
assertTrue(request.bodyPublisher().isPresent());
request = newBuilder(uri).method("POST" , BodyPublishers.ofString("" )).build();
assertEquals(request.method(), "POST" );
assertTrue(request.bodyPublisher().isPresent());
}
@Test
public void testHeaders() {
HttpRequest.Builder builder = newBuilder(uri);
String[] empty = new String[0];
assertThrows(IAE, () -> builder.headers(empty).build());
assertThrows(IAE, () -> builder.headers("1" ).build());
assertThrows(IAE, () -> builder.headers("1" , "2" , "3" ).build());
assertThrows(IAE, () -> builder.headers("1" , "2" , "3" , "4" , "5" ).build());
assertEquals(builder.build().headers().map().size(),0);
List<HttpRequest> requests = List.of(
// same header built from different combinations of the API
newBuilder(uri).header("A" , "B" ).build(),
newBuilder(uri).headers("A" , "B" ).build(),
newBuilder(uri).setHeader("A" , "B" ).build(),
newBuilder(uri).header("A" , "F" ).setHeader("A" , "B" ).build(),
newBuilder(uri).headers("A" , "F" ).setHeader("A" , "B" ).build()
);
for (HttpRequest r : requests) {
assertEquals(r.headers().map().size(), 1);
assertTrue(r.headers().firstValue("A" ).isPresent());
assertTrue(r.headers().firstValue("a" ).isPresent());
assertEquals(r.headers().firstValue("A" ).get(), "B" );
assertEquals(r.headers().allValues("A" ), List.of("B" ));
assertEquals(r.headers().allValues("C" ).size(), 0);
assertEquals(r.headers().map().get("A" ), List.of("B" ));
assertThrows(NFE, () -> r.headers().firstValueAsLong("A" ));
assertFalse(r.headers().firstValue("C" ).isPresent());
// a non-exhaustive list of mutators
assertThrows(UOE, () -> r.headers().map().put("Z" , List.of("Z" )));
assertThrows(UOE, () -> r.headers().map().remove("A" ));
assertThrows(UOE, () -> r.headers().map().remove("A" , "B" ));
assertThrows(UOE, () -> r.headers().map().clear());
assertThrows(UOE, () -> r.headers().allValues("A" ).remove("B" ));
assertThrows(UOE, () -> r.headers().allValues("A" ).remove(1));
assertThrows(UOE, () -> r.headers().allValues("A" ).clear());
assertThrows(UOE, () -> r.headers().allValues("A" ).add("Z" ));
assertThrows(UOE, () -> r.headers().allValues("A" ).addAll(List.of("Z" )));
assertThrows(UOE, () -> r.headers().allValues("A" ).add(1, "Z" ));
}
requests = List.of(
// same headers built from different combinations of the API
newBuilder(uri).header("A" , "B" )
.header("C" , "D" ).build(),
newBuilder(uri).header("A" , "B" )
.headers("C" , "D" ).build(),
newBuilder(uri).header("A" , "B" )
.setHeader("C" , "D" ).build(),
newBuilder(uri).headers("A" , "B" )
.headers("C" , "D" ).build(),
newBuilder(uri).headers("A" , "B" )
.header("C" , "D" ).build(),
newBuilder(uri).headers("A" , "B" )
.setHeader("C" , "D" ).build(),
newBuilder(uri).setHeader("A" , "B" )
.setHeader("C" , "D" ).build(),
newBuilder(uri).setHeader("A" , "B" )
.header("C" , "D" ).build(),
newBuilder(uri).setHeader("A" , "B" )
.headers("C" , "D" ).build(),
newBuilder(uri).headers("A" , "B" , "C" , "D" ).build()
);
for (HttpRequest r : requests) {
assertEquals(r.headers().map().size(), 2);
assertTrue(r.headers().firstValue("A" ).isPresent());
assertEquals(r.headers().firstValue("A" ).get(), "B" );
assertEquals(r.headers().allValues("A" ), List.of("B" ));
assertTrue(r.headers().firstValue("C" ).isPresent());
assertEquals(r.headers().firstValue("C" ).get(), "D" );
assertEquals(r.headers().allValues("C" ), List.of("D" ));
assertEquals(r.headers().map().get("C" ), List.of("D" ));
assertThrows(NFE, () -> r.headers().firstValueAsLong("C" ));
assertFalse(r.headers().firstValue("E" ).isPresent());
// a smaller non-exhaustive list of mutators
assertThrows(UOE, () -> r.headers().map().put("Z" , List.of("Z" )));
assertThrows(UOE, () -> r.headers().map().remove("C" ));
assertThrows(UOE, () -> r.headers().allValues("A" ).remove("B" ));
assertThrows(UOE, () -> r.headers().allValues("A" ).clear());
assertThrows(UOE, () -> r.headers().allValues("C" ).add("Z" ));
}
requests = List.of(
// same multi-value headers built from different combinations of the API
newBuilder(uri).header("A" , "B" )
.header("A" , "C" ).build(),
newBuilder(uri).header("A" , "B" )
.headers("A" , "C" ).build(),
newBuilder(uri).headers("A" , "B" )
.headers("A" , "C" ).build(),
newBuilder(uri).headers("A" , "B" )
.header("A" , "C" ).build(),
newBuilder(uri).setHeader("A" , "B" )
.header("A" , "C" ).build(),
newBuilder(uri).setHeader("A" , "B" )
.headers("A" , "C" ).build(),
newBuilder(uri).header("A" , "D" )
.setHeader("A" , "B" )
.headers("A" , "C" ).build(),
newBuilder(uri).headers("A" , "B" , "A" , "C" ).build()
);
for (HttpRequest r : requests) {
assertEquals(r.headers().map().size(), 1);
assertTrue(r.headers().firstValue("A" ).isPresent());
assertTrue(r.headers().allValues("A" ).containsAll(List.of("B" , "C" )));
assertEquals(r.headers().allValues("C" ).size(), 0);
assertEquals(r.headers().map().get("A" ), List.of("B" , "C" ));
assertThrows(NFE, () -> r.headers().firstValueAsLong("A" ));
assertFalse(r.headers().firstValue("C" ).isPresent());
// a non-exhaustive list of mutators
assertThrows(UOE, () -> r.headers().map().put("Z" , List.of("Z" )));
assertThrows(UOE, () -> r.headers().map().remove("A" ));
assertThrows(UOE, () -> r.headers().map().remove("A" , "B" ));
assertThrows(UOE, () -> r.headers().map().clear());
assertThrows(UOE, () -> r.headers().allValues("A" ).remove("B" ));
assertThrows(UOE, () -> r.headers().allValues("A" ).remove(1));
assertThrows(UOE, () -> r.headers().allValues("A" ).clear());
assertThrows(UOE, () -> r.headers().allValues("A" ).add("Z" ));
assertThrows(UOE, () -> r.headers().allValues("A" ).addAll(List.of("Z" )));
assertThrows(UOE, () -> r.headers().allValues("A" ).add(1, "Z" ));
}
// case-insensitivity
requests = List.of(
newBuilder(uri)
.header("Accept-Encoding" , "gzip, deflate" ).build(),
newBuilder(uri)
.header("accept-encoding" , "gzip, deflate" ).build(),
newBuilder(uri)
.header("AccePt-EncodINg" , "gzip, deflate" ).build(),
newBuilder(uri)
.header("AcCEpt-EncoDIng" , "gzip, deflate" ).build()
);
for (HttpRequest r : requests) {
for (String name : List.of("Accept-Encoding" , "accept-encoding" ,
"aCCept-EnCODing" , "accepT-encodinG" )) {
assertTrue(r.headers().firstValue(name).isPresent());
assertTrue(r.headers().allValues(name).contains("gzip, deflate" ));
assertEquals(r.headers().firstValue(name).get(), "gzip, deflate" );
assertEquals(r.headers().allValues(name).size(), 1);
assertEquals(r.headers().map().size(), 1);
assertEquals(r.headers().map().get(name).size(), 1);
assertEquals(r.headers().map().get(name).get(0), "gzip, deflate" );
}
}
}
// headers that are allowed now, but weren't before
private static final Set<String> FORMERLY_RESTRICTED = Set.of("referer" , "origin" ,
"OriGin" , "Referer" , "Date" , "via" , "WarnIng" );
@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" ,
"expect" , "host" , "upgrade" , "Connection" , "Content-Length" ,
"eXpect" , "hosT" , "upgradE" , "CONNection" , "CONTENT-LENGTH" ,
"EXPECT" , "Host" , "Upgrade" );
interface WithHeader {
HttpRequest.Builder withHeader(HttpRequest.Builder builder, String name, String value);
}
@Test
public void testRestricted() throws URISyntaxException {
URI uri = new URI("http://localhost:80/test/ ");
Map<String, WithHeader> lambdas = Map.of(
"Builder::header" , HttpRequest.Builder::header,
"Builder::headers" , (b, n, v) -> b.headers(n,v),
"Builder::setHeader" , HttpRequest.Builder::setHeader
);
for (Map.Entry<String, WithHeader> e : lambdas.entrySet()) {
System.out.println("Testing restricted headers with " + e.getKey());
WithHeader f = e.getValue();
for (String name : RESTRICTED) {
String value = name + "-value" ;
HttpRequest req = f.withHeader(HttpRequest.newBuilder(uri)
.GET(), "x-" + name, value).build();
String v = req.headers().firstValue("x-" + name).orElseThrow(
() -> new RuntimeException("header x-" + name + " not set" ));
assertEquals(v, value);
try {
f.withHeader(HttpRequest.newBuilder(uri)
.GET(), name, value).build();
throw new RuntimeException("Expected IAE not thrown for " + name);
} catch (IllegalArgumentException x) {
System.out.println("Got expected IAE for " + name + ": " + x);
}
}
}
}
@Test
public void testCopy() {
HttpRequest.Builder builder = newBuilder(uri).expectContinue(true )
.header("A" , "B" )
.POST(BodyPublishers.ofString("" ))
.timeout(ofSeconds(30))
.version(HTTP_1_1);
HttpRequest.Builder copy = builder.copy();
assertTrue(builder != copy);
// modify the original builder before building from the copy
builder.GET().timeout(ofSeconds(5)).version(HTTP_2).setHeader("A" , "C" );
HttpRequest copyRequest = copy.build();
assertEquals(copyRequest.uri(), uri);
assertEquals(copyRequest.expectContinue(), true );
assertEquals(copyRequest.headers().map().get("A" ), List.of("B" ));
assertEquals(copyRequest.method(), "POST" );
assertEquals(copyRequest.bodyPublisher().isPresent(), true );
assertEquals(copyRequest.timeout().get(), ofSeconds(30));
assertTrue(copyRequest.version().isPresent());
assertEquals(copyRequest.version().get(), HTTP_1_1);
// lazy set URI ( maybe builder as a template )
copyRequest = newBuilder().copy().uri(uri).build();
assertEquals(copyRequest.uri(), uri);
builder = newBuilder().header("C" , "D" );
copy = builder.copy();
copy.uri(uri);
copyRequest = copy.build();
assertEquals(copyRequest.uri(), uri);
assertEquals(copyRequest.headers().firstValue("C" ).get(), "D" );
}
@Test
public void testTimeout() {
HttpRequest.Builder builder = newBuilder(uri);
assertThrows(IAE, () -> builder.timeout(ZERO));
assertThrows(IAE, () -> builder.timeout(ofSeconds(0)));
assertThrows(IAE, () -> builder.timeout(ofSeconds(-1)));
assertThrows(IAE, () -> builder.timeout(ofNanos(-100)));
assertEquals(builder.timeout(ofNanos(15)).build().timeout().get(), ofNanos(15));
assertEquals(builder.timeout(ofSeconds(50)).build().timeout().get(), ofSeconds(50));
assertEquals(builder.timeout(ofMinutes(30)).build().timeout().get(), ofMinutes(30));
}
@Test
public void testExpect() {
HttpRequest.Builder builder = newBuilder(uri);
assertEquals(builder.build().expectContinue(), false );
assertEquals(builder.expectContinue(true ).build().expectContinue(), true );
assertEquals(builder.expectContinue(false ).build().expectContinue(), false );
assertEquals(builder.expectContinue(true ).build().expectContinue(), true );
}
@Test
public void testEquals() {
assertNotEquals(newBuilder(URI.create("http://foo.com ")),
newBuilder(URI.create("http://bar.com ")));
HttpRequest.Builder builder = newBuilder(uri);
assertEquals(builder.build(), builder.build());
assertEquals(builder.build(), newBuilder(uri).build());
builder.POST(BodyPublishers.noBody());
assertEquals(builder.build(), builder.build());
assertEquals(builder.build(), newBuilder(uri).POST(BodyPublishers.noBody()).build());
assertEquals(builder.build(), newBuilder(uri).POST(BodyPublishers.ofString("" )).build());
assertNotEquals(builder.build(), newBuilder(uri).build());
assertNotEquals(builder.build(), newBuilder(uri).GET().build());
assertNotEquals(builder.build(), newBuilder(uri).PUT(BodyPublishers.noBody()).build());
builder = newBuilder(uri).header("x" , "y" );
assertEquals(builder.build(), builder.build());
assertEquals(builder.build(), newBuilder(uri).header("x" , "y" ).build());
assertNotEquals(builder.build(), newBuilder(uri).header("x" , "Z" ).build());
assertNotEquals(builder.build(), newBuilder(uri).header("z" , "y" ).build());
}
}
quality 86%
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet)
¤
*© Formatika GbR, Deutschland