comparison src/http/modules/ngx_http_grpc_module.c @ 7680:39501ce97e29

gRPC: generate error when response size is wrong. As long as the "Content-Length" header is given, we now make sure it exactly matches the size of the response. If it doesn't, the response is considered malformed and must not be forwarded (https://tools.ietf.org/html/rfc7540#section-8.1.2.6). While it is not really possible to "not forward" the response which is already being forwarded, we generate an error instead, which is the closest equivalent. Previous behaviour was to pass everything to the client, but this seems to be suboptimal and causes issues (ticket #1695). Also this directly contradicts HTTP/2 specification requirements. Note that the new behaviour for the gRPC proxy is more strict than that applied in other variants of proxying. This is intentional, as HTTP/2 specification requires us to do so, while in other types of proxying malformed responses from backends are well known and historically tolerated.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 06 Jul 2020 18:36:25 +0300
parents 716eddd74bc2
children 485dba3e2a01
comparison
equal deleted inserted replaced
7679:05e42236e95b 7680:39501ce97e29
81 81
82 ngx_uint_t id; 82 ngx_uint_t id;
83 83
84 ngx_uint_t pings; 84 ngx_uint_t pings;
85 ngx_uint_t settings; 85 ngx_uint_t settings;
86
87 off_t length;
86 88
87 ssize_t send_window; 89 ssize_t send_window;
88 size_t recv_window; 90 size_t recv_window;
89 91
90 size_t rest; 92 size_t rest;
1951 ngx_http_upstream_t *u; 1953 ngx_http_upstream_t *u;
1952 1954
1953 r = ctx->request; 1955 r = ctx->request;
1954 u = r->upstream; 1956 u = r->upstream;
1955 1957
1956 u->length = 1; 1958 if (u->headers_in.status_n == NGX_HTTP_NO_CONTENT
1959 || u->headers_in.status_n == NGX_HTTP_NOT_MODIFIED
1960 || r->method == NGX_HTTP_HEAD)
1961 {
1962 ctx->length = 0;
1963
1964 } else {
1965 ctx->length = u->headers_in.content_length_n;
1966 }
1957 1967
1958 if (ctx->end_stream) { 1968 if (ctx->end_stream) {
1969
1970 if (ctx->length > 0) {
1971 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1972 "upstream prematurely closed stream");
1973 return NGX_ERROR;
1974 }
1975
1959 u->length = 0; 1976 u->length = 0;
1977
1978 } else {
1979 u->length = 1;
1960 } 1980 }
1961 1981
1962 return NGX_OK; 1982 return NGX_OK;
1963 } 1983 }
1964 1984
1996 rc = ngx_http_grpc_parse_frame(r, ctx, b); 2016 rc = ngx_http_grpc_parse_frame(r, ctx, b);
1997 2017
1998 if (rc == NGX_AGAIN) { 2018 if (rc == NGX_AGAIN) {
1999 2019
2000 if (ctx->done) { 2020 if (ctx->done) {
2021
2022 if (ctx->length > 0) {
2023 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2024 "upstream prematurely closed stream");
2025 return NGX_ERROR;
2026 }
2001 2027
2002 /* 2028 /*
2003 * We have finished parsing the response and the 2029 * We have finished parsing the response and the
2004 * remaining control frames. If there are unsent 2030 * remaining control frames. If there are unsent
2005 * control frames, post a write event to send them. 2031 * control frames, post a write event to send them.
2048 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 2074 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2049 "upstream sent data frame " 2075 "upstream sent data frame "
2050 "for unknown stream %ui", 2076 "for unknown stream %ui",
2051 ctx->stream_id); 2077 ctx->stream_id);
2052 return NGX_ERROR; 2078 return NGX_ERROR;
2079 }
2080
2081 if (ctx->length != -1) {
2082 if ((off_t) ctx->rest > ctx->length) {
2083 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2084 "upstream sent response body larger "
2085 "than indicated content length");
2086 return NGX_ERROR;
2087 }
2088
2089 ctx->length -= ctx->rest;
2053 } 2090 }
2054 2091
2055 if (ctx->rest > ctx->recv_window) { 2092 if (ctx->rest > ctx->recv_window) {
2056 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 2093 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
2057 "upstream violated stream flow control, " 2094 "upstream violated stream flow control, "