comparison src/http/ngx_http_request_body.c @ 633:f971949ffb58 release-0.3.38

nginx-0.3.38-RELEASE import *) Feature: the ngx_http_dav_module. *) Change: the ngx_http_perl_module optimizations. Thanks to Sergey Skvortsov. *) Feature: the ngx_http_perl_module supports the $r->request_body_file method. *) Feature: the "client_body_in_file_only" directive. *) Workaround: now on disk overflow nginx tries to write access logs once a second only. Thanks to Anton Yuzhaninov and Maxim Dounin. *) Bugfix: now the "limit_rate" directive more precisely limits rate if rate is more than 100 Kbyte/s. Thanks to ForJest. *) Bugfix: now the IMAP/POP3 proxy escapes the "\r" and "\n" symbols in login and password to pass authorization server. Thanks to Maxim Dounin.
author Igor Sysoev <igor@sysoev.ru>
date Fri, 14 Apr 2006 09:53:38 +0000
parents 4e296b7d25bf
children e60fe4cf1d4e
comparison
equal deleted inserted replaced
632:5c60f5f0887d 633:f971949ffb58
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11 11
12 12
13 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); 13 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
14 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); 14 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
15 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r,
16 ngx_chain_t *body);
17 static void ngx_http_finalize_request_body(ngx_http_request_t *r, ngx_int_t rc);
18 static void ngx_http_read_discarded_body_handler(ngx_http_request_t *r);
19 static ngx_int_t ngx_http_read_discarded_body(ngx_http_request_t *r);
20
15 21
16 /* 22 /*
17 * on completion ngx_http_read_client_request_body() adds to 23 * on completion ngx_http_read_client_request_body() adds to
18 * r->request_body->bufs one or two bufs: 24 * r->request_body->bufs one or two bufs:
19 * *) one memory buf that was preread in r->header_in; 25 * *) one memory buf that was preread in r->header_in;
21 */ 27 */
22 28
23 ngx_int_t 29 ngx_int_t
24 ngx_http_read_client_request_body(ngx_http_request_t *r, 30 ngx_http_read_client_request_body(ngx_http_request_t *r,
25 ngx_http_client_body_handler_pt post_handler) 31 ngx_http_client_body_handler_pt post_handler)
26 32 {
27 { 33 ssize_t size, preread;
28 ssize_t size;
29 ngx_buf_t *b; 34 ngx_buf_t *b;
30 ngx_chain_t *cl; 35 ngx_chain_t *cl, **next;
31 ngx_http_request_body_t *rb; 36 ngx_http_request_body_t *rb;
32 ngx_http_core_loc_conf_t *clcf; 37 ngx_http_core_loc_conf_t *clcf;
33 38
34 if (r->request_body || r->discard_body) { 39 if (r->request_body || r->discard_body) {
35 post_handler(r); 40 post_handler(r);
56 * rb->bufs = NULL; 61 * rb->bufs = NULL;
57 * rb->buf = NULL; 62 * rb->buf = NULL;
58 * rb->rest = 0; 63 * rb->rest = 0;
59 */ 64 */
60 65
61 size = r->header_in->last - r->header_in->pos; 66 preread = r->header_in->last - r->header_in->pos;
62 67
63 if (size) { 68 if (preread) {
64 69
65 /* there is the pre-read part of the request body */ 70 /* there is the pre-read part of the request body */
71
72 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
73 "http client request body preread %uz", preread);
66 74
67 b = ngx_calloc_buf(r->pool); 75 b = ngx_calloc_buf(r->pool);
68 if (b == NULL) { 76 if (b == NULL) {
69 return NGX_HTTP_INTERNAL_SERVER_ERROR; 77 return NGX_HTTP_INTERNAL_SERVER_ERROR;
70 } 78 }
71 79
72 b->temporary = 1; 80 b->temporary = 1;
73 b->start = b->pos = r->header_in->pos; 81 b->start = r->header_in->pos;
74 b->end = b->last = r->header_in->last; 82 b->pos = r->header_in->pos;
83 b->last = r->header_in->last;
84 b->end = r->header_in->end;
75 85
76 rb->bufs = ngx_alloc_chain_link(r->pool); 86 rb->bufs = ngx_alloc_chain_link(r->pool);
77 if (rb->bufs == NULL) { 87 if (rb->bufs == NULL) {
78 return NGX_HTTP_INTERNAL_SERVER_ERROR; 88 return NGX_HTTP_INTERNAL_SERVER_ERROR;
79 } 89 }
80 90
81 rb->bufs->buf = b; 91 rb->bufs->buf = b;
82 rb->bufs->next = NULL; 92 rb->bufs->next = NULL;
83 93
84 if (size >= r->headers_in.content_length_n) { 94 if (preread >= r->headers_in.content_length_n) {
85 95
86 /* the whole request body was pre-read */ 96 /* the whole request body was pre-read */
87 97
88 r->header_in->pos += r->headers_in.content_length_n; 98 r->header_in->pos += r->headers_in.content_length_n;
89 r->request_length += r->headers_in.content_length_n; 99 r->request_length += r->headers_in.content_length_n;
90 100
101 if (r->request_body_in_file_only) {
102 if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) {
103 return NGX_HTTP_INTERNAL_SERVER_ERROR;
104 }
105 }
106
91 post_handler(r); 107 post_handler(r);
92 108
93 return NGX_OK; 109 return NGX_OK;
94 } 110 }
95 111
112 /*
113 * to not consider the body as pipelined request in
114 * ngx_http_set_keepalive()
115 */
96 r->header_in->pos = r->header_in->last; 116 r->header_in->pos = r->header_in->last;
97 r->request_length += size; 117
98 } 118 r->request_length += preread;
99 119
120 rb->rest = r->headers_in.content_length_n - preread;
121
122 if (rb->rest <= (size_t) (b->end - b->last)) {
123
124 /* the whole request body may be placed in r->header_in */
125
126 rb->buf = b;
127
128 r->read_event_handler = ngx_http_read_client_request_body_handler;
129
130 return ngx_http_do_read_client_request_body(r);
131 }
132
133 next = &rb->bufs->next;
134
135 } else {
136 b = NULL;
137 rb->rest = r->headers_in.content_length_n;
138 next = &rb->bufs;
139 }
100 140
101 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 141 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
102 142
103 rb->rest = r->headers_in.content_length_n - size; 143 size = clcf->client_body_buffer_size;
104 144 size += size >> 2;
105 if (rb->rest < clcf->client_body_buffer_size 145
106 + (clcf->client_body_buffer_size >> 2)) 146 if (rb->rest < (size_t) size) {
107 {
108 size = rb->rest; 147 size = rb->rest;
148
149 if (r->request_body_in_single_buf) {
150 size += preread;
151 }
109 152
110 } else { 153 } else {
111 size = clcf->client_body_buffer_size; 154 size = clcf->client_body_buffer_size;
155
156 /* disable copying buffer for r->request_body_in_single_buf */
157 b = NULL;
112 } 158 }
113 159
114 rb->buf = ngx_create_temp_buf(r->pool, size); 160 rb->buf = ngx_create_temp_buf(r->pool, size);
115 if (rb->buf == NULL) { 161 if (rb->buf == NULL) {
116 return NGX_HTTP_INTERNAL_SERVER_ERROR; 162 return NGX_HTTP_INTERNAL_SERVER_ERROR;
122 } 168 }
123 169
124 cl->buf = rb->buf; 170 cl->buf = rb->buf;
125 cl->next = NULL; 171 cl->next = NULL;
126 172
127 if (rb->bufs) { 173 if (b && r->request_body_in_single_buf) {
128 rb->bufs->next = cl; 174 size = b->last - b->pos;
175 ngx_memcpy(rb->buf->pos, b->pos, size);
176 rb->buf->last += size;
177
178 next = &rb->bufs;
179 }
180
181 *next = cl;
182
183 if (r->request_body_in_file_only || r->request_body_in_single_buf) {
184 rb->to_write = rb->bufs;
129 185
130 } else { 186 } else {
131 rb->bufs = cl; 187 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
132 } 188 }
133 189
134 r->read_event_handler = ngx_http_read_client_request_body_handler; 190 r->read_event_handler = ngx_http_read_client_request_body_handler;
135 191
136 return ngx_http_do_read_client_request_body(r); 192 return ngx_http_do_read_client_request_body(r);
142 { 198 {
143 ngx_int_t rc; 199 ngx_int_t rc;
144 200
145 if (r->connection->read->timedout) { 201 if (r->connection->read->timedout) {
146 r->connection->timedout = 1; 202 r->connection->timedout = 1;
147 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); 203 ngx_http_finalize_request_body(r, NGX_HTTP_REQUEST_TIME_OUT);
148 return; 204 return;
149 } 205 }
150 206
151 rc = ngx_http_do_read_client_request_body(r); 207 rc = ngx_http_do_read_client_request_body(r);
152 208
153 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { 209 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
154 ngx_http_finalize_request(r, rc); 210 ngx_http_finalize_request_body(r, rc);
155 } 211 }
156 } 212 }
157 213
158 214
159 static ngx_int_t 215 static ngx_int_t
160 ngx_http_do_read_client_request_body(ngx_http_request_t *r) 216 ngx_http_do_read_client_request_body(ngx_http_request_t *r)
161 { 217 {
162 size_t size; 218 size_t size;
163 ssize_t n; 219 ssize_t n;
164 ngx_buf_t *b; 220 ngx_buf_t *b;
165 ngx_temp_file_t *tf;
166 ngx_connection_t *c; 221 ngx_connection_t *c;
167 ngx_http_request_body_t *rb; 222 ngx_http_request_body_t *rb;
168 ngx_http_core_loc_conf_t *clcf; 223 ngx_http_core_loc_conf_t *clcf;
169 224
170 c = r->connection; 225 c = r->connection;
174 "http read client request body"); 229 "http read client request body");
175 230
176 for ( ;; ) { 231 for ( ;; ) {
177 if (rb->buf->last == rb->buf->end) { 232 if (rb->buf->last == rb->buf->end) {
178 233
179 if (rb->temp_file == NULL) { 234 if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
180 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
181 if (tf == NULL) {
182 return NGX_ERROR;
183 }
184
185 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
186
187 tf->file.fd = NGX_INVALID_FILE;
188 tf->file.log = r->connection->log;
189 tf->path = clcf->client_body_temp_path;
190 tf->pool = r->pool;
191 tf->warn = "a client request body is buffered "
192 "to a temporary file";
193
194 rb->temp_file = tf;
195
196 }
197
198 n = ngx_write_chain_to_temp_file(rb->temp_file,
199 rb->bufs->next ? rb->bufs->next:
200 rb->bufs);
201
202 /* TODO: n == 0 or not complete and level event */
203
204 if (n == NGX_ERROR) {
205 return NGX_HTTP_INTERNAL_SERVER_ERROR; 235 return NGX_HTTP_INTERNAL_SERVER_ERROR;
206 } 236 }
207 237
208 rb->temp_file->offset += n; 238 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
209 rb->buf->last = rb->buf->start; 239 rb->buf->last = rb->buf->start;
210 } 240 }
211 241
212 size = rb->buf->end - rb->buf->last; 242 size = rb->buf->end - rb->buf->last;
213 243
263 293
264 if (c->read->timer_set) { 294 if (c->read->timer_set) {
265 ngx_del_timer(c->read); 295 ngx_del_timer(c->read);
266 } 296 }
267 297
268 if (rb->temp_file) { 298 if (rb->temp_file || r->request_body_in_file_only) {
269 299
270 /* save the last part */ 300 /* save the last part */
271 301
272 n = ngx_write_chain_to_temp_file(rb->temp_file, 302 if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
273 rb->bufs->next ? rb->bufs->next:
274 rb->bufs);
275
276 /* TODO: n == 0 or not complete and level event */
277
278 if (n == NGX_ERROR) {
279 return NGX_HTTP_INTERNAL_SERVER_ERROR; 303 return NGX_HTTP_INTERNAL_SERVER_ERROR;
280 } 304 }
281 305
282 b = ngx_calloc_buf(r->pool); 306 b = ngx_calloc_buf(r->pool);
283 if (b == NULL) { 307 if (b == NULL) {
295 } else { 319 } else {
296 rb->bufs->buf = b; 320 rb->bufs->buf = b;
297 } 321 }
298 } 322 }
299 323
324 if (r->request_body_in_file_only && rb->bufs->next) {
325 rb->bufs = rb->bufs->next;
326 }
327
300 rb->post_handler(r); 328 rb->post_handler(r);
301 329
302 return NGX_OK; 330 return NGX_OK;
303 } 331 }
332
333
334 static ngx_int_t
335 ngx_http_write_request_body(ngx_http_request_t *r, ngx_chain_t *body)
336 {
337 ssize_t n;
338 ngx_temp_file_t *tf;
339 ngx_http_request_body_t *rb;
340 ngx_http_core_loc_conf_t *clcf;
341
342 rb = r->request_body;
343
344 if (rb->temp_file == NULL) {
345 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
346 if (tf == NULL) {
347 return NGX_ERROR;
348 }
349
350 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
351
352 tf->file.fd = NGX_INVALID_FILE;
353 tf->file.log = r->connection->log;
354 tf->path = clcf->client_body_temp_path;
355 tf->pool = r->pool;
356 tf->warn = "a client request body is buffered to a temporary file";
357 tf->persistent = r->request_body_in_persistent_file;
358
359 if (r->request_body_file_group_access) {
360 tf->mode = 0660;
361 }
362
363 rb->temp_file = tf;
364 }
365
366 n = ngx_write_chain_to_temp_file(rb->temp_file, body);
367
368 /* TODO: n == 0 or not complete and level event */
369
370 if (n == NGX_ERROR) {
371 return NGX_ERROR;
372 }
373
374 rb->temp_file->offset += n;
375
376 return NGX_OK;
377 }
378
379
380 static void
381 ngx_http_finalize_request_body(ngx_http_request_t *r, ngx_int_t rc)
382 {
383 if (r->request_body->temp_file
384 && r->request_body_in_persistent_file
385 && r->request_body_delete_incomplete_file)
386 {
387 if (ngx_delete_file(r->request_body->temp_file->file.name.data)
388 == NGX_FILE_ERROR)
389 {
390 ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
391 ngx_delete_file_n " \"%s\" failed",
392 r->request_body->temp_file->file.name.data);
393 }
394 }
395
396 ngx_http_finalize_request(r, rc);
397 }
398
399
400 ngx_int_t
401 ngx_http_discard_body(ngx_http_request_t *r)
402 {
403 ssize_t size;
404 ngx_event_t *rev;
405
406 if (r != r->main) {
407 return NGX_OK;
408 }
409
410 rev = r->connection->read;
411
412 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");
413
414 if (rev->timer_set) {
415 ngx_del_timer(rev);
416 }
417
418 if (r->headers_in.content_length_n <= 0) {
419 return NGX_OK;
420 }
421
422 r->discard_body = 1;
423
424 size = r->header_in->last - r->header_in->pos;
425
426 if (size) {
427 if (r->headers_in.content_length_n > size) {
428 r->headers_in.content_length_n -= size;
429
430 } else {
431 r->header_in->pos += r->headers_in.content_length_n;
432 r->headers_in.content_length_n = 0;
433 return NGX_OK;
434 }
435 }
436
437 r->read_event_handler = ngx_http_read_discarded_body_handler;
438
439 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
440 return NGX_HTTP_INTERNAL_SERVER_ERROR;
441 }
442
443 return ngx_http_read_discarded_body(r);
444 }
445
446
447 static void
448 ngx_http_read_discarded_body_handler(ngx_http_request_t *r)
449 {
450 ngx_int_t rc;
451
452 rc = ngx_http_read_discarded_body(r);
453
454 if (rc == NGX_AGAIN) {
455 if (ngx_handle_read_event(r->connection->read, 0) == NGX_ERROR) {
456 ngx_http_finalize_request(r, rc);
457 return;
458 }
459 }
460
461 if (rc != NGX_OK) {
462 ngx_http_finalize_request(r, rc);
463 }
464 }
465
466
467 static ngx_int_t
468 ngx_http_read_discarded_body(ngx_http_request_t *r)
469 {
470 ssize_t size, n;
471 u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
472
473 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
474 "http read discarded body");
475
476 if (r->headers_in.content_length_n == 0) {
477 return NGX_OK;
478 }
479
480
481 size = r->headers_in.content_length_n;
482
483 if (size > NGX_HTTP_DISCARD_BUFFER_SIZE) {
484 size = NGX_HTTP_DISCARD_BUFFER_SIZE;
485 }
486
487 n = r->connection->recv(r->connection, buffer, size);
488
489 if (n == NGX_ERROR) {
490
491 r->connection->error = 1;
492
493 /*
494 * if a client request body is discarded then we already set
495 * some HTTP response code for client and we can ignore the error
496 */
497
498 return NGX_OK;
499 }
500
501 if (n == NGX_AGAIN) {
502 return NGX_AGAIN;
503 }
504
505 r->headers_in.content_length_n -= n;
506
507 return NGX_OK;
508 }