[nginx] gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
Ruslan Ermilov
ru at nginx.com
Thu Apr 23 12:11:02 UTC 2020
details: https://hg.nginx.org/nginx/rev/2096b21fcd10
branches:
changeset: 7646:2096b21fcd10
user: Ruslan Ermilov <ru at nginx.com>
date: Thu Apr 23 15:10:24 2020 +0300
description:
gRPC: RST_STREAM(NO_ERROR) handling (ticket #1792).
As per https://tools.ietf.org/html/rfc7540#section-8.1,
: A server can send a complete response prior to the client
: sending an entire request if the response does not depend on
: any portion of the request that has not been sent and
: received. When this is true, a server MAY request that the
: client abort transmission of a request without error by
: sending a RST_STREAM with an error code of NO_ERROR after
: sending a complete response (i.e., a frame with the
: END_STREAM flag). Clients MUST NOT discard responses as a
: result of receiving such a RST_STREAM, though clients can
: always discard responses at their discretion for other
: reasons.
Previously, RST_STREAM(NO_ERROR) received from upstream after
a frame with the END_STREAM flag was incorrectly treated as an
error. Now, a single RST_STREAM(NO_ERROR) is properly handled.
This fixes problems observed with modern grpc-c [1], as well
as with the Go gRPC module.
[1] https://github.com/grpc/grpc/pull/1661
diffstat:
src/http/modules/ngx_http_grpc_module.c | 26 ++++++++++++++++++++------
1 files changed, 20 insertions(+), 6 deletions(-)
diffs (57 lines):
diff -r ed3a10cf88e8 -r 2096b21fcd10 src/http/modules/ngx_http_grpc_module.c
--- a/src/http/modules/ngx_http_grpc_module.c Thu Apr 23 15:10:21 2020 +0300
+++ b/src/http/modules/ngx_http_grpc_module.c Thu Apr 23 15:10:24 2020 +0300
@@ -120,6 +120,7 @@ typedef struct {
unsigned end_stream:1;
unsigned done:1;
unsigned status:1;
+ unsigned rst:1;
ngx_http_request_t *request;
@@ -1205,6 +1206,7 @@ ngx_http_grpc_reinit_request(ngx_http_re
ctx->end_stream = 0;
ctx->done = 0;
ctx->status = 0;
+ ctx->rst = 0;
ctx->connection = NULL;
return NGX_OK;
@@ -2088,7 +2090,9 @@ ngx_http_grpc_filter(void *data, ssize_t
return NGX_ERROR;
}
- if (ctx->stream_id && ctx->done) {
+ if (ctx->stream_id && ctx->done
+ && ctx->type != NGX_HTTP_V2_RST_STREAM_FRAME)
+ {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent frame for closed stream %ui",
ctx->stream_id);
@@ -2131,11 +2135,21 @@ ngx_http_grpc_filter(void *data, ssize_t
return NGX_ERROR;
}
- ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "upstream rejected request with error %ui",
- ctx->error);
-
- return NGX_ERROR;
+ if (ctx->error || !ctx->done) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream rejected request with error %ui",
+ ctx->error);
+ return NGX_ERROR;
+ }
+
+ if (ctx->rst) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream sent frame for closed stream %ui",
+ ctx->stream_id);
+ return NGX_ERROR;
+ }
+
+ ctx->rst = 1;
}
if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
More information about the nginx-devel
mailing list