Skip to content
Permalink
Browse files
8276559: (httpclient) Consider adding an HttpRequest.Builder.HEAD met…
…hod to build a HEAD request.

Reviewed-by: cstein, dfuchs
  • Loading branch information
jaikiran committed Nov 17, 2021
1 parent a77d8dd commit 23e5117a55b3f3d0e3d26bf2d481f4ad1c99af57
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 44 deletions.
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@@ -256,6 +256,19 @@ public interface Builder {
*/
public Builder DELETE();

/**
* Sets the request method of this builder to HEAD.
*
* @implSpec The default implementation is expected to have the same behaviour as:
* {@code return method("HEAD", BodyPublishers.noBody());}
*
* @return this builder
* @since 18
*/
default Builder HEAD() {
return method("HEAD", BodyPublishers.noBody());
}

/**
* Sets the request method and request body of this builder to the
* given values.
@@ -360,12 +373,13 @@ public static Builder newBuilder(HttpRequest request, BiPredicate<String, String
request.bodyPublisher().ifPresentOrElse(
// if body is present, set it
bodyPublisher -> builder.method(method, bodyPublisher),
// otherwise, the body is absent, special case for GET/DELETE,
// otherwise, the body is absent, special case for GET/DELETE/HEAD,
// or else use empty body
() -> {
switch (method) {
case "GET" -> builder.GET();
case "DELETE" -> builder.DELETE();
case "HEAD" -> builder.HEAD();
default -> builder.method(method, HttpRequest.BodyPublishers.noBody());
}
}
@@ -182,6 +182,11 @@ public HttpRequest.Builder DELETE() {
return method0("DELETE", null);
}

@Override
public HttpRequest.Builder HEAD() {
return method0("HEAD", null);
}

@Override
public HttpRequest.Builder PUT(BodyPublisher body) {
return method0("PUT", requireNonNull(body));
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 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
@@ -23,7 +23,7 @@

/*
* @test
* @bug 8203433
* @bug 8203433 8276559
* @summary (httpclient) Add tests for HEAD and 304 responses.
* @modules java.base/sun.net.www.http
* java.net.http/jdk.internal.net.http.common
@@ -48,43 +48,20 @@
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Redirect;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.lang.System.out;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.net.HttpURLConnection.HTTP_OK;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;

public class HeadTest implements HttpServerAdapters {

@@ -98,8 +75,6 @@ public class HeadTest implements HttpServerAdapters {
String http2URI;
String https2URI;

static final String MESSAGE = "Basic HeadTest message body";
static final int ITERATIONS = 3;
static final String CONTENT_LEN = "300";

/*
@@ -133,27 +108,38 @@ public Object[][] positive() {
};
}

static final AtomicLong requestCounter = new AtomicLong();

@Test(dataProvider = "positive")
void test(String uriString, String method,
int expResp, HttpClient.Version version) throws Exception {
out.printf("%n---- starting (%s) ----%n", uriString);
HttpClient client = HttpClient.newBuilder()
.followRedirects(Redirect.ALWAYS)
.sslContext(sslContext)
.build();

URI uri = URI.create(uriString);

HttpRequest.Builder requestBuilder = HttpRequest
.newBuilder(uri)
.method(method, HttpRequest.BodyPublishers.noBody());

if (version != null) {
requestBuilder.version(version);
}
HttpRequest request = requestBuilder.build();
doTest(requestBuilder.build(), expResp);
// repeat the test this time by building the request using convenience
// GET and HEAD methods
requestBuilder = HttpRequest.newBuilder(uri);
if (version != null) {
requestBuilder.version(version);
}
switch (method) {
case "GET" -> requestBuilder.GET();
case "HEAD" -> requestBuilder.HEAD();
default -> throw new IllegalArgumentException("Unexpected method " + method);
}
doTest(requestBuilder.build(), expResp);
}

// issue a request with no body and verify the response code is the expected response code
private void doTest(HttpRequest request, int expResp) throws Exception {
HttpClient client = HttpClient.newBuilder()
.followRedirects(Redirect.ALWAYS)
.sslContext(sslContext)
.build();
out.println("Initial request: " + request.uri());

HttpResponse<String> response = client.send(request, BodyHandlers.ofString());
@@ -36,7 +36,7 @@

/**
* @test
* @bug 8170064
* @bug 8170064 8276559
* @summary HttpRequest[.Builder] API and behaviour checks
*/
public class HttpRequestBuilderTest {
@@ -156,6 +156,7 @@ public static void main(String[] args) throws Exception {
IllegalArgumentException.class);

test0("DELETE", () -> HttpRequest.newBuilder(TEST_URI).DELETE().build(), null);
test0("HEAD", () -> HttpRequest.newBuilder(TEST_URI).HEAD().build(), null);

builder = test1("POST", builder, builder::POST,
noBody(), null);
@@ -254,7 +255,9 @@ public static void main(String[] args) throws Exception {
() -> HttpRequest.newBuilder(TEST_URI).GET().DELETE(),
"DELETE");


method("newBuilder(TEST_URI).HEAD().build().method() == HEAD",
() -> HttpRequest.newBuilder(TEST_URI).HEAD(),
"HEAD");

}

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 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
@@ -51,7 +51,7 @@

/**
* @test
* @bug 8252304
* @bug 8252304 8276559
* @summary HttpRequest.newBuilder(HttpRequest) API and behaviour checks
* @run testng/othervm HttpRequestNewBuilderTest
*/
@@ -120,6 +120,7 @@ public Object[][] variants() {
.headers("testName1", "y")
.headers("testName1", "z").build() },
// dedicated method
{ HttpRequest.newBuilder(URI.create("https://method-0/")).HEAD().build() },
{ HttpRequest.newBuilder(URI.create("https://method-1/")).GET().build() },
{ HttpRequest.newBuilder(URI.create("https://method-2/")).DELETE().build() },
{ HttpRequest.newBuilder(URI.create("https://method-3/")).POST(HttpRequest.BodyPublishers.ofString("testData")).build() },
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
* 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
@@ -23,6 +23,7 @@

/*
* @test
* @bug 8276559
* @summary HttpRequest[.Builder] API and behaviour checks
* @run testng RequestBuilderTest
*/
@@ -160,6 +161,10 @@ public void testMethod() {
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());

1 comment on commit 23e5117

@openjdk-notifier
Copy link

@openjdk-notifier openjdk-notifier bot commented on 23e5117 Nov 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.