Mercurial > hg > nginx
comparison src/http/modules/ngx_http_grpc_module.c @ 7646:2096b21fcd10
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
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Thu, 23 Apr 2020 15:10:24 +0300 |
parents | 6439ef81e37d |
children | 716eddd74bc2 |
comparison
equal
deleted
inserted
replaced
7645:ed3a10cf88e8 | 7646:2096b21fcd10 |
---|---|
118 unsigned output_blocked:1; | 118 unsigned output_blocked:1; |
119 unsigned parsing_headers:1; | 119 unsigned parsing_headers:1; |
120 unsigned end_stream:1; | 120 unsigned end_stream:1; |
121 unsigned done:1; | 121 unsigned done:1; |
122 unsigned status:1; | 122 unsigned status:1; |
123 unsigned rst:1; | |
123 | 124 |
124 ngx_http_request_t *request; | 125 ngx_http_request_t *request; |
125 | 126 |
126 ngx_str_t host; | 127 ngx_str_t host; |
127 } ngx_http_grpc_ctx_t; | 128 } ngx_http_grpc_ctx_t; |
1203 ctx->output_blocked = 0; | 1204 ctx->output_blocked = 0; |
1204 ctx->parsing_headers = 0; | 1205 ctx->parsing_headers = 0; |
1205 ctx->end_stream = 0; | 1206 ctx->end_stream = 0; |
1206 ctx->done = 0; | 1207 ctx->done = 0; |
1207 ctx->status = 0; | 1208 ctx->status = 0; |
1209 ctx->rst = 0; | |
1208 ctx->connection = NULL; | 1210 ctx->connection = NULL; |
1209 | 1211 |
1210 return NGX_OK; | 1212 return NGX_OK; |
1211 } | 1213 } |
1212 | 1214 |
2086 "upstream sent frame for unknown stream %ui", | 2088 "upstream sent frame for unknown stream %ui", |
2087 ctx->stream_id); | 2089 ctx->stream_id); |
2088 return NGX_ERROR; | 2090 return NGX_ERROR; |
2089 } | 2091 } |
2090 | 2092 |
2091 if (ctx->stream_id && ctx->done) { | 2093 if (ctx->stream_id && ctx->done |
2094 && ctx->type != NGX_HTTP_V2_RST_STREAM_FRAME) | |
2095 { | |
2092 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | 2096 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
2093 "upstream sent frame for closed stream %ui", | 2097 "upstream sent frame for closed stream %ui", |
2094 ctx->stream_id); | 2098 ctx->stream_id); |
2095 return NGX_ERROR; | 2099 return NGX_ERROR; |
2096 } | 2100 } |
2129 | 2133 |
2130 if (rc == NGX_ERROR) { | 2134 if (rc == NGX_ERROR) { |
2131 return NGX_ERROR; | 2135 return NGX_ERROR; |
2132 } | 2136 } |
2133 | 2137 |
2134 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | 2138 if (ctx->error || !ctx->done) { |
2135 "upstream rejected request with error %ui", | 2139 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
2136 ctx->error); | 2140 "upstream rejected request with error %ui", |
2137 | 2141 ctx->error); |
2138 return NGX_ERROR; | 2142 return NGX_ERROR; |
2143 } | |
2144 | |
2145 if (ctx->rst) { | |
2146 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
2147 "upstream sent frame for closed stream %ui", | |
2148 ctx->stream_id); | |
2149 return NGX_ERROR; | |
2150 } | |
2151 | |
2152 ctx->rst = 1; | |
2139 } | 2153 } |
2140 | 2154 |
2141 if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { | 2155 if (ctx->type == NGX_HTTP_V2_GOAWAY_FRAME) { |
2142 | 2156 |
2143 rc = ngx_http_grpc_parse_goaway(r, ctx, b); | 2157 rc = ngx_http_grpc_parse_goaway(r, ctx, b); |