blob: ac09d56f1972da82803124d8a0e9334ea9a1a85e [file] [log] [blame] [raw]
Igor Sysoev7d66b1f2004-10-05 15:39:18 +00001
2/*
3 * Copyright (C) Igor Sysoev
NGINX team01f0bd52012-01-30 14:53:52 +00004 * Copyright (C) Nginx, Inc.
Igor Sysoev7d66b1f2004-10-05 15:39:18 +00005 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
Igor Sysoev7d66b1f2004-10-05 15:39:18 +000010#include <ngx_http.h>
11
12
Igor Sysoev4b4c1f62005-05-12 14:59:46 +000013static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
14static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
Igor Sysoev9fdefb12006-04-14 09:34:54 +000015static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r,
16 ngx_chain_t *body);
Igor Sysoev55c04d12007-08-15 12:44:43 +000017static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
Igor Sysoeva1ff67e2009-01-19 14:03:40 +000018static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
Igor Sysoev9fdefb12006-04-14 09:34:54 +000019
Igor Sysoev7d66b1f2004-10-05 15:39:18 +000020
Igor Sysoevea4ca082005-01-18 13:04:59 +000021/*
22 * on completion ngx_http_read_client_request_body() adds to
23 * r->request_body->bufs one or two bufs:
24 * *) one memory buf that was preread in r->header_in;
25 * *) one memory or file buf that contains the rest of the body
26 */
Igor Sysoev7d66b1f2004-10-05 15:39:18 +000027
Igor Sysoevc70429e2005-03-19 12:35:58 +000028ngx_int_t
29ngx_http_read_client_request_body(ngx_http_request_t *r,
30 ngx_http_client_body_handler_pt post_handler)
Igor Sysoev7d66b1f2004-10-05 15:39:18 +000031{
Igor Sysoevfdd76482006-07-07 16:31:14 +000032 size_t preread;
33 ssize_t size;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +000034 ngx_buf_t *b;
Igor Sysoev9fdefb12006-04-14 09:34:54 +000035 ngx_chain_t *cl, **next;
Igor Sysoevde83cd42006-10-02 11:53:50 +000036 ngx_temp_file_t *tf;
Igor Sysoevea4ca082005-01-18 13:04:59 +000037 ngx_http_request_body_t *rb;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +000038 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev4b4c1f62005-05-12 14:59:46 +000039
Igor Sysoev802fd202009-08-28 13:21:12 +000040 r->main->count++;
41
Igor Sysoev8408e632005-08-30 10:55:44 +000042 if (r->request_body || r->discard_body) {
Igor Sysoev4b4c1f62005-05-12 14:59:46 +000043 post_handler(r);
44 return NGX_OK;
Igor Sysoeva1ff67e2009-01-19 14:03:40 +000045 }
46
47 if (ngx_http_test_expect(r) != NGX_OK) {
48 return NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoev4b4c1f62005-05-12 14:59:46 +000049 }
Igor Sysoevea4ca082005-01-18 13:04:59 +000050
Igor Sysoevc70429e2005-03-19 12:35:58 +000051 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
52 if (rb == NULL) {
Igor Sysoevea4ca082005-01-18 13:04:59 +000053 return NGX_HTTP_INTERNAL_SERVER_ERROR;
54 }
55
56 r->request_body = rb;
57
Igor Sysoevde83cd42006-10-02 11:53:50 +000058 if (r->headers_in.content_length_n < 0) {
59 post_handler(r);
60 return NGX_OK;
61 }
62
63 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
64
65 if (r->headers_in.content_length_n == 0) {
66
67 if (r->request_body_in_file_only) {
68 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
69 if (tf == NULL) {
70 return NGX_HTTP_INTERNAL_SERVER_ERROR;
71 }
72
73 tf->file.fd = NGX_INVALID_FILE;
74 tf->file.log = r->connection->log;
75 tf->path = clcf->client_body_temp_path;
76 tf->pool = r->pool;
77 tf->warn = "a client request body is buffered to a temporary file";
78 tf->log_level = r->request_body_file_log_level;
79 tf->persistent = r->request_body_in_persistent_file;
Igor Sysoev50138442007-01-25 16:35:14 +000080 tf->clean = r->request_body_in_clean_file;
Igor Sysoevde83cd42006-10-02 11:53:50 +000081
82 if (r->request_body_file_group_access) {
Igor Sysoev6c8b6b32007-01-19 16:14:25 +000083 tf->access = 0660;
Igor Sysoevde83cd42006-10-02 11:53:50 +000084 }
85
86 rb->temp_file = tf;
87
88 if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
Igor Sysoev50138442007-01-25 16:35:14 +000089 tf->persistent, tf->clean, tf->access)
Igor Sysoevde83cd42006-10-02 11:53:50 +000090 != NGX_OK)
91 {
92 return NGX_HTTP_INTERNAL_SERVER_ERROR;
93 }
94 }
95
Igor Sysoevea4ca082005-01-18 13:04:59 +000096 post_handler(r);
Igor Sysoev7f4fcbd2007-07-12 11:23:11 +000097
Igor Sysoevea4ca082005-01-18 13:04:59 +000098 return NGX_OK;
99 }
100
101 rb->post_handler = post_handler;
102
103 /*
104 * set by ngx_pcalloc():
105 *
106 * rb->bufs = NULL;
107 * rb->buf = NULL;
108 * rb->rest = 0;
109 */
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000110
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000111 preread = r->header_in->last - r->header_in->pos;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000112
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000113 if (preread) {
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000114
115 /* there is the pre-read part of the request body */
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000116
117 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
118 "http client request body preread %uz", preread);
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000119
Igor Sysoevc70429e2005-03-19 12:35:58 +0000120 b = ngx_calloc_buf(r->pool);
121 if (b == NULL) {
Igor Sysoevea4ca082005-01-18 13:04:59 +0000122 return NGX_HTTP_INTERNAL_SERVER_ERROR;
123 }
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000124
125 b->temporary = 1;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000126 b->start = r->header_in->pos;
127 b->pos = r->header_in->pos;
128 b->last = r->header_in->last;
129 b->end = r->header_in->end;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000130
Igor Sysoevc70429e2005-03-19 12:35:58 +0000131 rb->bufs = ngx_alloc_chain_link(r->pool);
132 if (rb->bufs == NULL) {
Igor Sysoevea4ca082005-01-18 13:04:59 +0000133 return NGX_HTTP_INTERNAL_SERVER_ERROR;
134 }
135
136 rb->bufs->buf = b;
137 rb->bufs->next = NULL;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000138
Igor Sysoevebd9fbd2006-07-28 15:12:39 +0000139 rb->buf = b;
140
Igor Sysoev2b3fe492006-07-11 13:16:58 +0000141 if ((off_t) preread >= r->headers_in.content_length_n) {
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000142
143 /* the whole request body was pre-read */
144
Igor Sysoevfdd76482006-07-07 16:31:14 +0000145 r->header_in->pos += (size_t) r->headers_in.content_length_n;
Igor Sysoev54c804a2004-12-06 14:42:13 +0000146 r->request_length += r->headers_in.content_length_n;
Igor Sysoeve18abb42011-08-22 14:09:56 +0000147 b->last = r->header_in->pos;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000148
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000149 if (r->request_body_in_file_only) {
150 if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) {
151 return NGX_HTTP_INTERNAL_SERVER_ERROR;
152 }
153 }
154
Igor Sysoevea4ca082005-01-18 13:04:59 +0000155 post_handler(r);
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000156
157 return NGX_OK;
158 }
159
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000160 /*
161 * to not consider the body as pipelined request in
162 * ngx_http_set_keepalive()
163 */
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000164 r->header_in->pos = r->header_in->last;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000165
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000166 r->request_length += preread;
167
168 rb->rest = r->headers_in.content_length_n - preread;
169
Igor Sysoev2b3fe492006-07-11 13:16:58 +0000170 if (rb->rest <= (off_t) (b->end - b->last)) {
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000171
172 /* the whole request body may be placed in r->header_in */
Igor Sysoev6c8b6b32007-01-19 16:14:25 +0000173
174 rb->to_write = rb->bufs;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000175
176 r->read_event_handler = ngx_http_read_client_request_body_handler;
177
178 return ngx_http_do_read_client_request_body(r);
179 }
180
181 next = &rb->bufs->next;
182
183 } else {
184 b = NULL;
185 rb->rest = r->headers_in.content_length_n;
186 next = &rb->bufs;
187 }
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000188
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000189 size = clcf->client_body_buffer_size;
190 size += size >> 2;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000191
Igor Sysoevfdd76482006-07-07 16:31:14 +0000192 if (rb->rest < size) {
193 size = (ssize_t) rb->rest;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000194
195 if (r->request_body_in_single_buf) {
196 size += preread;
197 }
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000198
199 } else {
200 size = clcf->client_body_buffer_size;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000201
202 /* disable copying buffer for r->request_body_in_single_buf */
203 b = NULL;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000204 }
205
Igor Sysoevc70429e2005-03-19 12:35:58 +0000206 rb->buf = ngx_create_temp_buf(r->pool, size);
207 if (rb->buf == NULL) {
Igor Sysoevea4ca082005-01-18 13:04:59 +0000208 return NGX_HTTP_INTERNAL_SERVER_ERROR;
209 }
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000210
Igor Sysoevc70429e2005-03-19 12:35:58 +0000211 cl = ngx_alloc_chain_link(r->pool);
212 if (cl == NULL) {
Igor Sysoevea4ca082005-01-18 13:04:59 +0000213 return NGX_HTTP_INTERNAL_SERVER_ERROR;
214 }
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000215
Igor Sysoevea4ca082005-01-18 13:04:59 +0000216 cl->buf = rb->buf;
217 cl->next = NULL;
218
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000219 if (b && r->request_body_in_single_buf) {
220 size = b->last - b->pos;
221 ngx_memcpy(rb->buf->pos, b->pos, size);
222 rb->buf->last += size;
223
224 next = &rb->bufs;
225 }
226
227 *next = cl;
228
229 if (r->request_body_in_file_only || r->request_body_in_single_buf) {
230 rb->to_write = rb->bufs;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000231
232 } else {
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000233 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000234 }
235
Igor Sysoev4b4c1f62005-05-12 14:59:46 +0000236 r->read_event_handler = ngx_http_read_client_request_body_handler;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000237
Igor Sysoev4b4c1f62005-05-12 14:59:46 +0000238 return ngx_http_do_read_client_request_body(r);
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000239}
240
241
Igor Sysoevc70429e2005-03-19 12:35:58 +0000242static void
Igor Sysoev4b4c1f62005-05-12 14:59:46 +0000243ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000244{
Igor Sysoev4b4c1f62005-05-12 14:59:46 +0000245 ngx_int_t rc;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000246
Igor Sysoev4b4c1f62005-05-12 14:59:46 +0000247 if (r->connection->read->timedout) {
Igor Sysoevfb0f94f2005-11-15 12:26:51 +0000248 r->connection->timedout = 1;
Igor Sysoev50138442007-01-25 16:35:14 +0000249 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000250 return;
251 }
252
Igor Sysoev4b4c1f62005-05-12 14:59:46 +0000253 rc = ngx_http_do_read_client_request_body(r);
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000254
255 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
Igor Sysoev50138442007-01-25 16:35:14 +0000256 ngx_http_finalize_request(r, rc);
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000257 }
258}
259
260
Igor Sysoevc70429e2005-03-19 12:35:58 +0000261static ngx_int_t
Igor Sysoev4b4c1f62005-05-12 14:59:46 +0000262ngx_http_do_read_client_request_body(ngx_http_request_t *r)
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000263{
264 size_t size;
265 ssize_t n;
266 ngx_buf_t *b;
Igor Sysoev4b4c1f62005-05-12 14:59:46 +0000267 ngx_connection_t *c;
Igor Sysoevea4ca082005-01-18 13:04:59 +0000268 ngx_http_request_body_t *rb;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000269 ngx_http_core_loc_conf_t *clcf;
270
Igor Sysoev4b4c1f62005-05-12 14:59:46 +0000271 c = r->connection;
Igor Sysoevea4ca082005-01-18 13:04:59 +0000272 rb = r->request_body;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000273
274 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
275 "http read client request body");
276
277 for ( ;; ) {
Igor Sysoeve0cae6b2006-11-15 20:02:20 +0000278 for ( ;; ) {
279 if (rb->buf->last == rb->buf->end) {
Igor Sysoevea4ca082005-01-18 13:04:59 +0000280
Igor Sysoeve0cae6b2006-11-15 20:02:20 +0000281 if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
282 return NGX_HTTP_INTERNAL_SERVER_ERROR;
283 }
284
285 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
286 rb->buf->last = rb->buf->start;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000287 }
288
Igor Sysoeve0cae6b2006-11-15 20:02:20 +0000289 size = rb->buf->end - rb->buf->last;
290
291 if ((off_t) size > rb->rest) {
292 size = (size_t) rb->rest;
293 }
294
295 n = c->recv(c, rb->buf->last, size);
296
297 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
298 "http client request body recv %z", n);
299
300 if (n == NGX_AGAIN) {
301 break;
302 }
303
304 if (n == 0) {
305 ngx_log_error(NGX_LOG_INFO, c->log, 0,
306 "client closed prematurely connection");
307 }
308
309 if (n == 0 || n == NGX_ERROR) {
310 c->error = 1;
311 return NGX_HTTP_BAD_REQUEST;
312 }
313
314 rb->buf->last += n;
315 rb->rest -= n;
316 r->request_length += n;
317
318 if (rb->rest == 0) {
319 break;
320 }
321
322 if (rb->buf->last < rb->buf->end) {
323 break;
324 }
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000325 }
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000326
327 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
Igor Sysoev0125d542007-02-19 13:26:03 +0000328 "http client request body rest %O", rb->rest);
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000329
Igor Sysoevea4ca082005-01-18 13:04:59 +0000330 if (rb->rest == 0) {
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000331 break;
332 }
333
Igor Sysoeve0cae6b2006-11-15 20:02:20 +0000334 if (!c->read->ready) {
335 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
336 ngx_add_timer(c->read, clcf->client_body_timeout);
337
Igor Sysoevaccf3742008-12-15 11:30:58 +0000338 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
Igor Sysoeve0cae6b2006-11-15 20:02:20 +0000339 return NGX_HTTP_INTERNAL_SERVER_ERROR;
340 }
341
342 return NGX_AGAIN;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000343 }
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000344 }
345
Igor Sysoev9f37f032005-11-09 17:27:29 +0000346 if (c->read->timer_set) {
347 ngx_del_timer(c->read);
348 }
349
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000350 if (rb->temp_file || r->request_body_in_file_only) {
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000351
352 /* save the last part */
Igor Sysoevea4ca082005-01-18 13:04:59 +0000353
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000354 if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000355 return NGX_HTTP_INTERNAL_SERVER_ERROR;
356 }
357
Igor Sysoevc70429e2005-03-19 12:35:58 +0000358 b = ngx_calloc_buf(r->pool);
359 if (b == NULL) {
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000360 return NGX_HTTP_INTERNAL_SERVER_ERROR;
361 }
362
363 b->in_file = 1;
364 b->file_pos = 0;
Igor Sysoevea4ca082005-01-18 13:04:59 +0000365 b->file_last = rb->temp_file->file.offset;
366 b->file = &rb->temp_file->file;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000367
Igor Sysoevea4ca082005-01-18 13:04:59 +0000368 if (rb->bufs->next) {
369 rb->bufs->next->buf = b;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000370
371 } else {
Igor Sysoevea4ca082005-01-18 13:04:59 +0000372 rb->bufs->buf = b;
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000373 }
374 }
375
Igor Sysoeve18abb42011-08-22 14:09:56 +0000376 if (rb->bufs->next
377 && (r->request_body_in_file_only || r->request_body_in_single_buf))
378 {
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000379 rb->bufs = rb->bufs->next;
380 }
381
Igor Sysoev3eed28f2011-09-05 13:18:16 +0000382 r->read_event_handler = ngx_http_block_reading;
383
Igor Sysoevea4ca082005-01-18 13:04:59 +0000384 rb->post_handler(r);
Igor Sysoev7d66b1f2004-10-05 15:39:18 +0000385
386 return NGX_OK;
387}
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000388
389
390static ngx_int_t
391ngx_http_write_request_body(ngx_http_request_t *r, ngx_chain_t *body)
392{
393 ssize_t n;
394 ngx_temp_file_t *tf;
395 ngx_http_request_body_t *rb;
396 ngx_http_core_loc_conf_t *clcf;
397
398 rb = r->request_body;
399
400 if (rb->temp_file == NULL) {
401 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
402 if (tf == NULL) {
403 return NGX_ERROR;
404 }
405
406 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
407
408 tf->file.fd = NGX_INVALID_FILE;
409 tf->file.log = r->connection->log;
410 tf->path = clcf->client_body_temp_path;
411 tf->pool = r->pool;
412 tf->warn = "a client request body is buffered to a temporary file";
Igor Sysoev89fe1622006-04-19 15:24:22 +0000413 tf->log_level = r->request_body_file_log_level;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000414 tf->persistent = r->request_body_in_persistent_file;
Igor Sysoev50138442007-01-25 16:35:14 +0000415 tf->clean = r->request_body_in_clean_file;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000416
417 if (r->request_body_file_group_access) {
Igor Sysoev6c8b6b32007-01-19 16:14:25 +0000418 tf->access = 0660;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000419 }
420
421 rb->temp_file = tf;
422 }
423
424 n = ngx_write_chain_to_temp_file(rb->temp_file, body);
425
426 /* TODO: n == 0 or not complete and level event */
427
428 if (n == NGX_ERROR) {
429 return NGX_ERROR;
430 }
431
432 rb->temp_file->offset += n;
433
434 return NGX_OK;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000435}
436
437
438ngx_int_t
Igor Sysoev55c04d12007-08-15 12:44:43 +0000439ngx_http_discard_request_body(ngx_http_request_t *r)
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000440{
441 ssize_t size;
442 ngx_event_t *rev;
443
Igor Sysoev99c16dd2006-08-14 15:06:25 +0000444 if (r != r->main || r->discard_body) {
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000445 return NGX_OK;
446 }
447
Igor Sysoeva1ff67e2009-01-19 14:03:40 +0000448 if (ngx_http_test_expect(r) != NGX_OK) {
449 return NGX_HTTP_INTERNAL_SERVER_ERROR;
450 }
451
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000452 rev = r->connection->read;
453
454 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");
455
456 if (rev->timer_set) {
457 ngx_del_timer(rev);
458 }
459
Igor Sysoev388fd292007-10-22 11:17:22 +0000460 if (r->headers_in.content_length_n <= 0 || r->request_body) {
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000461 return NGX_OK;
462 }
Igor Sysoev55c04d12007-08-15 12:44:43 +0000463
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000464 size = r->header_in->last - r->header_in->pos;
465
466 if (size) {
467 if (r->headers_in.content_length_n > size) {
Igor Sysoevef4b4d72009-10-26 14:09:32 +0000468 r->header_in->pos += size;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000469 r->headers_in.content_length_n -= size;
470
471 } else {
Igor Sysoevfdd76482006-07-07 16:31:14 +0000472 r->header_in->pos += (size_t) r->headers_in.content_length_n;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000473 r->headers_in.content_length_n = 0;
474 return NGX_OK;
475 }
476 }
Igor Sysoev43335b32007-09-03 10:30:19 +0000477
Igor Sysoevef4b4d72009-10-26 14:09:32 +0000478 r->read_event_handler = ngx_http_discarded_request_body_handler;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000479
Igor Sysoevaccf3742008-12-15 11:30:58 +0000480 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000481 return NGX_HTTP_INTERNAL_SERVER_ERROR;
482 }
483
Igor Sysoev0183c2f2009-10-06 12:44:57 +0000484 if (ngx_http_read_discarded_request_body(r) == NGX_OK) {
485 r->lingering_close = 0;
486
487 } else {
Igor Sysoev49590f72009-09-28 13:08:15 +0000488 r->count++;
Igor Sysoev0183c2f2009-10-06 12:44:57 +0000489 r->discard_body = 1;
Igor Sysoev49590f72009-09-28 13:08:15 +0000490 }
Igor Sysoev55c04d12007-08-15 12:44:43 +0000491
492 return NGX_OK;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000493}
494
495
Igor Sysoevef4b4d72009-10-26 14:09:32 +0000496void
497ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000498{
Igor Sysoev55c04d12007-08-15 12:44:43 +0000499 ngx_int_t rc;
500 ngx_msec_t timer;
501 ngx_event_t *rev;
502 ngx_connection_t *c;
503 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000504
Igor Sysoev55c04d12007-08-15 12:44:43 +0000505 c = r->connection;
506 rev = c->read;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000507
Igor Sysoev55c04d12007-08-15 12:44:43 +0000508 if (rev->timedout) {
509 c->timedout = 1;
510 c->error = 1;
Igor Sysoevef4b4d72009-10-26 14:09:32 +0000511 ngx_http_finalize_request(r, NGX_ERROR);
Igor Sysoev55c04d12007-08-15 12:44:43 +0000512 return;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000513 }
514
Igor Sysoev55c04d12007-08-15 12:44:43 +0000515 if (r->lingering_time) {
Igor Sysoevaa639b22007-11-15 15:05:24 +0000516 timer = (ngx_msec_t) (r->lingering_time - ngx_time());
Igor Sysoev55c04d12007-08-15 12:44:43 +0000517
518 if (timer <= 0) {
519 r->discard_body = 0;
Igor Sysoev0183c2f2009-10-06 12:44:57 +0000520 r->lingering_close = 0;
Igor Sysoevef4b4d72009-10-26 14:09:32 +0000521 ngx_http_finalize_request(r, NGX_ERROR);
Igor Sysoev55c04d12007-08-15 12:44:43 +0000522 return;
523 }
524
525 } else {
526 timer = 0;
527 }
528
529 rc = ngx_http_read_discarded_request_body(r);
530
531 if (rc == NGX_OK) {
Igor Sysoev55c04d12007-08-15 12:44:43 +0000532 r->discard_body = 0;
Igor Sysoev0183c2f2009-10-06 12:44:57 +0000533 r->lingering_close = 0;
Igor Sysoevef4b4d72009-10-26 14:09:32 +0000534 ngx_http_finalize_request(r, NGX_DONE);
Igor Sysoev55c04d12007-08-15 12:44:43 +0000535 return;
536 }
537
538 /* rc == NGX_AGAIN */
539
Igor Sysoevaccf3742008-12-15 11:30:58 +0000540 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
Igor Sysoev43335b32007-09-03 10:30:19 +0000541 c->error = 1;
Igor Sysoevef4b4d72009-10-26 14:09:32 +0000542 ngx_http_finalize_request(r, NGX_ERROR);
Igor Sysoev55c04d12007-08-15 12:44:43 +0000543 return;
544 }
545
546 if (timer) {
547
548 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
549
550 timer *= 1000;
551
552 if (timer > clcf->lingering_timeout) {
553 timer = clcf->lingering_timeout;
554 }
555
556 ngx_add_timer(rev, timer);
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000557 }
558}
559
560
561static ngx_int_t
Igor Sysoev55c04d12007-08-15 12:44:43 +0000562ngx_http_read_discarded_request_body(ngx_http_request_t *r)
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000563{
Igor Sysoevfdd76482006-07-07 16:31:14 +0000564 size_t size;
565 ssize_t n;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000566 u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
567
568 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
569 "http read discarded body");
570
Igor Sysoev49590f72009-09-28 13:08:15 +0000571 for ( ;; ) {
Igor Sysoev55c04d12007-08-15 12:44:43 +0000572 if (r->headers_in.content_length_n == 0) {
573 r->read_event_handler = ngx_http_block_reading;
574 return NGX_OK;
Igor Sysoev49590f72009-09-28 13:08:15 +0000575 }
576
577 if (!r->connection->read->ready) {
578 return NGX_AGAIN;
Igor Sysoev55c04d12007-08-15 12:44:43 +0000579 }
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000580
Igor Sysoev55c04d12007-08-15 12:44:43 +0000581 size = (r->headers_in.content_length_n > NGX_HTTP_DISCARD_BUFFER_SIZE) ?
582 NGX_HTTP_DISCARD_BUFFER_SIZE:
583 (size_t) r->headers_in.content_length_n;
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000584
Igor Sysoev55c04d12007-08-15 12:44:43 +0000585 n = r->connection->recv(r->connection, buffer, size);
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000586
Igor Sysoev55c04d12007-08-15 12:44:43 +0000587 if (n == NGX_ERROR) {
588 r->connection->error = 1;
589 return NGX_OK;
590 }
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000591
Igor Sysoev55c04d12007-08-15 12:44:43 +0000592 if (n == NGX_AGAIN) {
593 return NGX_AGAIN;
594 }
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000595
Igor Sysoev650585b2007-08-28 16:23:30 +0000596 if (n == 0) {
597 return NGX_OK;
598 }
599
Igor Sysoev55c04d12007-08-15 12:44:43 +0000600 r->headers_in.content_length_n -= n;
Igor Sysoev49590f72009-09-28 13:08:15 +0000601 }
Igor Sysoev9fdefb12006-04-14 09:34:54 +0000602}
Igor Sysoeva1ff67e2009-01-19 14:03:40 +0000603
604
605static ngx_int_t
606ngx_http_test_expect(ngx_http_request_t *r)
607{
608 ngx_int_t n;
609 ngx_str_t *expect;
610
611 if (r->expect_tested
612 || r->headers_in.expect == NULL
613 || r->http_version < NGX_HTTP_VERSION_11)
614 {
615 return NGX_OK;
616 }
617
618 r->expect_tested = 1;
619
620 expect = &r->headers_in.expect->value;
621
622 if (expect->len != sizeof("100-continue") - 1
623 || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
624 sizeof("100-continue") - 1)
625 != 0)
626 {
627 return NGX_OK;
628 }
629
630 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
631 "send 100 Continue");
632
633 n = r->connection->send(r->connection,
634 (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
635 sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
636
637 if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
638 return NGX_OK;
639 }
640
641 /* we assume that such small packet should be send successfully */
642
643 return NGX_ERROR;
644}