Mercurial > hg > nginx
comparison src/http/v2/ngx_http_v2.c @ 6412:4ba91a4c66a3
HTTP/2: implemented per request timeouts (closes #626).
Previously, there were only three timeouts used globally for the whole HTTP/2
connection:
1. Idle timeout for inactivity when there are no streams in processing
(the "http2_idle_timeout" directive);
2. Receive timeout for incomplete frames when there are no streams in
processing (the "http2_recv_timeout" directive);
3. Send timeout when there are frames waiting in the output queue
(the "send_timeout" directive on a server level).
Reaching one of these timeouts leads to HTTP/2 connection close.
This left a number of scenarios when a connection can get stuck without any
processing and timeouts:
1. A client has sent the headers block partially so nginx starts processing
a new stream but cannot continue without the rest of HEADERS and/or
CONTINUATION frames;
2. When nginx waits for the request body;
3. All streams are stuck on exhausted connection or stream windows.
The first idea that was rejected was to detect when the whole connection
gets stuck because of these situations and set the global receive timeout.
The disadvantage of such approach would be inconsistent behaviour in some
typical use cases. For example, if a user never replies to the browser's
question about where to save the downloaded file, the stream will be
eventually closed by a timeout. On the other hand, this will not happen
if there's some activity in other concurrent streams.
Now almost all the request timeouts work like in HTTP/1.x connections, so
the "client_header_timeout", "client_body_timeout", and "send_timeout" are
respected. These timeouts close the request.
The global timeouts work as before.
Previously, the c->write->delayed flag was abused to avoid setting timeouts on
stream events. Now, the "active" and "ready" flags are manipulated instead to
control the processing of individual streams.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Wed, 24 Feb 2016 15:58:07 +0300 |
parents | 8ec349bb60b2 |
children | 4d1d3c2530e0 |
comparison
equal
deleted
inserted
replaced
6411:8ec349bb60b2 | 6412:4ba91a4c66a3 |
---|---|
112 u_char *pos, u_char *end); | 112 u_char *pos, u_char *end); |
113 static u_char *ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, | 113 static u_char *ngx_http_v2_state_skip(ngx_http_v2_connection_t *h2c, |
114 u_char *pos, u_char *end); | 114 u_char *pos, u_char *end); |
115 static u_char *ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, | 115 static u_char *ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, |
116 u_char *pos, u_char *end, ngx_http_v2_handler_pt handler); | 116 u_char *pos, u_char *end, ngx_http_v2_handler_pt handler); |
117 static u_char *ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c, | |
118 u_char *pos, u_char *end, ngx_http_v2_handler_pt handler); | |
117 static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, | 119 static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, |
118 ngx_uint_t err); | 120 ngx_uint_t err); |
119 | 121 |
120 static ngx_int_t ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, | 122 static ngx_int_t ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, |
121 u_char **pos, u_char *end, ngx_uint_t prefix); | 123 u_char **pos, u_char *end, ngx_uint_t prefix); |
160 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r, | 162 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r, |
161 ngx_http_v2_header_t *header); | 163 ngx_http_v2_header_t *header); |
162 static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); | 164 static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); |
163 static void ngx_http_v2_run_request(ngx_http_request_t *r); | 165 static void ngx_http_v2_run_request(ngx_http_request_t *r); |
164 static ngx_int_t ngx_http_v2_init_request_body(ngx_http_request_t *r); | 166 static ngx_int_t ngx_http_v2_init_request_body(ngx_http_request_t *r); |
167 static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r); | |
165 | 168 |
166 static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, | 169 static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, |
167 ngx_http_v2_stream_t *stream, ngx_uint_t status); | 170 ngx_http_v2_stream_t *stream, ngx_uint_t status); |
168 static void ngx_http_v2_close_stream_handler(ngx_event_t *ev); | 171 static void ngx_http_v2_close_stream_handler(ngx_event_t *ev); |
169 static void ngx_http_v2_handle_connection_handler(ngx_event_t *rev); | 172 static void ngx_http_v2_handle_connection_handler(ngx_event_t *rev); |
428 | 431 |
429 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | 432 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
430 "run http2 stream %ui", stream->node->id); | 433 "run http2 stream %ui", stream->node->id); |
431 | 434 |
432 wev = stream->request->connection->write; | 435 wev = stream->request->connection->write; |
436 | |
437 wev->active = 0; | |
438 wev->ready = 1; | |
439 | |
433 wev->handler(wev); | 440 wev->handler(wev); |
434 } | 441 } |
435 | 442 |
436 h2c->blocked = 0; | 443 h2c->blocked = 0; |
437 | 444 |
881 size_t size; | 888 size_t size; |
882 ssize_t n; | 889 ssize_t n; |
883 ngx_buf_t *buf; | 890 ngx_buf_t *buf; |
884 ngx_int_t rc; | 891 ngx_int_t rc; |
885 ngx_temp_file_t *tf; | 892 ngx_temp_file_t *tf; |
893 ngx_connection_t *fc; | |
886 ngx_http_request_t *r; | 894 ngx_http_request_t *r; |
887 ngx_http_v2_stream_t *stream; | 895 ngx_http_v2_stream_t *stream; |
888 ngx_http_request_body_t *rb; | 896 ngx_http_request_body_t *rb; |
889 ngx_http_core_loc_conf_t *clcf; | 897 ngx_http_core_loc_conf_t *clcf; |
890 | 898 |
917 { | 925 { |
918 stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; | 926 stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; |
919 return ngx_http_v2_state_skip_padded(h2c, pos, end); | 927 return ngx_http_v2_state_skip_padded(h2c, pos, end); |
920 } | 928 } |
921 | 929 |
930 fc = r->connection; | |
922 rb = r->request_body; | 931 rb = r->request_body; |
923 tf = rb->temp_file; | 932 tf = rb->temp_file; |
924 buf = rb->buf; | 933 buf = rb->buf; |
925 | 934 |
926 if (size) { | 935 if (size) { |
927 rb->rest += size; | 936 rb->rest += size; |
928 | 937 |
929 if (r->headers_in.content_length_n != -1 | 938 if (r->headers_in.content_length_n != -1 |
930 && r->headers_in.content_length_n < rb->rest) | 939 && r->headers_in.content_length_n < rb->rest) |
931 { | 940 { |
932 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | 941 ngx_log_error(NGX_LOG_INFO, fc->log, 0, |
933 "client intended to send body data " | 942 "client intended to send body data " |
934 "larger than declared"); | 943 "larger than declared"); |
935 | 944 |
936 stream->skip_data = NGX_HTTP_V2_DATA_ERROR; | 945 stream->skip_data = NGX_HTTP_V2_DATA_ERROR; |
937 goto error; | 946 goto error; |
940 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | 949 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
941 | 950 |
942 if (clcf->client_max_body_size | 951 if (clcf->client_max_body_size |
943 && clcf->client_max_body_size < rb->rest) | 952 && clcf->client_max_body_size < rb->rest) |
944 { | 953 { |
945 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | 954 ngx_log_error(NGX_LOG_ERR, fc->log, 0, |
946 "client intended to send " | 955 "client intended to send " |
947 "too large chunked body: %O bytes", rb->rest); | 956 "too large chunked body: %O bytes", rb->rest); |
948 | 957 |
949 stream->skip_data = NGX_HTTP_V2_DATA_ERROR; | 958 stream->skip_data = NGX_HTTP_V2_DATA_ERROR; |
950 goto error; | 959 goto error; |
980 | 989 |
981 r->request_length += size; | 990 r->request_length += size; |
982 } | 991 } |
983 | 992 |
984 if (h2c->state.length) { | 993 if (h2c->state.length) { |
994 if (rb->post_handler) { | |
995 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
996 ngx_add_timer(fc->read, clcf->client_body_timeout); | |
997 } | |
998 | |
985 return ngx_http_v2_state_save(h2c, pos, end, | 999 return ngx_http_v2_state_save(h2c, pos, end, |
986 ngx_http_v2_state_read_data); | 1000 ngx_http_v2_state_read_data); |
987 } | 1001 } |
988 | 1002 |
989 if (h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) { | 1003 if (h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) { |
991 | 1005 |
992 if (r->headers_in.content_length_n < 0) { | 1006 if (r->headers_in.content_length_n < 0) { |
993 r->headers_in.content_length_n = rb->rest; | 1007 r->headers_in.content_length_n = rb->rest; |
994 | 1008 |
995 } else if (r->headers_in.content_length_n != rb->rest) { | 1009 } else if (r->headers_in.content_length_n != rb->rest) { |
996 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, | 1010 ngx_log_error(NGX_LOG_INFO, fc->log, 0, |
997 "client prematurely closed stream: " | 1011 "client prematurely closed stream: " |
998 "only %O out of %O bytes of request body received", | 1012 "only %O out of %O bytes of request body received", |
999 rb->rest, r->headers_in.content_length_n); | 1013 rb->rest, r->headers_in.content_length_n); |
1000 | 1014 |
1001 stream->skip_data = NGX_HTTP_V2_DATA_ERROR; | 1015 stream->skip_data = NGX_HTTP_V2_DATA_ERROR; |
1011 | 1025 |
1012 rb->buf = NULL; | 1026 rb->buf = NULL; |
1013 } | 1027 } |
1014 | 1028 |
1015 if (rb->post_handler) { | 1029 if (rb->post_handler) { |
1030 if (fc->read->timer_set) { | |
1031 ngx_del_timer(fc->read); | |
1032 } | |
1033 | |
1016 r->read_event_handler = ngx_http_block_reading; | 1034 r->read_event_handler = ngx_http_block_reading; |
1017 rb->post_handler(r); | 1035 rb->post_handler(r); |
1018 } | 1036 } |
1037 | |
1038 } else if (rb->post_handler) { | |
1039 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
1040 ngx_add_timer(fc->read, clcf->client_body_timeout); | |
1019 } | 1041 } |
1020 | 1042 |
1021 if (h2c->state.padding) { | 1043 if (h2c->state.padding) { |
1022 return ngx_http_v2_state_skip_padded(h2c, pos, end); | 1044 return ngx_http_v2_state_skip_padded(h2c, pos, end); |
1023 } | 1045 } |
1025 return ngx_http_v2_state_complete(h2c, pos, end); | 1047 return ngx_http_v2_state_complete(h2c, pos, end); |
1026 | 1048 |
1027 error: | 1049 error: |
1028 | 1050 |
1029 if (rb->post_handler) { | 1051 if (rb->post_handler) { |
1052 if (fc->read->timer_set) { | |
1053 ngx_del_timer(fc->read); | |
1054 } | |
1030 | 1055 |
1031 if (stream->skip_data == NGX_HTTP_V2_DATA_ERROR) { | 1056 if (stream->skip_data == NGX_HTTP_V2_DATA_ERROR) { |
1032 rc = (r->headers_in.content_length_n == -1) | 1057 rc = (r->headers_in.content_length_n == -1) |
1033 ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE : NGX_HTTP_BAD_REQUEST; | 1058 ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE : NGX_HTTP_BAD_REQUEST; |
1034 | 1059 |
1216 u_char ch; | 1241 u_char ch; |
1217 ngx_int_t value; | 1242 ngx_int_t value; |
1218 ngx_uint_t indexed, size_update, prefix; | 1243 ngx_uint_t indexed, size_update, prefix; |
1219 | 1244 |
1220 if (end - pos < 1) { | 1245 if (end - pos < 1) { |
1221 return ngx_http_v2_state_save(h2c, pos, end, | 1246 return ngx_http_v2_state_headers_save(h2c, pos, end, |
1222 ngx_http_v2_state_header_block); | 1247 ngx_http_v2_state_header_block); |
1223 } | 1248 } |
1224 | 1249 |
1225 if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) | 1250 if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) |
1226 && h2c->state.length < NGX_HTTP_V2_INT_OCTETS) | 1251 && h2c->state.length < NGX_HTTP_V2_INT_OCTETS) |
1227 { | 1252 { |
1260 | 1285 |
1261 value = ngx_http_v2_parse_int(h2c, &pos, end, prefix); | 1286 value = ngx_http_v2_parse_int(h2c, &pos, end, prefix); |
1262 | 1287 |
1263 if (value < 0) { | 1288 if (value < 0) { |
1264 if (value == NGX_AGAIN) { | 1289 if (value == NGX_AGAIN) { |
1265 return ngx_http_v2_state_save(h2c, pos, end, | 1290 return ngx_http_v2_state_headers_save(h2c, pos, end, |
1266 ngx_http_v2_state_header_block); | 1291 ngx_http_v2_state_header_block); |
1267 } | 1292 } |
1268 | 1293 |
1269 if (value == NGX_DECLINED) { | 1294 if (value == NGX_DECLINED) { |
1270 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | 1295 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, |
1271 "client sent header block with too long %s value", | 1296 "client sent header block with too long %s value", |
1331 | 1356 |
1332 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); | 1357 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); |
1333 } | 1358 } |
1334 | 1359 |
1335 if (end - pos < 1) { | 1360 if (end - pos < 1) { |
1336 return ngx_http_v2_state_save(h2c, pos, end, | 1361 return ngx_http_v2_state_headers_save(h2c, pos, end, |
1337 ngx_http_v2_state_field_len); | 1362 ngx_http_v2_state_field_len); |
1338 } | 1363 } |
1339 | 1364 |
1340 huff = *pos >> 7; | 1365 huff = *pos >> 7; |
1341 len = ngx_http_v2_parse_int(h2c, &pos, end, ngx_http_v2_prefix(7)); | 1366 len = ngx_http_v2_parse_int(h2c, &pos, end, ngx_http_v2_prefix(7)); |
1342 | 1367 |
1343 if (len < 0) { | 1368 if (len < 0) { |
1344 if (len == NGX_AGAIN) { | 1369 if (len == NGX_AGAIN) { |
1345 return ngx_http_v2_state_save(h2c, pos, end, | 1370 return ngx_http_v2_state_headers_save(h2c, pos, end, |
1346 ngx_http_v2_state_field_len); | 1371 ngx_http_v2_state_field_len); |
1347 } | 1372 } |
1348 | 1373 |
1349 if (len == NGX_DECLINED) { | 1374 if (len == NGX_DECLINED) { |
1350 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | 1375 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, |
1351 "client sent header field with too long length value"); | 1376 "client sent header field with too long length value"); |
1433 *h2c->state.field_end = '\0'; | 1458 *h2c->state.field_end = '\0'; |
1434 return ngx_http_v2_state_process_header(h2c, pos, end); | 1459 return ngx_http_v2_state_process_header(h2c, pos, end); |
1435 } | 1460 } |
1436 | 1461 |
1437 if (h2c->state.length) { | 1462 if (h2c->state.length) { |
1438 return ngx_http_v2_state_save(h2c, pos, end, | 1463 return ngx_http_v2_state_headers_save(h2c, pos, end, |
1439 ngx_http_v2_state_field_huff); | 1464 ngx_http_v2_state_field_huff); |
1440 } | 1465 } |
1441 | 1466 |
1442 if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) { | 1467 if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) { |
1443 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | 1468 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, |
1444 "client sent header field with incorrect length"); | 1469 "client sent header field with incorrect length"); |
1478 *h2c->state.field_end = '\0'; | 1503 *h2c->state.field_end = '\0'; |
1479 return ngx_http_v2_state_process_header(h2c, pos, end); | 1504 return ngx_http_v2_state_process_header(h2c, pos, end); |
1480 } | 1505 } |
1481 | 1506 |
1482 if (h2c->state.length) { | 1507 if (h2c->state.length) { |
1483 return ngx_http_v2_state_save(h2c, pos, end, | 1508 return ngx_http_v2_state_headers_save(h2c, pos, end, |
1484 ngx_http_v2_state_field_raw); | 1509 ngx_http_v2_state_field_raw); |
1485 } | 1510 } |
1486 | 1511 |
1487 if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) { | 1512 if (h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG) { |
1488 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | 1513 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, |
1489 "client sent header field with incorrect length"); | 1514 "client sent header field with incorrect length"); |
1752 pos += skip; | 1777 pos += skip; |
1753 ngx_memmove(pos, p, len); | 1778 ngx_memmove(pos, p, len); |
1754 } | 1779 } |
1755 | 1780 |
1756 if ((size_t) (end - pos) < len + NGX_HTTP_V2_FRAME_HEADER_SIZE) { | 1781 if ((size_t) (end - pos) < len + NGX_HTTP_V2_FRAME_HEADER_SIZE) { |
1757 return ngx_http_v2_state_save(h2c, pos, end, handler); | 1782 return ngx_http_v2_state_headers_save(h2c, pos, end, handler); |
1758 } | 1783 } |
1759 | 1784 |
1760 p = pos + len; | 1785 p = pos + len; |
1761 | 1786 |
1762 head = ngx_http_v2_parse_uint32(p); | 1787 head = ngx_http_v2_parse_uint32(p); |
2227 if (stream->exhausted) { | 2252 if (stream->exhausted) { |
2228 stream->exhausted = 0; | 2253 stream->exhausted = 0; |
2229 | 2254 |
2230 wev = stream->request->connection->write; | 2255 wev = stream->request->connection->write; |
2231 | 2256 |
2232 if (!wev->timer_set) { | 2257 wev->active = 0; |
2233 wev->delayed = 0; | 2258 wev->ready = 1; |
2259 | |
2260 if (!wev->delayed) { | |
2234 wev->handler(wev); | 2261 wev->handler(wev); |
2235 } | 2262 } |
2236 } | 2263 } |
2237 | 2264 |
2238 return ngx_http_v2_state_complete(h2c, pos, end); | 2265 return ngx_http_v2_state_complete(h2c, pos, end); |
2260 | 2287 |
2261 stream->handled = 0; | 2288 stream->handled = 0; |
2262 | 2289 |
2263 wev = stream->request->connection->write; | 2290 wev = stream->request->connection->write; |
2264 | 2291 |
2265 if (!wev->timer_set) { | 2292 wev->active = 0; |
2266 wev->delayed = 0; | 2293 wev->ready = 1; |
2294 | |
2295 if (!wev->delayed) { | |
2267 wev->handler(wev); | 2296 wev->handler(wev); |
2268 | 2297 |
2269 if (h2c->send_window == 0) { | 2298 if (h2c->send_window == 0) { |
2270 break; | 2299 break; |
2271 } | 2300 } |
2365 h2c->state.buffer_used = size; | 2394 h2c->state.buffer_used = size; |
2366 h2c->state.handler = handler; | 2395 h2c->state.handler = handler; |
2367 h2c->state.incomplete = 1; | 2396 h2c->state.incomplete = 1; |
2368 | 2397 |
2369 return end; | 2398 return end; |
2399 } | |
2400 | |
2401 | |
2402 static u_char * | |
2403 ngx_http_v2_state_headers_save(ngx_http_v2_connection_t *h2c, u_char *pos, | |
2404 u_char *end, ngx_http_v2_handler_pt handler) | |
2405 { | |
2406 ngx_event_t *rev; | |
2407 ngx_http_request_t *r; | |
2408 ngx_http_core_srv_conf_t *cscf; | |
2409 | |
2410 if (h2c->state.stream) { | |
2411 r = h2c->state.stream->request; | |
2412 rev = r->connection->read; | |
2413 | |
2414 if (!rev->timer_set) { | |
2415 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); | |
2416 ngx_add_timer(rev, cscf->client_header_timeout); | |
2417 } | |
2418 } | |
2419 | |
2420 return ngx_http_v2_state_save(h2c, pos, end, handler); | |
2370 } | 2421 } |
2371 | 2422 |
2372 | 2423 |
2373 static u_char * | 2424 static u_char * |
2374 ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, | 2425 ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, |
2746 } | 2797 } |
2747 | 2798 |
2748 ngx_memcpy(log, h2c->connection->log, sizeof(ngx_log_t)); | 2799 ngx_memcpy(log, h2c->connection->log, sizeof(ngx_log_t)); |
2749 | 2800 |
2750 log->data = ctx; | 2801 log->data = ctx; |
2802 log->action = "reading client request headers"; | |
2751 | 2803 |
2752 ngx_memzero(rev, sizeof(ngx_event_t)); | 2804 ngx_memzero(rev, sizeof(ngx_event_t)); |
2753 | 2805 |
2754 rev->data = fc; | 2806 rev->data = fc; |
2755 rev->ready = 1; | 2807 rev->ready = 1; |
3552 | 3604 |
3553 ngx_int_t | 3605 ngx_int_t |
3554 ngx_http_v2_read_request_body(ngx_http_request_t *r, | 3606 ngx_http_v2_read_request_body(ngx_http_request_t *r, |
3555 ngx_http_client_body_handler_pt post_handler) | 3607 ngx_http_client_body_handler_pt post_handler) |
3556 { | 3608 { |
3557 ngx_http_v2_stream_t *stream; | 3609 ngx_http_v2_stream_t *stream; |
3610 ngx_http_core_loc_conf_t *clcf; | |
3558 | 3611 |
3559 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 3612 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
3560 "http2 read request body"); | 3613 "http2 read request body"); |
3561 | 3614 |
3562 stream = r->stream; | 3615 stream = r->stream; |
3588 return NGX_OK; | 3641 return NGX_OK; |
3589 } | 3642 } |
3590 | 3643 |
3591 r->request_body->post_handler = post_handler; | 3644 r->request_body->post_handler = post_handler; |
3592 | 3645 |
3593 r->read_event_handler = ngx_http_test_reading; | 3646 r->read_event_handler = ngx_http_v2_read_client_request_body_handler; |
3594 r->write_event_handler = ngx_http_request_empty_handler; | 3647 r->write_event_handler = ngx_http_request_empty_handler; |
3595 | 3648 |
3649 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
3650 ngx_add_timer(r->connection->read, clcf->client_body_timeout); | |
3651 | |
3596 return NGX_AGAIN; | 3652 return NGX_AGAIN; |
3653 } | |
3654 | |
3655 | |
3656 static void | |
3657 ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) | |
3658 { | |
3659 ngx_connection_t *fc; | |
3660 | |
3661 fc = r->connection; | |
3662 | |
3663 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
3664 "http2 read client request body handler"); | |
3665 | |
3666 if (fc->read->timedout) { | |
3667 ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out"); | |
3668 | |
3669 fc->timedout = 1; | |
3670 r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD; | |
3671 | |
3672 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); | |
3673 return; | |
3674 } | |
3675 | |
3676 if (fc->error) { | |
3677 ngx_log_error(NGX_LOG_INFO, fc->log, 0, | |
3678 "client prematurely closed stream"); | |
3679 | |
3680 r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD; | |
3681 | |
3682 ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); | |
3683 return; | |
3684 } | |
3597 } | 3685 } |
3598 | 3686 |
3599 | 3687 |
3600 static ngx_int_t | 3688 static ngx_int_t |
3601 ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, | 3689 ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, |
3645 return; | 3733 return; |
3646 } | 3734 } |
3647 | 3735 |
3648 if (!stream->out_closed) { | 3736 if (!stream->out_closed) { |
3649 if (ngx_http_v2_send_rst_stream(h2c, node->id, | 3737 if (ngx_http_v2_send_rst_stream(h2c, node->id, |
3650 NGX_HTTP_V2_INTERNAL_ERROR) | 3738 fc->timedout ? NGX_HTTP_V2_PROTOCOL_ERROR |
3739 : NGX_HTTP_V2_INTERNAL_ERROR) | |
3651 != NGX_OK) | 3740 != NGX_OK) |
3652 { | 3741 { |
3653 h2c->connection->error = 1; | 3742 h2c->connection->error = 1; |
3654 } | 3743 } |
3655 } | 3744 } |
3682 h2c->state.keep_pool = 0; | 3771 h2c->state.keep_pool = 0; |
3683 } | 3772 } |
3684 | 3773 |
3685 ev = fc->read; | 3774 ev = fc->read; |
3686 | 3775 |
3687 if (ev->active || ev->disabled) { | |
3688 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, | |
3689 "fake read event was activated"); | |
3690 } | |
3691 | |
3692 if (ev->timer_set) { | 3776 if (ev->timer_set) { |
3693 ngx_del_timer(ev); | 3777 ngx_del_timer(ev); |
3694 } | 3778 } |
3695 | 3779 |
3696 if (ev->posted) { | 3780 if (ev->posted) { |
3697 ngx_delete_posted_event(ev); | 3781 ngx_delete_posted_event(ev); |
3698 } | 3782 } |
3699 | 3783 |
3700 ev = fc->write; | 3784 ev = fc->write; |
3701 | 3785 |
3702 if (ev->active || ev->disabled) { | |
3703 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, | |
3704 "fake write event was activated"); | |
3705 } | |
3706 | |
3707 if (ev->timer_set) { | 3786 if (ev->timer_set) { |
3708 ngx_del_timer(ev); | 3787 ngx_del_timer(ev); |
3709 } | 3788 } |
3710 | 3789 |
3711 if (ev->posted) { | 3790 if (ev->posted) { |
3735 ngx_http_request_t *r; | 3814 ngx_http_request_t *r; |
3736 | 3815 |
3737 fc = ev->data; | 3816 fc = ev->data; |
3738 r = fc->data; | 3817 r = fc->data; |
3739 | 3818 |
3740 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 3819 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, |
3741 "http2 close stream handler"); | 3820 "http2 close stream handler"); |
3821 | |
3822 if (ev->timedout) { | |
3823 ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out"); | |
3824 | |
3825 fc->timedout = 1; | |
3826 | |
3827 ngx_http_v2_close_stream(r->stream, NGX_HTTP_REQUEST_TIME_OUT); | |
3828 return; | |
3829 } | |
3742 | 3830 |
3743 ngx_http_v2_close_stream(r->stream, 0); | 3831 ngx_http_v2_close_stream(r->stream, 0); |
3744 } | 3832 } |
3745 | 3833 |
3746 | 3834 |
3747 static void | 3835 static void |
3748 ngx_http_v2_handle_connection_handler(ngx_event_t *rev) | 3836 ngx_http_v2_handle_connection_handler(ngx_event_t *rev) |
3749 { | 3837 { |
3750 ngx_connection_t *c; | 3838 ngx_connection_t *c; |
3839 ngx_http_v2_connection_t *h2c; | |
3840 | |
3841 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, | |
3842 "http2 handle connection handler"); | |
3751 | 3843 |
3752 rev->handler = ngx_http_v2_read_handler; | 3844 rev->handler = ngx_http_v2_read_handler; |
3753 | 3845 |
3754 if (rev->ready) { | 3846 if (rev->ready) { |
3755 ngx_http_v2_read_handler(rev); | 3847 ngx_http_v2_read_handler(rev); |
3756 return; | 3848 return; |
3757 } | 3849 } |
3758 | 3850 |
3759 c = rev->data; | 3851 c = rev->data; |
3852 h2c = c->data; | |
3853 | |
3854 if (h2c->last_out && ngx_http_v2_send_output_queue(h2c) == NGX_ERROR) { | |
3855 ngx_http_v2_finalize_connection(h2c, 0); | |
3856 return; | |
3857 } | |
3760 | 3858 |
3761 ngx_http_v2_handle_connection(c->data); | 3859 ngx_http_v2_handle_connection(c->data); |
3762 } | 3860 } |
3763 | 3861 |
3764 | 3862 |
3876 | 3974 |
3877 fc->error = 1; | 3975 fc->error = 1; |
3878 | 3976 |
3879 if (stream->queued) { | 3977 if (stream->queued) { |
3880 stream->queued = 0; | 3978 stream->queued = 0; |
3881 | |
3882 ev = fc->write; | 3979 ev = fc->write; |
3883 ev->delayed = 0; | |
3884 | 3980 |
3885 } else { | 3981 } else { |
3886 ev = fc->read; | 3982 ev = fc->read; |
3887 } | 3983 } |
3888 | 3984 |
3947 if (stream->send_window > 0 && stream->exhausted) { | 4043 if (stream->send_window > 0 && stream->exhausted) { |
3948 stream->exhausted = 0; | 4044 stream->exhausted = 0; |
3949 | 4045 |
3950 wev = stream->request->connection->write; | 4046 wev = stream->request->connection->write; |
3951 | 4047 |
3952 if (!wev->timer_set) { | 4048 wev->active = 0; |
3953 wev->delayed = 0; | 4049 wev->ready = 1; |
4050 | |
4051 if (!wev->delayed) { | |
3954 wev->handler(wev); | 4052 wev->handler(wev); |
3955 } | 4053 } |
3956 } | 4054 } |
3957 } | 4055 } |
3958 } | 4056 } |