mirror of
https://github.com/nginx/nginx.git
synced 2024-12-25 08:21:13 -06:00
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
This commit is contained in:
parent
8c0a49472c
commit
4c8abb84e3
@ -120,6 +120,7 @@ typedef struct {
|
|||||||
unsigned end_stream:1;
|
unsigned end_stream:1;
|
||||||
unsigned done:1;
|
unsigned done:1;
|
||||||
unsigned status:1;
|
unsigned status:1;
|
||||||
|
unsigned rst:1;
|
||||||
|
|
||||||
ngx_http_request_t *request;
|
ngx_http_request_t *request;
|
||||||
|
|
||||||
@ -1205,6 +1206,7 @@ ngx_http_grpc_reinit_request(ngx_http_request_t *r)
|
|||||||
ctx->end_stream = 0;
|
ctx->end_stream = 0;
|
||||||
ctx->done = 0;
|
ctx->done = 0;
|
||||||
ctx->status = 0;
|
ctx->status = 0;
|
||||||
|
ctx->rst = 0;
|
||||||
ctx->connection = NULL;
|
ctx->connection = NULL;
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
@ -2088,7 +2090,9 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
|
|||||||
return NGX_ERROR;
|
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,
|
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||||
"upstream sent frame for closed stream %ui",
|
"upstream sent frame for closed stream %ui",
|
||||||
ctx->stream_id);
|
ctx->stream_id);
|
||||||
@ -2131,13 +2135,23 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
|
|||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ctx->error || !ctx->done) {
|
||||||
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
|
||||||
"upstream rejected request with error %ui",
|
"upstream rejected request with error %ui",
|
||||||
ctx->error);
|
ctx->error);
|
||||||
|
|
||||||
return NGX_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) {
|
if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) {
|
||||||
|
|
||||||
rc = ngx_http_grpc_parse_goaway(r, ctx, b);
|
rc = ngx_http_grpc_parse_goaway(r, ctx, b);
|
||||||
|
Loading…
Reference in New Issue
Block a user