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);