Mercurial > hg > nginx
comparison src/http/v2/ngx_http_v2.c @ 6411:8ec349bb60b2
HTTP/2: always use temporary pool for processing headers.
This is required for implementing per request timeouts.
Previously, the temporary pool was used only during skipping of
headers and the request pool was used otherwise. That required
switching of pools if the request was closed while parsing.
It wasn't a problem since the request could be closed only after
the validation of the fully parsed header. With the per request
timeouts, the request can be closed at any moment, and switching
of pools in the middle of parsing header name or value becomes a
problem.
To overcome this, the temporary pool is now always created and
used. Special checks are added to keep it when either the stream
is being processed or until header block is fully parsed.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Wed, 24 Feb 2016 16:05:47 +0300 |
parents | c6ccc1ea9450 |
children | 4ba91a4c66a3 |
comparison
equal
deleted
inserted
replaced
6410:c6ccc1ea9450 | 6411:8ec349bb60b2 |
---|---|
110 u_char *pos, u_char *end); | 110 u_char *pos, u_char *end); |
111 static u_char *ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c, | 111 static u_char *ngx_http_v2_state_skip_padded(ngx_http_v2_connection_t *h2c, |
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_skip_headers(ngx_http_v2_connection_t *h2c, | |
116 u_char *pos, u_char *end); | |
117 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, |
118 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); |
119 static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, | 117 static u_char *ngx_http_v2_connection_error(ngx_http_v2_connection_t *h2c, |
120 ngx_uint_t err); | 118 ngx_uint_t err); |
121 | 119 |
1131 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); | 1129 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR); |
1132 } | 1130 } |
1133 | 1131 |
1134 h2c->last_sid = h2c->state.sid; | 1132 h2c->last_sid = h2c->state.sid; |
1135 | 1133 |
1134 h2c->state.pool = ngx_create_pool(1024, h2c->connection->log); | |
1135 if (h2c->state.pool == NULL) { | |
1136 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
1137 } | |
1138 | |
1136 if (depend == h2c->state.sid) { | 1139 if (depend == h2c->state.sid) { |
1137 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, | 1140 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, |
1138 "client sent HEADERS frame for stream %ui " | 1141 "client sent HEADERS frame for stream %ui " |
1139 "with incorrect dependency", h2c->state.sid); | 1142 "with incorrect dependency", h2c->state.sid); |
1140 | 1143 |
1144 { | 1147 { |
1145 return ngx_http_v2_connection_error(h2c, | 1148 return ngx_http_v2_connection_error(h2c, |
1146 NGX_HTTP_V2_INTERNAL_ERROR); | 1149 NGX_HTTP_V2_INTERNAL_ERROR); |
1147 } | 1150 } |
1148 | 1151 |
1149 return ngx_http_v2_state_skip_headers(h2c, pos, end); | 1152 return ngx_http_v2_state_header_block(h2c, pos, end); |
1150 } | 1153 } |
1151 | 1154 |
1152 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, | 1155 h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, |
1153 ngx_http_v2_module); | 1156 ngx_http_v2_module); |
1154 | 1157 |
1164 { | 1167 { |
1165 return ngx_http_v2_connection_error(h2c, | 1168 return ngx_http_v2_connection_error(h2c, |
1166 NGX_HTTP_V2_INTERNAL_ERROR); | 1169 NGX_HTTP_V2_INTERNAL_ERROR); |
1167 } | 1170 } |
1168 | 1171 |
1169 return ngx_http_v2_state_skip_headers(h2c, pos, end); | 1172 return ngx_http_v2_state_header_block(h2c, pos, end); |
1170 } | 1173 } |
1171 | 1174 |
1172 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1); | 1175 node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 1); |
1173 | 1176 |
1174 if (node == NULL) { | 1177 if (node == NULL) { |
1183 stream = ngx_http_v2_create_stream(h2c); | 1186 stream = ngx_http_v2_create_stream(h2c); |
1184 if (stream == NULL) { | 1187 if (stream == NULL) { |
1185 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | 1188 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); |
1186 } | 1189 } |
1187 | 1190 |
1191 h2c->state.stream = stream; | |
1192 | |
1193 stream->pool = h2c->state.pool; | |
1194 h2c->state.keep_pool = 1; | |
1195 | |
1188 stream->request->request_length = h2c->state.length; | 1196 stream->request->request_length = h2c->state.length; |
1189 | 1197 |
1190 stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; | 1198 stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; |
1191 stream->node = node; | 1199 stream->node = node; |
1192 | 1200 |
1193 node->stream = stream; | 1201 node->stream = stream; |
1194 | |
1195 h2c->state.stream = stream; | |
1196 h2c->state.pool = stream->request->pool; | |
1197 | 1202 |
1198 if (priority || node->parent == NULL) { | 1203 if (priority || node->parent == NULL) { |
1199 node->weight = weight; | 1204 node->weight = weight; |
1200 ngx_http_v2_set_dependency(h2c, node, depend, excl); | 1205 ngx_http_v2_set_dependency(h2c, node, depend, excl); |
1201 } | 1206 } |
1684 return ngx_http_v2_state_header_complete(h2c, pos, end); | 1689 return ngx_http_v2_state_header_complete(h2c, pos, end); |
1685 | 1690 |
1686 error: | 1691 error: |
1687 | 1692 |
1688 h2c->state.stream = NULL; | 1693 h2c->state.stream = NULL; |
1689 h2c->state.pool = NULL; | |
1690 | 1694 |
1691 return ngx_http_v2_state_header_complete(h2c, pos, end); | 1695 return ngx_http_v2_state_header_complete(h2c, pos, end); |
1692 } | 1696 } |
1693 | 1697 |
1694 | 1698 |
1697 u_char *end) | 1701 u_char *end) |
1698 { | 1702 { |
1699 ngx_http_v2_stream_t *stream; | 1703 ngx_http_v2_stream_t *stream; |
1700 | 1704 |
1701 if (h2c->state.length) { | 1705 if (h2c->state.length) { |
1702 h2c->state.handler = h2c->state.pool ? ngx_http_v2_state_header_block | 1706 h2c->state.handler = ngx_http_v2_state_header_block; |
1703 : ngx_http_v2_state_skip_headers; | |
1704 return pos; | 1707 return pos; |
1705 } | 1708 } |
1706 | 1709 |
1707 if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)) { | 1710 if (!(h2c->state.flags & NGX_HTTP_V2_END_HEADERS_FLAG)) { |
1708 return ngx_http_v2_handle_continuation(h2c, pos, end, | 1711 return ngx_http_v2_handle_continuation(h2c, pos, end, |
1711 | 1714 |
1712 stream = h2c->state.stream; | 1715 stream = h2c->state.stream; |
1713 | 1716 |
1714 if (stream) { | 1717 if (stream) { |
1715 ngx_http_v2_run_request(stream->request); | 1718 ngx_http_v2_run_request(stream->request); |
1716 | 1719 } |
1717 } else if (h2c->state.pool) { | 1720 |
1721 if (!h2c->state.keep_pool) { | |
1718 ngx_destroy_pool(h2c->state.pool); | 1722 ngx_destroy_pool(h2c->state.pool); |
1719 } | 1723 } |
1720 | 1724 |
1721 h2c->state.pool = NULL; | 1725 h2c->state.pool = NULL; |
1726 h2c->state.keep_pool = 0; | |
1722 | 1727 |
1723 if (h2c->state.padding) { | 1728 if (h2c->state.padding) { |
1724 return ngx_http_v2_state_skip_padded(h2c, pos, end); | 1729 return ngx_http_v2_state_skip_padded(h2c, pos, end); |
1725 } | 1730 } |
1726 | 1731 |
2331 | 2336 |
2332 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | 2337 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, |
2333 "http2 frame skip %uz", h2c->state.length); | 2338 "http2 frame skip %uz", h2c->state.length); |
2334 | 2339 |
2335 return ngx_http_v2_state_complete(h2c, pos + h2c->state.length, end); | 2340 return ngx_http_v2_state_complete(h2c, pos + h2c->state.length, end); |
2336 } | |
2337 | |
2338 | |
2339 static u_char * | |
2340 ngx_http_v2_state_skip_headers(ngx_http_v2_connection_t *h2c, u_char *pos, | |
2341 u_char *end) | |
2342 { | |
2343 h2c->state.pool = ngx_create_pool(1024, h2c->connection->log); | |
2344 if (h2c->state.pool == NULL) { | |
2345 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); | |
2346 } | |
2347 | |
2348 return ngx_http_v2_state_header_block(h2c, pos, end); | |
2349 } | 2341 } |
2350 | 2342 |
2351 | 2343 |
2352 static u_char * | 2344 static u_char * |
2353 ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end, | 2345 ngx_http_v2_state_save(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end, |
3631 | 3623 |
3632 | 3624 |
3633 void | 3625 void |
3634 ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) | 3626 ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc) |
3635 { | 3627 { |
3628 ngx_pool_t *pool; | |
3636 ngx_event_t *ev; | 3629 ngx_event_t *ev; |
3637 ngx_connection_t *fc; | 3630 ngx_connection_t *fc; |
3638 ngx_http_v2_node_t *node; | 3631 ngx_http_v2_node_t *node; |
3639 ngx_http_v2_connection_t *h2c; | 3632 ngx_http_v2_connection_t *h2c; |
3640 | 3633 |
3668 node->stream = NULL; | 3661 node->stream = NULL; |
3669 | 3662 |
3670 ngx_queue_insert_tail(&h2c->closed, &node->reuse); | 3663 ngx_queue_insert_tail(&h2c->closed, &node->reuse); |
3671 h2c->closed_nodes++; | 3664 h2c->closed_nodes++; |
3672 | 3665 |
3666 /* | |
3667 * This pool keeps decoded request headers which can be used by log phase | |
3668 * handlers in ngx_http_free_request(). | |
3669 * | |
3670 * The pointer is stored into local variable because the stream object | |
3671 * will be destroyed after a call to ngx_http_free_request(). | |
3672 */ | |
3673 pool = stream->pool; | |
3674 | |
3673 ngx_http_free_request(stream->request, rc); | 3675 ngx_http_free_request(stream->request, rc); |
3676 | |
3677 if (pool != h2c->state.pool) { | |
3678 ngx_destroy_pool(pool); | |
3679 | |
3680 } else { | |
3681 /* pool will be destroyed when the complete header is parsed */ | |
3682 h2c->state.keep_pool = 0; | |
3683 } | |
3674 | 3684 |
3675 ev = fc->read; | 3685 ev = fc->read; |
3676 | 3686 |
3677 if (ev->active || ev->disabled) { | 3687 if (ev->active || ev->disabled) { |
3678 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, | 3688 ngx_log_error(NGX_LOG_ALERT, h2c->connection->log, 0, |
3823 | 3833 |
3824 c = h2c->connection; | 3834 c = h2c->connection; |
3825 | 3835 |
3826 if (h2c->state.stream) { | 3836 if (h2c->state.stream) { |
3827 h2c->state.stream->out_closed = 1; | 3837 h2c->state.stream->out_closed = 1; |
3828 h2c->state.pool = NULL; | |
3829 ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); | 3838 ngx_http_v2_close_stream(h2c->state.stream, NGX_HTTP_BAD_REQUEST); |
3830 } | 3839 } |
3831 | 3840 |
3832 h2c->blocked = 1; | 3841 h2c->blocked = 1; |
3833 | 3842 |