Mercurial > hg > nginx
comparison src/http/v2/ngx_http_v2.c @ 7908:0dcec8e5d50a
HTTP/2: reworked body reading to better match HTTP/1.x code.
In particular, now the code always uses a buffer limited by
client_body_buffer_size. At the cost of an additional copy it
ensures that small DATA frames are not directly mapped to small
write() syscalls, but rather buffered in memory before writing.
Further, requests without Content-Length are no longer forced
to use temporary files.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sun, 29 Aug 2021 22:20:36 +0300 |
parents | 51f463301f86 |
children | f302c1096f7b |
comparison
equal
deleted
inserted
replaced
7907:51f463301f86 | 7908:0dcec8e5d50a |
---|---|
4030 h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); | 4030 h2scf = ngx_http_get_module_srv_conf(r, ngx_http_v2_module); |
4031 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | 4031 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
4032 | 4032 |
4033 len = r->headers_in.content_length_n; | 4033 len = r->headers_in.content_length_n; |
4034 | 4034 |
4035 if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { | |
4036 len = clcf->client_body_buffer_size; | |
4037 } | |
4038 | |
4035 if (r->request_body_no_buffering && !stream->in_closed) { | 4039 if (r->request_body_no_buffering && !stream->in_closed) { |
4036 | |
4037 if (len < 0 || len > (off_t) clcf->client_body_buffer_size) { | |
4038 len = clcf->client_body_buffer_size; | |
4039 } | |
4040 | 4040 |
4041 /* | 4041 /* |
4042 * We need a room to store data up to the stream's initial window size, | 4042 * We need a room to store data up to the stream's initial window size, |
4043 * at least until this window will be exhausted. | 4043 * at least until this window will be exhausted. |
4044 */ | 4044 */ |
4048 } | 4048 } |
4049 | 4049 |
4050 if (len > NGX_HTTP_V2_MAX_WINDOW) { | 4050 if (len > NGX_HTTP_V2_MAX_WINDOW) { |
4051 len = NGX_HTTP_V2_MAX_WINDOW; | 4051 len = NGX_HTTP_V2_MAX_WINDOW; |
4052 } | 4052 } |
4053 | 4053 } |
4054 rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); | 4054 |
4055 | 4055 rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); |
4056 } else if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size | |
4057 && !r->request_body_in_file_only) | |
4058 { | |
4059 rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); | |
4060 | |
4061 } else { | |
4062 rb->buf = ngx_calloc_buf(r->pool); | |
4063 | |
4064 if (rb->buf != NULL) { | |
4065 rb->buf->sync = 1; | |
4066 } | |
4067 } | |
4068 | 4056 |
4069 if (rb->buf == NULL) { | 4057 if (rb->buf == NULL) { |
4070 stream->skip_data = 1; | 4058 stream->skip_data = 1; |
4071 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 4059 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
4072 } | 4060 } |
4142 | 4130 |
4143 static ngx_int_t | 4131 static ngx_int_t |
4144 ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, | 4132 ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos, |
4145 size_t size, ngx_uint_t last) | 4133 size_t size, ngx_uint_t last) |
4146 { | 4134 { |
4147 ngx_buf_t *buf; | 4135 size_t n; |
4148 ngx_int_t rc; | 4136 ngx_int_t rc; |
4149 ngx_connection_t *fc; | 4137 ngx_connection_t *fc; |
4150 ngx_http_request_body_t *rb; | 4138 ngx_http_request_body_t *rb; |
4151 ngx_http_core_loc_conf_t *clcf; | 4139 ngx_http_core_loc_conf_t *clcf; |
4152 | 4140 |
4153 fc = r->connection; | 4141 fc = r->connection; |
4154 rb = r->request_body; | 4142 rb = r->request_body; |
4155 buf = rb->buf; | |
4156 | 4143 |
4157 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, | 4144 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, |
4158 "http2 process request body"); | 4145 "http2 process request body"); |
4159 | 4146 |
4160 if (size) { | 4147 if (size == 0 && !last) { |
4161 if (buf->sync) { | 4148 return NGX_OK; |
4162 buf->pos = buf->start = pos; | 4149 } |
4163 buf->last = buf->end = pos + size; | 4150 |
4164 | 4151 for ( ;; ) { |
4165 r->request_body_in_file_only = 1; | 4152 for ( ;; ) { |
4166 | 4153 if (rb->buf->last == rb->buf->end && size) { |
4167 } else { | 4154 |
4168 if (size > (size_t) (buf->end - buf->last)) { | 4155 if (r->request_body_no_buffering) { |
4169 ngx_log_error(NGX_LOG_INFO, fc->log, 0, | 4156 |
4170 "client intended to send body data " | 4157 /* should never happen due to flow control */ |
4171 "larger than declared"); | 4158 |
4172 | 4159 ngx_log_error(NGX_LOG_ALERT, fc->log, 0, |
4173 return NGX_HTTP_BAD_REQUEST; | 4160 "no space in http2 body buffer"); |
4161 | |
4162 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
4163 } | |
4164 | |
4165 /* update chains */ | |
4166 | |
4167 ngx_log_error(NGX_LOG_DEBUG, fc->log, 0, | |
4168 "http2 body update chains"); | |
4169 | |
4170 rc = ngx_http_v2_filter_request_body(r); | |
4171 | |
4172 if (rc != NGX_OK) { | |
4173 return rc; | |
4174 } | |
4175 | |
4176 if (rb->busy != NULL) { | |
4177 ngx_log_error(NGX_LOG_ALERT, fc->log, 0, | |
4178 "busy buffers after request body flush"); | |
4179 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
4180 } | |
4181 | |
4182 rb->buf->pos = rb->buf->start; | |
4183 rb->buf->last = rb->buf->start; | |
4174 } | 4184 } |
4175 | 4185 |
4176 buf->last = ngx_cpymem(buf->last, pos, size); | 4186 /* copy body data to the buffer */ |
4177 } | 4187 |
4178 } | 4188 n = rb->buf->end - rb->buf->last; |
4179 | 4189 |
4180 if (last) { | 4190 if (n > size) { |
4181 rb->rest = 0; | 4191 n = size; |
4182 | 4192 } |
4183 if (fc->read->timer_set) { | 4193 |
4184 ngx_del_timer(fc->read); | 4194 rb->buf->last = ngx_cpymem(rb->buf->last, pos, n); |
4185 } | 4195 |
4186 | 4196 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, |
4187 if (r->request_body_no_buffering) { | 4197 "http2 request body recv %uz", n); |
4188 ngx_post_event(fc->read, &ngx_posted_events); | 4198 |
4199 pos += n; | |
4200 size -= n; | |
4201 | |
4202 if (size == 0 && last) { | |
4203 rb->rest = 0; | |
4204 } | |
4205 | |
4206 if (r->request_body_no_buffering) { | |
4207 break; | |
4208 } | |
4209 | |
4210 /* pass buffer to request body filter chain */ | |
4211 | |
4212 rc = ngx_http_v2_filter_request_body(r); | |
4213 | |
4214 if (rc != NGX_OK) { | |
4215 return rc; | |
4216 } | |
4217 | |
4218 if (rb->rest == 0) { | |
4219 break; | |
4220 } | |
4221 | |
4222 if (size == 0) { | |
4223 break; | |
4224 } | |
4225 } | |
4226 | |
4227 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
4228 "http2 request body rest %O", rb->rest); | |
4229 | |
4230 if (rb->rest == 0) { | |
4231 break; | |
4232 } | |
4233 | |
4234 if (size == 0) { | |
4235 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
4236 ngx_add_timer(fc->read, clcf->client_body_timeout); | |
4237 | |
4238 if (r->request_body_no_buffering) { | |
4239 ngx_post_event(fc->read, &ngx_posted_events); | |
4240 return NGX_OK; | |
4241 } | |
4242 | |
4189 return NGX_OK; | 4243 return NGX_OK; |
4190 } | 4244 } |
4191 | 4245 } |
4192 rc = ngx_http_v2_filter_request_body(r); | 4246 |
4193 | 4247 if (fc->read->timer_set) { |
4194 if (rc != NGX_OK) { | 4248 ngx_del_timer(fc->read); |
4195 return rc; | 4249 } |
4196 } | |
4197 | |
4198 if (buf->sync) { | |
4199 /* prevent reusing this buffer in the upstream module */ | |
4200 rb->buf = NULL; | |
4201 } | |
4202 | |
4203 if (r->headers_in.chunked) { | |
4204 r->headers_in.content_length_n = rb->received; | |
4205 } | |
4206 | |
4207 r->read_event_handler = ngx_http_block_reading; | |
4208 rb->post_handler(r); | |
4209 | |
4210 return NGX_OK; | |
4211 } | |
4212 | |
4213 if (size == 0) { | |
4214 return NGX_OK; | |
4215 } | |
4216 | |
4217 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | |
4218 ngx_add_timer(fc->read, clcf->client_body_timeout); | |
4219 | 4250 |
4220 if (r->request_body_no_buffering) { | 4251 if (r->request_body_no_buffering) { |
4221 ngx_post_event(fc->read, &ngx_posted_events); | 4252 ngx_post_event(fc->read, &ngx_posted_events); |
4222 return NGX_OK; | 4253 return NGX_OK; |
4223 } | 4254 } |
4224 | 4255 |
4225 if (buf->sync) { | 4256 if (r->headers_in.chunked) { |
4226 return ngx_http_v2_filter_request_body(r); | 4257 r->headers_in.content_length_n = rb->received; |
4227 } | 4258 } |
4259 | |
4260 r->read_event_handler = ngx_http_block_reading; | |
4261 rb->post_handler(r); | |
4228 | 4262 |
4229 return NGX_OK; | 4263 return NGX_OK; |
4230 } | 4264 } |
4231 | 4265 |
4232 | 4266 |