* 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:
parent
f6e963c841
commit
62e6cf2b76
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue