-
Notifications
You must be signed in to change notification settings - Fork 942
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
Avoid leaking request contexts from server-side #6166
Conversation
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.
The new approach looks nice. 👍
@@ -842,6 +843,11 @@ private void handleRequestOrResponseComplete() { | |||
unfinishedRequests.remove(req); | |||
} | |||
|
|||
if (responseEncoder instanceof ServerHttp2ObjectEncoder) { | |||
((ServerHttp2ObjectEncoder) responseEncoder) | |||
.maybeResetStream(req.streamId(), Http2Error.CANCEL); |
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.
question:
Can we do this only when needsDisconnection
is 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.
Simplicity 👍
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.
👍👍
Motivation: It has been pointed out that server-side may hold strong references to the `ServiceRequestContext` in line#6108. In general, a server-side `HttpRequest` may be closed either 1) by the client 2) or by the user. When the request is closed by the client, the connection or stream state is reflected to the `HttpRequest` - hence the two are in sync. However, if the `HttpRequest` is closed by the user the state is not always reflected to the connection or stream. For instance, setting `ServerBuilder#requestAutoAbortDelayMillis` will close the request but not the underlying connection or stream. The handling of `ContentTooLargeException` attempts to handle this issue. However, if `setShouldResetOnlyIfRemoteIsOpen` is set after the response is fully written, then the underlying stream may still never be closed. https://github.com/line/armeria/blob/6dbed576fe8f0774f445716c74c01c7572799ee6/core/src/main/java/com/linecorp/armeria/server/AbstractHttpResponseSubscriber.java#L389 **Proposal** I propose the following: - HTTP1: - If there is a protocol failure, the `Http1RequestDecoder` is responsible for closing the connection - Otherwise, the underlying stream will be completed once the remote completes the request. Because pipelining is rarely used, HTTP1 connections will have a constraint of 1 concurrent request which probably won't impose a memory burden. - HTTP2: - Once the `HttpRequest`/`HttpResponse` is completed, the underlying stream state is checked. If the underlying stream is not closed yet, a `RST_STREAM` is sent to sync the stream state with the `HttpRequest`/`HttpResponse` state. - Note that this behavior relies on the fact that `Http2Stream#State` is updated synchronously when `Http2FrameWriter#writeHeaders` is called. Modifications: - Introduced `ServerHttp2ObjectEncoder#maybeResetStream` which sends a `RST_STREAM` if the underlying state is not complete. - `ServerHttp2ObjectEncoder#maybeResetStream` is called when the protocol is HTTP2 and the request/response is complete. - Removed `resetOnlyIfRemoteIsOpen` since `maybeResetStream` replaces this functionality. Result: - Users no longer observe memory pressure due to incomplete HTTP2 streams.
Motivation:
It has been pointed out that server-side may hold strong references to the
ServiceRequestContext
in #6108.In general, a server-side
HttpRequest
may be closed either 1) by the client 2) or by the user.When the request is closed by the client, the connection or stream state is reflected to the
HttpRequest
- hence the two are in sync.However, if the
HttpRequest
is closed by the user the state is not always reflected to the connection or stream.For instance, setting
ServerBuilder#requestAutoAbortDelayMillis
will close the request but not the underlying connection or stream.The handling of
ContentTooLargeException
attempts to handle this issue. However, ifsetShouldResetOnlyIfRemoteIsOpen
is set after the response is fully written, then the underlying stream may still never be closed.armeria/core/src/main/java/com/linecorp/armeria/server/AbstractHttpResponseSubscriber.java
Line 389 in 6dbed57
Proposal
I propose the following:
Http1RequestDecoder
is responsible for closing the connectionHttpRequest
/HttpResponse
is completed, the underlying stream state is checked. If the underlying stream is not closed yet, aRST_STREAM
is sent to sync the stream state with theHttpRequest
/HttpResponse
state.Http2Stream#State
is updated synchronously whenHttp2FrameWriter#writeHeaders
is called.Modifications:
ServerHttp2ObjectEncoder#maybeResetStream
which sends aRST_STREAM
if the underlying state is not complete.ServerHttp2ObjectEncoder#maybeResetStream
is called when the protocol is HTTP2 and the request/response is complete.resetOnlyIfRemoteIsOpen
sincemaybeResetStream
replaces this functionality.Result: