Mercurial > hg > nginx
comparison src/http/ngx_http_request_body.c @ 7914:9cf043a5d9ca
Request body: reading body buffering in filters.
If a filter wants to buffer the request body during reading (for
example, to check an external scanner), it can now do so. To make
it possible, the code now checks rb->last_saved (introduced in the
previous change) along with rb->rest == 0.
Since in HTTP/2 this requires flow control to avoid overflowing the
request body buffer, so filters which need buffering have to set
the rb->filter_need_buffering flag on the first filter call. (Note
that each filter is expected to call the next filter, so all filters
will be able set the flag if needed.)
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sun, 29 Aug 2021 22:22:02 +0300 |
parents | 185c86b830ef |
children | 97cf8284fd19 fac88e160653 |
comparison
equal
deleted
inserted
replaced
7913:185c86b830ef | 7914:9cf043a5d9ca |
---|---|
67 * rb->buf = NULL; | 67 * rb->buf = NULL; |
68 * rb->free = NULL; | 68 * rb->free = NULL; |
69 * rb->busy = NULL; | 69 * rb->busy = NULL; |
70 * rb->chunked = NULL; | 70 * rb->chunked = NULL; |
71 * rb->received = 0; | 71 * rb->received = 0; |
72 * rb->filter_need_buffering = 0; | |
73 * rb->last_sent = 0; | |
72 * rb->last_saved = 0; | 74 * rb->last_saved = 0; |
73 */ | 75 */ |
74 | 76 |
75 rb->rest = -1; | 77 rb->rest = -1; |
76 rb->post_handler = post_handler; | 78 rb->post_handler = post_handler; |
145 if (rc != NGX_OK) { | 147 if (rc != NGX_OK) { |
146 goto done; | 148 goto done; |
147 } | 149 } |
148 } | 150 } |
149 | 151 |
150 if (rb->rest == 0) { | 152 if (rb->rest == 0 && rb->last_saved) { |
151 /* the whole request body was pre-read */ | 153 /* the whole request body was pre-read */ |
152 r->request_body_no_buffering = 0; | 154 r->request_body_no_buffering = 0; |
153 post_handler(r); | 155 post_handler(r); |
154 return NGX_OK; | 156 return NGX_OK; |
155 } | 157 } |
173 | 175 |
174 if (r->request_body_in_single_buf) { | 176 if (r->request_body_in_single_buf) { |
175 size += preread; | 177 size += preread; |
176 } | 178 } |
177 | 179 |
180 if (size == 0) { | |
181 size++; | |
182 } | |
183 | |
178 } else { | 184 } else { |
179 size = clcf->client_body_buffer_size; | 185 size = clcf->client_body_buffer_size; |
180 } | 186 } |
181 | 187 |
182 rb->buf = ngx_create_temp_buf(r->pool, size); | 188 rb->buf = ngx_create_temp_buf(r->pool, size); |
271 { | 277 { |
272 off_t rest; | 278 off_t rest; |
273 size_t size; | 279 size_t size; |
274 ssize_t n; | 280 ssize_t n; |
275 ngx_int_t rc; | 281 ngx_int_t rc; |
282 ngx_uint_t flush; | |
276 ngx_chain_t out; | 283 ngx_chain_t out; |
277 ngx_connection_t *c; | 284 ngx_connection_t *c; |
278 ngx_http_request_body_t *rb; | 285 ngx_http_request_body_t *rb; |
279 ngx_http_core_loc_conf_t *clcf; | 286 ngx_http_core_loc_conf_t *clcf; |
280 | 287 |
281 c = r->connection; | 288 c = r->connection; |
282 rb = r->request_body; | 289 rb = r->request_body; |
290 flush = 1; | |
283 | 291 |
284 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | 292 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, |
285 "http read client request body"); | 293 "http read client request body"); |
286 | 294 |
287 for ( ;; ) { | 295 for ( ;; ) { |
288 for ( ;; ) { | 296 for ( ;; ) { |
297 if (rb->rest == 0) { | |
298 break; | |
299 } | |
300 | |
289 if (rb->buf->last == rb->buf->end) { | 301 if (rb->buf->last == rb->buf->end) { |
290 | 302 |
291 /* update chains */ | 303 /* update chains */ |
292 | 304 |
293 rc = ngx_http_request_body_filter(r, NULL); | 305 rc = ngx_http_request_body_filter(r, NULL); |
307 } | 319 } |
308 | 320 |
309 return NGX_AGAIN; | 321 return NGX_AGAIN; |
310 } | 322 } |
311 | 323 |
324 if (rb->filter_need_buffering) { | |
325 clcf = ngx_http_get_module_loc_conf(r, | |
326 ngx_http_core_module); | |
327 ngx_add_timer(c->read, clcf->client_body_timeout); | |
328 | |
329 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | |
330 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
331 } | |
332 | |
333 return NGX_AGAIN; | |
334 } | |
335 | |
312 ngx_log_error(NGX_LOG_ALERT, c->log, 0, | 336 ngx_log_error(NGX_LOG_ALERT, c->log, 0, |
313 "busy buffers after request body flush"); | 337 "busy buffers after request body flush"); |
314 | 338 |
315 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 339 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
316 } | 340 } |
317 | 341 |
342 flush = 0; | |
318 rb->buf->pos = rb->buf->start; | 343 rb->buf->pos = rb->buf->start; |
319 rb->buf->last = rb->buf->start; | 344 rb->buf->last = rb->buf->start; |
320 } | 345 } |
321 | 346 |
322 size = rb->buf->end - rb->buf->last; | 347 size = rb->buf->end - rb->buf->last; |
323 rest = rb->rest - (rb->buf->last - rb->buf->pos); | 348 rest = rb->rest - (rb->buf->last - rb->buf->pos); |
324 | 349 |
325 if ((off_t) size > rest) { | 350 if ((off_t) size > rest) { |
326 size = (size_t) rest; | 351 size = (size_t) rest; |
352 } | |
353 | |
354 if (size == 0) { | |
355 break; | |
327 } | 356 } |
328 | 357 |
329 n = c->recv(c, rb->buf->last, size); | 358 n = c->recv(c, rb->buf->last, size); |
330 | 359 |
331 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | 360 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
348 rb->buf->last += n; | 377 rb->buf->last += n; |
349 r->request_length += n; | 378 r->request_length += n; |
350 | 379 |
351 /* pass buffer to request body filter chain */ | 380 /* pass buffer to request body filter chain */ |
352 | 381 |
382 flush = 0; | |
353 out.buf = rb->buf; | 383 out.buf = rb->buf; |
354 out.next = NULL; | 384 out.next = NULL; |
355 | 385 |
356 rc = ngx_http_request_body_filter(r, &out); | 386 rc = ngx_http_request_body_filter(r, &out); |
357 | 387 |
369 } | 399 } |
370 | 400 |
371 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | 401 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
372 "http client request body rest %O", rb->rest); | 402 "http client request body rest %O", rb->rest); |
373 | 403 |
374 if (rb->rest == 0) { | 404 if (flush) { |
405 rc = ngx_http_request_body_filter(r, NULL); | |
406 | |
407 if (rc != NGX_OK) { | |
408 return rc; | |
409 } | |
410 } | |
411 | |
412 if (rb->rest == 0 && rb->last_saved) { | |
375 break; | 413 break; |
376 } | 414 } |
377 | 415 |
378 if (!c->read->ready) { | 416 if (!c->read->ready || rb->rest == 0) { |
379 | 417 |
380 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | 418 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
381 ngx_add_timer(c->read, clcf->client_body_timeout); | 419 ngx_add_timer(c->read, clcf->client_body_timeout); |
382 | 420 |
383 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | 421 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { |
1278 } | 1316 } |
1279 | 1317 |
1280 return NGX_OK; | 1318 return NGX_OK; |
1281 } | 1319 } |
1282 | 1320 |
1283 /* rb->rest == 0 */ | 1321 if (!rb->last_saved) { |
1322 return NGX_OK; | |
1323 } | |
1284 | 1324 |
1285 if (rb->temp_file || r->request_body_in_file_only) { | 1325 if (rb->temp_file || r->request_body_in_file_only) { |
1286 | 1326 |
1287 if (rb->bufs && rb->bufs->buf->in_file) { | 1327 if (rb->bufs && rb->bufs->buf->in_file) { |
1288 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | 1328 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, |