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 }