Fix #9953 handled HEAD (#9957)

* Fix #9953 handled HEAD

Fix #9953 so that if a Handler self handles HEAD by not writing content, then the length checks do not fire if 0 bytes have been written.

* updates from review
This commit is contained in:
Greg Wilkins 2023-06-23 17:21:27 +02:00 committed by GitHub
parent f6e963c841
commit 62e6cf2b76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 79 additions and 7 deletions

View File

@ -1176,16 +1176,15 @@ public class HttpChannelState implements HttpChannel, Components
{
long length = BufferUtil.length(content);
long totalWritten;
HttpChannelState httpChannelState;
HttpStream stream = null;
Throwable failure = null;
Throwable failure;
MetaData.Response responseMetaData = null;
try (AutoLock ignored = _request._lock.lock())
{
httpChannelState = _request.lockedGetHttpChannelState();
long committedContentLength = httpChannelState._committedContentLength;
totalWritten = _contentBytesWritten + length;
long totalWritten = _contentBytesWritten + length;
long contentLength = committedContentLength >= 0 ? committedContentLength : getHeaders().getLongField(HttpHeader.CONTENT_LENGTH);
if (_writeCallback != null)
@ -1193,11 +1192,14 @@ public class HttpChannelState implements HttpChannel, Components
else
{
failure = getFailure(httpChannelState);
if (failure == null && contentLength >= 0)
if (failure == null && contentLength >= 0 && totalWritten != contentLength)
{
// If the content length were not compatible with what was written, then we need to abort.
String lengthError = (totalWritten > contentLength) ? "written %d > %d content-length"
: (last && totalWritten < contentLength) ? "written %d < %d content-length" : null;
String lengthError = null;
if (totalWritten > contentLength)
lengthError = "written %d > %d content-length";
else if (last && !(totalWritten == 0 && HttpMethod.HEAD.is(_request.getMethod())))
lengthError = "written %d < %d content-length";
if (lengthError != null)
{
String message = lengthError.formatted(totalWritten, contentLength);
@ -1439,7 +1441,7 @@ public class HttpChannelState implements HttpChannel, Components
long totalWritten = response._contentBytesWritten;
long committedContentLength = httpChannelState._committedContentLength;
if (committedContentLength >= 0 && committedContentLength != totalWritten)
if (committedContentLength >= 0 && committedContentLength != totalWritten && !(totalWritten == 0 && HttpMethod.HEAD.is(_request.getMethod())))
failure = new IOException("content-length %d != %d written".formatted(committedContentLength, totalWritten));
// is the request fully consumed?

View File

@ -36,6 +36,7 @@ import java.util.concurrent.atomic.AtomicReference;
import org.awaitility.Awaitility;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.io.AbstractConnection;
@ -1334,6 +1335,75 @@ public abstract class HttpServerTestBase extends HttpServerTestFixture
}
}
@Test
public void testHeadHandled() throws Exception
{
startServer(new Handler.Abstract()
{
@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{
response.getHeaders().put(HttpHeader.CONTENT_LENGTH, 10);
if (HttpMethod.HEAD.is(request.getMethod()))
{
if (request.getHttpURI().getCanonicalPath().equals("/writeNull"))
response.write(true, null, callback);
else
callback.succeeded();
}
else
{
Content.Sink.write(response, true, "123456789\n", callback);
}
return true;
}
});
_httpConfiguration.setSendDateHeader(false);
_httpConfiguration.setSendServerVersion(false);
_httpConfiguration.setSendXPoweredBy(false);
try (Socket client = newSocket(_serverURI.getHost(), _serverURI.getPort()))
{
OutputStream os = client.getOutputStream();
InputStream is = client.getInputStream();
os.write("""
GET / HTTP/1.1
Host: localhost
HEAD / HTTP/1.1
Host: localhost
HEAD /writeNull HTTP/1.1
Host: localhost
GET / HTTP/1.1
Host: localhost
Connection: close
""".getBytes(StandardCharsets.ISO_8859_1));
String in = IO.toString(is);
assertThat(in.replace("\r", ""), is("""
HTTP/1.1 200 OK
Content-Length: 10
123456789
HTTP/1.1 200 OK
Content-Length: 10
HTTP/1.1 200 OK
Content-Length: 10
HTTP/1.1 200 OK
Content-Length: 10
Connection: close
123456789
"""));
}
}
@Test
public void testBlockedClient() throws Exception
{