Mercurial > hg > nginx-vendor-current
comparison src/http/ngx_http_request_body.c @ 182:13710a1813ad NGINX_0_3_38
nginx 0.3.38
*) 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 <http://sysoev.ru> |
---|---|
date | Fri, 14 Apr 2006 00:00:00 +0400 |
parents | 91372f004adf |
children | 54aabf2b0bc6 |
comparison
equal
deleted
inserted
replaced
181:de8983d10e75 | 182:13710a1813ad |
---|---|
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 } |