Mercurial > hg > nginx
comparison src/http/modules/ngx_http_grpc_module.c @ 7416:c948804cd628 stable-1.14
gRPC: improved keepalive handling.
The code is now able to parse additional control frames after
the response is received, and can send control frames as well.
This fixes keepalive problems as observed with grpc-c, which can
send window update and ping frames after the response, see
http://mailman.nginx.org/pipermail/nginx/2018-August/056620.html.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 03 Sep 2018 19:34:01 +0300 |
parents | 9ac0e8b9aced |
children | dc69f7aa6ca6 |
comparison
equal
deleted
inserted
replaced
7415:2cf1d945bbb3 | 7416:c948804cd628 |
---|---|
112 | 112 |
113 unsigned header_sent:1; | 113 unsigned header_sent:1; |
114 unsigned output_closed:1; | 114 unsigned output_closed:1; |
115 unsigned parsing_headers:1; | 115 unsigned parsing_headers:1; |
116 unsigned end_stream:1; | 116 unsigned end_stream:1; |
117 unsigned done:1; | |
117 unsigned status:1; | 118 unsigned status:1; |
118 | 119 |
119 ngx_http_request_t *request; | 120 ngx_http_request_t *request; |
120 } ngx_http_grpc_ctx_t; | 121 } ngx_http_grpc_ctx_t; |
121 | 122 |
1075 ctx->state = 0; | 1076 ctx->state = 0; |
1076 ctx->header_sent = 0; | 1077 ctx->header_sent = 0; |
1077 ctx->output_closed = 0; | 1078 ctx->output_closed = 0; |
1078 ctx->parsing_headers = 0; | 1079 ctx->parsing_headers = 0; |
1079 ctx->end_stream = 0; | 1080 ctx->end_stream = 0; |
1081 ctx->done = 0; | |
1080 ctx->status = 0; | 1082 ctx->status = 0; |
1081 ctx->connection = NULL; | 1083 ctx->connection = NULL; |
1082 | 1084 |
1083 return NGX_OK; | 1085 return NGX_OK; |
1084 } | 1086 } |
1094 size_t len, limit; | 1096 size_t len, limit; |
1095 ngx_buf_t *b; | 1097 ngx_buf_t *b; |
1096 ngx_int_t rc; | 1098 ngx_int_t rc; |
1097 ngx_uint_t next, last; | 1099 ngx_uint_t next, last; |
1098 ngx_chain_t *cl, *out, **ll; | 1100 ngx_chain_t *cl, *out, **ll; |
1101 ngx_http_upstream_t *u; | |
1099 ngx_http_grpc_ctx_t *ctx; | 1102 ngx_http_grpc_ctx_t *ctx; |
1100 ngx_http_grpc_frame_t *f; | 1103 ngx_http_grpc_frame_t *f; |
1101 | 1104 |
1102 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 1105 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
1103 "grpc output filter"); | 1106 "grpc output filter"); |
1406 } | 1409 } |
1407 } | 1410 } |
1408 | 1411 |
1409 if (rc == NGX_OK && ctx->in) { | 1412 if (rc == NGX_OK && ctx->in) { |
1410 rc = NGX_AGAIN; | 1413 rc = NGX_AGAIN; |
1414 } | |
1415 | |
1416 if (ctx->done) { | |
1417 | |
1418 /* | |
1419 * We have already got the response and were sending some additional | |
1420 * control frames. Even if there is still something unsent, stop | |
1421 * here anyway. | |
1422 */ | |
1423 | |
1424 u = r->upstream; | |
1425 u->length = 0; | |
1426 | |
1427 if (ctx->in == NULL | |
1428 && ctx->out == NULL | |
1429 && ctx->output_closed | |
1430 && ctx->state == ngx_http_grpc_st_start) | |
1431 { | |
1432 u->keepalive = 1; | |
1433 } | |
1434 | |
1435 ngx_post_event(u->peer.connection->read, &ngx_posted_events); | |
1411 } | 1436 } |
1412 | 1437 |
1413 return rc; | 1438 return rc; |
1414 } | 1439 } |
1415 | 1440 |
1833 if (ctx->state < ngx_http_grpc_st_payload) { | 1858 if (ctx->state < ngx_http_grpc_st_payload) { |
1834 | 1859 |
1835 rc = ngx_http_grpc_parse_frame(r, ctx, b); | 1860 rc = ngx_http_grpc_parse_frame(r, ctx, b); |
1836 | 1861 |
1837 if (rc == NGX_AGAIN) { | 1862 if (rc == NGX_AGAIN) { |
1863 | |
1864 if (ctx->done) { | |
1865 | |
1866 /* | |
1867 * We have finished parsing the response and the | |
1868 * remaining control frames. If there are unsent | |
1869 * control frames, post a write event to send them. | |
1870 */ | |
1871 | |
1872 if (ctx->out) { | |
1873 ngx_post_event(u->peer.connection->write, | |
1874 &ngx_posted_events); | |
1875 return NGX_AGAIN; | |
1876 } | |
1877 | |
1878 u->length = 0; | |
1879 | |
1880 if (ctx->in == NULL | |
1881 && ctx->output_closed | |
1882 && ctx->state == ngx_http_grpc_st_start) | |
1883 { | |
1884 u->keepalive = 1; | |
1885 } | |
1886 | |
1887 break; | |
1888 } | |
1889 | |
1838 return NGX_AGAIN; | 1890 return NGX_AGAIN; |
1839 } | 1891 } |
1840 | 1892 |
1841 if (rc == NGX_ERROR) { | 1893 if (rc == NGX_ERROR) { |
1842 return NGX_ERROR; | 1894 return NGX_ERROR; |
1899 "upstream sent frame for unknown stream %ui", | 1951 "upstream sent frame for unknown stream %ui", |
1900 ctx->stream_id); | 1952 ctx->stream_id); |
1901 return NGX_ERROR; | 1953 return NGX_ERROR; |
1902 } | 1954 } |
1903 | 1955 |
1956 if (ctx->stream_id && ctx->done) { | |
1957 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
1958 "upstream sent frame for closed stream %ui", | |
1959 ctx->stream_id); | |
1960 return NGX_ERROR; | |
1961 } | |
1962 | |
1904 ctx->padding = 0; | 1963 ctx->padding = 0; |
1905 } | 1964 } |
1906 | 1965 |
1907 if (ctx->state == ngx_http_grpc_st_padding) { | 1966 if (ctx->state == ngx_http_grpc_st_padding) { |
1908 | 1967 |
1915 b->pos += ctx->rest; | 1974 b->pos += ctx->rest; |
1916 ctx->rest = 0; | 1975 ctx->rest = 0; |
1917 ctx->state = ngx_http_grpc_st_start; | 1976 ctx->state = ngx_http_grpc_st_start; |
1918 | 1977 |
1919 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) { | 1978 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) { |
1920 u->length = 0; | 1979 ctx->done = 1; |
1921 | |
1922 if (ctx->in == NULL | |
1923 && ctx->out == NULL | |
1924 && ctx->output_closed | |
1925 && b->last == b->pos) | |
1926 { | |
1927 u->keepalive = 1; | |
1928 } | |
1929 | |
1930 break; | |
1931 } | 1980 } |
1932 | 1981 |
1933 continue; | 1982 continue; |
1934 } | 1983 } |
1935 | 1984 |
2095 | 2144 |
2096 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 2145 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2097 "grpc trailer done"); | 2146 "grpc trailer done"); |
2098 | 2147 |
2099 if (ctx->end_stream) { | 2148 if (ctx->end_stream) { |
2100 u->length = 0; | 2149 ctx->done = 1; |
2101 | 2150 break; |
2102 if (ctx->in == NULL | |
2103 && ctx->out == NULL | |
2104 && ctx->output_closed | |
2105 && b->last == b->pos) | |
2106 { | |
2107 u->keepalive = 1; | |
2108 } | |
2109 | |
2110 return NGX_OK; | |
2111 } | 2151 } |
2112 | 2152 |
2113 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | 2153 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
2114 "upstream sent trailer without " | 2154 "upstream sent trailer without " |
2115 "end stream flag"); | 2155 "end stream flag"); |
2120 | 2160 |
2121 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | 2161 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
2122 "upstream sent invalid trailer"); | 2162 "upstream sent invalid trailer"); |
2123 | 2163 |
2124 return NGX_ERROR; | 2164 return NGX_ERROR; |
2165 } | |
2166 | |
2167 if (rc == NGX_HTTP_PARSE_HEADER_DONE) { | |
2168 continue; | |
2125 } | 2169 } |
2126 | 2170 |
2127 /* rc == NGX_AGAIN */ | 2171 /* rc == NGX_AGAIN */ |
2128 | 2172 |
2129 if (ctx->rest == 0) { | 2173 if (ctx->rest == 0) { |
2238 } | 2282 } |
2239 | 2283 |
2240 ctx->state = ngx_http_grpc_st_start; | 2284 ctx->state = ngx_http_grpc_st_start; |
2241 | 2285 |
2242 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) { | 2286 if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) { |
2243 u->length = 0; | 2287 ctx->done = 1; |
2244 | |
2245 if (ctx->in == NULL | |
2246 && ctx->out == NULL | |
2247 && ctx->output_closed | |
2248 && b->last == b->pos) | |
2249 { | |
2250 u->keepalive = 1; | |
2251 } | |
2252 | |
2253 break; | |
2254 } | 2288 } |
2255 } | 2289 } |
2256 | 2290 |
2257 return NGX_OK; | 2291 return NGX_OK; |
2258 } | 2292 } |