blob: 9d47300f5a2fadc4ac22d1ce59bfb259975d7c99 [file] [log] [blame]
Igor Sysoeva09f08d2003-04-25 14:43:13 +00001
Igor Sysoevd90282d2004-09-28 08:34:51 +00002/*
Igor Sysoevff8da912004-09-29 16:00:49 +00003 * Copyright (C) Igor Sysoev
Igor Sysoevd90282d2004-09-28 08:34:51 +00004 */
5
6
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +00007#include <ngx_config.h>
8#include <ngx_core.h>
9#include <ngx_http.h>
Igor Sysoeva09f08d2003-04-25 14:43:13 +000010
11
Igor Sysoev899b44e2005-05-12 14:58:06 +000012static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
13static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +000014static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r,
15 ngx_chain_t *body);
Igor Sysoev832571f2007-08-06 15:37:22 +000016static void ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r);
17static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
Igor Sysoev303df472008-12-26 13:43:42 +000018static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +000019
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000020
Igor Sysoev02025fd2005-01-18 13:03:58 +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 Sysoev10fc9ef2003-10-27 08:53:49 +000027
Igor Sysoevc1571722005-03-19 12:38:37 +000028ngx_int_t
29ngx_http_read_client_request_body(ngx_http_request_t *r,
30 ngx_http_client_body_handler_pt post_handler)
Igor Sysoeva09f08d2003-04-25 14:43:13 +000031{
Igor Sysoev1765f472006-07-07 16:33:19 +000032 size_t preread;
33 ssize_t size;
Igor Sysoev369145c2004-05-28 15:49:23 +000034 ngx_buf_t *b;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +000035 ngx_chain_t *cl, **next;
Igor Sysoev4c7f5112006-10-01 07:17:01 +000036 ngx_temp_file_t *tf;
Igor Sysoev02025fd2005-01-18 13:03:58 +000037 ngx_http_request_body_t *rb;
Igor Sysoevdbb27762004-04-01 16:20:53 +000038 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev11dbe972004-03-29 17:43:58 +000039
Igor Sysoeve5035392005-08-30 10:55:07 +000040 if (r->request_body || r->discard_body) {
Igor Sysoev899b44e2005-05-12 14:58:06 +000041 post_handler(r);
42 return NGX_OK;
43 }
44
Igor Sysoev303df472008-12-26 13:43:42 +000045 if (ngx_http_test_expect(r) != NGX_OK) {
46 return NGX_HTTP_INTERNAL_SERVER_ERROR;
47 }
48
Igor Sysoevc1571722005-03-19 12:38:37 +000049 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
50 if (rb == NULL) {
Igor Sysoev02025fd2005-01-18 13:03:58 +000051 return NGX_HTTP_INTERNAL_SERVER_ERROR;
52 }
53
54 r->request_body = rb;
55
Igor Sysoev4c7f5112006-10-01 07:17:01 +000056 if (r->headers_in.content_length_n < 0) {
57 post_handler(r);
58 return NGX_OK;
59 }
60
61 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
62
63 if (r->headers_in.content_length_n == 0) {
64
65 if (r->request_body_in_file_only) {
66 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
67 if (tf == NULL) {
68 return NGX_HTTP_INTERNAL_SERVER_ERROR;
69 }
70
71 tf->file.fd = NGX_INVALID_FILE;
72 tf->file.log = r->connection->log;
73 tf->path = clcf->client_body_temp_path;
74 tf->pool = r->pool;
75 tf->warn = "a client request body is buffered to a temporary file";
76 tf->log_level = r->request_body_file_log_level;
77 tf->persistent = r->request_body_in_persistent_file;
Igor Sysoevcd5b99a2007-01-25 08:45:04 +000078 tf->clean = r->request_body_in_clean_file;
Igor Sysoev4c7f5112006-10-01 07:17:01 +000079
80 if (r->request_body_file_group_access) {
Igor Sysoevfe1cb8c2007-01-18 19:52:18 +000081 tf->access = 0660;
Igor Sysoev4c7f5112006-10-01 07:17:01 +000082 }
83
84 rb->temp_file = tf;
85
86 if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
Igor Sysoevcd5b99a2007-01-25 08:45:04 +000087 tf->persistent, tf->clean, tf->access)
Igor Sysoev4c7f5112006-10-01 07:17:01 +000088 != NGX_OK)
89 {
90 return NGX_HTTP_INTERNAL_SERVER_ERROR;
91 }
92 }
93
Igor Sysoev02025fd2005-01-18 13:03:58 +000094 post_handler(r);
Igor Sysoevef6e3622007-07-11 20:12:26 +000095
Igor Sysoev02025fd2005-01-18 13:03:58 +000096 return NGX_OK;
97 }
98
99 rb->post_handler = post_handler;
100
101 /*
102 * set by ngx_pcalloc():
103 *
104 * rb->bufs = NULL;
105 * rb->buf = NULL;
106 * rb->rest = 0;
107 */
108
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000109 preread = r->header_in->last - r->header_in->pos;
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000110
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000111 if (preread) {
Igor Sysoev14f02ed2004-03-26 16:13:01 +0000112
113 /* there is the pre-read part of the request body */
114
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000115 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
116 "http client request body preread %uz", preread);
117
Igor Sysoevc1571722005-03-19 12:38:37 +0000118 b = ngx_calloc_buf(r->pool);
119 if (b == NULL) {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000120 return NGX_HTTP_INTERNAL_SERVER_ERROR;
121 }
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000122
Igor Sysoev369145c2004-05-28 15:49:23 +0000123 b->temporary = 1;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000124 b->start = r->header_in->pos;
125 b->pos = r->header_in->pos;
126 b->last = r->header_in->last;
127 b->end = r->header_in->end;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000128
Igor Sysoevc1571722005-03-19 12:38:37 +0000129 rb->bufs = ngx_alloc_chain_link(r->pool);
130 if (rb->bufs == NULL) {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000131 return NGX_HTTP_INTERNAL_SERVER_ERROR;
132 }
133
134 rb->bufs->buf = b;
135 rb->bufs->next = NULL;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000136
Igor Sysoev8f125582006-07-28 15:16:17 +0000137 rb->buf = b;
138
Igor Sysoevbb28b6d2006-07-11 13:20:19 +0000139 if ((off_t) preread >= r->headers_in.content_length_n) {
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000140
Igor Sysoev14f02ed2004-03-26 16:13:01 +0000141 /* the whole request body was pre-read */
142
Igor Sysoev1765f472006-07-07 16:33:19 +0000143 r->header_in->pos += (size_t) r->headers_in.content_length_n;
Igor Sysoev6a12fc92004-12-06 14:45:08 +0000144 r->request_length += r->headers_in.content_length_n;
Igor Sysoev6707ba92004-03-30 15:59:50 +0000145
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000146 if (r->request_body_in_file_only) {
147 if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) {
148 return NGX_HTTP_INTERNAL_SERVER_ERROR;
149 }
150 }
151
Igor Sysoev02025fd2005-01-18 13:03:58 +0000152 post_handler(r);
Igor Sysoev6707ba92004-03-30 15:59:50 +0000153
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000154 return NGX_OK;
155 }
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000156
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000157 /*
158 * to not consider the body as pipelined request in
159 * ngx_http_set_keepalive()
160 */
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000161 r->header_in->pos = r->header_in->last;
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000162
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000163 r->request_length += preread;
164
165 rb->rest = r->headers_in.content_length_n - preread;
166
Igor Sysoevbb28b6d2006-07-11 13:20:19 +0000167 if (rb->rest <= (off_t) (b->end - b->last)) {
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000168
169 /* the whole request body may be placed in r->header_in */
170
Igor Sysoev36588962007-01-19 16:13:15 +0000171 rb->to_write = rb->bufs;
172
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000173 r->read_event_handler = ngx_http_read_client_request_body_handler;
174
Igor Sysoevcd5b99a2007-01-25 08:45:04 +0000175 return ngx_http_do_read_client_request_body(r);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000176 }
177
178 next = &rb->bufs->next;
179
180 } else {
181 b = NULL;
182 rb->rest = r->headers_in.content_length_n;
183 next = &rb->bufs;
184 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000185
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000186 size = clcf->client_body_buffer_size;
187 size += size >> 2;
Igor Sysoev14f02ed2004-03-26 16:13:01 +0000188
Igor Sysoev1765f472006-07-07 16:33:19 +0000189 if (rb->rest < size) {
190 size = (ssize_t) rb->rest;
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000191
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000192 if (r->request_body_in_single_buf) {
193 size += preread;
194 }
195
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000196 } else {
Igor Sysoevdbb27762004-04-01 16:20:53 +0000197 size = clcf->client_body_buffer_size;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000198
199 /* disable copying buffer for r->request_body_in_single_buf */
200 b = NULL;
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000201 }
202
Igor Sysoevc1571722005-03-19 12:38:37 +0000203 rb->buf = ngx_create_temp_buf(r->pool, size);
204 if (rb->buf == NULL) {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000205 return NGX_HTTP_INTERNAL_SERVER_ERROR;
206 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000207
Igor Sysoevc1571722005-03-19 12:38:37 +0000208 cl = ngx_alloc_chain_link(r->pool);
209 if (cl == NULL) {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000210 return NGX_HTTP_INTERNAL_SERVER_ERROR;
211 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000212
Igor Sysoev02025fd2005-01-18 13:03:58 +0000213 cl->buf = rb->buf;
214 cl->next = NULL;
215
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000216 if (b && r->request_body_in_single_buf) {
217 size = b->last - b->pos;
218 ngx_memcpy(rb->buf->pos, b->pos, size);
219 rb->buf->last += size;
220
221 next = &rb->bufs;
222 }
223
224 *next = cl;
225
226 if (r->request_body_in_file_only || r->request_body_in_single_buf) {
227 rb->to_write = rb->bufs;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000228
229 } else {
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000230 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000231 }
232
Igor Sysoev899b44e2005-05-12 14:58:06 +0000233 r->read_event_handler = ngx_http_read_client_request_body_handler;
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000234
Igor Sysoevcd5b99a2007-01-25 08:45:04 +0000235 return ngx_http_do_read_client_request_body(r);
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000236}
237
238
Igor Sysoevc1571722005-03-19 12:38:37 +0000239static void
Igor Sysoev899b44e2005-05-12 14:58:06 +0000240ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000241{
Igor Sysoev899b44e2005-05-12 14:58:06 +0000242 ngx_int_t rc;
Igor Sysoevae02c192004-03-19 05:25:53 +0000243
Igor Sysoev899b44e2005-05-12 14:58:06 +0000244 if (r->connection->read->timedout) {
Igor Sysoev0e5dc5c2005-11-15 13:30:52 +0000245 r->connection->timedout = 1;
Igor Sysoevcd5b99a2007-01-25 08:45:04 +0000246 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
Igor Sysoev6707ba92004-03-30 15:59:50 +0000247 return;
248 }
249
Igor Sysoev899b44e2005-05-12 14:58:06 +0000250 rc = ngx_http_do_read_client_request_body(r);
Igor Sysoevae02c192004-03-19 05:25:53 +0000251
252 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
Igor Sysoevcd5b99a2007-01-25 08:45:04 +0000253 ngx_http_finalize_request(r, rc);
Igor Sysoevae02c192004-03-19 05:25:53 +0000254 }
255}
256
257
Igor Sysoevc1571722005-03-19 12:38:37 +0000258static ngx_int_t
Igor Sysoev899b44e2005-05-12 14:58:06 +0000259ngx_http_do_read_client_request_body(ngx_http_request_t *r)
Igor Sysoevae02c192004-03-19 05:25:53 +0000260{
Igor Sysoev10a543a2004-03-16 07:10:12 +0000261 size_t size;
262 ssize_t n;
Igor Sysoev369145c2004-05-28 15:49:23 +0000263 ngx_buf_t *b;
Igor Sysoev899b44e2005-05-12 14:58:06 +0000264 ngx_connection_t *c;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000265 ngx_http_request_body_t *rb;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000266 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev1d8d9ee2003-04-28 15:06:39 +0000267
Igor Sysoev899b44e2005-05-12 14:58:06 +0000268 c = r->connection;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000269 rb = r->request_body;
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000270
Igor Sysoevda85f7f2004-03-16 21:26:01 +0000271 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
272 "http read client request body");
273
274 for ( ;; ) {
Igor Sysoev12c94ae2006-11-13 20:40:17 +0000275 for ( ;; ) {
276 if (rb->buf->last == rb->buf->end) {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000277
Igor Sysoev12c94ae2006-11-13 20:40:17 +0000278 if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
279 return NGX_HTTP_INTERNAL_SERVER_ERROR;
280 }
281
282 rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
283 rb->buf->last = rb->buf->start;
Igor Sysoevda85f7f2004-03-16 21:26:01 +0000284 }
285
Igor Sysoev12c94ae2006-11-13 20:40:17 +0000286 size = rb->buf->end - rb->buf->last;
287
288 if ((off_t) size > rb->rest) {
289 size = (size_t) rb->rest;
290 }
291
292 n = c->recv(c, rb->buf->last, size);
293
294 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
295 "http client request body recv %z", n);
296
297 if (n == NGX_AGAIN) {
298 break;
299 }
300
301 if (n == 0) {
302 ngx_log_error(NGX_LOG_INFO, c->log, 0,
303 "client closed prematurely connection");
304 }
305
306 if (n == 0 || n == NGX_ERROR) {
307 c->error = 1;
308 return NGX_HTTP_BAD_REQUEST;
309 }
310
311 rb->buf->last += n;
312 rb->rest -= n;
313 r->request_length += n;
314
315 if (rb->rest == 0) {
316 break;
317 }
318
319 if (rb->buf->last < rb->buf->end) {
320 break;
321 }
Igor Sysoevda85f7f2004-03-16 21:26:01 +0000322 }
323
Igor Sysoevae02c192004-03-19 05:25:53 +0000324 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
Igor Sysoevcf815022007-02-15 14:13:24 +0000325 "http client request body rest %O", rb->rest);
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000326
Igor Sysoev02025fd2005-01-18 13:03:58 +0000327 if (rb->rest == 0) {
Igor Sysoev89690bf2004-03-23 06:01:52 +0000328 break;
329 }
330
Igor Sysoev12c94ae2006-11-13 20:40:17 +0000331 if (!c->read->ready) {
332 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
333 ngx_add_timer(c->read, clcf->client_body_timeout);
334
Igor Sysoevc9aae142008-12-09 17:27:48 +0000335 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
Igor Sysoev12c94ae2006-11-13 20:40:17 +0000336 return NGX_HTTP_INTERNAL_SERVER_ERROR;
337 }
338
339 return NGX_AGAIN;
Igor Sysoevda85f7f2004-03-16 21:26:01 +0000340 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000341 }
342
Igor Sysoev09c684b2005-11-09 17:25:55 +0000343 if (c->read->timer_set) {
344 ngx_del_timer(c->read);
345 }
346
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000347 if (rb->temp_file || r->request_body_in_file_only) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000348
349 /* save the last part */
Igor Sysoev02025fd2005-01-18 13:03:58 +0000350
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000351 if (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
Igor Sysoevae02c192004-03-19 05:25:53 +0000352 return NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoev2b0c76c2003-10-27 21:01:00 +0000353 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000354
Igor Sysoevc1571722005-03-19 12:38:37 +0000355 b = ngx_calloc_buf(r->pool);
356 if (b == NULL) {
Igor Sysoevae02c192004-03-19 05:25:53 +0000357 return NGX_HTTP_INTERNAL_SERVER_ERROR;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000358 }
359
Igor Sysoev369145c2004-05-28 15:49:23 +0000360 b->in_file = 1;
361 b->file_pos = 0;
Igor Sysoev02025fd2005-01-18 13:03:58 +0000362 b->file_last = rb->temp_file->file.offset;
363 b->file = &rb->temp_file->file;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000364
Igor Sysoev02025fd2005-01-18 13:03:58 +0000365 if (rb->bufs->next) {
366 rb->bufs->next->buf = b;
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000367
368 } else {
Igor Sysoev02025fd2005-01-18 13:03:58 +0000369 rb->bufs->buf = b;
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000370 }
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000371 }
372
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000373 if (r->request_body_in_file_only && rb->bufs->next) {
374 rb->bufs = rb->bufs->next;
375 }
376
Igor Sysoev02025fd2005-01-18 13:03:58 +0000377 rb->post_handler(r);
Igor Sysoevae02c192004-03-19 05:25:53 +0000378
379 return NGX_OK;
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000380}
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000381
382
383static ngx_int_t
384ngx_http_write_request_body(ngx_http_request_t *r, ngx_chain_t *body)
385{
386 ssize_t n;
387 ngx_temp_file_t *tf;
388 ngx_http_request_body_t *rb;
389 ngx_http_core_loc_conf_t *clcf;
390
391 rb = r->request_body;
392
393 if (rb->temp_file == NULL) {
394 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
395 if (tf == NULL) {
396 return NGX_ERROR;
397 }
398
399 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
400
401 tf->file.fd = NGX_INVALID_FILE;
402 tf->file.log = r->connection->log;
403 tf->path = clcf->client_body_temp_path;
404 tf->pool = r->pool;
405 tf->warn = "a client request body is buffered to a temporary file";
Igor Sysoev7bdb7202006-04-19 15:30:56 +0000406 tf->log_level = r->request_body_file_log_level;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000407 tf->persistent = r->request_body_in_persistent_file;
Igor Sysoevcd5b99a2007-01-25 08:45:04 +0000408 tf->clean = r->request_body_in_clean_file;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000409
410 if (r->request_body_file_group_access) {
Igor Sysoevfe1cb8c2007-01-18 19:52:18 +0000411 tf->access = 0660;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000412 }
413
414 rb->temp_file = tf;
415 }
416
417 n = ngx_write_chain_to_temp_file(rb->temp_file, body);
418
419 /* TODO: n == 0 or not complete and level event */
420
421 if (n == NGX_ERROR) {
422 return NGX_ERROR;
423 }
424
425 rb->temp_file->offset += n;
426
427 return NGX_OK;
428}
429
430
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000431ngx_int_t
Igor Sysoev832571f2007-08-06 15:37:22 +0000432ngx_http_discard_request_body(ngx_http_request_t *r)
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000433{
434 ssize_t size;
435 ngx_event_t *rev;
436
Igor Sysoev08e63d42006-08-14 15:09:38 +0000437 if (r != r->main || r->discard_body) {
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000438 return NGX_OK;
439 }
440
Igor Sysoev303df472008-12-26 13:43:42 +0000441 if (ngx_http_test_expect(r) != NGX_OK) {
442 return NGX_HTTP_INTERNAL_SERVER_ERROR;
443 }
444
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000445 rev = r->connection->read;
446
447 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");
448
449 if (rev->timer_set) {
450 ngx_del_timer(rev);
451 }
452
Igor Sysoevcc4078f2007-10-18 11:29:15 +0000453 if (r->headers_in.content_length_n <= 0 || r->request_body) {
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000454 return NGX_OK;
455 }
456
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000457 size = r->header_in->last - r->header_in->pos;
458
459 if (size) {
460 if (r->headers_in.content_length_n > size) {
461 r->headers_in.content_length_n -= size;
462
463 } else {
Igor Sysoev1765f472006-07-07 16:33:19 +0000464 r->header_in->pos += (size_t) r->headers_in.content_length_n;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000465 r->headers_in.content_length_n = 0;
466 return NGX_OK;
467 }
468 }
469
Igor Sysoev22530642007-09-01 16:40:19 +0000470 r->discard_body = 1;
471
Igor Sysoev832571f2007-08-06 15:37:22 +0000472 r->read_event_handler = ngx_http_read_discarded_request_body_handler;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000473
Igor Sysoevc9aae142008-12-09 17:27:48 +0000474 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000475 return NGX_HTTP_INTERNAL_SERVER_ERROR;
476 }
477
Igor Sysoev4fbd8682007-08-07 10:53:27 +0000478 (void) ngx_http_read_discarded_request_body(r);
479
480 return NGX_OK;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000481}
482
483
484static void
Igor Sysoev832571f2007-08-06 15:37:22 +0000485ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r)
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000486{
Igor Sysoev4fbd8682007-08-07 10:53:27 +0000487 ngx_int_t rc;
488 ngx_msec_t timer;
489 ngx_event_t *rev;
490 ngx_connection_t *c;
491 ngx_http_core_loc_conf_t *clcf;
492
493 c = r->connection;
494 rev = c->read;
495
496 if (rev->timedout) {
497 c->timedout = 1;
498 c->error = 1;
499 ngx_http_finalize_request(r, 0);
500 return;
501 }
502
503 if (r->lingering_time) {
Igor Sysoev1d04b142007-11-15 14:26:36 +0000504 timer = (ngx_msec_t) (r->lingering_time - ngx_time());
Igor Sysoev4fbd8682007-08-07 10:53:27 +0000505
506 if (timer <= 0) {
507 r->discard_body = 0;
508 ngx_http_finalize_request(r, 0);
509 return;
510 }
511
512 } else {
513 timer = 0;
514 }
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000515
Igor Sysoev832571f2007-08-06 15:37:22 +0000516 rc = ngx_http_read_discarded_request_body(r);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000517
Igor Sysoev4fbd8682007-08-07 10:53:27 +0000518 if (rc == NGX_OK) {
519
520 r->discard_body = 0;
521
522 if (r->done) {
523 ngx_http_finalize_request(r, 0);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000524 }
Igor Sysoev4fbd8682007-08-07 10:53:27 +0000525
526 return;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000527 }
528
Igor Sysoev4fbd8682007-08-07 10:53:27 +0000529 /* rc == NGX_AGAIN */
530
Igor Sysoevc9aae142008-12-09 17:27:48 +0000531 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
Igor Sysoev1b982e12007-09-01 16:41:52 +0000532 c->error = 1;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000533 ngx_http_finalize_request(r, rc);
Igor Sysoev4fbd8682007-08-07 10:53:27 +0000534 return;
535 }
536
537 if (timer) {
538
539 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
540
541 timer *= 1000;
542
543 if (timer > clcf->lingering_timeout) {
544 timer = clcf->lingering_timeout;
545 }
546
547 ngx_add_timer(rev, timer);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000548 }
549}
550
551
552static ngx_int_t
Igor Sysoev832571f2007-08-06 15:37:22 +0000553ngx_http_read_discarded_request_body(ngx_http_request_t *r)
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000554{
Igor Sysoev1765f472006-07-07 16:33:19 +0000555 size_t size;
556 ssize_t n;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000557 u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
558
559 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
560 "http read discarded body");
561
Igor Sysoeve5d40202007-08-06 15:18:24 +0000562 do {
563 if (r->headers_in.content_length_n == 0) {
Igor Sysoevce6bcc02007-08-06 15:31:00 +0000564 r->read_event_handler = ngx_http_block_reading;
Igor Sysoeve5d40202007-08-06 15:18:24 +0000565 return NGX_OK;
566 }
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000567
Igor Sysoeve5d40202007-08-06 15:18:24 +0000568 size = (r->headers_in.content_length_n > NGX_HTTP_DISCARD_BUFFER_SIZE) ?
569 NGX_HTTP_DISCARD_BUFFER_SIZE:
570 (size_t) r->headers_in.content_length_n;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000571
Igor Sysoeve5d40202007-08-06 15:18:24 +0000572 n = r->connection->recv(r->connection, buffer, size);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000573
Igor Sysoeve5d40202007-08-06 15:18:24 +0000574 if (n == NGX_ERROR) {
Igor Sysoeve5d40202007-08-06 15:18:24 +0000575 r->connection->error = 1;
Igor Sysoeve5d40202007-08-06 15:18:24 +0000576 return NGX_OK;
577 }
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000578
Igor Sysoeve5d40202007-08-06 15:18:24 +0000579 if (n == NGX_AGAIN) {
580 return NGX_AGAIN;
581 }
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000582
Igor Sysoevfe8137a2007-08-27 15:38:46 +0000583 if (n == 0) {
584 return NGX_OK;
585 }
586
Igor Sysoeve5d40202007-08-06 15:18:24 +0000587 r->headers_in.content_length_n -= n;
588
589 } while (r->connection->read->ready);
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000590
Igor Sysoev4fbd8682007-08-07 10:53:27 +0000591 return NGX_AGAIN;
Igor Sysoev8a2b2fb2006-04-14 09:53:38 +0000592}
Igor Sysoev303df472008-12-26 13:43:42 +0000593
594
595static ngx_int_t
596ngx_http_test_expect(ngx_http_request_t *r)
597{
598 ngx_int_t n;
599 ngx_str_t *expect;
600
601 if (r->expect_tested
602 || r->headers_in.expect == NULL
603 || r->http_version < NGX_HTTP_VERSION_11)
604 {
605 return NGX_OK;
606 }
607
608 r->expect_tested = 1;
609
610 expect = &r->headers_in.expect->value;
611
612 if (expect->len != sizeof("100-continue") - 1
613 || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
614 sizeof("100-continue") - 1)
615 != 0)
616 {
617 return NGX_OK;
618 }
619
620 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
621 "send 100 Continue");
622
623 n = r->connection->send(r->connection,
624 (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
625 sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
626
627 if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
628 return NGX_OK;
629 }
630
631 /* we assume that such small packet should be send successfully */
632
633 return NGX_ERROR;
634}