-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixes #5685 - AsyncProxyServlet calls onProxyResponseSuccess() when internally it throws "Response header too large" exception. #12351
Changes from 7 commits
3f903e2
e5a672c
53dff62
ad00741
af31788
8a8ba79
e5a89c3
92c516e
9fb5bd8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,9 +41,14 @@ public class HttpGenerator | |
private static final Logger LOG = LoggerFactory.getLogger(HttpGenerator.class); | ||
|
||
public static final boolean __STRICT = Boolean.getBoolean("org.eclipse.jetty.http.HttpGenerator.STRICT"); | ||
|
||
private static final byte[] __colon_space = new byte[]{':', ' '}; | ||
public static final MetaData.Response CONTINUE_100_INFO = new MetaData.Response(100, null, HttpVersion.HTTP_1_1, HttpFields.EMPTY); | ||
private static final Index<Boolean> ASSUMED_CONTENT_METHODS = new Index.Builder<Boolean>() | ||
.caseSensitive(false) | ||
.with(HttpMethod.POST.asString(), Boolean.TRUE) | ||
.with(HttpMethod.PUT.asString(), Boolean.TRUE) | ||
.build(); | ||
public static final int CHUNK_SIZE = 12; | ||
|
||
// states | ||
public enum State | ||
|
@@ -68,25 +73,14 @@ public enum Result | |
DONE // The current phase of generation is complete | ||
} | ||
|
||
// other statics | ||
public static final int CHUNK_SIZE = 12; | ||
|
||
private State _state = State.START; | ||
private EndOfContent _endOfContent = EndOfContent.UNKNOWN_CONTENT; | ||
private MetaData _info; | ||
|
||
private long _contentPrepared = 0; | ||
private boolean _noContentResponse = false; | ||
private Boolean _persistent = null; | ||
|
||
private static final Index<Boolean> ASSUMED_CONTENT_METHODS = new Index.Builder<Boolean>() | ||
.caseSensitive(false) | ||
.with(HttpMethod.POST.asString(), Boolean.TRUE) | ||
.with(HttpMethod.PUT.asString(), Boolean.TRUE) | ||
.build(); | ||
|
||
// data | ||
private boolean _needCRLF = false; | ||
private int _maxHeaderBytes; | ||
|
||
public HttpGenerator() | ||
{ | ||
|
@@ -103,6 +97,16 @@ public void reset() | |
_needCRLF = false; | ||
} | ||
|
||
public int getMaxHeaderBytes() | ||
{ | ||
return _maxHeaderBytes; | ||
} | ||
|
||
public void setMaxHeaderBytes(int maxHeaderBytes) | ||
{ | ||
_maxHeaderBytes = maxHeaderBytes; | ||
} | ||
Comment on lines
+100
to
+108
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is kind of a duplicate in the server as we already have So why are we duplicating this mechanism? Can't the client just allocate a buffer of a specific size when it is asked for a HEADERs buffer? |
||
|
||
public State getState() | ||
{ | ||
return _state; | ||
|
@@ -594,28 +598,28 @@ private void generateHeaders(ByteBuffer header, ByteBuffer content, boolean last | |
HttpField field = fields.getField(f); | ||
HttpHeader h = field.getHeader(); | ||
if (h == null) | ||
{ | ||
putTo(field, header); | ||
} | ||
else | ||
{ | ||
switch (h) | ||
{ | ||
case CONTENT_LENGTH: | ||
case CONTENT_LENGTH -> | ||
{ | ||
if (contentLength < 0) | ||
contentLength = field.getLongValue(); | ||
else if (contentLength != field.getLongValue()) | ||
throw new HttpException.RuntimeException(INTERNAL_SERVER_ERROR_500, String.format("Incorrect Content-Length %d!=%d", contentLength, field.getLongValue())); | ||
contentLengthField = true; | ||
break; | ||
|
||
case CONTENT_TYPE: | ||
} | ||
case CONTENT_TYPE -> | ||
{ | ||
// write the field to the header | ||
contentType = true; | ||
putTo(field, header); | ||
break; | ||
} | ||
|
||
case TRANSFER_ENCODING: | ||
case TRANSFER_ENCODING -> | ||
{ | ||
if (http11) | ||
{ | ||
|
@@ -627,10 +631,8 @@ else if (contentLength != field.getLongValue()) | |
transferEncoding = transferEncoding.withValues(field.getValues()); | ||
chunkedHint |= field.contains(HttpHeaderValue.CHUNKED.asString()); | ||
} | ||
break; | ||
} | ||
|
||
case CONNECTION: | ||
case CONNECTION -> | ||
{ | ||
// Save to connection field for processing when all other fields are known | ||
if (connection == null) | ||
|
@@ -641,13 +643,11 @@ else if (contentLength != field.getLongValue()) | |
connectionClose |= field.contains(HttpHeaderValue.CLOSE.asString()); | ||
connectionKeepAlive |= field.contains(HttpHeaderValue.KEEP_ALIVE.asString()); | ||
connectionUpgrade |= field.contains(HttpHeaderValue.UPGRADE.asString()); | ||
break; | ||
} | ||
|
||
default: | ||
putTo(field, header); | ||
default -> putTo(field, header); | ||
} | ||
} | ||
checkMaxHeaderBytes(header); | ||
} | ||
} | ||
|
||
|
@@ -887,12 +887,23 @@ else if (http10) | |
|
||
// end the header. | ||
header.put(HttpTokens.CRLF); | ||
|
||
checkMaxHeaderBytes(header); | ||
} | ||
|
||
private void checkMaxHeaderBytes(ByteBuffer header) | ||
{ | ||
int maxHeaderBytes = getMaxHeaderBytes(); | ||
if (maxHeaderBytes > 0 && header.position() > maxHeaderBytes) | ||
throw new BufferOverflowException(); | ||
} | ||
|
||
private static void putContentLength(ByteBuffer header, long contentLength) | ||
{ | ||
if (contentLength == 0) | ||
{ | ||
header.put(CONTENT_LENGTH_0); | ||
} | ||
else | ||
{ | ||
header.put(HttpHeader.CONTENT_LENGTH.getBytesColonSpace()); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if 0 is a sensible default, even if we always call the setter before using the generator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We did not check for response headers max size before, so
0
keeps the original behavior.