Skip to content

Commit 23e5117

Browse files
committed
8276559: (httpclient) Consider adding an HttpRequest.Builder.HEAD method to build a HEAD request.
Reviewed-by: cstein, dfuchs
1 parent a77d8dd commit 23e5117

File tree

6 files changed

+58
-44
lines changed

6 files changed

+58
-44
lines changed

Diff for: src/java.net.http/share/classes/java/net/http/HttpRequest.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -256,6 +256,19 @@ public interface Builder {
256256
*/
257257
public Builder DELETE();
258258

259+
/**
260+
* Sets the request method of this builder to HEAD.
261+
*
262+
* @implSpec The default implementation is expected to have the same behaviour as:
263+
* {@code return method("HEAD", BodyPublishers.noBody());}
264+
*
265+
* @return this builder
266+
* @since 18
267+
*/
268+
default Builder HEAD() {
269+
return method("HEAD", BodyPublishers.noBody());
270+
}
271+
259272
/**
260273
* Sets the request method and request body of this builder to the
261274
* given values.
@@ -360,12 +373,13 @@ public static Builder newBuilder(HttpRequest request, BiPredicate<String, String
360373
request.bodyPublisher().ifPresentOrElse(
361374
// if body is present, set it
362375
bodyPublisher -> builder.method(method, bodyPublisher),
363-
// otherwise, the body is absent, special case for GET/DELETE,
376+
// otherwise, the body is absent, special case for GET/DELETE/HEAD,
364377
// or else use empty body
365378
() -> {
366379
switch (method) {
367380
case "GET" -> builder.GET();
368381
case "DELETE" -> builder.DELETE();
382+
case "HEAD" -> builder.HEAD();
369383
default -> builder.method(method, HttpRequest.BodyPublishers.noBody());
370384
}
371385
}

Diff for: src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java

+5
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ public HttpRequest.Builder DELETE() {
182182
return method0("DELETE", null);
183183
}
184184

185+
@Override
186+
public HttpRequest.Builder HEAD() {
187+
return method0("HEAD", null);
188+
}
189+
185190
@Override
186191
public HttpRequest.Builder PUT(BodyPublisher body) {
187192
return method0("PUT", requireNonNull(body));

Diff for: test/jdk/java/net/httpclient/HeadTest.java

+23-37
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2021 Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
2323

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

51-
import javax.net.ServerSocketFactory;
5251
import javax.net.ssl.SSLContext;
5352
import java.io.IOException;
5453
import java.io.InputStream;
55-
import java.io.OutputStream;
56-
import java.io.OutputStreamWriter;
57-
import java.io.PrintWriter;
58-
import java.io.Writer;
5954
import java.net.InetAddress;
6055
import java.net.InetSocketAddress;
61-
import java.net.ServerSocket;
62-
import java.net.Socket;
6356
import java.net.URI;
6457
import java.net.http.HttpClient;
6558
import java.net.http.HttpClient.Redirect;
6659
import java.net.http.HttpRequest;
6760
import java.net.http.HttpResponse;
6861
import java.net.http.HttpResponse.BodyHandlers;
69-
import java.util.ArrayList;
70-
import java.util.Arrays;
71-
import java.util.Collections;
72-
import java.util.HashMap;
73-
import java.util.List;
74-
import java.util.Locale;
75-
import java.util.Map;
76-
import java.util.StringTokenizer;
77-
import java.util.concurrent.ConcurrentHashMap;
78-
import java.util.concurrent.ConcurrentLinkedQueue;
79-
import java.util.concurrent.atomic.AtomicLong;
80-
import java.util.stream.Collectors;
81-
import java.util.stream.Stream;
8262

8363
import static java.lang.System.out;
84-
import static java.nio.charset.StandardCharsets.UTF_8;
85-
import static java.net.HttpURLConnection.HTTP_OK;
8664
import static org.testng.Assert.assertEquals;
87-
import static org.testng.Assert.assertTrue;
8865

8966
public class HeadTest implements HttpServerAdapters {
9067

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

101-
static final String MESSAGE = "Basic HeadTest message body";
102-
static final int ITERATIONS = 3;
10378
static final String CONTENT_LEN = "300";
10479

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

136-
static final AtomicLong requestCounter = new AtomicLong();
137-
138111
@Test(dataProvider = "positive")
139112
void test(String uriString, String method,
140113
int expResp, HttpClient.Version version) throws Exception {
141114
out.printf("%n---- starting (%s) ----%n", uriString);
142-
HttpClient client = HttpClient.newBuilder()
143-
.followRedirects(Redirect.ALWAYS)
144-
.sslContext(sslContext)
145-
.build();
146-
147115
URI uri = URI.create(uriString);
148-
149116
HttpRequest.Builder requestBuilder = HttpRequest
150117
.newBuilder(uri)
151118
.method(method, HttpRequest.BodyPublishers.noBody());
152-
153119
if (version != null) {
154120
requestBuilder.version(version);
155121
}
156-
HttpRequest request = requestBuilder.build();
122+
doTest(requestBuilder.build(), expResp);
123+
// repeat the test this time by building the request using convenience
124+
// GET and HEAD methods
125+
requestBuilder = HttpRequest.newBuilder(uri);
126+
if (version != null) {
127+
requestBuilder.version(version);
128+
}
129+
switch (method) {
130+
case "GET" -> requestBuilder.GET();
131+
case "HEAD" -> requestBuilder.HEAD();
132+
default -> throw new IllegalArgumentException("Unexpected method " + method);
133+
}
134+
doTest(requestBuilder.build(), expResp);
135+
}
136+
137+
// issue a request with no body and verify the response code is the expected response code
138+
private void doTest(HttpRequest request, int expResp) throws Exception {
139+
HttpClient client = HttpClient.newBuilder()
140+
.followRedirects(Redirect.ALWAYS)
141+
.sslContext(sslContext)
142+
.build();
157143
out.println("Initial request: " + request.uri());
158144

159145
HttpResponse<String> response = client.send(request, BodyHandlers.ofString());

Diff for: test/jdk/java/net/httpclient/HttpRequestBuilderTest.java

+5-2
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

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

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

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

257-
258+
method("newBuilder(TEST_URI).HEAD().build().method() == HEAD",
259+
() -> HttpRequest.newBuilder(TEST_URI).HEAD(),
260+
"HEAD");
258261

259262
}
260263

Diff for: test/jdk/java/net/httpclient/HttpRequestNewBuilderTest.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -51,7 +51,7 @@
5151

5252
/**
5353
* @test
54-
* @bug 8252304
54+
* @bug 8252304 8276559
5555
* @summary HttpRequest.newBuilder(HttpRequest) API and behaviour checks
5656
* @run testng/othervm HttpRequestNewBuilderTest
5757
*/
@@ -120,6 +120,7 @@ public Object[][] variants() {
120120
.headers("testName1", "y")
121121
.headers("testName1", "z").build() },
122122
// dedicated method
123+
{ HttpRequest.newBuilder(URI.create("https://method-0/")).HEAD().build() },
123124
{ HttpRequest.newBuilder(URI.create("https://method-1/")).GET().build() },
124125
{ HttpRequest.newBuilder(URI.create("https://method-2/")).DELETE().build() },
125126
{ HttpRequest.newBuilder(URI.create("https://method-3/")).POST(HttpRequest.BodyPublishers.ofString("testData")).build() },

Diff for: test/jdk/java/net/httpclient/RequestBuilderTest.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
2323

2424
/*
2525
* @test
26+
* @bug 8276559
2627
* @summary HttpRequest[.Builder] API and behaviour checks
2728
* @run testng RequestBuilderTest
2829
*/
@@ -160,6 +161,10 @@ public void testMethod() {
160161
assertEquals(request.method(), "DELETE");
161162
assertTrue(!request.bodyPublisher().isPresent());
162163

164+
request = newBuilder(uri).HEAD().build();
165+
assertEquals(request.method(), "HEAD");
166+
assertFalse(request.bodyPublisher().isPresent());
167+
163168
request = newBuilder(uri).GET().POST(BodyPublishers.ofString("")).build();
164169
assertEquals(request.method(), "POST");
165170
assertTrue(request.bodyPublisher().isPresent());

0 commit comments

Comments
 (0)