Skip to content

Commit a3aebce

Browse files
authored
Merge pull request #1290 from carterkozak/UNDERTOW-2019
UNDERTOW-2019: Blocking exchanges can set HEAD response length
2 parents 8531ff7 + 05fcd52 commit a3aebce

File tree

2 files changed

+73
-1
lines changed

2 files changed

+73
-1
lines changed

core/src/main/java/io/undertow/io/UndertowOutputStream.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import io.undertow.UndertowMessages;
2727
import io.undertow.server.HttpServerExchange;
2828
import io.undertow.util.Headers;
29+
import io.undertow.util.Methods;
2930
import org.xnio.Buffers;
3031
import io.undertow.connector.ByteBufferPool;
3132
import io.undertow.connector.PooledByteBuffer;
@@ -327,7 +328,9 @@ public void close() throws IOException {
327328
if (anyAreSet(state, FLAG_CLOSED)) return;
328329
try {
329330
state |= FLAG_CLOSED;
330-
if (anyAreClear(state, FLAG_WRITE_STARTED) && channel == null) {
331+
if (anyAreClear(state, FLAG_WRITE_STARTED)
332+
&& channel == null
333+
&& !isHeadRequestWithContentLength(exchange)) {
331334
if (buffer == null) {
332335
exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, "0");
333336
} else {
@@ -356,6 +359,12 @@ public void close() throws IOException {
356359
}
357360
}
358361

362+
// Head request handlers may set the content-length response header in lieu of writing bytes
363+
private static boolean isHeadRequestWithContentLength(HttpServerExchange exchange) {
364+
return Methods.HEAD.equals(exchange.getRequestMethod())
365+
&& exchange.getResponseHeaders().contains(Headers.CONTENT_LENGTH);
366+
}
367+
359368
private ByteBuffer buffer() {
360369
ByteBuffer buffer = this.buffer;
361370
if (buffer != null) {
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* JBoss, Home of Professional Open Source.
3+
* Copyright 2022 Red Hat, Inc., and individual contributors
4+
* as indicated by the @author tags.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
package io.undertow.server.handlers;
20+
21+
import io.undertow.testutils.DefaultServer;
22+
import io.undertow.testutils.HttpClientUtils;
23+
import io.undertow.testutils.TestHttpClient;
24+
import io.undertow.util.Headers;
25+
import io.undertow.util.StatusCodes;
26+
import org.apache.http.HttpResponse;
27+
import org.apache.http.client.methods.HttpHead;
28+
import org.junit.Assert;
29+
import org.junit.BeforeClass;
30+
import org.junit.Test;
31+
import org.junit.runner.RunWith;
32+
33+
import java.io.IOException;
34+
35+
/**
36+
* Test that {@code HEAD} requests can be used with a blocking exchange, setting response
37+
* content-length without unnecessarily writing bytes.
38+
*
39+
* @author Carter Kozak
40+
*/
41+
@RunWith(DefaultServer.class)
42+
public class HeadBlockingExchangeTestCase {
43+
44+
@BeforeClass
45+
public static void setup() {
46+
DefaultServer.setRootHandler(new BlockingHandler(
47+
exchange -> exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, "" + 100)));
48+
}
49+
50+
@Test
51+
public void sendHttpHead() throws IOException {
52+
HttpHead head = new HttpHead(DefaultServer.getDefaultServerURL());
53+
TestHttpClient client = new TestHttpClient();
54+
try {
55+
HttpResponse result = client.execute(head);
56+
Assert.assertEquals(StatusCodes.OK, result.getStatusLine().getStatusCode());
57+
Assert.assertEquals("", HttpClientUtils.readResponse(result));
58+
Assert.assertEquals("100", result.getFirstHeader("Content-Length").getValue());
59+
} finally {
60+
client.getConnectionManager().shutdown();
61+
}
62+
}
63+
}

0 commit comments

Comments
 (0)