1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @summary HttpRequest[.Builder] API and behaviour checks
  27  * @run testng RequestBuilderTest
  28  */
  29 
  30 import java.net.URI;
  31 import java.util.List;
  32 import jdk.incubator.http.HttpRequest;
  33 import static java.time.Duration.ofNanos;
  34 import static java.time.Duration.ofMinutes;
  35 import static java.time.Duration.ofSeconds;
  36 import static java.time.Duration.ZERO;
  37 import static jdk.incubator.http.HttpClient.Version.HTTP_1_1;
  38 import static jdk.incubator.http.HttpClient.Version.HTTP_2;
  39 import static jdk.incubator.http.HttpRequest.BodyPublisher.fromString;
  40 import static jdk.incubator.http.HttpRequest.BodyPublisher.noBody;
  41 import static jdk.incubator.http.HttpRequest.newBuilder;
  42 import static org.testng.Assert.*;
  43 import org.testng.annotations.Test;
  44 
  45 public class RequestBuilderTest {
  46 
  47     static final URI uri = URI.create("http://foo.com/");
  48     static final Class<NullPointerException> NPE = NullPointerException.class;
  49     static final Class<IllegalArgumentException> IAE = IllegalArgumentException.class;
  50     static final Class<IllegalStateException> ISE = IllegalStateException.class;
  51     static final Class<NumberFormatException> NFE = NumberFormatException.class;
  52     static final Class<UnsupportedOperationException> UOE = UnsupportedOperationException.class;
  53 
  54     @Test
  55     public void testDefaults() {
  56         List<HttpRequest.Builder> builders = List.of(newBuilder().uri(uri),
  57                                                      newBuilder(uri));
  58         for (HttpRequest.Builder builder : builders) {
  59             assertFalse(builder.build().expectContinue());
  60             assertEquals(builder.build().method(), "GET");
  61             assertFalse(builder.build().bodyPublisher().isPresent());
  62             assertFalse(builder.build().version().isPresent());
  63             assertFalse(builder.build().timeout().isPresent());
  64             assertTrue(builder.build().headers() != null);
  65             assertEquals(builder.build().headers().map().size(), 0);
  66         }
  67     }
  68 
  69     @Test
  70     public void testNull() {
  71         HttpRequest.Builder builder = newBuilder();
  72 
  73         assertThrows(NPE, () -> newBuilder(null).build());
  74         assertThrows(NPE, () -> newBuilder(uri).uri(null).build());
  75         assertThrows(NPE, () -> builder.uri(null));
  76         assertThrows(NPE, () -> builder.version(null));
  77         assertThrows(NPE, () -> builder.header(null, null));
  78         assertThrows(NPE, () -> builder.header("name", null));
  79         assertThrows(NPE, () -> builder.header(null, "value"));
  80         assertThrows(NPE, () -> builder.headers(null));
  81         assertThrows(NPE, () -> builder.headers(new String[] { null, null }));
  82         assertThrows(NPE, () -> builder.headers(new String[] { "name", null }));
  83         assertThrows(NPE, () -> builder.headers(new String[] { null, "value" }));
  84         assertThrows(NPE, () -> builder.method(null, null));
  85         assertThrows(NPE, () -> builder.method("GET", null));
  86         assertThrows(NPE, () -> builder.method("POST", null));
  87         assertThrows(NPE, () -> builder.method("PUT", null));
  88         assertThrows(NPE, () -> builder.method("DELETE", null));
  89         assertThrows(NPE, () -> builder.setHeader(null, null));
  90         assertThrows(NPE, () -> builder.setHeader("name", null));
  91         assertThrows(NPE, () -> builder.setHeader(null, "value"));
  92         assertThrows(NPE, () -> builder.timeout(null));
  93         assertThrows(NPE, () -> builder.DELETE(null));
  94         assertThrows(NPE, () -> builder.POST(null));
  95         assertThrows(NPE, () -> builder.PUT(null));
  96     }
  97 
  98     @Test
  99     public void testURI() {
 100         assertThrows(ISE, () -> newBuilder().build());
 101         List<URI> uris = List.of(
 102                 URI.create("ws://foo.com"),
 103                 URI.create("wss://foo.com"),
 104                 URI.create("ftp://foo.com"),
 105                 URI.create("gopher://foo.com"),
 106                 URI.create("mailto:a@b.com"),
 107                 URI.create("scheme:example.com"),
 108                 URI.create("scheme:example.com"),
 109                 URI.create("scheme:example.com/path"),
 110                 URI.create("path"),
 111                 URI.create("/path")
 112         );
 113         for (URI u : uris) {
 114             assertThrows(IAE, () -> newBuilder(u));
 115             assertThrows(IAE, () -> newBuilder().uri(u));
 116         }
 117 
 118         assertEquals(newBuilder(uri).build().uri(), uri);
 119         assertEquals(newBuilder().uri(uri).build().uri(), uri);
 120         URI https = URI.create("https://foo.com");
 121         assertEquals(newBuilder(https).build().uri(), https);
 122         assertEquals(newBuilder().uri(https).build().uri(), https);
 123     }
 124 
 125     @Test
 126     public void testMethod() {
 127         HttpRequest request = newBuilder(uri).build();
 128         assertEquals(request.method(), "GET");
 129         assertTrue(!request.bodyPublisher().isPresent());
 130 
 131         request = newBuilder(uri).GET().build();
 132         assertEquals(request.method(), "GET");
 133         assertTrue(!request.bodyPublisher().isPresent());
 134 
 135         request = newBuilder(uri).POST(fromString("")).GET().build();
 136         assertEquals(request.method(), "GET");
 137         assertTrue(!request.bodyPublisher().isPresent());
 138 
 139         request = newBuilder(uri).PUT(fromString("")).GET().build();
 140         assertEquals(request.method(), "GET");
 141         assertTrue(!request.bodyPublisher().isPresent());
 142 
 143         request = newBuilder(uri).DELETE(fromString("")).GET().build();
 144         assertEquals(request.method(), "GET");
 145         assertTrue(!request.bodyPublisher().isPresent());
 146 
 147         request = newBuilder(uri).POST(fromString("")).build();
 148         assertEquals(request.method(), "POST");
 149         assertTrue(request.bodyPublisher().isPresent());
 150 
 151         request = newBuilder(uri).PUT(fromString("")).build();
 152         assertEquals(request.method(), "PUT");
 153         assertTrue(request.bodyPublisher().isPresent());
 154 
 155         request = newBuilder(uri).DELETE(fromString("")).build();
 156         assertEquals(request.method(), "DELETE");
 157         assertTrue(request.bodyPublisher().isPresent());
 158 
 159         request = newBuilder(uri).GET().POST(fromString("")).build();
 160         assertEquals(request.method(), "POST");
 161         assertTrue(request.bodyPublisher().isPresent());
 162 
 163         request = newBuilder(uri).GET().PUT(fromString("")).build();
 164         assertEquals(request.method(), "PUT");
 165         assertTrue(request.bodyPublisher().isPresent());
 166 
 167         request = newBuilder(uri).GET().DELETE(fromString("")).build();
 168         assertEquals(request.method(), "DELETE");
 169         assertTrue(request.bodyPublisher().isPresent());
 170 
 171         // CONNECT is disallowed in the implementation, since it is used for
 172         // tunneling, and is handled separately for security checks.
 173         assertThrows(IAE, () -> newBuilder(uri).method("CONNECT", noBody()).build());
 174 
 175         request = newBuilder(uri).method("GET", noBody()).build();
 176         assertEquals(request.method(), "GET");
 177         assertTrue(request.bodyPublisher().isPresent());
 178 
 179         request = newBuilder(uri).method("POST", fromString("")).build();
 180         assertEquals(request.method(), "POST");
 181         assertTrue(request.bodyPublisher().isPresent());
 182     }
 183 
 184     @Test
 185     public void testHeaders() {
 186         HttpRequest.Builder builder = newBuilder(uri);
 187 
 188         String[] empty = new String[0];
 189         assertThrows(IAE, () -> builder.headers(empty).build());
 190         assertThrows(IAE, () -> builder.headers("1").build());
 191         assertThrows(IAE, () -> builder.headers("1", "2", "3").build());
 192         assertThrows(IAE, () -> builder.headers("1", "2", "3", "4", "5").build());
 193         assertEquals(builder.build().headers().map().size(),0);
 194 
 195         List<HttpRequest> requests = List.of(
 196                 // same header built from different combinations of the API
 197                 newBuilder(uri).header("A", "B").build(),
 198                 newBuilder(uri).headers("A", "B").build(),
 199                 newBuilder(uri).setHeader("A", "B").build(),
 200                 newBuilder(uri).header("A", "F").setHeader("A", "B").build(),
 201                 newBuilder(uri).headers("A", "F").setHeader("A", "B").build()
 202         );
 203 
 204         for (HttpRequest r : requests) {
 205             assertEquals(r.headers().map().size(), 1);
 206             assertTrue(r.headers().firstValue("A").isPresent());
 207             assertEquals(r.headers().firstValue("A").get(), "B");
 208             assertEquals(r.headers().allValues("A"), List.of("B"));
 209             assertEquals(r.headers().allValues("C").size(), 0);
 210             assertEquals(r.headers().map().get("A"), List.of("B"));
 211             assertThrows(NFE, () -> r.headers().firstValueAsLong("A"));
 212             assertFalse(r.headers().firstValue("C").isPresent());
 213             // a non-exhaustive list of mutators
 214             assertThrows(UOE, () -> r.headers().map().put("Z", List.of("Z")));
 215             assertThrows(UOE, () -> r.headers().map().remove("A"));
 216             assertThrows(UOE, () -> r.headers().map().remove("A", "B"));
 217             assertThrows(UOE, () -> r.headers().map().clear());
 218             assertThrows(UOE, () -> r.headers().allValues("A").remove("B"));
 219             assertThrows(UOE, () -> r.headers().allValues("A").remove(1));
 220             assertThrows(UOE, () -> r.headers().allValues("A").clear());
 221             assertThrows(UOE, () -> r.headers().allValues("A").add("Z"));
 222             assertThrows(UOE, () -> r.headers().allValues("A").addAll(List.of("Z")));
 223             assertThrows(UOE, () -> r.headers().allValues("A").add(1, "Z"));
 224         }
 225 
 226         requests = List.of(
 227                 // same headers built from different combinations of the API
 228                 newBuilder(uri).header("A", "B")
 229                                .header("C", "D").build(),
 230                 newBuilder(uri).header("A", "B")
 231                                .headers("C", "D").build(),
 232                 newBuilder(uri).header("A", "B")
 233                                .setHeader("C", "D").build(),
 234                 newBuilder(uri).headers("A", "B")
 235                                .headers("C", "D").build(),
 236                 newBuilder(uri).headers("A", "B")
 237                                .header("C", "D").build(),
 238                 newBuilder(uri).headers("A", "B")
 239                                .setHeader("C", "D").build(),
 240                 newBuilder(uri).setHeader("A", "B")
 241                                .setHeader("C", "D").build(),
 242                 newBuilder(uri).setHeader("A", "B")
 243                                .header("C", "D").build(),
 244                 newBuilder(uri).setHeader("A", "B")
 245                                .headers("C", "D").build(),
 246                 newBuilder(uri).headers("A", "B", "C", "D").build()
 247         );
 248 
 249         for (HttpRequest r : requests) {
 250             assertEquals(r.headers().map().size(), 2);
 251             assertTrue(r.headers().firstValue("A").isPresent());
 252             assertEquals(r.headers().firstValue("A").get(), "B");
 253             assertEquals(r.headers().allValues("A"), List.of("B"));
 254             assertTrue(r.headers().firstValue("C").isPresent());
 255             assertEquals(r.headers().firstValue("C").get(), "D");
 256             assertEquals(r.headers().allValues("C"), List.of("D"));
 257             assertEquals(r.headers().map().get("C"), List.of("D"));
 258             assertThrows(NFE, () -> r.headers().firstValueAsLong("C"));
 259             assertFalse(r.headers().firstValue("E").isPresent());
 260             // a smaller non-exhaustive list of mutators
 261             assertThrows(UOE, () -> r.headers().map().put("Z", List.of("Z")));
 262             assertThrows(UOE, () -> r.headers().map().remove("C"));
 263             assertThrows(UOE, () -> r.headers().allValues("A").remove("B"));
 264             assertThrows(UOE, () -> r.headers().allValues("A").clear());
 265             assertThrows(UOE, () -> r.headers().allValues("C").add("Z"));
 266         }
 267 
 268         requests = List.of(
 269                 // same multi-value headers built from different combinations of the API
 270                 newBuilder(uri).header("A", "B")
 271                                .header("A", "C").build(),
 272                 newBuilder(uri).header("A", "B")
 273                                .headers("A", "C").build(),
 274                 newBuilder(uri).headers("A", "B")
 275                                .headers("A", "C").build(),
 276                 newBuilder(uri).headers("A", "B")
 277                                .header("A", "C").build(),
 278                 newBuilder(uri).setHeader("A", "B")
 279                                .header("A", "C").build(),
 280                 newBuilder(uri).setHeader("A", "B")
 281                                .headers("A", "C").build(),
 282                 newBuilder(uri).header("A", "D")
 283                                .setHeader("A", "B")
 284                                .headers("A", "C").build(),
 285                 newBuilder(uri).headers("A", "B", "A", "C").build()
 286         );
 287 
 288         for (HttpRequest r : requests) {
 289             assertEquals(r.headers().map().size(), 1);
 290             assertTrue(r.headers().firstValue("A").isPresent());
 291             assertTrue(r.headers().allValues("A").containsAll(List.of("B", "C")));
 292             assertEquals(r.headers().allValues("C").size(), 0);
 293             assertEquals(r.headers().map().get("A"), List.of("B", "C"));
 294             assertThrows(NFE, () -> r.headers().firstValueAsLong("A"));
 295             assertFalse(r.headers().firstValue("C").isPresent());
 296             // a non-exhaustive list of mutators
 297             assertThrows(UOE, () -> r.headers().map().put("Z", List.of("Z")));
 298             assertThrows(UOE, () -> r.headers().map().remove("A"));
 299             assertThrows(UOE, () -> r.headers().map().remove("A", "B"));
 300             assertThrows(UOE, () -> r.headers().map().clear());
 301             assertThrows(UOE, () -> r.headers().allValues("A").remove("B"));
 302             assertThrows(UOE, () -> r.headers().allValues("A").remove(1));
 303             assertThrows(UOE, () -> r.headers().allValues("A").clear());
 304             assertThrows(UOE, () -> r.headers().allValues("A").add("Z"));
 305             assertThrows(UOE, () -> r.headers().allValues("A").addAll(List.of("Z")));
 306             assertThrows(UOE, () -> r.headers().allValues("A").add(1, "Z"));
 307         }
 308     }
 309 
 310     @Test
 311     public void testCopy() {
 312         HttpRequest.Builder builder = newBuilder(uri).expectContinue(true)
 313                                                      .header("A", "B")
 314                                                      .POST(fromString(""))
 315                                                      .timeout(ofSeconds(30))
 316                                                      .version(HTTP_1_1);
 317         HttpRequest.Builder copy = builder.copy();
 318         assertTrue(builder != copy);
 319 
 320         // modify the original builder before building from the copy
 321         builder.GET().timeout(ofSeconds(5)).version(HTTP_2).setHeader("A", "C");
 322 
 323         HttpRequest copyRequest = copy.build();
 324         assertEquals(copyRequest.uri(), uri);
 325         assertEquals(copyRequest.expectContinue(), true);
 326         assertEquals(copyRequest.headers().map().get("A"), List.of("B"));
 327         assertEquals(copyRequest.method(), "POST");
 328         assertEquals(copyRequest.bodyPublisher().isPresent(), true);
 329         assertEquals(copyRequest.timeout().get(), ofSeconds(30));
 330         assertTrue(copyRequest.version().isPresent());
 331         assertEquals(copyRequest.version().get(), HTTP_1_1);
 332     }
 333 
 334     @Test
 335     public void testTimeout() {
 336         HttpRequest.Builder builder = newBuilder(uri);
 337         assertThrows(IAE, () -> builder.timeout(ZERO));
 338         assertThrows(IAE, () -> builder.timeout(ofSeconds(0)));
 339         assertThrows(IAE, () -> builder.timeout(ofSeconds(-1)));
 340         assertThrows(IAE, () -> builder.timeout(ofNanos(-100)));
 341         assertEquals(builder.timeout(ofNanos(15)).build().timeout().get(), ofNanos(15));
 342         assertEquals(builder.timeout(ofSeconds(50)).build().timeout().get(), ofSeconds(50));
 343         assertEquals(builder.timeout(ofMinutes(30)).build().timeout().get(), ofMinutes(30));
 344     }
 345 
 346     @Test
 347     public void testExpect() {
 348         HttpRequest.Builder builder = newBuilder(uri);
 349         assertEquals(builder.build().expectContinue(), false);
 350         assertEquals(builder.expectContinue(true).build().expectContinue(), true);
 351         assertEquals(builder.expectContinue(false).build().expectContinue(), false);
 352         assertEquals(builder.expectContinue(true).build().expectContinue(), true);
 353     }
 354 
 355     @Test
 356     public void testEquals() {
 357         assertNotEquals(newBuilder(URI.create("http://foo.com")),
 358                         newBuilder(URI.create("http://bar.com")));
 359 
 360         HttpRequest.Builder builder = newBuilder(uri);
 361         assertEquals(builder.build(), builder.build());
 362         assertEquals(builder.build(), newBuilder(uri).build());
 363 
 364         builder.POST(noBody());
 365         assertEquals(builder.build(), builder.build());
 366         assertEquals(builder.build(), newBuilder(uri).POST(noBody()).build());
 367         assertEquals(builder.build(), newBuilder(uri).POST(fromString("")).build());
 368         assertNotEquals(builder.build(), newBuilder(uri).build());
 369         assertNotEquals(builder.build(), newBuilder(uri).GET().build());
 370         assertNotEquals(builder.build(), newBuilder(uri).PUT(noBody()).build());
 371 
 372         builder = newBuilder(uri).header("x", "y");
 373         assertEquals(builder.build(), builder.build());
 374         assertEquals(builder.build(), newBuilder(uri).header("x", "y").build());
 375         assertNotEquals(builder.build(), newBuilder(uri).header("x", "Z").build());
 376         assertNotEquals(builder.build(), newBuilder(uri).header("z", "y").build());
 377     }
 378 }