blob: 28308dc00514de8254470a812e42bab1032d9c1d [file] [log] [blame]
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00001
2#include <ngx_config.h>
Igor Sysoev0ad17c02002-08-26 15:18:19 +00003#include <ngx_core.h>
Igor Sysoevfcce8d52003-01-23 18:47:54 +00004#include <ngx_event.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00005#include <ngx_http.h>
6
Igor Sysoeva58e3ca2002-09-02 14:48:24 +00007
Igor Sysoev6b863e32003-05-12 15:52:24 +00008static void ngx_http_init_request(ngx_event_t *ev);
9static void ngx_http_process_request_line(ngx_event_t *rev);
10static void ngx_http_process_request_headers(ngx_event_t *rev);
Igor Sysoev6b863e32003-05-12 15:52:24 +000011static ssize_t ngx_http_read_request_header(ngx_http_request_t *r);
Igor Sysoev419f9ac2003-10-21 16:49:56 +000012static int ngx_http_process_request_header(ngx_http_request_t *r);
Igor Sysoev6b863e32003-05-12 15:52:24 +000013
Igor Sysoevb3e73d82003-10-10 15:10:50 +000014static void ngx_http_set_write_handler(ngx_http_request_t *r);
Igor Sysoev6b863e32003-05-12 15:52:24 +000015
Igor Sysoev6ddfbf02003-05-15 15:42:53 +000016static void ngx_http_block_read(ngx_event_t *ev);
17static void ngx_http_read_discarded_body_event(ngx_event_t *rev);
18static int ngx_http_read_discarded_body(ngx_http_request_t *r);
Igor Sysoev3a40d482002-09-12 14:42:29 +000019
Igor Sysoevd581fd52003-05-13 16:02:32 +000020static void ngx_http_set_keepalive(ngx_http_request_t *r);
21static void ngx_http_keepalive_handler(ngx_event_t *ev);
22static void ngx_http_set_lingering_close(ngx_http_request_t *r);
23static void ngx_http_lingering_close_handler(ngx_event_t *ev);
24
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000025static void ngx_http_client_error(ngx_http_request_t *r,
26 int client_error, int error);
Igor Sysoev0ad17c02002-08-26 15:18:19 +000027static size_t ngx_http_log_error(void *data, char *buf, size_t len);
28
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000029
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000030/* NGX_HTTP_PARSE_... errors */
Igor Sysoev0ad17c02002-08-26 15:18:19 +000031
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000032static char *client_header_errors[] = {
Igor Sysoev016b8522002-08-29 16:59:54 +000033 "client %s sent invalid method",
34 "client %s sent invalid request",
Igor Sysoev1af7c822002-09-13 14:47:42 +000035 "client %s sent too long URI",
Igor Sysoev6ddfbf02003-05-15 15:42:53 +000036 "client %s sent invalid method in HTTP/0.9 request",
Igor Sysoev6a644c62003-03-04 06:33:48 +000037
38 "client %s sent invalid header, URL: %s",
39 "client %s sent too long header line, URL: %s",
Igor Sysoeva09f08d2003-04-25 14:43:13 +000040 "client %s sent HTTP/1.1 request without \"Host\" header, URL: %s",
41 "client %s sent invalid \"Content-Length\" header, URL: %s"
Igor Sysoev016b8522002-08-29 16:59:54 +000042};
43
44
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000045static void ngx_http_dummy(ngx_event_t *wev)
46{
47 return;
48}
49
50
Igor Sysoev6b863e32003-05-12 15:52:24 +000051void ngx_http_init_connection(ngx_connection_t *c)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000052{
Igor Sysoev6253ca12003-05-27 12:18:54 +000053 ngx_event_t *rev;
Igor Sysoev160d7742003-11-19 16:26:41 +000054 ngx_http_log_ctx_t *ctx;
Igor Sysoev6b863e32003-05-12 15:52:24 +000055
Igor Sysoev239baac2003-06-11 15:28:34 +000056 c->addr_text.data = ngx_palloc(c->pool, c->listening->addr_text_max_len);
Igor Sysoev6b863e32003-05-12 15:52:24 +000057 if (c->addr_text.data == NULL) {
58 ngx_http_close_connection(c);
59 return;
60 }
61
Igor Sysoev239baac2003-06-11 15:28:34 +000062 c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr,
63 c->addr_text.data,
64 c->listening->addr_text_max_len);
Igor Sysoev6b863e32003-05-12 15:52:24 +000065 if (c->addr_text.len == 0) {
66 ngx_http_close_connection(c);
67 return;
68 }
69
Igor Sysoev160d7742003-11-19 16:26:41 +000070 if (!(ctx = ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +000071 ngx_http_close_connection(c);
72 return;
73 }
74
Igor Sysoev160d7742003-11-19 16:26:41 +000075 ctx->connection = c->number;
76 ctx->client = c->addr_text.data;
77 ctx->action = "reading client request line";
78 c->log->data = ctx;
Igor Sysoev6b863e32003-05-12 15:52:24 +000079 c->log->handler = ngx_http_log_error;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000080
Igor Sysoevdc479b42003-03-20 16:09:44 +000081 rev = c->read;
82 rev->event_handler = ngx_http_init_request;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +000083
Igor Sysoevdc479b42003-03-20 16:09:44 +000084 if (rev->ready) {
Igor Sysoevb5faed22003-10-29 08:30:44 +000085 /* deferred accept, aio, iocp, epoll */
Igor Sysoev6b863e32003-05-12 15:52:24 +000086 ngx_http_init_request(rev);
87 return;
Igor Sysoev016b8522002-08-29 16:59:54 +000088 }
Igor Sysoev73009772003-02-06 17:21:13 +000089
Igor Sysoev239baac2003-06-11 15:28:34 +000090 ngx_add_timer(rev, c->listening->post_accept_timeout);
Igor Sysoev9b25d692003-01-26 21:08:14 +000091
Igor Sysoevb5faed22003-10-29 08:30:44 +000092 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
Igor Sysoevb3e73d82003-10-10 15:10:50 +000093 ngx_http_close_connection(c);
94 return;
95 }
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000096
97#if 0
Igor Sysoevfe0f5cc2003-10-31 16:05:33 +000098 /* TODO: learn SO_SNDBUF (to use in zerocopy) via kqueue's EV_CLEAR event */
99
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000100 c->write->ready = 0;
101 c->write->event_handler = ngx_http_dummy;
102
103 if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) {
104 ngx_http_close_connection(c);
105 return;
106 }
107#endif
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000108}
109
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000110
Igor Sysoev6b863e32003-05-12 15:52:24 +0000111static void ngx_http_init_request(ngx_event_t *rev)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000112{
Igor Sysoev6253ca12003-05-27 12:18:54 +0000113 int i;
114 socklen_t len;
115 struct sockaddr_in addr_in;
Igor Sysoev187fcd82003-05-23 11:53:01 +0000116 ngx_connection_t *c;
117 ngx_http_request_t *r;
Igor Sysoev6253ca12003-05-27 12:18:54 +0000118 ngx_http_in_port_t *in_port;
119 ngx_http_in_addr_t *in_addr;
120 ngx_http_server_name_t *server_name;
Igor Sysoev187fcd82003-05-23 11:53:01 +0000121 ngx_http_core_srv_conf_t *cscf;
Igor Sysoev890fc962003-07-20 21:15:59 +0000122 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000123
Igor Sysoeva9830112003-05-19 16:39:14 +0000124 c = rev->data;
Igor Sysoeva9830112003-05-19 16:39:14 +0000125
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000126 if (rev->timedout) {
127 ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
128 ngx_http_close_connection(c);
129 return;
130 }
131
Igor Sysoev0a280a32003-10-12 16:49:16 +0000132 if (c->data) {
133 r = c->data;
134 ngx_memzero(r, sizeof(ngx_http_request_t));
135
136 } else {
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000137 if (!(r = ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)))) {
Igor Sysoev0a280a32003-10-12 16:49:16 +0000138 ngx_http_close_connection(c);
139 return;
140 }
Igor Sysoev6253ca12003-05-27 12:18:54 +0000141 }
142
143 /* find the server configuration for the address:port */
144
145 /* AF_INET only */
146
147 in_port = c->servers;
148 in_addr = in_port->addrs.elts;
149
Igor Sysoev9d639522003-07-07 06:11:50 +0000150ngx_log_debug(rev->log, "IN: %08x" _ in_port);
151
Igor Sysoev6253ca12003-05-27 12:18:54 +0000152 r->port = in_port->port;
153 r->port_name = &in_port->port_name;
154
155 i = 0;
156
157 if (in_port->addrs.nelts > 1) {
158
Igor Sysoev239baac2003-06-11 15:28:34 +0000159 /*
Igor Sysoevbb6ec8c2003-11-20 07:05:50 +0000160 * There're the several addresses on this port and one of them
Igor Sysoev239baac2003-06-11 15:28:34 +0000161 * is "*:port" so getsockname() is needed to determine
162 * the server address.
163 * AcceptEx() already gave this address.
164 */
Igor Sysoev6253ca12003-05-27 12:18:54 +0000165
Igor Sysoev239baac2003-06-11 15:28:34 +0000166#if (WIN32)
167 if (c->local_sockaddr) {
168 r->in_addr =
169 ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr;
Igor Sysoev6253ca12003-05-27 12:18:54 +0000170
Igor Sysoev239baac2003-06-11 15:28:34 +0000171 } else {
172#endif
173 len = sizeof(struct sockaddr_in);
174 if (getsockname(c->fd, (struct sockaddr *) &addr_in, &len) == -1) {
175 ngx_log_error(NGX_LOG_CRIT, rev->log, ngx_socket_errno,
176 "getsockname() failed");
177 ngx_http_close_connection(c);
178 return;
179 }
180#if (WIN32)
Igor Sysoev6253ca12003-05-27 12:18:54 +0000181 }
Igor Sysoev239baac2003-06-11 15:28:34 +0000182#endif
Igor Sysoev6253ca12003-05-27 12:18:54 +0000183
184 r->in_addr = addr_in.sin_addr.s_addr;
185
186 /* the last in_port->addrs address is "*" */
187
188 for ( /* void */ ; i < in_port->addrs.nelts - 1; i++) {
189 if (in_addr[i].addr == r->in_addr) {
190 break;
191 }
192 }
193
194 } else {
195 r->in_addr = in_addr[0].addr;
196 }
197
198 r->virtual_names = &in_addr[i].names;
199
200 /* the default server configuration for the address:port */
201 cscf = in_addr[i].core_srv_conf;
202
203 r->main_conf = cscf->ctx->main_conf;
204 r->srv_conf = cscf->ctx->srv_conf;
205 r->loc_conf = cscf->ctx->loc_conf;
206
207 server_name = cscf->server_names.elts;
208 r->server_name = &server_name->name;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000209
Igor Sysoev890fc962003-07-20 21:15:59 +0000210 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
211 c->log->file = clcf->err_log->file;
212 c->log->log_level = clcf->err_log->log_level;
213
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000214 if (c->buffer == NULL) {
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000215 c->buffer =
216 ngx_create_temp_hunk(c->pool, cscf->client_header_buffer_size);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000217 if (c->buffer == NULL) {
218 ngx_http_close_connection(c);
219 return;
220 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000221 }
222
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000223 if (!(r->pool = ngx_create_pool(cscf->request_pool_size, c->log))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000224 ngx_http_close_connection(c);
225 return;
226 }
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000227
Igor Sysoevc2bba092003-11-28 17:41:47 +0000228 r->cleanup.elts = ngx_palloc(r->pool, 5 * sizeof(ngx_http_cleanup_t));
229 if (r->cleanup.elts == NULL) {
230 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
231 ngx_http_close_connection(c);
232 return;
233 }
234 /*
235 * set by ngx_pcalloc():
236 *
237 * r->cleanup.nelts = 0;
238 */
239 r->cleanup.nalloc = 5;
240 r->cleanup.size = sizeof(ngx_http_cleanup_t);
241 r->cleanup.pool = r->pool;
242
Igor Sysoev74e95c22003-11-09 20:03:38 +0000243 /* TODO: ngx_init_table */
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000244 if (!(r->headers_out.headers = ngx_create_table(r->pool, 20))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000245 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
246 ngx_http_close_connection(c);
247 return;
248 }
249
250 r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
251 if (r->ctx == NULL) {
252 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
253 ngx_http_close_connection(c);
254 return;
255 }
Igor Sysoeve0268b92002-09-11 15:18:33 +0000256
Igor Sysoev6b863e32003-05-12 15:52:24 +0000257 c->sent = 0;
258 c->data = r;
259 r->connection = c;
260 r->pipeline = c->pipeline;
261 r->header_in = c->buffer;
262
263 r->file.fd = NGX_INVALID_FILE;
264
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000265 r->headers_in.content_length_n = -1;
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000266 r->headers_in.keep_alive_n = -1;
267 r->headers_out.content_length_n = -1;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000268 r->headers_out.last_modified_time = -1;
269
Igor Sysoev6b863e32003-05-12 15:52:24 +0000270 rev->event_handler = ngx_http_process_request_line;
271 ngx_http_process_request_line(rev);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000272}
273
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000274
Igor Sysoev6b863e32003-05-12 15:52:24 +0000275static void ngx_http_process_request_line(ngx_event_t *rev)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000276{
Igor Sysoev187fcd82003-05-23 11:53:01 +0000277 int rc, offset;
278 ssize_t n;
279 ngx_connection_t *c;
280 ngx_http_request_t *r;
Igor Sysoev160d7742003-11-19 16:26:41 +0000281 ngx_http_log_ctx_t *ctx;
Igor Sysoev187fcd82003-05-23 11:53:01 +0000282 ngx_http_core_srv_conf_t *cscf;
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000283
Igor Sysoeva9830112003-05-19 16:39:14 +0000284 c = rev->data;
285 r = c->data;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000286
Igor Sysoev6b863e32003-05-12 15:52:24 +0000287 ngx_log_debug(rev->log, "http process request line");
Igor Sysoevdc479b42003-03-20 16:09:44 +0000288
289 if (rev->timedout) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000290 ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000291 return;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000292 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000293
Igor Sysoev6b863e32003-05-12 15:52:24 +0000294 n = ngx_http_read_request_header(r);
Igor Sysoev016b8522002-08-29 16:59:54 +0000295
Igor Sysoev6b863e32003-05-12 15:52:24 +0000296 if (n == NGX_AGAIN || n == NGX_ERROR) {
297 return;
Igor Sysoev830c4ce2003-01-24 16:09:40 +0000298 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000299
Igor Sysoeve6779222003-10-03 15:50:53 +0000300 rc = ngx_http_parse_request_line(r);
Igor Sysoevdc479b42003-03-20 16:09:44 +0000301
Igor Sysoev016b8522002-08-29 16:59:54 +0000302 if (rc == NGX_OK) {
Igor Sysoevdc479b42003-03-20 16:09:44 +0000303
Igor Sysoev6b863e32003-05-12 15:52:24 +0000304 /* the request line has been parsed successfully */
305
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000306 /* TODO: we need to handle such URIs */
Igor Sysoevc2bba092003-11-28 17:41:47 +0000307 if (r->unusual_uri) {
Igor Sysoev1c104622003-06-03 15:42:58 +0000308 r->request_line.len = r->request_end - r->request_start;
309 r->request_line.data = r->request_start;
310 r->request_line.data[r->request_line.len] = '\0';
311
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000312 ngx_http_client_error(r, NGX_HTTP_PARSE_INVALID_REQUEST,
313 NGX_HTTP_BAD_REQUEST);
Igor Sysoev7578ec92003-06-02 15:24:30 +0000314 return;
315 }
316
Igor Sysoev6253ca12003-05-27 12:18:54 +0000317 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
Igor Sysoeva9830112003-05-19 16:39:14 +0000318
Igor Sysoeve2a31542003-04-08 15:40:10 +0000319 if (r->http_version >= NGX_HTTP_VERSION_10
Igor Sysoev187fcd82003-05-23 11:53:01 +0000320 && cscf->large_client_header == 0
Igor Sysoeve2a31542003-04-08 15:40:10 +0000321 && r->header_in->pos == r->header_in->end)
322 {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000323 /* no space for "\r\n" at the end of the header */
324
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000325 ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
326 NGX_HTTP_REQUEST_URI_TOO_LARGE);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000327 return;
Igor Sysoeve2a31542003-04-08 15:40:10 +0000328 }
329
Igor Sysoev6414b962003-10-24 16:10:38 +0000330
Igor Sysoevc2bba092003-11-28 17:41:47 +0000331 /* copy unparsed URI */
332
333 r->unparsed_uri.len = r->uri_end - r->uri_start;
334 r->unparsed_uri.data = ngx_palloc(r->pool, r->unparsed_uri.len + 1);
335 if (r->unparsed_uri.data == NULL) {
336 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
337 ngx_http_close_connection(c);
338 return;
339 }
340
341 ngx_cpystrn(r->unparsed_uri.data, r->uri_start,
342 r->unparsed_uri.len + 1);
343
344
Igor Sysoev6a644c62003-03-04 06:33:48 +0000345 /* copy URI */
Igor Sysoevdc479b42003-03-20 16:09:44 +0000346
347 if (r->args_start) {
348 r->uri.len = r->args_start - 1 - r->uri_start;
349 } else {
350 r->uri.len = r->uri_end - r->uri_start;
351 }
352
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000353 if (!(r->uri.data = ngx_palloc(r->pool, r->uri.len + 1))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000354 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
355 ngx_http_close_connection(c);
356 return;
357 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000358
Igor Sysoevc2bba092003-11-28 17:41:47 +0000359 if (r->complex_uri) {
360 rc = ngx_http_parse_complex_uri(r);
Igor Sysoev016b8522002-08-29 16:59:54 +0000361
Igor Sysoevc2bba092003-11-28 17:41:47 +0000362 } else {
363 ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1);
Igor Sysoeva9830112003-05-19 16:39:14 +0000364 }
365
Igor Sysoeva9830112003-05-19 16:39:14 +0000366
Igor Sysoevdc479b42003-03-20 16:09:44 +0000367 r->request_line.len = r->request_end - r->request_start;
368
Igor Sysoev187fcd82003-05-23 11:53:01 +0000369 if (cscf->large_client_header) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000370
Igor Sysoevbb6ec8c2003-11-20 07:05:50 +0000371 /*
372 * if the large client headers are enabled then
373 * we need to copy a request line
374 */
375
Igor Sysoev6b863e32003-05-12 15:52:24 +0000376 r->request_line.data = ngx_palloc(r->pool, r->request_line.len + 1);
377 if (r->request_line.data == NULL) {
378 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
379 ngx_http_close_connection(c);
380 return;
381 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000382
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000383 ngx_cpystrn(r->request_line.data, r->request_start,
Igor Sysoev6a644c62003-03-04 06:33:48 +0000384 r->request_line.len + 1);
385
386 } else {
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000387 r->request_line.data = r->request_start;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000388 r->request_line.data[r->request_line.len] = '\0';
389 }
390
Igor Sysoevdc479b42003-03-20 16:09:44 +0000391
Igor Sysoevc2bba092003-11-28 17:41:47 +0000392 if (rc != NGX_OK) {
393 /*
394 * we check ngx_http_parse_complex_uri() result here to log
395 * the request line
396 */
397 ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
398 return;
399 }
400
401
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000402 if (r->uri_ext) {
Igor Sysoevbb6ec8c2003-11-20 07:05:50 +0000403
404 /* copy URI extention */
405
Igor Sysoevdc479b42003-03-20 16:09:44 +0000406 if (r->args_start) {
407 r->exten.len = r->args_start - 1 - r->uri_ext;
408 } else {
409 r->exten.len = r->uri_end - r->uri_ext;
410 }
411
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000412 if (!(r->exten.data = ngx_palloc(r->pool, r->exten.len + 1))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000413 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
414 ngx_http_close_connection(c);
415 return;
416 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000417
Igor Sysoevb0869052002-12-10 18:05:12 +0000418 ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1);
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000419 }
420
Igor Sysoevdc479b42003-03-20 16:09:44 +0000421 if (r->args_start && r->uri_end > r->args_start) {
Igor Sysoevbb6ec8c2003-11-20 07:05:50 +0000422
423 /* copy URI arguments */
424
Igor Sysoevdc479b42003-03-20 16:09:44 +0000425 r->args.len = r->uri_end - r->args_start;
426
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000427 if (!(r->args.data = ngx_palloc(r->pool, r->args.len + 1))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000428 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
429 ngx_http_close_connection(c);
430 return;
431 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000432
433 ngx_cpystrn(r->args.data, r->args_start, r->args.len + 1);
434 }
435
Igor Sysoev6b863e32003-05-12 15:52:24 +0000436#if 1 /* DEBUG */
437 if (r->exten.data == NULL) { r->exten.data = ""; }
438 if (r->args.data == NULL) { r->args.data = ""; }
439 ngx_log_debug(c->log, "HTTP: %d, %d, '%s', '%s', '%s'" _
Igor Sysoevb0869052002-12-10 18:05:12 +0000440 r->method _ r->http_version _
Igor Sysoevdc479b42003-03-20 16:09:44 +0000441 r->uri.data _ r->exten.data _ r->args.data);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000442 if (r->exten.data[0] == '\0') { r->exten.data = NULL; }
443 if (r->args.data[0] == '\0') { r->args.data = NULL; }
Igor Sysoev295bb632002-12-23 18:22:18 +0000444#endif
Igor Sysoev016b8522002-08-29 16:59:54 +0000445
Igor Sysoev7578ec92003-06-02 15:24:30 +0000446 if (r->http_version < NGX_HTTP_VERSION_10) {
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000447 rev->event_handler = ngx_http_block_read;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000448 ngx_http_handler(r);
449 return;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000450 }
Igor Sysoev1af7c822002-09-13 14:47:42 +0000451
Igor Sysoev160d7742003-11-19 16:26:41 +0000452 ctx = c->log->data;
453 ctx->action = "reading client request headers";
454 ctx->url = r->unparsed_uri.data;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000455 /* TODO: ngx_init_table */
Igor Sysoev14be46e2003-10-29 17:39:05 +0000456 r->headers_in.headers = ngx_create_table(r->pool, 20);
Igor Sysoevdc479b42003-03-20 16:09:44 +0000457
Igor Sysoev187fcd82003-05-23 11:53:01 +0000458 if (cscf->large_client_header
Igor Sysoevdc479b42003-03-20 16:09:44 +0000459 && r->header_in->pos == r->header_in->last)
460 {
461 r->header_in->pos = r->header_in->last = r->header_in->start;
462 }
Igor Sysoev016b8522002-08-29 16:59:54 +0000463
Igor Sysoevd581fd52003-05-13 16:02:32 +0000464 rev->event_handler = ngx_http_process_request_headers;
465 ngx_http_process_request_headers(rev);
466
467 return;
468
Igor Sysoev0dad6292003-03-05 17:30:51 +0000469 } else if (rc != NGX_AGAIN) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000470
471 /* there was error while a request line parsing */
472
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000473 ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000474
Igor Sysoev6b863e32003-05-12 15:52:24 +0000475 return;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000476 }
477
Igor Sysoev0dad6292003-03-05 17:30:51 +0000478 /* NGX_AGAIN: a request line parsing is still not complete */
479
Igor Sysoevb7387572003-03-11 20:38:13 +0000480 if (r->header_in->last == r->header_in->end) {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000481
Igor Sysoev0a280a32003-10-12 16:49:16 +0000482 /*
483 * If it's a pipelined request and a request line is not complete
Igor Sysoevbb6ec8c2003-11-20 07:05:50 +0000484 * then we have to copy it to the start of the r->header_in hunk.
485 * We have to copy it here only if the large client headers
Igor Sysoev0a280a32003-10-12 16:49:16 +0000486 * are enabled otherwise a request line had been already copied
487 * to the start of the r->header_in hunk in ngx_http_set_keepalive().
488 */
Igor Sysoev0dad6292003-03-05 17:30:51 +0000489
Igor Sysoev6253ca12003-05-27 12:18:54 +0000490 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
Igor Sysoeva9830112003-05-19 16:39:14 +0000491
Igor Sysoev187fcd82003-05-23 11:53:01 +0000492 if (cscf->large_client_header) {
Igor Sysoev0dad6292003-03-05 17:30:51 +0000493 offset = r->request_start - r->header_in->start;
494
495 if (offset == 0) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000496 ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
497 NGX_HTTP_REQUEST_URI_TOO_LARGE);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000498 return;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000499 }
500
501 ngx_memcpy(r->header_in->start, r->request_start,
Igor Sysoevb7387572003-03-11 20:38:13 +0000502 r->header_in->last - r->request_start);
Igor Sysoev0dad6292003-03-05 17:30:51 +0000503
Igor Sysoevb7387572003-03-11 20:38:13 +0000504 r->header_in->pos -= offset;
505 r->header_in->last -= offset;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000506 r->request_start = r->header_in->start;
507 r->request_end -= offset;
508 r->uri_start -= offset;
509 r->uri_end -= offset;
510 if (r->uri_ext) {
511 r->uri_ext -= offset;
512 }
513 if (r->args_start) {
514 r->args_start -= offset;
515 }
516
517 } else {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000518 ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
519 NGX_HTTP_REQUEST_URI_TOO_LARGE);
Igor Sysoev0dad6292003-03-05 17:30:51 +0000520 }
Igor Sysoev1af7c822002-09-13 14:47:42 +0000521 }
522
Igor Sysoev6b863e32003-05-12 15:52:24 +0000523 return;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000524}
525
Igor Sysoev1af7c822002-09-13 14:47:42 +0000526
Igor Sysoev6b863e32003-05-12 15:52:24 +0000527static void ngx_http_process_request_headers(ngx_event_t *rev)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000528{
Igor Sysoev187fcd82003-05-23 11:53:01 +0000529 int rc, i, offset;
Igor Sysoev187fcd82003-05-23 11:53:01 +0000530 ssize_t n;
531 ngx_table_elt_t *h;
532 ngx_connection_t *c;
533 ngx_http_request_t *r;
Igor Sysoev187fcd82003-05-23 11:53:01 +0000534 ngx_http_core_srv_conf_t *cscf;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000535
Igor Sysoeva9830112003-05-19 16:39:14 +0000536 c = rev->data;
537 r = c->data;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000538
539 ngx_log_debug(rev->log, "http process request header line");
540
Igor Sysoev6b863e32003-05-12 15:52:24 +0000541 if (rev->timedout) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000542 ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000543 return;
544 }
545
Igor Sysoev6253ca12003-05-27 12:18:54 +0000546 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
547
Igor Sysoevd581fd52003-05-13 16:02:32 +0000548 rc = NGX_AGAIN;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000549
Igor Sysoev016b8522002-08-29 16:59:54 +0000550 for ( ;; ) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000551 if (rc == NGX_AGAIN) {
552 n = ngx_http_read_request_header(r);
553
554 if (n == NGX_AGAIN || n == NGX_ERROR) {
555 return;
556 }
557 }
558
Igor Sysoeve6779222003-10-03 15:50:53 +0000559 rc = ngx_http_parse_header_line(r, r->header_in);
Igor Sysoev016b8522002-08-29 16:59:54 +0000560
Igor Sysoev0dad6292003-03-05 17:30:51 +0000561 if (rc == NGX_OK) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000562
563 /* a header line has been parsed successfully */
564
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000565 h = ngx_http_add_header(&r->headers_in, ngx_http_headers_in);
566 if (h == NULL) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000567 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
568 ngx_http_close_connection(c);
569 return;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000570 }
571
Igor Sysoevd581fd52003-05-13 16:02:32 +0000572 h->key.len = r->header_name_end - r->header_name_start;
573 h->value.len = r->header_end - r->header_start;
574
575 /* if the large client headers are enabled then
576 we need to copy the header name and value */
577
Igor Sysoev187fcd82003-05-23 11:53:01 +0000578 if (cscf->large_client_header) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000579 h->key.data = ngx_palloc(r->pool,
580 h->key.len + 1 + h->value.len + 1);
581 if (h->key.data == NULL) {
582 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
583 ngx_http_close_connection(c);
584 return;
585 }
586
587 h->value.data = h->key.data + h->key.len + 1;
588 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
589 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
590
591 } else {
592 h->key.data = r->header_name_start;
593 h->key.data[h->key.len] = '\0';
594 h->value.data = r->header_start;
595 h->value.data[h->value.len] = '\0';
596 }
597
Igor Sysoevb5faed22003-10-29 08:30:44 +0000598 for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) {
599 if (ngx_http_headers_in[i].name.len != h->key.len) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000600 continue;
601 }
602
Igor Sysoevb5faed22003-10-29 08:30:44 +0000603 if (ngx_strcasecmp(ngx_http_headers_in[i].name.data,
604 h->key.data) == 0)
605 {
606 *((ngx_table_elt_t **) ((char *) &r->headers_in
607 + ngx_http_headers_in[i].offset)) = h;
Igor Sysoev9760a132003-10-21 07:47:21 +0000608 break;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000609 }
610 }
611
612 ngx_log_debug(r->connection->log, "HTTP header: '%s: %s'" _
613 h->key.data _ h->value.data);
614
Igor Sysoev187fcd82003-05-23 11:53:01 +0000615 if (cscf->large_client_header
Igor Sysoevdc479b42003-03-20 16:09:44 +0000616 && r->header_in->pos == r->header_in->last)
617 {
618 r->header_in->pos = r->header_in->last = r->header_in->start;
Igor Sysoeva19a85e2003-01-28 15:56:37 +0000619 }
620
Igor Sysoev6253ca12003-05-27 12:18:54 +0000621 continue;
622
Igor Sysoev1af7c822002-09-13 14:47:42 +0000623 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000624
625 /* a whole header has been parsed successfully */
626
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000627 ngx_log_debug(r->connection->log, "HTTP header done");
Igor Sysoev42feecb2002-12-15 06:25:09 +0000628
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000629 rc = ngx_http_process_request_header(r);
Igor Sysoeva19a85e2003-01-28 15:56:37 +0000630
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000631 if (rc != NGX_OK) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000632 ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000633 return;
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000634 }
635
Igor Sysoev425a42c2003-10-27 16:16:17 +0000636 if (rev->timer_set) {
Igor Sysoev0a280a32003-10-12 16:49:16 +0000637 ngx_del_timer(rev);
638 }
639
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000640 rev->event_handler = ngx_http_block_read;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000641 ngx_http_handler(r);
642 return;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000643
Igor Sysoev0dad6292003-03-05 17:30:51 +0000644 } else if (rc != NGX_AGAIN) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000645
646 /* there was error while a header line parsing */
647
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000648 ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000649 return;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000650 }
651
652 /* NGX_AGAIN: a header line parsing is still not complete */
653
Igor Sysoevb7387572003-03-11 20:38:13 +0000654 if (r->header_in->last == r->header_in->end) {
Igor Sysoev0dad6292003-03-05 17:30:51 +0000655
Igor Sysoevb7387572003-03-11 20:38:13 +0000656 /* if the large client headers are enabled then
Igor Sysoev0dad6292003-03-05 17:30:51 +0000657 we need to compact r->header_in hunk */
658
Igor Sysoev187fcd82003-05-23 11:53:01 +0000659 if (cscf->large_client_header) {
Igor Sysoev0dad6292003-03-05 17:30:51 +0000660 offset = r->header_name_start - r->header_in->start;
661
662 if (offset == 0) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000663 ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_HEADER,
664 NGX_HTTP_BAD_REQUEST);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000665 return;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000666 }
667
668 ngx_memcpy(r->header_in->start, r->header_name_start,
Igor Sysoevb7387572003-03-11 20:38:13 +0000669 r->header_in->last - r->header_name_start);
Igor Sysoev0dad6292003-03-05 17:30:51 +0000670
Igor Sysoevb7387572003-03-11 20:38:13 +0000671 r->header_in->last -= offset;
672 r->header_in->pos -= offset;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000673 r->header_name_start = r->header_in->start;
674 r->header_name_end -= offset;
675 r->header_start -= offset;
676 r->header_end -= offset;
677
678 } else {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000679 ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_HEADER,
680 NGX_HTTP_BAD_REQUEST);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000681 return;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000682 }
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000683 }
684 }
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000685}
686
Igor Sysoevb0869052002-12-10 18:05:12 +0000687
Igor Sysoev6b863e32003-05-12 15:52:24 +0000688static ssize_t ngx_http_read_request_header(ngx_http_request_t *r)
689{
Igor Sysoev187fcd82003-05-23 11:53:01 +0000690 ssize_t n;
691 ngx_event_t *rev;
692 ngx_http_core_srv_conf_t *cscf;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000693
Igor Sysoev239baac2003-06-11 15:28:34 +0000694 rev = r->connection->read;
695
Igor Sysoev6b863e32003-05-12 15:52:24 +0000696 n = r->header_in->last - r->header_in->pos;
697
698 if (n > 0) {
699 return n;
700 }
701
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000702 if (!rev->ready) {
703 return NGX_AGAIN;
704 }
705
Igor Sysoev239baac2003-06-11 15:28:34 +0000706 n = ngx_recv(r->connection, r->header_in->last,
707 r->header_in->end - r->header_in->last);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000708
709 if (n == NGX_AGAIN) {
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000710 if (!r->header_timeout_set) {
Igor Sysoev6253ca12003-05-27 12:18:54 +0000711 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
Igor Sysoev187fcd82003-05-23 11:53:01 +0000712 ngx_add_timer(rev, cscf->client_header_timeout);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000713 r->header_timeout_set = 1;
714 }
715
Igor Sysoevb5faed22003-10-29 08:30:44 +0000716 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000717 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
718 ngx_http_close_connection(r->connection);
719 return NGX_ERROR;
720 }
721
Igor Sysoev6b863e32003-05-12 15:52:24 +0000722 return NGX_AGAIN;
723 }
724
725 if (n == 0) {
726 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
727 "client closed prematurely connection");
Igor Sysoevd581fd52003-05-13 16:02:32 +0000728 }
Igor Sysoev6b863e32003-05-12 15:52:24 +0000729
730 if (n == 0 || n == NGX_ERROR) {
731 ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000732 ngx_http_close_connection(r->connection);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000733 return NGX_ERROR;
734 }
735
736 r->header_in->last += n;
737
738 return n;
739}
740
741
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000742static int ngx_http_process_request_header(ngx_http_request_t *r)
743{
744 int i;
745 size_t len;
746 ngx_http_server_name_t *name;
747 ngx_http_core_loc_conf_t *clcf;
748
749 if (r->headers_in.host) {
750 for (len = 0; len < r->headers_in.host->value.len; len++) {
751 if (r->headers_in.host->value.data[len] == ':') {
752 break;
753 }
754 }
755 r->headers_in.host_name_len = len;
756
757 /* find the name based server configuration */
758
759 name = r->virtual_names->elts;
760 for (i = 0; i < r->virtual_names->nelts; i++) {
761 if (r->headers_in.host_name_len != name[i].name.len) {
762 continue;
763 }
764
765 if (ngx_strncasecmp(r->headers_in.host->value.data,
766 name[i].name.data,
767 r->headers_in.host_name_len) == 0)
768 {
769 r->srv_conf = name[i].core_srv_conf->ctx->srv_conf;
770 r->loc_conf = name[i].core_srv_conf->ctx->loc_conf;
771
772 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
773 r->connection->log->file = clcf->err_log->file;
774 r->connection->log->log_level = clcf->err_log->log_level;
775
776 break;
777 }
778 }
779
780 } else {
781 if (r->http_version > NGX_HTTP_VERSION_10) {
782 return NGX_HTTP_PARSE_NO_HOST_HEADER;
783 }
784 r->headers_in.host_name_len = 0;
785 }
786
787 if (r->headers_in.content_length) {
788 r->headers_in.content_length_n =
789 ngx_atoi(r->headers_in.content_length->value.data,
790 r->headers_in.content_length->value.len);
791
792 if (r->headers_in.content_length_n == NGX_ERROR) {
793 return NGX_HTTP_PARSE_INVALID_CL_HEADER;
794 }
795 }
796
797 if (r->headers_in.connection) {
798 if (r->headers_in.connection->value.len == 5
799 && ngx_strcasecmp(r->headers_in.connection->value.data, "close")
800 == 0)
801 {
802 r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
803
804 } else if (r->headers_in.connection->value.len == 10
805 && ngx_strcasecmp(r->headers_in.connection->value.data,
806 "keep-alive") == 0)
807 {
808 r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE;
809
810 if (r->headers_in.keep_alive) {
811 r->headers_in.keep_alive_n =
812 ngx_atoi(r->headers_in.keep_alive->value.data,
813 r->headers_in.keep_alive->value.len);
814 }
815 }
816 }
817
818 return NGX_OK;
819}
820
821
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000822void ngx_http_finalize_request(ngx_http_request_t *r, int rc)
Igor Sysoevd581fd52003-05-13 16:02:32 +0000823{
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000824 /* r can be already destroyed when rc == NGX_DONE */
Igor Sysoevd581fd52003-05-13 16:02:32 +0000825
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000826 if (rc == NGX_DONE || r->main) {
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000827 return;
828 }
829
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000830 ngx_log_debug(r->connection->log, "finalize http request");
831
Igor Sysoevd581fd52003-05-13 16:02:32 +0000832 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
833
Igor Sysoev0a280a32003-10-12 16:49:16 +0000834 if (r->connection->read->timer_set) {
835 ngx_del_timer(r->connection->read);
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000836 }
837
Igor Sysoev0a280a32003-10-12 16:49:16 +0000838 if (r->connection->write->timer_set) {
839 ngx_del_timer(r->connection->write);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000840 }
841
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000842 ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc));
Igor Sysoev239baac2003-06-11 15:28:34 +0000843
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000844 return;
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000845
Igor Sysoev239baac2003-06-11 15:28:34 +0000846 } else if (rc == NGX_ERROR) {
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000847 ngx_http_close_request(r, 0);
848 ngx_http_close_connection(r->connection);
849 return;
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000850
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000851 } else if (rc == NGX_AGAIN) {
852 ngx_http_set_write_handler(r);
853 return;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000854 }
855
Igor Sysoev0a280a32003-10-12 16:49:16 +0000856 if (r->connection->read->timer_set) {
857 ngx_del_timer(r->connection->read);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000858 }
859
Igor Sysoev0a280a32003-10-12 16:49:16 +0000860 if (r->connection->write->timer_set) {
861 ngx_del_timer(r->connection->write);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000862 }
863
864 if (r->keepalive != 0) {
865 ngx_http_set_keepalive(r);
866
867 } else if (r->lingering_close) {
868 ngx_http_set_lingering_close(r);
869
870 } else {
871 ngx_http_close_request(r, 0);
872 ngx_http_close_connection(r->connection);
873 }
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000874
875 return;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000876}
877
878
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000879static void ngx_http_set_write_handler(ngx_http_request_t *r)
Igor Sysoevd581fd52003-05-13 16:02:32 +0000880{
Igor Sysoevd581fd52003-05-13 16:02:32 +0000881 ngx_event_t *wev;
Igor Sysoeva9830112003-05-19 16:39:14 +0000882 ngx_http_core_loc_conf_t *clcf;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000883
884 wev = r->connection->write;
885 wev->event_handler = ngx_http_writer;
886
887 if (wev->delayed && wev->ready) {
888 return;
889 }
890
Igor Sysoev6253ca12003-05-27 12:18:54 +0000891 clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
892 ngx_http_core_module);
Igor Sysoeva9830112003-05-19 16:39:14 +0000893 ngx_add_timer(wev, clcf->send_timeout);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000894
Igor Sysoev222a2ad2003-11-18 16:49:00 +0000895 wev->available = clcf->send_lowat;
896 if (ngx_handle_write_event(wev, NGX_LOWAT_EVENT) == NGX_ERROR) {
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000897 ngx_http_close_request(r, 0);
898 ngx_http_close_connection(r->connection);
899 }
900
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000901 return;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000902}
903
904
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000905void ngx_http_writer(ngx_event_t *wev)
Igor Sysoevd581fd52003-05-13 16:02:32 +0000906{
907 int rc;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000908 ngx_connection_t *c;
909 ngx_http_request_t *r;
Igor Sysoev6253ca12003-05-27 12:18:54 +0000910 ngx_http_core_loc_conf_t *clcf;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000911
Igor Sysoev160d7742003-11-19 16:26:41 +0000912 ngx_log_debug(wev->log, "http writer handler");
913
Igor Sysoev6253ca12003-05-27 12:18:54 +0000914 c = wev->data;
915 r = c->data;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000916
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000917#if 0 /* TODO: THINK */
918 if (wev->delayed) {
919 return;
920 }
921#endif
922
923 if (wev->timedout) {
924 ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
925 return;
926 }
927
Igor Sysoevd581fd52003-05-13 16:02:32 +0000928 rc = ngx_http_output_filter(r, NULL);
929
930 ngx_log_debug(c->log, "writer output filter: %d" _ rc);
931
932 if (rc == NGX_AGAIN) {
Igor Sysoev0a280a32003-10-12 16:49:16 +0000933 if (!wev->ready) {
934 clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
935 ngx_http_core_module);
936 ngx_add_timer(wev, clcf->send_timeout);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000937 }
938
Igor Sysoev0a280a32003-10-12 16:49:16 +0000939 if (ngx_handle_level_write_event(wev) == NGX_ERROR) {
940 ngx_http_close_request(r, 0);
941 ngx_http_close_connection(r->connection);
942 }
Igor Sysoevd581fd52003-05-13 16:02:32 +0000943
944 return;
945 }
946
Igor Sysoevd581fd52003-05-13 16:02:32 +0000947 ngx_log_debug(c->log, "http writer done");
948
Igor Sysoev0a280a32003-10-12 16:49:16 +0000949 ngx_http_finalize_request(r, rc);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000950}
951
952
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000953static void ngx_http_block_read(ngx_event_t *rev)
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000954{
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000955 ngx_connection_t *c;
956 ngx_http_request_t *r;
957
958 ngx_log_debug(rev->log, "http read blocked");
Igor Sysoev42feecb2002-12-15 06:25:09 +0000959
Igor Sysoev73009772003-02-06 17:21:13 +0000960 /* aio does not call this handler */
961
Igor Sysoev0a280a32003-10-12 16:49:16 +0000962 if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) {
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000963 if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
Igor Sysoev0a280a32003-10-12 16:49:16 +0000964 c = rev->data;
965 r = c->data;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000966 ngx_http_close_request(r, 0);
967 ngx_http_close_connection(c);
968 }
Igor Sysoev73009772003-02-06 17:21:13 +0000969 }
970
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000971 return;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000972}
973
974
Igor Sysoevd581fd52003-05-13 16:02:32 +0000975int ngx_http_discard_body(ngx_http_request_t *r)
976{
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000977 ssize_t size;
978 ngx_event_t *rev;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000979
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000980 rev = r->connection->read;
Igor Sysoev9b25d692003-01-26 21:08:14 +0000981
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000982 ngx_log_debug(rev->log, "set discard body");
Igor Sysoev9b25d692003-01-26 21:08:14 +0000983
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000984 if (rev->timer_set) {
985 ngx_del_timer(rev);
Igor Sysoev9b25d692003-01-26 21:08:14 +0000986 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000987
Igor Sysoev0a280a32003-10-12 16:49:16 +0000988 if (r->headers_in.content_length_n <= 0) {
989 return NGX_OK;
990 }
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000991
Igor Sysoev0a280a32003-10-12 16:49:16 +0000992 size = r->header_in->last - r->header_in->pos;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000993
Igor Sysoev0a280a32003-10-12 16:49:16 +0000994 if (size) {
995 if (r->headers_in.content_length_n > size) {
996 r->headers_in.content_length_n -= size;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000997
Igor Sysoev0a280a32003-10-12 16:49:16 +0000998 } else {
999 r->header_in->pos += r->headers_in.content_length_n;
1000 r->headers_in.content_length_n = 0;
1001 return NGX_OK;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001002 }
Igor Sysoev73009772003-02-06 17:21:13 +00001003 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001004
Igor Sysoev0a280a32003-10-12 16:49:16 +00001005 rev->event_handler = ngx_http_read_discarded_body_event;
1006
1007 if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
1008 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1009 }
1010
1011 return ngx_http_read_discarded_body(r);
1012
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001013 return NGX_OK;
1014}
1015
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001016
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001017static void ngx_http_read_discarded_body_event(ngx_event_t *rev)
Igor Sysoev42feecb2002-12-15 06:25:09 +00001018{
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001019 int rc;
1020 ngx_connection_t *c;
1021 ngx_http_request_t *r;
1022
Igor Sysoev6253ca12003-05-27 12:18:54 +00001023 c = rev->data;
1024 r = c->data;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001025
1026 rc = ngx_http_read_discarded_body(r);
1027
Igor Sysoev0a280a32003-10-12 16:49:16 +00001028 if (rc == NGX_AGAIN) {
1029 if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
1030 ngx_http_close_request(r, rc);
1031 ngx_http_close_connection(c);
1032 return;
1033 }
1034 }
1035
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001036 if (rc != NGX_OK) {
1037 ngx_http_close_request(r, rc);
1038 ngx_http_close_connection(c);
1039 }
1040}
1041
1042
1043static int ngx_http_read_discarded_body(ngx_http_request_t *r)
1044{
Igor Sysoev09159772003-06-12 05:54:39 +00001045 ssize_t size, n;
Igor Sysoev6253ca12003-05-27 12:18:54 +00001046 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev42feecb2002-12-15 06:25:09 +00001047
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001048 ngx_log_debug(r->connection->log, "http read discarded body");
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001049
Igor Sysoev0a280a32003-10-12 16:49:16 +00001050 if (r->headers_in.content_length_n == 0) {
1051 return NGX_OK;
1052 }
1053
Igor Sysoev6253ca12003-05-27 12:18:54 +00001054 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001055
Igor Sysoevdc479b42003-03-20 16:09:44 +00001056 if (r->discarded_buffer == NULL) {
Igor Sysoev6253ca12003-05-27 12:18:54 +00001057 r->discarded_buffer = ngx_palloc(r->pool, clcf->discarded_buffer_size);
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001058 if (r->discarded_buffer == NULL) {
1059 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1060 }
Igor Sysoevdc479b42003-03-20 16:09:44 +00001061 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001062
Igor Sysoeva09f08d2003-04-25 14:43:13 +00001063 size = r->headers_in.content_length_n;
Igor Sysoev0a280a32003-10-12 16:49:16 +00001064
Igor Sysoev6253ca12003-05-27 12:18:54 +00001065 if (size > clcf->discarded_buffer_size) {
1066 size = clcf->discarded_buffer_size;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001067 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001068
Igor Sysoev239baac2003-06-11 15:28:34 +00001069 n = ngx_recv(r->connection, r->discarded_buffer, size);
Igor Sysoevdc479b42003-03-20 16:09:44 +00001070 if (n == NGX_ERROR) {
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001071 return NGX_HTTP_BAD_REQUEST;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001072 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001073
Igor Sysoevdc479b42003-03-20 16:09:44 +00001074 if (n == NGX_AGAIN) {
Igor Sysoev0a280a32003-10-12 16:49:16 +00001075 return NGX_AGAIN;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001076 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001077
Igor Sysoeva09f08d2003-04-25 14:43:13 +00001078 r->headers_in.content_length_n -= n;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001079
Igor Sysoev42feecb2002-12-15 06:25:09 +00001080 return NGX_OK;
1081}
1082
1083
Igor Sysoevd581fd52003-05-13 16:02:32 +00001084static void ngx_http_set_keepalive(ngx_http_request_t *r)
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001085{
Igor Sysoev0a280a32003-10-12 16:49:16 +00001086 int len;
Igor Sysoev187fcd82003-05-23 11:53:01 +00001087 ngx_hunk_t *h;
1088 ngx_event_t *rev, *wev;
1089 ngx_connection_t *c;
1090 ngx_http_log_ctx_t *ctx;
1091 ngx_http_core_srv_conf_t *cscf;
1092 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001093
Igor Sysoev6253ca12003-05-27 12:18:54 +00001094 c = r->connection;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001095 rev = c->read;
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001096
Igor Sysoev6a1cc902003-05-22 15:23:47 +00001097 ngx_log_debug(c->log, "set http keepalive handler");
1098
Igor Sysoev6a644c62003-03-04 06:33:48 +00001099 ctx = (ngx_http_log_ctx_t *) c->log->data;
1100 ctx->action = "closing request";
Igor Sysoevdc479b42003-03-20 16:09:44 +00001101 ngx_http_close_request(r, 0);
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001102
Igor Sysoev6253ca12003-05-27 12:18:54 +00001103 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoevfa73aac2003-05-21 13:28:21 +00001104 ngx_add_timer(rev, clcf->keepalive_timeout);
1105
Igor Sysoev0a280a32003-10-12 16:49:16 +00001106 if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
1107 ngx_http_close_connection(c);
1108 return;
Igor Sysoevb7387572003-03-11 20:38:13 +00001109 }
1110
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001111 h = c->buffer;
1112
Igor Sysoevb7387572003-03-11 20:38:13 +00001113 if (h->pos < h->last) {
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001114
Igor Sysoev74e95c22003-11-09 20:03:38 +00001115 /*
1116 * Pipelined request.
Igor Sysoev0a280a32003-10-12 16:49:16 +00001117 *
1118 * We do not know here whether a pipelined request is complete
1119 * so if the large client headers are not enabled
1120 * we need to copy the data to the start of c->buffer.
1121 * This copy should be rare because clients that support
1122 * pipelined requests (Mozilla 1.x, Opera 6.x+) are still rare.
1123 */
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001124
Igor Sysoev6253ca12003-05-27 12:18:54 +00001125 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
Igor Sysoeva9830112003-05-19 16:39:14 +00001126
Igor Sysoev187fcd82003-05-23 11:53:01 +00001127 if (!cscf->large_client_header) {
1128 len = h->last - h->pos;
Igor Sysoevb7387572003-03-11 20:38:13 +00001129 ngx_memcpy(h->start, h->pos, len);
1130 h->pos = h->start;
1131 h->last = h->start + len;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001132 }
1133
Igor Sysoev6253ca12003-05-27 12:18:54 +00001134 ngx_log_debug(c->log, "pipelined request");
1135
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001136 c->pipeline = 1;
1137 ctx->action = "reading client pipelined request line";
Igor Sysoevd581fd52003-05-13 16:02:32 +00001138 ngx_http_init_request(rev);
1139 return;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001140 }
1141
1142 c->pipeline = 0;
1143
Igor Sysoevb7387572003-03-11 20:38:13 +00001144 h->pos = h->last = h->start;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001145 rev->event_handler = ngx_http_keepalive_handler;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001146 wev = c->write;
Igor Sysoev0a280a32003-10-12 16:49:16 +00001147 wev->event_handler = ngx_http_empty_handler;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001148
Igor Sysoevd9d0ca12003-11-21 06:30:49 +00001149 if (wev->active) {
1150 if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
1151 if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_DISABLE_EVENT)
1152 == NGX_ERROR)
1153 {
1154 ngx_http_close_connection(c);
1155 return;
1156 }
1157
1158 } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
1159 if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
1160 ngx_http_close_connection(c);
1161 return;
1162 }
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001163 }
1164 }
1165
Igor Sysoev6a644c62003-03-04 06:33:48 +00001166 ctx->action = "keepalive";
1167
Igor Sysoev9cf78302003-06-04 17:28:33 +00001168 if (c->tcp_nopush) {
1169 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
1170 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
1171 ngx_tcp_push_n " failed");
1172 ngx_http_close_connection(c);
1173 return;
1174 }
1175 c->tcp_nopush = 0;
1176 }
1177
Igor Sysoevb5faed22003-10-29 08:30:44 +00001178 if (rev->ready) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001179 ngx_http_keepalive_handler(rev);
Igor Sysoevb7387572003-03-11 20:38:13 +00001180 }
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001181}
1182
1183
Igor Sysoevd581fd52003-05-13 16:02:32 +00001184static void ngx_http_keepalive_handler(ngx_event_t *rev)
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001185{
Igor Sysoev0a280a32003-10-12 16:49:16 +00001186 ssize_t n;
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001187 ngx_connection_t *c;
Igor Sysoev160d7742003-11-19 16:26:41 +00001188 ngx_http_log_ctx_t *ctx;
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001189
Igor Sysoevdc479b42003-03-20 16:09:44 +00001190 c = (ngx_connection_t *) rev->data;
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001191
Igor Sysoevdc479b42003-03-20 16:09:44 +00001192 ngx_log_debug(c->log, "http keepalive handler");
Igor Sysoev1af7c822002-09-13 14:47:42 +00001193
Igor Sysoevdc479b42003-03-20 16:09:44 +00001194 if (rev->timedout) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001195 ngx_http_close_connection(c);
1196 return;
Igor Sysoev90ace682003-03-12 17:32:22 +00001197 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001198
Igor Sysoev0a280a32003-10-12 16:49:16 +00001199 /*
1200 * MSIE closes a keepalive connection with RST flag
1201 * so we ignore ECONNRESET here.
1202 */
Igor Sysoevb7387572003-03-11 20:38:13 +00001203
Igor Sysoevdc479b42003-03-20 16:09:44 +00001204 rev->ignore_econnreset = 1;
Igor Sysoevb7387572003-03-11 20:38:13 +00001205 ngx_set_socket_errno(0);
Igor Sysoev239baac2003-06-11 15:28:34 +00001206 n = ngx_recv(c, c->buffer->last, c->buffer->end - c->buffer->last);
Igor Sysoevdc479b42003-03-20 16:09:44 +00001207 rev->ignore_econnreset = 0;
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001208
Igor Sysoevd581fd52003-05-13 16:02:32 +00001209 if (n == NGX_AGAIN) {
1210 return;
1211 }
1212
1213 if (n == NGX_ERROR) {
1214 ngx_http_close_connection(c);
1215 return;
Igor Sysoev90ace682003-03-12 17:32:22 +00001216 }
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001217
Igor Sysoev160d7742003-11-19 16:26:41 +00001218 ctx = (ngx_http_log_ctx_t *) rev->log->data;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001219 rev->log->handler = NULL;
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001220
1221 if (n == 0) {
Igor Sysoevdc479b42003-03-20 16:09:44 +00001222 ngx_log_error(NGX_LOG_INFO, c->log, ngx_socket_errno,
Igor Sysoev160d7742003-11-19 16:26:41 +00001223 "client %s closed keepalive connection", ctx->client);
Igor Sysoevd581fd52003-05-13 16:02:32 +00001224 ngx_http_close_connection(c);
1225 return;
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001226 }
1227
Igor Sysoevb7387572003-03-11 20:38:13 +00001228 c->buffer->last += n;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001229 rev->log->handler = ngx_http_log_error;
Igor Sysoev160d7742003-11-19 16:26:41 +00001230 ctx->action = "reading client request line";
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001231
Igor Sysoevd581fd52003-05-13 16:02:32 +00001232 ngx_http_init_request(rev);
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001233}
1234
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001235
Igor Sysoevd581fd52003-05-13 16:02:32 +00001236static void ngx_http_set_lingering_close(ngx_http_request_t *r)
Igor Sysoev1af7c822002-09-13 14:47:42 +00001237{
Igor Sysoev0a280a32003-10-12 16:49:16 +00001238 ngx_event_t *rev, *wev;
Igor Sysoevb7387572003-03-11 20:38:13 +00001239 ngx_connection_t *c;
Igor Sysoev6253ca12003-05-27 12:18:54 +00001240 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001241
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001242 c = r->connection;
Igor Sysoev9b25d692003-01-26 21:08:14 +00001243
Igor Sysoev6253ca12003-05-27 12:18:54 +00001244 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001245
Igor Sysoev0a280a32003-10-12 16:49:16 +00001246 rev = c->read;
Igor Sysoevd581fd52003-05-13 16:02:32 +00001247 rev->event_handler = ngx_http_lingering_close_handler;
Igor Sysoev42feecb2002-12-15 06:25:09 +00001248
Igor Sysoev0a280a32003-10-12 16:49:16 +00001249 r->lingering_time = ngx_time() + clcf->lingering_time / 1000;
Igor Sysoev6253ca12003-05-27 12:18:54 +00001250 ngx_add_timer(rev, clcf->lingering_timeout);
Igor Sysoev9b25d692003-01-26 21:08:14 +00001251
Igor Sysoev0a280a32003-10-12 16:49:16 +00001252 if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
1253 ngx_http_close_request(r, 0);
1254 ngx_http_close_connection(c);
1255 return;
1256 }
1257
1258 wev = c->write;
1259 wev->event_handler = ngx_http_empty_handler;
1260
Igor Sysoevd9d0ca12003-11-21 06:30:49 +00001261 if (wev->active) {
1262 if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) {
1263 if (ngx_del_event(wev, NGX_WRITE_EVENT, NGX_DISABLE_EVENT)
1264 == NGX_ERROR)
1265 {
1266 ngx_http_close_connection(c);
1267 return;
1268 }
1269
1270 } else if (ngx_event_flags & NGX_USE_LEVEL_EVENT) {
1271 if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
1272 ngx_http_close_connection(c);
1273 return;
1274 }
Igor Sysoevb7387572003-03-11 20:38:13 +00001275 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001276 }
1277
Igor Sysoevb7387572003-03-11 20:38:13 +00001278 if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
1279 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
Igor Sysoev42feecb2002-12-15 06:25:09 +00001280 ngx_shutdown_socket_n " failed");
Igor Sysoevd581fd52003-05-13 16:02:32 +00001281 ngx_http_close_request(r, 0);
1282 ngx_http_close_connection(c);
1283 return;
Igor Sysoev42feecb2002-12-15 06:25:09 +00001284 }
1285
Igor Sysoevb5faed22003-10-29 08:30:44 +00001286 if (rev->ready) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001287 ngx_http_lingering_close_handler(rev);
Igor Sysoevb7387572003-03-11 20:38:13 +00001288 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001289}
1290
1291
Igor Sysoevd581fd52003-05-13 16:02:32 +00001292static void ngx_http_lingering_close_handler(ngx_event_t *rev)
Igor Sysoev42feecb2002-12-15 06:25:09 +00001293{
Igor Sysoevdc479b42003-03-20 16:09:44 +00001294 ssize_t n;
1295 ngx_msec_t timer;
1296 ngx_connection_t *c;
1297 ngx_http_request_t *r;
Igor Sysoev6253ca12003-05-27 12:18:54 +00001298 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev1af7c822002-09-13 14:47:42 +00001299
Igor Sysoev6253ca12003-05-27 12:18:54 +00001300 c = rev->data;
1301 r = c->data;
Igor Sysoev86de4cb2003-01-30 07:28:09 +00001302
Igor Sysoevdc479b42003-03-20 16:09:44 +00001303 ngx_log_debug(c->log, "http lingering close handler");
1304
1305 if (rev->timedout) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001306 ngx_http_close_request(r, 0);
1307 ngx_http_close_connection(c);
1308 return;
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001309 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001310
Igor Sysoev1af7c822002-09-13 14:47:42 +00001311 timer = r->lingering_time - ngx_time();
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001312 if (timer <= 0) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001313 ngx_http_close_request(r, 0);
1314 ngx_http_close_connection(c);
1315 return;
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001316 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001317
Igor Sysoev6253ca12003-05-27 12:18:54 +00001318 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001319
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001320 if (r->discarded_buffer == NULL) {
Igor Sysoevb7387572003-03-11 20:38:13 +00001321
1322 /* TODO: r->header_in->start (if large headers are enabled)
1323 or the end of parsed header (otherwise)
1324 instead of r->header_in->last */
1325
Igor Sysoev09159772003-06-12 05:54:39 +00001326 if (r->header_in->end - r->header_in->last
Igor Sysoev6253ca12003-05-27 12:18:54 +00001327 >= clcf->discarded_buffer_size) {
Igor Sysoevb7387572003-03-11 20:38:13 +00001328 r->discarded_buffer = r->header_in->last;
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001329
1330 } else {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001331 r->discarded_buffer = ngx_palloc(c->pool,
Igor Sysoev6253ca12003-05-27 12:18:54 +00001332 clcf->discarded_buffer_size);
Igor Sysoevd581fd52003-05-13 16:02:32 +00001333 if (r->discarded_buffer) {
1334 ngx_http_close_request(r, 0);
1335 ngx_http_close_connection(c);
1336 return;
1337 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001338 }
1339 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001340
Igor Sysoevdc479b42003-03-20 16:09:44 +00001341 do {
Igor Sysoev239baac2003-06-11 15:28:34 +00001342 n = ngx_recv(c, r->discarded_buffer, clcf->discarded_buffer_size);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001343
Igor Sysoevdc479b42003-03-20 16:09:44 +00001344 ngx_log_debug(c->log, "lingering read: %d" _ n);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001345
Igor Sysoevdc479b42003-03-20 16:09:44 +00001346 if (n == NGX_ERROR || n == 0) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001347 ngx_http_close_request(r, 0);
1348 ngx_http_close_connection(c);
1349 return;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001350 }
1351
1352 } while (rev->ready);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001353
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001354 timer *= 1000;
Igor Sysoev6253ca12003-05-27 12:18:54 +00001355 if (timer > clcf->lingering_timeout) {
1356 timer = clcf->lingering_timeout;
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001357 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001358
Igor Sysoevdc479b42003-03-20 16:09:44 +00001359 ngx_add_timer(rev, timer);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001360
Igor Sysoevd581fd52003-05-13 16:02:32 +00001361 return;
Igor Sysoev1af7c822002-09-13 14:47:42 +00001362}
1363
Igor Sysoev2b542382002-08-20 14:48:28 +00001364
Igor Sysoev160d7742003-11-19 16:26:41 +00001365void ngx_http_empty_handler(ngx_event_t *wev)
Igor Sysoev6a1cc902003-05-22 15:23:47 +00001366{
Igor Sysoev0a280a32003-10-12 16:49:16 +00001367 ngx_log_debug(wev->log, "http EMPTY handler");
Igor Sysoev6a1cc902003-05-22 15:23:47 +00001368
1369 return;
1370}
1371
1372
Igor Sysoev1342d9c2003-10-09 07:00:45 +00001373int ngx_http_send_last(ngx_http_request_t *r)
1374{
Igor Sysoev419f9ac2003-10-21 16:49:56 +00001375 ngx_hunk_t *h;
1376 ngx_chain_t out;
Igor Sysoev1342d9c2003-10-09 07:00:45 +00001377
1378 ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
1379 h->type = NGX_HUNK_LAST;
Igor Sysoev419f9ac2003-10-21 16:49:56 +00001380 out.hunk = h;
1381 out.next = NULL;
Igor Sysoev1342d9c2003-10-09 07:00:45 +00001382
Igor Sysoev419f9ac2003-10-21 16:49:56 +00001383 return ngx_http_output_filter(r, &out);
Igor Sysoev1342d9c2003-10-09 07:00:45 +00001384}
1385
1386
Igor Sysoevd581fd52003-05-13 16:02:32 +00001387void ngx_http_close_request(ngx_http_request_t *r, int error)
1388{
Igor Sysoevc2bba092003-11-28 17:41:47 +00001389 ngx_int_t i;
Igor Sysoevd581fd52003-05-13 16:02:32 +00001390 ngx_http_log_ctx_t *ctx;
Igor Sysoevc2bba092003-11-28 17:41:47 +00001391 ngx_http_cleanup_t *cleanup;
Igor Sysoevd581fd52003-05-13 16:02:32 +00001392
1393 ngx_log_debug(r->connection->log, "close http request");
1394
1395 if (r->pool == NULL) {
1396 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001397 "http request already closed");
Igor Sysoevd581fd52003-05-13 16:02:32 +00001398 return;
1399 }
1400
1401 if (error) {
1402 r->headers_out.status = error;
1403 }
1404
1405 ngx_http_log_handler(r);
1406
Igor Sysoevc2bba092003-11-28 17:41:47 +00001407 cleanup = r->cleanup.elts;
1408 for (i = 0; i < r->cleanup.nelts; i++) {
1409 if (cleanup[i].cache) {
1410 ngx_http_cache_unlock(cleanup[i].data.cache.hash,
1411 cleanup[i].data.cache.cache,
1412 r->connection->log);
1413 continue;
1414 }
1415
1416 if (ngx_close_file(cleanup[i].data.file.fd) == NGX_FILE_ERROR) {
1417 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
1418 ngx_close_file_n " \"%s\" failed",
1419 cleanup[i].data.file.name);
1420 }
1421 }
1422
Igor Sysoevd581fd52003-05-13 16:02:32 +00001423 if (r->file.fd != NGX_INVALID_FILE) {
1424 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
1425 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
1426 ngx_close_file_n " \"%s\" failed", r->file.name.data);
1427 }
1428 }
1429
1430 /* ctx->url was allocated from r->pool */
Igor Sysoev0a280a32003-10-12 16:49:16 +00001431 ctx = r->connection->log->data;
Igor Sysoevd581fd52003-05-13 16:02:32 +00001432 ctx->url = NULL;
1433
1434 ngx_destroy_pool(r->pool);
Igor Sysoevb3e73d82003-10-10 15:10:50 +00001435
Igor Sysoevb3e73d82003-10-10 15:10:50 +00001436 return;
Igor Sysoevd581fd52003-05-13 16:02:32 +00001437}
1438
1439
1440void ngx_http_close_connection(ngx_connection_t *c)
Igor Sysoev6b863e32003-05-12 15:52:24 +00001441{
1442 ngx_log_debug(c->log, "close connection: %d" _ c->fd);
1443
Igor Sysoevd581fd52003-05-13 16:02:32 +00001444 if (c->pool == NULL) {
Igor Sysoev6b863e32003-05-12 15:52:24 +00001445 ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
1446 return;
1447 }
1448
1449 if (c->read->timer_set) {
1450 ngx_del_timer(c->read);
Igor Sysoev6b863e32003-05-12 15:52:24 +00001451 }
1452
Igor Sysoev6b863e32003-05-12 15:52:24 +00001453 if (c->write->timer_set) {
1454 ngx_del_timer(c->write);
Igor Sysoev6b863e32003-05-12 15:52:24 +00001455 }
1456
Igor Sysoev6253ca12003-05-27 12:18:54 +00001457 if (ngx_del_conn) {
Igor Sysoev6a1cc902003-05-22 15:23:47 +00001458 ngx_del_conn(c);
1459
1460 } else {
1461 if (c->read->active) {
1462 ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
1463 }
1464
1465 if (c->write->active) {
1466 ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
1467 }
Igor Sysoev6b863e32003-05-12 15:52:24 +00001468 }
1469
1470 if (ngx_close_socket(c->fd) == -1) {
1471 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
1472 ngx_close_socket_n " failed");
1473 }
1474
1475 c->fd = -1;
1476
1477 ngx_destroy_pool(c->pool);
Igor Sysoevb3e73d82003-10-10 15:10:50 +00001478
1479 return;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +00001480}
1481
1482
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001483static void ngx_http_client_error(ngx_http_request_t *r,
1484 int client_error, int error)
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001485{
1486 ngx_http_log_ctx_t *ctx;
1487
1488 ctx = r->connection->log->data;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001489
1490 if (error == NGX_HTTP_REQUEST_TIME_OUT) {
1491 ngx_log_error(NGX_LOG_INFO, r->connection->log, NGX_ETIMEDOUT,
1492 "client timed out");
1493 ngx_http_close_request(r, error);
1494 ngx_http_close_connection(r->connection);
1495 return;
1496 }
1497
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001498 r->connection->log->handler = NULL;
1499
1500 if (ctx->url) {
1501 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001502 client_header_errors[client_error - NGX_HTTP_CLIENT_ERROR],
1503 ctx->client, ctx->url);
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001504
1505 } else {
1506 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001507 client_header_errors[client_error - NGX_HTTP_CLIENT_ERROR],
1508 ctx->client);
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001509 }
1510
1511 r->connection->log->handler = ngx_http_log_error;
Igor Sysoev0a280a32003-10-12 16:49:16 +00001512
1513 ngx_http_finalize_request(r, error);
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001514}
1515
1516
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001517static size_t ngx_http_log_error(void *data, char *buf, size_t len)
1518{
Igor Sysoev160d7742003-11-19 16:26:41 +00001519 ngx_http_log_ctx_t *ctx = data;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +00001520
Igor Sysoev7578ec92003-06-02 15:24:30 +00001521 if (ctx->action && ctx->url) {
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001522 return ngx_snprintf(buf, len, " while %s, client: %s, URL: %s",
1523 ctx->action, ctx->client, ctx->url);
Igor Sysoev7578ec92003-06-02 15:24:30 +00001524
1525 } else if (ctx->action == NULL && ctx->url) {
1526 return ngx_snprintf(buf, len, ", client: %s, URL: %s",
1527 ctx->client, ctx->url);
1528
Igor Sysoevdc479b42003-03-20 16:09:44 +00001529 } else {
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001530 return ngx_snprintf(buf, len, " while %s, client: %s",
1531 ctx->action, ctx->client);
Igor Sysoevdc479b42003-03-20 16:09:44 +00001532 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00001533}