Mercurial > hg > nginx
comparison src/http/ngx_http_request_body.c @ 6050:a08fad30aeac
Request body: unbuffered reading.
The r->request_body_no_buffering flag was introduced. It instructs
client request body reading code to avoid reading the whole body, and
to call post_handler early instead. The caller should use the
ngx_http_read_unbuffered_request_body() function to read remaining
parts of the body.
Upstream module is now able to use this mode, if configured with
the proxy_request_buffering directive.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 23 Mar 2015 21:09:19 +0300 |
parents | 42d9beeb22db |
children | 231a5bbd9e9c |
comparison
equal
deleted
inserted
replaced
6049:42d9beeb22db | 6050:a08fad30aeac |
---|---|
40 | 40 |
41 r->main->count++; | 41 r->main->count++; |
42 | 42 |
43 #if (NGX_HTTP_SPDY) | 43 #if (NGX_HTTP_SPDY) |
44 if (r->spdy_stream && r == r->main) { | 44 if (r->spdy_stream && r == r->main) { |
45 r->request_body_no_buffering = 0; | |
45 rc = ngx_http_spdy_read_request_body(r, post_handler); | 46 rc = ngx_http_spdy_read_request_body(r, post_handler); |
46 goto done; | 47 goto done; |
47 } | 48 } |
48 #endif | 49 #endif |
49 | 50 |
50 if (r != r->main || r->request_body || r->discard_body) { | 51 if (r != r->main || r->request_body || r->discard_body) { |
52 r->request_body_no_buffering = 0; | |
51 post_handler(r); | 53 post_handler(r); |
52 return NGX_OK; | 54 return NGX_OK; |
53 } | 55 } |
54 | 56 |
55 if (ngx_http_test_expect(r) != NGX_OK) { | 57 if (ngx_http_test_expect(r) != NGX_OK) { |
56 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | 58 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; |
57 goto done; | 59 goto done; |
60 } | |
61 | |
62 if (r->request_body_no_buffering) { | |
63 r->request_body_in_file_only = 0; | |
58 } | 64 } |
59 | 65 |
60 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); | 66 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); |
61 if (rb == NULL) { | 67 if (rb == NULL) { |
62 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; | 68 rc = NGX_HTTP_INTERNAL_SERVER_ERROR; |
77 rb->post_handler = post_handler; | 83 rb->post_handler = post_handler; |
78 | 84 |
79 r->request_body = rb; | 85 r->request_body = rb; |
80 | 86 |
81 if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) { | 87 if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) { |
88 r->request_body_no_buffering = 0; | |
82 post_handler(r); | 89 post_handler(r); |
83 return NGX_OK; | 90 return NGX_OK; |
84 } | 91 } |
85 | 92 |
86 preread = r->header_in->last - r->header_in->pos; | 93 preread = r->header_in->last - r->header_in->pos; |
169 } else { | 176 } else { |
170 rb->bufs = NULL; | 177 rb->bufs = NULL; |
171 } | 178 } |
172 } | 179 } |
173 | 180 |
181 r->request_body_no_buffering = 0; | |
182 | |
174 post_handler(r); | 183 post_handler(r); |
175 | 184 |
176 return NGX_OK; | 185 return NGX_OK; |
177 } | 186 } |
178 | 187 |
212 | 221 |
213 rc = ngx_http_do_read_client_request_body(r); | 222 rc = ngx_http_do_read_client_request_body(r); |
214 | 223 |
215 done: | 224 done: |
216 | 225 |
226 if (r->request_body_no_buffering | |
227 && (rc == NGX_OK || rc == NGX_AGAIN)) | |
228 { | |
229 if (rc == NGX_OK) { | |
230 r->request_body_no_buffering = 0; | |
231 | |
232 } else { | |
233 /* rc == NGX_AGAIN */ | |
234 r->reading_body = 1; | |
235 } | |
236 | |
237 r->read_event_handler = ngx_http_block_reading; | |
238 post_handler(r); | |
239 } | |
240 | |
217 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { | 241 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { |
218 r->main->count--; | 242 r->main->count--; |
243 } | |
244 | |
245 return rc; | |
246 } | |
247 | |
248 | |
249 ngx_int_t | |
250 ngx_http_read_unbuffered_request_body(ngx_http_request_t *r) | |
251 { | |
252 ngx_int_t rc; | |
253 | |
254 if (r->connection->read->timedout) { | |
255 r->connection->timedout = 1; | |
256 return NGX_HTTP_REQUEST_TIME_OUT; | |
257 } | |
258 | |
259 rc = ngx_http_do_read_client_request_body(r); | |
260 | |
261 if (rc == NGX_OK) { | |
262 r->reading_body = 0; | |
219 } | 263 } |
220 | 264 |
221 return rc; | 265 return rc; |
222 } | 266 } |
223 | 267 |
262 | 306 |
263 for ( ;; ) { | 307 for ( ;; ) { |
264 for ( ;; ) { | 308 for ( ;; ) { |
265 if (rb->buf->last == rb->buf->end) { | 309 if (rb->buf->last == rb->buf->end) { |
266 | 310 |
311 if (rb->buf->pos != rb->buf->last) { | |
312 | |
313 /* pass buffer to request body filter chain */ | |
314 | |
315 out.buf = rb->buf; | |
316 out.next = NULL; | |
317 | |
318 rc = ngx_http_request_body_filter(r, &out); | |
319 | |
320 if (rc != NGX_OK) { | |
321 return rc; | |
322 } | |
323 | |
324 } else { | |
325 | |
326 /* update chains */ | |
327 | |
328 rc = ngx_http_request_body_filter(r, NULL); | |
329 | |
330 if (rc != NGX_OK) { | |
331 return rc; | |
332 } | |
333 } | |
334 | |
335 if (rb->busy != NULL) { | |
336 if (r->request_body_no_buffering) { | |
337 if (c->read->timer_set) { | |
338 ngx_del_timer(c->read); | |
339 } | |
340 | |
341 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | |
342 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
343 } | |
344 | |
345 return NGX_AGAIN; | |
346 } | |
347 | |
348 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
349 } | |
350 | |
351 rb->buf->pos = rb->buf->start; | |
352 rb->buf->last = rb->buf->start; | |
353 } | |
354 | |
355 size = rb->buf->end - rb->buf->last; | |
356 rest = rb->rest - (rb->buf->last - rb->buf->pos); | |
357 | |
358 if ((off_t) size > rest) { | |
359 size = (size_t) rest; | |
360 } | |
361 | |
362 n = c->recv(c, rb->buf->last, size); | |
363 | |
364 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
365 "http client request body recv %z", n); | |
366 | |
367 if (n == NGX_AGAIN) { | |
368 break; | |
369 } | |
370 | |
371 if (n == 0) { | |
372 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
373 "client prematurely closed connection"); | |
374 } | |
375 | |
376 if (n == 0 || n == NGX_ERROR) { | |
377 c->error = 1; | |
378 return NGX_HTTP_BAD_REQUEST; | |
379 } | |
380 | |
381 rb->buf->last += n; | |
382 r->request_length += n; | |
383 | |
384 if (n == rest) { | |
267 /* pass buffer to request body filter chain */ | 385 /* pass buffer to request body filter chain */ |
268 | 386 |
269 out.buf = rb->buf; | 387 out.buf = rb->buf; |
270 out.next = NULL; | 388 out.next = NULL; |
271 | 389 |
272 rc = ngx_http_request_body_filter(r, &out); | 390 rc = ngx_http_request_body_filter(r, &out); |
273 | 391 |
274 if (rc != NGX_OK) { | 392 if (rc != NGX_OK) { |
275 return rc; | 393 return rc; |
276 } | 394 } |
277 | 395 } |
278 if (rb->busy != NULL) { | 396 |
279 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 397 if (rb->rest == 0) { |
280 } | |
281 | |
282 rb->buf->pos = rb->buf->start; | |
283 rb->buf->last = rb->buf->start; | |
284 } | |
285 | |
286 size = rb->buf->end - rb->buf->last; | |
287 rest = rb->rest - (rb->buf->last - rb->buf->pos); | |
288 | |
289 if ((off_t) size > rest) { | |
290 size = (size_t) rest; | |
291 } | |
292 | |
293 n = c->recv(c, rb->buf->last, size); | |
294 | |
295 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
296 "http client request body recv %z", n); | |
297 | |
298 if (n == NGX_AGAIN) { | |
299 break; | 398 break; |
300 } | 399 } |
301 | 400 |
302 if (n == 0) { | 401 if (rb->buf->last < rb->buf->end) { |
303 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 402 break; |
304 "client prematurely closed connection"); | 403 } |
305 } | 404 } |
306 | 405 |
307 if (n == 0 || n == NGX_ERROR) { | 406 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, |
308 c->error = 1; | 407 "http client request body rest %O", rb->rest); |
309 return NGX_HTTP_BAD_REQUEST; | 408 |
310 } | 409 if (rb->rest == 0) { |
311 | 410 break; |
312 rb->buf->last += n; | 411 } |
313 r->request_length += n; | 412 |
314 | 413 if (!c->read->ready) { |
315 if (n == rest) { | 414 |
415 if (r->request_body_no_buffering | |
416 && rb->buf->pos != rb->buf->last) | |
417 { | |
316 /* pass buffer to request body filter chain */ | 418 /* pass buffer to request body filter chain */ |
317 | 419 |
318 out.buf = rb->buf; | 420 out.buf = rb->buf; |
319 out.next = NULL; | 421 out.next = NULL; |
320 | 422 |
323 if (rc != NGX_OK) { | 425 if (rc != NGX_OK) { |
324 return rc; | 426 return rc; |
325 } | 427 } |
326 } | 428 } |
327 | 429 |
328 if (rb->rest == 0) { | |
329 break; | |
330 } | |
331 | |
332 if (rb->buf->last < rb->buf->end) { | |
333 break; | |
334 } | |
335 } | |
336 | |
337 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
338 "http client request body rest %O", rb->rest); | |
339 | |
340 if (rb->rest == 0) { | |
341 break; | |
342 } | |
343 | |
344 if (!c->read->ready) { | |
345 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | 430 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
346 ngx_add_timer(c->read, clcf->client_body_timeout); | 431 ngx_add_timer(c->read, clcf->client_body_timeout); |
347 | 432 |
348 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | 433 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { |
349 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 434 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
385 } else { | 470 } else { |
386 rb->bufs = NULL; | 471 rb->bufs = NULL; |
387 } | 472 } |
388 } | 473 } |
389 | 474 |
390 r->read_event_handler = ngx_http_block_reading; | 475 if (!r->request_body_no_buffering) { |
391 | 476 r->read_event_handler = ngx_http_block_reading; |
392 rb->post_handler(r); | 477 rb->post_handler(r); |
478 } | |
393 | 479 |
394 return NGX_OK; | 480 return NGX_OK; |
395 } | 481 } |
396 | 482 |
397 | 483 |
1083 if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) { | 1169 if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) { |
1084 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 1170 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
1085 } | 1171 } |
1086 | 1172 |
1087 if (rb->rest > 0 | 1173 if (rb->rest > 0 |
1088 && rb->buf && rb->buf->last == rb->buf->end) | 1174 && rb->buf && rb->buf->last == rb->buf->end |
1175 && !r->request_body_no_buffering) | |
1089 { | 1176 { |
1090 if (ngx_http_write_request_body(r) != NGX_OK) { | 1177 if (ngx_http_write_request_body(r) != NGX_OK) { |
1091 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 1178 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
1092 } | 1179 } |
1093 } | 1180 } |