-
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
EagerContentHandler. #9051 #12077
base: jetty-12.1.x
Are you sure you want to change the base?
EagerContentHandler. #9051 #12077
Conversation
@sbordet @lorban Your thoughts on doing this? If you think it is a good idea, can you contribute the h2 and h3 delayed dispatch handling to this branch. |
Implementation-wise, this looks alright assuming the same logic can be replicated in H2/H3 (but I doubt this is going to be troublesome). But could you summarize what benefits/drawbacks this has over the existing |
@lorban wrote:
The |
I've also taken the opportunity to cleanup lots of deprecation and TODOs in HttpConnection |
@lachlan-roberts Can you take over the handling of delayed multipart in this PR? |
…tty-12.1.x/delayedDispatch
Signed-off-by: Lachlan Roberts <[email protected]>
…ispatch' into experiment/jetty-12.1.x/delayedDispatch
jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormData.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
…tty-12.1.x/delayedDispatch # Conflicts: # jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java # jetty-core/jetty-tests/jetty-test-client-transports/src/test/java/org/eclipse/jetty/test/client/transport/AbstractTest.java # jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/ServletTest.java # jetty-ee11/jetty-ee11-servlet/src/test/java/org/eclipse/jetty/ee11/servlet/ServletTest.java # jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/ServletTest.java
jetty-core/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractConnection.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartFormData.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnectionFactory.java
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java
Outdated
Show resolved
Hide resolved
jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/ServletTest.java
Outdated
Show resolved
Hide resolved
jetty-ee11/jetty-ee11-servlet/src/test/java/org/eclipse/jetty/ee11/servlet/ServletTest.java
Outdated
Show resolved
Hide resolved
jetty-ee9/jetty-ee9-servlet/src/test/java/org/eclipse/jetty/ee9/servlet/ServletTest.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/config/modules/delay-until-content.mod
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
...re/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java
Outdated
Show resolved
Hide resolved
...re/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java
Outdated
Show resolved
Hide resolved
...re/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java
Outdated
Show resolved
Hide resolved
...re/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java
Outdated
Show resolved
Hide resolved
...re/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java
Outdated
Show resolved
Hide resolved
+ rename save to hold + added "Bytes" to configuration
@lorban I've implemented for H3, but I don't know if it needs the same holdBuffer logic as h2. Do you think there is a release race? We will see from tests I guess.... |
...re/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java
Outdated
Show resolved
Hide resolved
...re/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java
Outdated
Show resolved
Hide resolved
...ransports/src/test/java/org/eclipse/jetty/test/client/transport/ServerRetainContentTest.java
Show resolved
Hide resolved
...ty-http3/jetty-http3-common/src/main/java/org/eclipse/jetty/http3/HTTP3StreamConnection.java
Outdated
Show resolved
Hide resolved
...ty-http3/jetty-http3-common/src/main/java/org/eclipse/jetty/http3/HTTP3StreamConnection.java
Outdated
Show resolved
Hide resolved
...ty-http3/jetty-http3-common/src/main/java/org/eclipse/jetty/http3/HTTP3StreamConnection.java
Outdated
Show resolved
Hide resolved
...ty-http3/jetty-http3-common/src/main/java/org/eclipse/jetty/http3/HTTP3StreamConnection.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
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.
Not another configuration parameter, see comment.
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
Outdated
Show resolved
Hide resolved
@sbordet I ended up making it extensible, with a I've not yet finished the modules and xml, but I've started, so you can see how this design makes that configuration make more sense (note that I'll be putting the optional non default MultiPartConfig in its own module). |
…tty-12.1.x/delayedDispatch # Conflicts: # jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/FormFields.java
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 quite like this new EagerContentHandler
, the way its implemented and made configurable.
Besides that new helper in the MultiPartConfig
builder which I find its implemented wrong, this LGTM.
jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartConfig.java
Show resolved
Hide resolved
…e used for setters with properties
I found several bugs in XmlConfiguration that prevented it being used with a Builder pattern. This PR now fixes them so we can build a MultiPartConfig in XML. Adding @lachlan-roberts to reviewers so he can check that. |
jetty-core/jetty-server/src/main/config/etc/jetty-eager-multipart-content.xml
Outdated
Show resolved
Hide resolved
* @param maxFields The maximum number of fields to accept | ||
* @param maxLength The maximum length of fields | ||
* @param maxFields The maximum number of fields to accept; or -1 for a default | ||
* @param maxLength The maximum length of fields; or -1 for a default |
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.
This is a bit misleading in a way, I think it was clearer before.
Because you can configure these to be -1 for no limit on the length.
So now if the context attribute of MAX_LENGTH_ATTRIBUTE
was set to -1, then it is unlimited, but if you call this method with -1 it is limited to MAX_LENGTH_DEFAULT
.
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 agree it is a bit confusing, but I need a way to pass in "use default value", otherwise we end up encoding default values in XML (see jetty-eager-content.xml) and in java. Do you have an alternative suggestion?
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.
It's also an issue if you want to use the default for maxFields, but pass in a maxLength value. With the current API, once you choose to pass in values, you have to pass in both and cannot access the default.
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 just tried added a <Default>
element to the XML to get the constants from Java, but the <Arg>
element doesn't allow a <Default>
element :(
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.
@lachlan-roberts and finally... the other API is deprecated, so it will soon go away. You can pass in MAX_VALUE for unlimited.
jetty-core/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlConfiguration.java
Show resolved
Hide resolved
…e used for setters with properties
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 like this approach much better.
Mostly nits, but few more important ones.
Documentation and DistributionTests are missing, but I can add them.
<Item> | ||
<New class="org.eclipse.jetty.server.handler.EagerContentHandler$RetainedContentLoaderFactory"> | ||
<Arg type="int"><Property name="jetty.eager.retained.maxRetainedBytes" default="-1"/></Arg> | ||
<Arg type="int"><Property name="jetty.eager.retained.frameOverhead" default="-1"/></Arg> |
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.
<Arg type="int"><Property name="jetty.eager.retained.frameOverhead" default="-1"/></Arg> | |
<Arg type="int"><Property name="jetty.eager.retained.framingOverhead" default="-1"/></Arg> |
<New class="org.eclipse.jetty.server.handler.EagerContentHandler$RetainedContentLoaderFactory"> | ||
<Arg type="int"><Property name="jetty.eager.retained.maxRetainedBytes" default="-1"/></Arg> | ||
<Arg type="int"><Property name="jetty.eager.retained.frameOverhead" default="-1"/></Arg> | ||
<Arg type="boolean"><Property name="jetty.eager.retained.reject" default="false"/></Arg> |
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.
<Arg type="boolean"><Property name="jetty.eager.retained.reject" default="false"/></Arg> | |
<Arg type="boolean"><Property name="jetty.eager.retained.rejectWhenExceeded" default="false"/></Arg> |
</Arg> | ||
</Call> | ||
|
||
<!-- TODO fields --> |
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.
What fields?
@@ -0,0 +1,43 @@ | |||
|
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.
Remove empty line.
# jetty.eager.retained.maxRetainedBytes=-1 | ||
|
||
## The frame overhead to use when calculating the retained bytes or -1 for a default | ||
# jetty.eager.retained.frameOverhead=-1 |
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.
# jetty.eager.retained.frameOverhead=-1 | |
# jetty.eager.retained.framingOverhead=-1 |
Response.writeError(getRequest(), getResponse(), getCallback(), t); | ||
} | ||
// return false to indicate the passed request/response/callback were not used. | ||
return false; |
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.
Cannot return false
here, because in all cases the response is generated and the callback completed.
This return value is only used in RetainedContentLoader.doHandle()
to release the chunks, but since the callback is invoked in all cases, they will be released already.
Perhaps we do not need a boolean
return type, just void
.
{ | ||
release(); | ||
_callback.succeeded(); | ||
} |
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.
Override failed(Throwable)
to release the chunks in case an error response fails.
{ | ||
private final Deque<Content.Chunk> _chunks = new ArrayDeque<>(); | ||
private final long _maxRetainedBytes; | ||
private final int _chunkOverhead; |
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.
private final int _chunkOverhead; | |
private final int _framingOverhead; |
* @param frameOverhead The bytes to account for per chunk when calculating the size; or -1 for a heuristic. | ||
* @param reject If {@code true} then requests are rejected if the content is not complete before maxRetainedBytes. | ||
*/ | ||
public RetainedContentLoader(Handler handler, Request request, Response response, Callback callback, long maxRetainedBytes, int frameOverhead, boolean reject) |
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.
public RetainedContentLoader(Handler handler, Request request, Response response, Callback callback, long maxRetainedBytes, int frameOverhead, boolean reject) | |
public RetainedContentLoader(Handler handler, Request request, Response response, Callback callback, long maxRetainedBytes, int framingOverhead, boolean rejectWhenExceeded) |
? Math.max(1, request.getConnectionMetaData().getConnector().getConnectionFactory(HttpConnectionFactory.class).getInputBufferSize() - 1500) | ||
: maxRetainedBytes; | ||
_chunkOverhead = frameOverhead < 0 | ||
? (request.getConnectionMetaData().getHttpVersion() == HttpVersion.HTTP_2 ? 9 : 8) |
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.
Also for HTTP/3, the framing depends on the content size, but it can only be at most 9 bytes.
So perhaps:
? (request.getConnectionMetaData().getHttpVersion() == HttpVersion.HTTP_2 ? 9 : 8) | |
? (request.getConnectionMetaData().getHttpVersion().getVersion() <= HttpVersion.HTTP_1_1.getVersion() ? 8 : 9) |
Fix #9051 with EagerContentHandler to replace DelayedHandler
The make the
EagerContentHandler.RetainedContentLoader
work efficiently this PR adjusted the buffering strategy of h1, h2 and h3 to keep and reuse a retained buffer until it is mostly full.Also fixed several bugs in XmlConfiguration: