blob: 9dd040e437da560af344d2a9f9d17049ca942f41 [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);
Igor Sysoev6a1cc902003-05-22 15:23:47 +000024static void ngx_http_empty_handler(ngx_event_t *wev);
Igor Sysoevd581fd52003-05-13 16:02:32 +000025
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000026static void ngx_http_client_error(ngx_http_request_t *r,
27 int client_error, int error);
Igor Sysoev0ad17c02002-08-26 15:18:19 +000028static size_t ngx_http_log_error(void *data, char *buf, size_t len);
29
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000030
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000031/* NGX_HTTP_PARSE_... errors */
Igor Sysoev0ad17c02002-08-26 15:18:19 +000032
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000033static char *client_header_errors[] = {
Igor Sysoev016b8522002-08-29 16:59:54 +000034 "client %s sent invalid method",
35 "client %s sent invalid request",
Igor Sysoev1af7c822002-09-13 14:47:42 +000036 "client %s sent too long URI",
Igor Sysoev6ddfbf02003-05-15 15:42:53 +000037 "client %s sent invalid method in HTTP/0.9 request",
Igor Sysoev6a644c62003-03-04 06:33:48 +000038
39 "client %s sent invalid header, URL: %s",
40 "client %s sent too long header line, URL: %s",
Igor Sysoeva09f08d2003-04-25 14:43:13 +000041 "client %s sent HTTP/1.1 request without \"Host\" header, URL: %s",
42 "client %s sent invalid \"Content-Length\" header, URL: %s"
Igor Sysoev016b8522002-08-29 16:59:54 +000043};
44
45
Igor Sysoev10fc9ef2003-10-27 08:53:49 +000046static void ngx_http_dummy(ngx_event_t *wev)
47{
48 return;
49}
50
51
Igor Sysoev6b863e32003-05-12 15:52:24 +000052void ngx_http_init_connection(ngx_connection_t *c)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000053{
Igor Sysoev6253ca12003-05-27 12:18:54 +000054 ngx_event_t *rev;
Igor Sysoev890fc962003-07-20 21:15:59 +000055 ngx_http_log_ctx_t *lctx;
Igor Sysoev6b863e32003-05-12 15:52:24 +000056
Igor Sysoev239baac2003-06-11 15:28:34 +000057 c->addr_text.data = ngx_palloc(c->pool, c->listening->addr_text_max_len);
Igor Sysoev6b863e32003-05-12 15:52:24 +000058 if (c->addr_text.data == NULL) {
59 ngx_http_close_connection(c);
60 return;
61 }
62
Igor Sysoev239baac2003-06-11 15:28:34 +000063 c->addr_text.len = ngx_sock_ntop(c->listening->family, c->sockaddr,
64 c->addr_text.data,
65 c->listening->addr_text_max_len);
Igor Sysoev6b863e32003-05-12 15:52:24 +000066 if (c->addr_text.len == 0) {
67 ngx_http_close_connection(c);
68 return;
69 }
70
Igor Sysoev68ee8f12003-10-30 08:51:06 +000071 if (!(lctx = ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +000072 ngx_http_close_connection(c);
73 return;
74 }
75
Igor Sysoev890fc962003-07-20 21:15:59 +000076 lctx->client = c->addr_text.data;
77 lctx->action = "reading client request line";
78 c->log->data = lctx;
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 /*
160 * there're the several addresses on this port and one of them
161 * 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 Sysoev74e95c22003-11-09 20:03:38 +0000228 /* TODO: ngx_init_table */
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000229 if (!(r->headers_out.headers = ngx_create_table(r->pool, 20))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000230 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
231 ngx_http_close_connection(c);
232 return;
233 }
234
235 r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module);
236 if (r->ctx == NULL) {
237 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
238 ngx_http_close_connection(c);
239 return;
240 }
Igor Sysoeve0268b92002-09-11 15:18:33 +0000241
Igor Sysoev6b863e32003-05-12 15:52:24 +0000242 c->sent = 0;
243 c->data = r;
244 r->connection = c;
245 r->pipeline = c->pipeline;
246 r->header_in = c->buffer;
247
248 r->file.fd = NGX_INVALID_FILE;
249
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000250 r->headers_in.content_length_n = -1;
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000251 r->headers_in.keep_alive_n = -1;
252 r->headers_out.content_length_n = -1;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000253 r->headers_out.last_modified_time = -1;
254
Igor Sysoev6b863e32003-05-12 15:52:24 +0000255 rev->event_handler = ngx_http_process_request_line;
256 ngx_http_process_request_line(rev);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000257}
258
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000259
Igor Sysoev6b863e32003-05-12 15:52:24 +0000260static void ngx_http_process_request_line(ngx_event_t *rev)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000261{
Igor Sysoev187fcd82003-05-23 11:53:01 +0000262 int rc, offset;
263 ssize_t n;
264 ngx_connection_t *c;
265 ngx_http_request_t *r;
Igor Sysoev890fc962003-07-20 21:15:59 +0000266 ngx_http_log_ctx_t *lctx;
Igor Sysoev187fcd82003-05-23 11:53:01 +0000267 ngx_http_core_srv_conf_t *cscf;
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000268
Igor Sysoeva9830112003-05-19 16:39:14 +0000269 c = rev->data;
270 r = c->data;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000271
Igor Sysoev6b863e32003-05-12 15:52:24 +0000272 ngx_log_debug(rev->log, "http process request line");
Igor Sysoevdc479b42003-03-20 16:09:44 +0000273
274 if (rev->timedout) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000275 ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000276 return;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000277 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000278
Igor Sysoev6b863e32003-05-12 15:52:24 +0000279 n = ngx_http_read_request_header(r);
Igor Sysoev016b8522002-08-29 16:59:54 +0000280
Igor Sysoev6b863e32003-05-12 15:52:24 +0000281 if (n == NGX_AGAIN || n == NGX_ERROR) {
282 return;
Igor Sysoev830c4ce2003-01-24 16:09:40 +0000283 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000284
Igor Sysoeve6779222003-10-03 15:50:53 +0000285 rc = ngx_http_parse_request_line(r);
Igor Sysoevdc479b42003-03-20 16:09:44 +0000286
Igor Sysoev016b8522002-08-29 16:59:54 +0000287 if (rc == NGX_OK) {
Igor Sysoevdc479b42003-03-20 16:09:44 +0000288
Igor Sysoev6b863e32003-05-12 15:52:24 +0000289 /* the request line has been parsed successfully */
290
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000291 /* TODO: we need to handle such URIs */
Igor Sysoev7578ec92003-06-02 15:24:30 +0000292 if (r->complex_uri || r->unusual_uri) {
Igor Sysoev1c104622003-06-03 15:42:58 +0000293 r->request_line.len = r->request_end - r->request_start;
294 r->request_line.data = r->request_start;
295 r->request_line.data[r->request_line.len] = '\0';
296
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000297 ngx_http_client_error(r, NGX_HTTP_PARSE_INVALID_REQUEST,
298 NGX_HTTP_BAD_REQUEST);
Igor Sysoev7578ec92003-06-02 15:24:30 +0000299 return;
300 }
301
Igor Sysoev6253ca12003-05-27 12:18:54 +0000302 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
Igor Sysoeva9830112003-05-19 16:39:14 +0000303
Igor Sysoeve2a31542003-04-08 15:40:10 +0000304 if (r->http_version >= NGX_HTTP_VERSION_10
Igor Sysoev187fcd82003-05-23 11:53:01 +0000305 && cscf->large_client_header == 0
Igor Sysoeve2a31542003-04-08 15:40:10 +0000306 && r->header_in->pos == r->header_in->end)
307 {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000308 /* no space for "\r\n" at the end of the header */
309
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000310 ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
311 NGX_HTTP_REQUEST_URI_TOO_LARGE);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000312 return;
Igor Sysoeve2a31542003-04-08 15:40:10 +0000313 }
314
Igor Sysoev6414b962003-10-24 16:10:38 +0000315
Igor Sysoev6a644c62003-03-04 06:33:48 +0000316 /* copy URI */
Igor Sysoevdc479b42003-03-20 16:09:44 +0000317
318 if (r->args_start) {
319 r->uri.len = r->args_start - 1 - r->uri_start;
320 } else {
321 r->uri.len = r->uri_end - r->uri_start;
322 }
323
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000324 if (!(r->uri.data = ngx_palloc(r->pool, r->uri.len + 1))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000325 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
326 ngx_http_close_connection(c);
327 return;
328 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000329
Igor Sysoevb0869052002-12-10 18:05:12 +0000330 ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1);
Igor Sysoev016b8522002-08-29 16:59:54 +0000331
Igor Sysoeva9830112003-05-19 16:39:14 +0000332
333 /* copy unparsed URI */
334
335 r->unparsed_uri.len = r->uri_end - r->uri_start;
336 r->unparsed_uri.data = ngx_palloc(r->pool, r->unparsed_uri.len + 1);
337 if (r->unparsed_uri.data == NULL) {
338 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
339 ngx_http_close_connection(c);
340 return;
341 }
342
343 ngx_cpystrn(r->unparsed_uri.data, r->uri_start,
344 r->unparsed_uri.len + 1);
345
Igor Sysoeva9830112003-05-19 16:39:14 +0000346
Igor Sysoevdc479b42003-03-20 16:09:44 +0000347 r->request_line.len = r->request_end - r->request_start;
348
Igor Sysoevd581fd52003-05-13 16:02:32 +0000349 /* if the large client headers are enabled then
Igor Sysoev0dad6292003-03-05 17:30:51 +0000350 we need to copy a request line */
Igor Sysoev2d0d9092002-12-03 15:45:38 +0000351
Igor Sysoev187fcd82003-05-23 11:53:01 +0000352 if (cscf->large_client_header) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000353
354 r->request_line.data = ngx_palloc(r->pool, r->request_line.len + 1);
355 if (r->request_line.data == NULL) {
356 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
357 ngx_http_close_connection(c);
358 return;
359 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000360
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000361 ngx_cpystrn(r->request_line.data, r->request_start,
Igor Sysoev6a644c62003-03-04 06:33:48 +0000362 r->request_line.len + 1);
363
364 } else {
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000365 r->request_line.data = r->request_start;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000366 r->request_line.data[r->request_line.len] = '\0';
367 }
368
369 /* copy URI extention if it exists */
Igor Sysoevdc479b42003-03-20 16:09:44 +0000370
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000371 if (r->uri_ext) {
Igor Sysoevdc479b42003-03-20 16:09:44 +0000372 if (r->args_start) {
373 r->exten.len = r->args_start - 1 - r->uri_ext;
374 } else {
375 r->exten.len = r->uri_end - r->uri_ext;
376 }
377
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000378 if (!(r->exten.data = ngx_palloc(r->pool, r->exten.len + 1))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000379 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
380 ngx_http_close_connection(c);
381 return;
382 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000383
Igor Sysoevb0869052002-12-10 18:05:12 +0000384 ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1);
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000385 }
386
Igor Sysoevdc479b42003-03-20 16:09:44 +0000387 /* copy URI arguments if they exist */
388
389 if (r->args_start && r->uri_end > r->args_start) {
390 r->args.len = r->uri_end - r->args_start;
391
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000392 if (!(r->args.data = ngx_palloc(r->pool, r->args.len + 1))) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000393 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
394 ngx_http_close_connection(c);
395 return;
396 }
Igor Sysoevdc479b42003-03-20 16:09:44 +0000397
398 ngx_cpystrn(r->args.data, r->args_start, r->args.len + 1);
399 }
400
Igor Sysoev6b863e32003-05-12 15:52:24 +0000401#if 1 /* DEBUG */
402 if (r->exten.data == NULL) { r->exten.data = ""; }
403 if (r->args.data == NULL) { r->args.data = ""; }
404 ngx_log_debug(c->log, "HTTP: %d, %d, '%s', '%s', '%s'" _
Igor Sysoevb0869052002-12-10 18:05:12 +0000405 r->method _ r->http_version _
Igor Sysoevdc479b42003-03-20 16:09:44 +0000406 r->uri.data _ r->exten.data _ r->args.data);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000407 if (r->exten.data[0] == '\0') { r->exten.data = NULL; }
408 if (r->args.data[0] == '\0') { r->args.data = NULL; }
Igor Sysoev295bb632002-12-23 18:22:18 +0000409#endif
Igor Sysoev016b8522002-08-29 16:59:54 +0000410
Igor Sysoev7578ec92003-06-02 15:24:30 +0000411 if (r->http_version < NGX_HTTP_VERSION_10) {
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000412 rev->event_handler = ngx_http_block_read;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000413 ngx_http_handler(r);
414 return;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000415 }
Igor Sysoev1af7c822002-09-13 14:47:42 +0000416
Igor Sysoev890fc962003-07-20 21:15:59 +0000417 lctx = c->log->data;
418 lctx->action = "reading client request headers";
419 lctx->url = r->unparsed_uri.data;
Igor Sysoev74e95c22003-11-09 20:03:38 +0000420 /* TODO: ngx_init_table */
Igor Sysoev14be46e2003-10-29 17:39:05 +0000421 r->headers_in.headers = ngx_create_table(r->pool, 20);
Igor Sysoevdc479b42003-03-20 16:09:44 +0000422
Igor Sysoev187fcd82003-05-23 11:53:01 +0000423 if (cscf->large_client_header
Igor Sysoevdc479b42003-03-20 16:09:44 +0000424 && r->header_in->pos == r->header_in->last)
425 {
426 r->header_in->pos = r->header_in->last = r->header_in->start;
427 }
Igor Sysoev016b8522002-08-29 16:59:54 +0000428
Igor Sysoevd581fd52003-05-13 16:02:32 +0000429 rev->event_handler = ngx_http_process_request_headers;
430 ngx_http_process_request_headers(rev);
431
432 return;
433
Igor Sysoev0dad6292003-03-05 17:30:51 +0000434 } else if (rc != NGX_AGAIN) {
Igor Sysoev6b863e32003-05-12 15:52:24 +0000435
436 /* there was error while a request line parsing */
437
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000438 ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000439
Igor Sysoev6b863e32003-05-12 15:52:24 +0000440 return;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000441 }
442
Igor Sysoev0dad6292003-03-05 17:30:51 +0000443 /* NGX_AGAIN: a request line parsing is still not complete */
444
Igor Sysoevb7387572003-03-11 20:38:13 +0000445 if (r->header_in->last == r->header_in->end) {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000446
Igor Sysoev0a280a32003-10-12 16:49:16 +0000447 /*
448 * If it's a pipelined request and a request line is not complete
449 * then we need to copy it to the start of the r->header_in hunk.
450 * We need to copy it here only if the large client headers
451 * are enabled otherwise a request line had been already copied
452 * to the start of the r->header_in hunk in ngx_http_set_keepalive().
453 */
Igor Sysoev0dad6292003-03-05 17:30:51 +0000454
Igor Sysoev6253ca12003-05-27 12:18:54 +0000455 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
Igor Sysoeva9830112003-05-19 16:39:14 +0000456
Igor Sysoev187fcd82003-05-23 11:53:01 +0000457 if (cscf->large_client_header) {
Igor Sysoev0dad6292003-03-05 17:30:51 +0000458 offset = r->request_start - r->header_in->start;
459
460 if (offset == 0) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000461 ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
462 NGX_HTTP_REQUEST_URI_TOO_LARGE);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000463 return;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000464 }
465
466 ngx_memcpy(r->header_in->start, r->request_start,
Igor Sysoevb7387572003-03-11 20:38:13 +0000467 r->header_in->last - r->request_start);
Igor Sysoev0dad6292003-03-05 17:30:51 +0000468
Igor Sysoevb7387572003-03-11 20:38:13 +0000469 r->header_in->pos -= offset;
470 r->header_in->last -= offset;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000471 r->request_start = r->header_in->start;
472 r->request_end -= offset;
473 r->uri_start -= offset;
474 r->uri_end -= offset;
475 if (r->uri_ext) {
476 r->uri_ext -= offset;
477 }
478 if (r->args_start) {
479 r->args_start -= offset;
480 }
481
482 } else {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000483 ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_URI,
484 NGX_HTTP_REQUEST_URI_TOO_LARGE);
Igor Sysoev0dad6292003-03-05 17:30:51 +0000485 }
Igor Sysoev1af7c822002-09-13 14:47:42 +0000486 }
487
Igor Sysoev6b863e32003-05-12 15:52:24 +0000488 return;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000489}
490
Igor Sysoev1af7c822002-09-13 14:47:42 +0000491
Igor Sysoev6b863e32003-05-12 15:52:24 +0000492static void ngx_http_process_request_headers(ngx_event_t *rev)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000493{
Igor Sysoev187fcd82003-05-23 11:53:01 +0000494 int rc, i, offset;
Igor Sysoev187fcd82003-05-23 11:53:01 +0000495 ssize_t n;
496 ngx_table_elt_t *h;
497 ngx_connection_t *c;
498 ngx_http_request_t *r;
Igor Sysoev187fcd82003-05-23 11:53:01 +0000499 ngx_http_core_srv_conf_t *cscf;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000500
Igor Sysoeva9830112003-05-19 16:39:14 +0000501 c = rev->data;
502 r = c->data;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000503
504 ngx_log_debug(rev->log, "http process request header line");
505
Igor Sysoev6b863e32003-05-12 15:52:24 +0000506 if (rev->timedout) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000507 ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000508 return;
509 }
510
Igor Sysoev6253ca12003-05-27 12:18:54 +0000511 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
512
Igor Sysoevd581fd52003-05-13 16:02:32 +0000513 rc = NGX_AGAIN;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000514
Igor Sysoev016b8522002-08-29 16:59:54 +0000515 for ( ;; ) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000516 if (rc == NGX_AGAIN) {
517 n = ngx_http_read_request_header(r);
518
519 if (n == NGX_AGAIN || n == NGX_ERROR) {
520 return;
521 }
522 }
523
Igor Sysoeve6779222003-10-03 15:50:53 +0000524 rc = ngx_http_parse_header_line(r, r->header_in);
Igor Sysoev016b8522002-08-29 16:59:54 +0000525
Igor Sysoev0dad6292003-03-05 17:30:51 +0000526 if (rc == NGX_OK) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000527
528 /* a header line has been parsed successfully */
529
Igor Sysoev68ee8f12003-10-30 08:51:06 +0000530 h = ngx_http_add_header(&r->headers_in, ngx_http_headers_in);
531 if (h == NULL) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000532 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
533 ngx_http_close_connection(c);
534 return;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000535 }
536
Igor Sysoevd581fd52003-05-13 16:02:32 +0000537 h->key.len = r->header_name_end - r->header_name_start;
538 h->value.len = r->header_end - r->header_start;
539
540 /* if the large client headers are enabled then
541 we need to copy the header name and value */
542
Igor Sysoev187fcd82003-05-23 11:53:01 +0000543 if (cscf->large_client_header) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000544 h->key.data = ngx_palloc(r->pool,
545 h->key.len + 1 + h->value.len + 1);
546 if (h->key.data == NULL) {
547 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
548 ngx_http_close_connection(c);
549 return;
550 }
551
552 h->value.data = h->key.data + h->key.len + 1;
553 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
554 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
555
556 } else {
557 h->key.data = r->header_name_start;
558 h->key.data[h->key.len] = '\0';
559 h->value.data = r->header_start;
560 h->value.data[h->value.len] = '\0';
561 }
562
Igor Sysoevb5faed22003-10-29 08:30:44 +0000563 for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) {
564 if (ngx_http_headers_in[i].name.len != h->key.len) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000565 continue;
566 }
567
Igor Sysoevb5faed22003-10-29 08:30:44 +0000568 if (ngx_strcasecmp(ngx_http_headers_in[i].name.data,
569 h->key.data) == 0)
570 {
571 *((ngx_table_elt_t **) ((char *) &r->headers_in
572 + ngx_http_headers_in[i].offset)) = h;
Igor Sysoev9760a132003-10-21 07:47:21 +0000573 break;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000574 }
575 }
576
577 ngx_log_debug(r->connection->log, "HTTP header: '%s: %s'" _
578 h->key.data _ h->value.data);
579
Igor Sysoev187fcd82003-05-23 11:53:01 +0000580 if (cscf->large_client_header
Igor Sysoevdc479b42003-03-20 16:09:44 +0000581 && r->header_in->pos == r->header_in->last)
582 {
583 r->header_in->pos = r->header_in->last = r->header_in->start;
Igor Sysoeva19a85e2003-01-28 15:56:37 +0000584 }
585
Igor Sysoev6253ca12003-05-27 12:18:54 +0000586 continue;
587
Igor Sysoev1af7c822002-09-13 14:47:42 +0000588 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000589
590 /* a whole header has been parsed successfully */
591
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000592 ngx_log_debug(r->connection->log, "HTTP header done");
Igor Sysoev42feecb2002-12-15 06:25:09 +0000593
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000594 rc = ngx_http_process_request_header(r);
Igor Sysoeva19a85e2003-01-28 15:56:37 +0000595
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000596 if (rc != NGX_OK) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000597 ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000598 return;
Igor Sysoeva09f08d2003-04-25 14:43:13 +0000599 }
600
Igor Sysoev425a42c2003-10-27 16:16:17 +0000601 if (rev->timer_set) {
Igor Sysoev0a280a32003-10-12 16:49:16 +0000602 ngx_del_timer(rev);
603 }
604
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000605 rev->event_handler = ngx_http_block_read;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000606 ngx_http_handler(r);
607 return;
Igor Sysoevdc479b42003-03-20 16:09:44 +0000608
Igor Sysoev0dad6292003-03-05 17:30:51 +0000609 } else if (rc != NGX_AGAIN) {
Igor Sysoevd581fd52003-05-13 16:02:32 +0000610
611 /* there was error while a header line parsing */
612
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000613 ngx_http_client_error(r, rc, NGX_HTTP_BAD_REQUEST);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000614 return;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000615 }
616
617 /* NGX_AGAIN: a header line parsing is still not complete */
618
Igor Sysoevb7387572003-03-11 20:38:13 +0000619 if (r->header_in->last == r->header_in->end) {
Igor Sysoev0dad6292003-03-05 17:30:51 +0000620
Igor Sysoevb7387572003-03-11 20:38:13 +0000621 /* if the large client headers are enabled then
Igor Sysoev0dad6292003-03-05 17:30:51 +0000622 we need to compact r->header_in hunk */
623
Igor Sysoev187fcd82003-05-23 11:53:01 +0000624 if (cscf->large_client_header) {
Igor Sysoev0dad6292003-03-05 17:30:51 +0000625 offset = r->header_name_start - r->header_in->start;
626
627 if (offset == 0) {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000628 ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_HEADER,
629 NGX_HTTP_BAD_REQUEST);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000630 return;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000631 }
632
633 ngx_memcpy(r->header_in->start, r->header_name_start,
Igor Sysoevb7387572003-03-11 20:38:13 +0000634 r->header_in->last - r->header_name_start);
Igor Sysoev0dad6292003-03-05 17:30:51 +0000635
Igor Sysoevb7387572003-03-11 20:38:13 +0000636 r->header_in->last -= offset;
637 r->header_in->pos -= offset;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000638 r->header_name_start = r->header_in->start;
639 r->header_name_end -= offset;
640 r->header_start -= offset;
641 r->header_end -= offset;
642
643 } else {
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000644 ngx_http_client_error(r, NGX_HTTP_PARSE_TOO_LONG_HEADER,
645 NGX_HTTP_BAD_REQUEST);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000646 return;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000647 }
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000648 }
649 }
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000650}
651
Igor Sysoevb0869052002-12-10 18:05:12 +0000652
Igor Sysoev6b863e32003-05-12 15:52:24 +0000653static ssize_t ngx_http_read_request_header(ngx_http_request_t *r)
654{
Igor Sysoev187fcd82003-05-23 11:53:01 +0000655 ssize_t n;
656 ngx_event_t *rev;
657 ngx_http_core_srv_conf_t *cscf;
Igor Sysoev6b863e32003-05-12 15:52:24 +0000658
Igor Sysoev239baac2003-06-11 15:28:34 +0000659 rev = r->connection->read;
660
Igor Sysoev6b863e32003-05-12 15:52:24 +0000661 n = r->header_in->last - r->header_in->pos;
662
663 if (n > 0) {
664 return n;
665 }
666
Igor Sysoev239baac2003-06-11 15:28:34 +0000667 n = ngx_recv(r->connection, r->header_in->last,
668 r->header_in->end - r->header_in->last);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000669
670 if (n == NGX_AGAIN) {
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000671 if (!r->header_timeout_set) {
Igor Sysoev6253ca12003-05-27 12:18:54 +0000672 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
Igor Sysoev187fcd82003-05-23 11:53:01 +0000673 ngx_add_timer(rev, cscf->client_header_timeout);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000674 r->header_timeout_set = 1;
675 }
676
Igor Sysoevb5faed22003-10-29 08:30:44 +0000677 if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000678 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
679 ngx_http_close_connection(r->connection);
680 return NGX_ERROR;
681 }
682
Igor Sysoev6b863e32003-05-12 15:52:24 +0000683 return NGX_AGAIN;
684 }
685
686 if (n == 0) {
687 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
688 "client closed prematurely connection");
Igor Sysoevd581fd52003-05-13 16:02:32 +0000689 }
Igor Sysoev6b863e32003-05-12 15:52:24 +0000690
691 if (n == 0 || n == NGX_ERROR) {
692 ngx_http_close_request(r, NGX_HTTP_BAD_REQUEST);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000693 ngx_http_close_connection(r->connection);
Igor Sysoev6b863e32003-05-12 15:52:24 +0000694 return NGX_ERROR;
695 }
696
697 r->header_in->last += n;
698
699 return n;
700}
701
702
Igor Sysoev419f9ac2003-10-21 16:49:56 +0000703static int ngx_http_process_request_header(ngx_http_request_t *r)
704{
705 int i;
706 size_t len;
707 ngx_http_server_name_t *name;
708 ngx_http_core_loc_conf_t *clcf;
709
710 if (r->headers_in.host) {
711 for (len = 0; len < r->headers_in.host->value.len; len++) {
712 if (r->headers_in.host->value.data[len] == ':') {
713 break;
714 }
715 }
716 r->headers_in.host_name_len = len;
717
718 /* find the name based server configuration */
719
720 name = r->virtual_names->elts;
721 for (i = 0; i < r->virtual_names->nelts; i++) {
722 if (r->headers_in.host_name_len != name[i].name.len) {
723 continue;
724 }
725
726 if (ngx_strncasecmp(r->headers_in.host->value.data,
727 name[i].name.data,
728 r->headers_in.host_name_len) == 0)
729 {
730 r->srv_conf = name[i].core_srv_conf->ctx->srv_conf;
731 r->loc_conf = name[i].core_srv_conf->ctx->loc_conf;
732
733 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
734 r->connection->log->file = clcf->err_log->file;
735 r->connection->log->log_level = clcf->err_log->log_level;
736
737 break;
738 }
739 }
740
741 } else {
742 if (r->http_version > NGX_HTTP_VERSION_10) {
743 return NGX_HTTP_PARSE_NO_HOST_HEADER;
744 }
745 r->headers_in.host_name_len = 0;
746 }
747
748 if (r->headers_in.content_length) {
749 r->headers_in.content_length_n =
750 ngx_atoi(r->headers_in.content_length->value.data,
751 r->headers_in.content_length->value.len);
752
753 if (r->headers_in.content_length_n == NGX_ERROR) {
754 return NGX_HTTP_PARSE_INVALID_CL_HEADER;
755 }
756 }
757
758 if (r->headers_in.connection) {
759 if (r->headers_in.connection->value.len == 5
760 && ngx_strcasecmp(r->headers_in.connection->value.data, "close")
761 == 0)
762 {
763 r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
764
765 } else if (r->headers_in.connection->value.len == 10
766 && ngx_strcasecmp(r->headers_in.connection->value.data,
767 "keep-alive") == 0)
768 {
769 r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE;
770
771 if (r->headers_in.keep_alive) {
772 r->headers_in.keep_alive_n =
773 ngx_atoi(r->headers_in.keep_alive->value.data,
774 r->headers_in.keep_alive->value.len);
775 }
776 }
777 }
778
779 return NGX_OK;
780}
781
782
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000783void ngx_http_finalize_request(ngx_http_request_t *r, int rc)
Igor Sysoevd581fd52003-05-13 16:02:32 +0000784{
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000785 /* r can be already destroyed when rc == NGX_DONE */
Igor Sysoevd581fd52003-05-13 16:02:32 +0000786
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000787 if (rc == NGX_DONE || r->main) {
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000788 return;
789 }
790
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000791 ngx_log_debug(r->connection->log, "finalize http request");
792
Igor Sysoevd581fd52003-05-13 16:02:32 +0000793 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
794
Igor Sysoev0a280a32003-10-12 16:49:16 +0000795 if (r->connection->read->timer_set) {
796 ngx_del_timer(r->connection->read);
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000797 }
798
Igor Sysoev0a280a32003-10-12 16:49:16 +0000799 if (r->connection->write->timer_set) {
800 ngx_del_timer(r->connection->write);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000801 }
802
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000803 ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc));
Igor Sysoev239baac2003-06-11 15:28:34 +0000804
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000805 return;
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000806
Igor Sysoev239baac2003-06-11 15:28:34 +0000807 } else if (rc == NGX_ERROR) {
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000808 ngx_http_close_request(r, 0);
809 ngx_http_close_connection(r->connection);
810 return;
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000811
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000812 } else if (rc == NGX_AGAIN) {
813 ngx_http_set_write_handler(r);
814 return;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000815 }
816
Igor Sysoev0a280a32003-10-12 16:49:16 +0000817 if (r->connection->read->timer_set) {
818 ngx_del_timer(r->connection->read);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000819 }
820
Igor Sysoev0a280a32003-10-12 16:49:16 +0000821 if (r->connection->write->timer_set) {
822 ngx_del_timer(r->connection->write);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000823 }
824
825 if (r->keepalive != 0) {
826 ngx_http_set_keepalive(r);
827
828 } else if (r->lingering_close) {
829 ngx_http_set_lingering_close(r);
830
831 } else {
832 ngx_http_close_request(r, 0);
833 ngx_http_close_connection(r->connection);
834 }
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000835
836 return;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000837}
838
839
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000840static void ngx_http_set_write_handler(ngx_http_request_t *r)
Igor Sysoevd581fd52003-05-13 16:02:32 +0000841{
Igor Sysoevd581fd52003-05-13 16:02:32 +0000842 ngx_event_t *wev;
Igor Sysoeva9830112003-05-19 16:39:14 +0000843 ngx_http_core_loc_conf_t *clcf;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000844
845 wev = r->connection->write;
846 wev->event_handler = ngx_http_writer;
847
848 if (wev->delayed && wev->ready) {
849 return;
850 }
851
Igor Sysoev6253ca12003-05-27 12:18:54 +0000852 clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
853 ngx_http_core_module);
Igor Sysoeva9830112003-05-19 16:39:14 +0000854 ngx_add_timer(wev, clcf->send_timeout);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000855
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000856 if (ngx_handle_write_event(wev, clcf->send_lowat) == NGX_ERROR) {
857 ngx_http_close_request(r, 0);
858 ngx_http_close_connection(r->connection);
859 }
860
Igor Sysoev1342d9c2003-10-09 07:00:45 +0000861 return;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000862}
863
864
Igor Sysoevb3e73d82003-10-10 15:10:50 +0000865void ngx_http_writer(ngx_event_t *wev)
Igor Sysoevd581fd52003-05-13 16:02:32 +0000866{
867 int rc;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000868 ngx_connection_t *c;
869 ngx_http_request_t *r;
Igor Sysoev6253ca12003-05-27 12:18:54 +0000870 ngx_http_core_loc_conf_t *clcf;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000871
Igor Sysoev6253ca12003-05-27 12:18:54 +0000872 c = wev->data;
873 r = c->data;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000874
Igor Sysoev10fc9ef2003-10-27 08:53:49 +0000875#if 0 /* TODO: THINK */
876 if (wev->delayed) {
877 return;
878 }
879#endif
880
881 if (wev->timedout) {
882 ngx_http_client_error(r, 0, NGX_HTTP_REQUEST_TIME_OUT);
883 return;
884 }
885
Igor Sysoevd581fd52003-05-13 16:02:32 +0000886 rc = ngx_http_output_filter(r, NULL);
887
888 ngx_log_debug(c->log, "writer output filter: %d" _ rc);
889
890 if (rc == NGX_AGAIN) {
Igor Sysoev0a280a32003-10-12 16:49:16 +0000891 if (!wev->ready) {
892 clcf = ngx_http_get_module_loc_conf(r->main ? r->main : r,
893 ngx_http_core_module);
894 ngx_add_timer(wev, clcf->send_timeout);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000895 }
896
Igor Sysoev0a280a32003-10-12 16:49:16 +0000897 if (ngx_handle_level_write_event(wev) == NGX_ERROR) {
898 ngx_http_close_request(r, 0);
899 ngx_http_close_connection(r->connection);
900 }
Igor Sysoevd581fd52003-05-13 16:02:32 +0000901
902 return;
903 }
904
Igor Sysoevd581fd52003-05-13 16:02:32 +0000905 ngx_log_debug(c->log, "http writer done");
906
Igor Sysoev0a280a32003-10-12 16:49:16 +0000907 ngx_http_finalize_request(r, rc);
Igor Sysoevd581fd52003-05-13 16:02:32 +0000908}
909
910
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000911static void ngx_http_block_read(ngx_event_t *rev)
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000912{
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000913 ngx_connection_t *c;
914 ngx_http_request_t *r;
915
916 ngx_log_debug(rev->log, "http read blocked");
Igor Sysoev42feecb2002-12-15 06:25:09 +0000917
Igor Sysoev73009772003-02-06 17:21:13 +0000918 /* aio does not call this handler */
919
Igor Sysoev0a280a32003-10-12 16:49:16 +0000920 if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && rev->active) {
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000921 if (ngx_del_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) {
Igor Sysoev0a280a32003-10-12 16:49:16 +0000922 c = rev->data;
923 r = c->data;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000924 ngx_http_close_request(r, 0);
925 ngx_http_close_connection(c);
926 }
Igor Sysoev73009772003-02-06 17:21:13 +0000927 }
928
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000929 return;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000930}
931
932
Igor Sysoevd581fd52003-05-13 16:02:32 +0000933int ngx_http_discard_body(ngx_http_request_t *r)
934{
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000935 ssize_t size;
936 ngx_event_t *rev;
Igor Sysoevd581fd52003-05-13 16:02:32 +0000937
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000938 rev = r->connection->read;
Igor Sysoev9b25d692003-01-26 21:08:14 +0000939
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000940 ngx_log_debug(rev->log, "set discard body");
Igor Sysoev9b25d692003-01-26 21:08:14 +0000941
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000942 if (rev->timer_set) {
943 ngx_del_timer(rev);
Igor Sysoev9b25d692003-01-26 21:08:14 +0000944 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000945
Igor Sysoev0a280a32003-10-12 16:49:16 +0000946 if (r->headers_in.content_length_n <= 0) {
947 return NGX_OK;
948 }
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000949
Igor Sysoev0a280a32003-10-12 16:49:16 +0000950 size = r->header_in->last - r->header_in->pos;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000951
Igor Sysoev0a280a32003-10-12 16:49:16 +0000952 if (size) {
953 if (r->headers_in.content_length_n > size) {
954 r->headers_in.content_length_n -= size;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000955
Igor Sysoev0a280a32003-10-12 16:49:16 +0000956 } else {
957 r->header_in->pos += r->headers_in.content_length_n;
958 r->headers_in.content_length_n = 0;
959 return NGX_OK;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000960 }
Igor Sysoev73009772003-02-06 17:21:13 +0000961 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000962
Igor Sysoev0a280a32003-10-12 16:49:16 +0000963 rev->event_handler = ngx_http_read_discarded_body_event;
964
965 if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
966 return NGX_HTTP_INTERNAL_SERVER_ERROR;
967 }
968
969 return ngx_http_read_discarded_body(r);
970
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000971 return NGX_OK;
972}
973
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000974
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000975static void ngx_http_read_discarded_body_event(ngx_event_t *rev)
Igor Sysoev42feecb2002-12-15 06:25:09 +0000976{
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000977 int rc;
978 ngx_connection_t *c;
979 ngx_http_request_t *r;
980
Igor Sysoev6253ca12003-05-27 12:18:54 +0000981 c = rev->data;
982 r = c->data;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000983
984 rc = ngx_http_read_discarded_body(r);
985
Igor Sysoev0a280a32003-10-12 16:49:16 +0000986 if (rc == NGX_AGAIN) {
987 if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
988 ngx_http_close_request(r, rc);
989 ngx_http_close_connection(c);
990 return;
991 }
992 }
993
Igor Sysoev6ddfbf02003-05-15 15:42:53 +0000994 if (rc != NGX_OK) {
995 ngx_http_close_request(r, rc);
996 ngx_http_close_connection(c);
997 }
998}
999
1000
1001static int ngx_http_read_discarded_body(ngx_http_request_t *r)
1002{
Igor Sysoev09159772003-06-12 05:54:39 +00001003 ssize_t size, n;
Igor Sysoev6253ca12003-05-27 12:18:54 +00001004 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev42feecb2002-12-15 06:25:09 +00001005
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001006 ngx_log_debug(r->connection->log, "http read discarded body");
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001007
Igor Sysoev0a280a32003-10-12 16:49:16 +00001008 if (r->headers_in.content_length_n == 0) {
1009 return NGX_OK;
1010 }
1011
Igor Sysoev6253ca12003-05-27 12:18:54 +00001012 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001013
Igor Sysoevdc479b42003-03-20 16:09:44 +00001014 if (r->discarded_buffer == NULL) {
Igor Sysoev6253ca12003-05-27 12:18:54 +00001015 r->discarded_buffer = ngx_palloc(r->pool, clcf->discarded_buffer_size);
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001016 if (r->discarded_buffer == NULL) {
1017 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1018 }
Igor Sysoevdc479b42003-03-20 16:09:44 +00001019 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001020
Igor Sysoeva09f08d2003-04-25 14:43:13 +00001021 size = r->headers_in.content_length_n;
Igor Sysoev0a280a32003-10-12 16:49:16 +00001022
Igor Sysoev6253ca12003-05-27 12:18:54 +00001023 if (size > clcf->discarded_buffer_size) {
1024 size = clcf->discarded_buffer_size;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001025 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001026
Igor Sysoev239baac2003-06-11 15:28:34 +00001027 n = ngx_recv(r->connection, r->discarded_buffer, size);
Igor Sysoevdc479b42003-03-20 16:09:44 +00001028 if (n == NGX_ERROR) {
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001029 return NGX_HTTP_BAD_REQUEST;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001030 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001031
Igor Sysoevdc479b42003-03-20 16:09:44 +00001032 if (n == NGX_AGAIN) {
Igor Sysoev0a280a32003-10-12 16:49:16 +00001033 return NGX_AGAIN;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001034 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001035
Igor Sysoeva09f08d2003-04-25 14:43:13 +00001036 r->headers_in.content_length_n -= n;
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001037
Igor Sysoev42feecb2002-12-15 06:25:09 +00001038 return NGX_OK;
1039}
1040
1041
Igor Sysoevd581fd52003-05-13 16:02:32 +00001042static void ngx_http_set_keepalive(ngx_http_request_t *r)
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001043{
Igor Sysoev0a280a32003-10-12 16:49:16 +00001044 int len;
Igor Sysoev187fcd82003-05-23 11:53:01 +00001045 ngx_hunk_t *h;
1046 ngx_event_t *rev, *wev;
1047 ngx_connection_t *c;
1048 ngx_http_log_ctx_t *ctx;
1049 ngx_http_core_srv_conf_t *cscf;
1050 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001051
Igor Sysoev6253ca12003-05-27 12:18:54 +00001052 c = r->connection;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001053 rev = c->read;
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001054
Igor Sysoev6a1cc902003-05-22 15:23:47 +00001055 ngx_log_debug(c->log, "set http keepalive handler");
1056
Igor Sysoev6a644c62003-03-04 06:33:48 +00001057 ctx = (ngx_http_log_ctx_t *) c->log->data;
1058 ctx->action = "closing request";
Igor Sysoevdc479b42003-03-20 16:09:44 +00001059 ngx_http_close_request(r, 0);
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001060
Igor Sysoev6253ca12003-05-27 12:18:54 +00001061 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoevfa73aac2003-05-21 13:28:21 +00001062 ngx_add_timer(rev, clcf->keepalive_timeout);
1063
Igor Sysoev0a280a32003-10-12 16:49:16 +00001064 if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
1065 ngx_http_close_connection(c);
1066 return;
Igor Sysoevb7387572003-03-11 20:38:13 +00001067 }
1068
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001069 h = c->buffer;
1070
Igor Sysoevb7387572003-03-11 20:38:13 +00001071 if (h->pos < h->last) {
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001072
Igor Sysoev74e95c22003-11-09 20:03:38 +00001073 /*
1074 * Pipelined request.
Igor Sysoev0a280a32003-10-12 16:49:16 +00001075 *
1076 * We do not know here whether a pipelined request is complete
1077 * so if the large client headers are not enabled
1078 * we need to copy the data to the start of c->buffer.
1079 * This copy should be rare because clients that support
1080 * pipelined requests (Mozilla 1.x, Opera 6.x+) are still rare.
1081 */
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001082
Igor Sysoev6253ca12003-05-27 12:18:54 +00001083 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
Igor Sysoeva9830112003-05-19 16:39:14 +00001084
Igor Sysoev187fcd82003-05-23 11:53:01 +00001085 if (!cscf->large_client_header) {
1086 len = h->last - h->pos;
Igor Sysoevb7387572003-03-11 20:38:13 +00001087 ngx_memcpy(h->start, h->pos, len);
1088 h->pos = h->start;
1089 h->last = h->start + len;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001090 }
1091
Igor Sysoev6253ca12003-05-27 12:18:54 +00001092 ngx_log_debug(c->log, "pipelined request");
1093
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001094 c->pipeline = 1;
1095 ctx->action = "reading client pipelined request line";
Igor Sysoevd581fd52003-05-13 16:02:32 +00001096 ngx_http_init_request(rev);
1097 return;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001098 }
1099
1100 c->pipeline = 0;
1101
Igor Sysoevb7387572003-03-11 20:38:13 +00001102 h->pos = h->last = h->start;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001103 rev->event_handler = ngx_http_keepalive_handler;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001104 wev = c->write;
Igor Sysoev0a280a32003-10-12 16:49:16 +00001105 wev->event_handler = ngx_http_empty_handler;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001106
Igor Sysoev0a280a32003-10-12 16:49:16 +00001107 if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && wev->active) {
1108 if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
1109 ngx_http_close_connection(c);
1110 return;
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001111 }
1112 }
1113
Igor Sysoev6a644c62003-03-04 06:33:48 +00001114 ctx->action = "keepalive";
1115
Igor Sysoev9cf78302003-06-04 17:28:33 +00001116 if (c->tcp_nopush) {
1117 if (ngx_tcp_push(c->fd) == NGX_ERROR) {
1118 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
1119 ngx_tcp_push_n " failed");
1120 ngx_http_close_connection(c);
1121 return;
1122 }
1123 c->tcp_nopush = 0;
1124 }
1125
Igor Sysoevb5faed22003-10-29 08:30:44 +00001126 if (rev->ready) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001127 ngx_http_keepalive_handler(rev);
Igor Sysoevb7387572003-03-11 20:38:13 +00001128 }
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001129}
1130
1131
Igor Sysoevd581fd52003-05-13 16:02:32 +00001132static void ngx_http_keepalive_handler(ngx_event_t *rev)
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001133{
Igor Sysoev0a280a32003-10-12 16:49:16 +00001134 ssize_t n;
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001135 ngx_connection_t *c;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001136 ngx_http_log_ctx_t *lctx;
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001137
Igor Sysoevdc479b42003-03-20 16:09:44 +00001138 c = (ngx_connection_t *) rev->data;
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001139
Igor Sysoevdc479b42003-03-20 16:09:44 +00001140 ngx_log_debug(c->log, "http keepalive handler");
Igor Sysoev1af7c822002-09-13 14:47:42 +00001141
Igor Sysoevdc479b42003-03-20 16:09:44 +00001142 if (rev->timedout) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001143 ngx_http_close_connection(c);
1144 return;
Igor Sysoev90ace682003-03-12 17:32:22 +00001145 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001146
Igor Sysoev0a280a32003-10-12 16:49:16 +00001147 /*
1148 * MSIE closes a keepalive connection with RST flag
1149 * so we ignore ECONNRESET here.
1150 */
Igor Sysoevb7387572003-03-11 20:38:13 +00001151
Igor Sysoevdc479b42003-03-20 16:09:44 +00001152 rev->ignore_econnreset = 1;
Igor Sysoevb7387572003-03-11 20:38:13 +00001153 ngx_set_socket_errno(0);
Igor Sysoev239baac2003-06-11 15:28:34 +00001154 n = ngx_recv(c, c->buffer->last, c->buffer->end - c->buffer->last);
Igor Sysoevdc479b42003-03-20 16:09:44 +00001155 rev->ignore_econnreset = 0;
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001156
Igor Sysoevd581fd52003-05-13 16:02:32 +00001157 if (n == NGX_AGAIN) {
1158 return;
1159 }
1160
1161 if (n == NGX_ERROR) {
1162 ngx_http_close_connection(c);
1163 return;
Igor Sysoev90ace682003-03-12 17:32:22 +00001164 }
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001165
Igor Sysoevdc479b42003-03-20 16:09:44 +00001166 lctx = (ngx_http_log_ctx_t *) rev->log->data;
1167 rev->log->handler = NULL;
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001168
1169 if (n == 0) {
Igor Sysoevdc479b42003-03-20 16:09:44 +00001170 ngx_log_error(NGX_LOG_INFO, c->log, ngx_socket_errno,
1171 "client %s closed keepalive connection", lctx->client);
Igor Sysoevd581fd52003-05-13 16:02:32 +00001172 ngx_http_close_connection(c);
1173 return;
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001174 }
1175
Igor Sysoevb7387572003-03-11 20:38:13 +00001176 c->buffer->last += n;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001177 rev->log->handler = ngx_http_log_error;
1178 lctx->action = "reading client request line";
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001179
Igor Sysoevd581fd52003-05-13 16:02:32 +00001180 ngx_http_init_request(rev);
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001181}
1182
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001183
Igor Sysoevd581fd52003-05-13 16:02:32 +00001184static void ngx_http_set_lingering_close(ngx_http_request_t *r)
Igor Sysoev1af7c822002-09-13 14:47:42 +00001185{
Igor Sysoev0a280a32003-10-12 16:49:16 +00001186 ngx_event_t *rev, *wev;
Igor Sysoevb7387572003-03-11 20:38:13 +00001187 ngx_connection_t *c;
Igor Sysoev6253ca12003-05-27 12:18:54 +00001188 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001189
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001190 c = r->connection;
Igor Sysoev9b25d692003-01-26 21:08:14 +00001191
Igor Sysoev6253ca12003-05-27 12:18:54 +00001192 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001193
Igor Sysoev0a280a32003-10-12 16:49:16 +00001194 rev = c->read;
Igor Sysoevd581fd52003-05-13 16:02:32 +00001195 rev->event_handler = ngx_http_lingering_close_handler;
Igor Sysoev42feecb2002-12-15 06:25:09 +00001196
Igor Sysoev0a280a32003-10-12 16:49:16 +00001197 r->lingering_time = ngx_time() + clcf->lingering_time / 1000;
Igor Sysoev6253ca12003-05-27 12:18:54 +00001198 ngx_add_timer(rev, clcf->lingering_timeout);
Igor Sysoev9b25d692003-01-26 21:08:14 +00001199
Igor Sysoev0a280a32003-10-12 16:49:16 +00001200 if (ngx_handle_level_read_event(rev) == NGX_ERROR) {
1201 ngx_http_close_request(r, 0);
1202 ngx_http_close_connection(c);
1203 return;
1204 }
1205
1206 wev = c->write;
1207 wev->event_handler = ngx_http_empty_handler;
1208
1209 if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && wev->active) {
1210 if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001211 ngx_http_close_request(r, 0);
1212 ngx_http_close_connection(c);
1213 return;
Igor Sysoevb7387572003-03-11 20:38:13 +00001214 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001215 }
1216
Igor Sysoevb7387572003-03-11 20:38:13 +00001217 if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
1218 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
Igor Sysoev42feecb2002-12-15 06:25:09 +00001219 ngx_shutdown_socket_n " failed");
Igor Sysoevd581fd52003-05-13 16:02:32 +00001220 ngx_http_close_request(r, 0);
1221 ngx_http_close_connection(c);
1222 return;
Igor Sysoev42feecb2002-12-15 06:25:09 +00001223 }
1224
Igor Sysoevb5faed22003-10-29 08:30:44 +00001225 if (rev->ready) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001226 ngx_http_lingering_close_handler(rev);
Igor Sysoevb7387572003-03-11 20:38:13 +00001227 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001228}
1229
1230
Igor Sysoevd581fd52003-05-13 16:02:32 +00001231static void ngx_http_lingering_close_handler(ngx_event_t *rev)
Igor Sysoev42feecb2002-12-15 06:25:09 +00001232{
Igor Sysoevdc479b42003-03-20 16:09:44 +00001233 ssize_t n;
1234 ngx_msec_t timer;
1235 ngx_connection_t *c;
1236 ngx_http_request_t *r;
Igor Sysoev6253ca12003-05-27 12:18:54 +00001237 ngx_http_core_loc_conf_t *clcf;
Igor Sysoev1af7c822002-09-13 14:47:42 +00001238
Igor Sysoev6253ca12003-05-27 12:18:54 +00001239 c = rev->data;
1240 r = c->data;
Igor Sysoev86de4cb2003-01-30 07:28:09 +00001241
Igor Sysoevdc479b42003-03-20 16:09:44 +00001242 ngx_log_debug(c->log, "http lingering close handler");
1243
1244 if (rev->timedout) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001245 ngx_http_close_request(r, 0);
1246 ngx_http_close_connection(c);
1247 return;
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001248 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001249
Igor Sysoev1af7c822002-09-13 14:47:42 +00001250 timer = r->lingering_time - ngx_time();
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001251 if (timer <= 0) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001252 ngx_http_close_request(r, 0);
1253 ngx_http_close_connection(c);
1254 return;
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001255 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001256
Igor Sysoev6253ca12003-05-27 12:18:54 +00001257 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001258
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001259 if (r->discarded_buffer == NULL) {
Igor Sysoevb7387572003-03-11 20:38:13 +00001260
1261 /* TODO: r->header_in->start (if large headers are enabled)
1262 or the end of parsed header (otherwise)
1263 instead of r->header_in->last */
1264
Igor Sysoev09159772003-06-12 05:54:39 +00001265 if (r->header_in->end - r->header_in->last
Igor Sysoev6253ca12003-05-27 12:18:54 +00001266 >= clcf->discarded_buffer_size) {
Igor Sysoevb7387572003-03-11 20:38:13 +00001267 r->discarded_buffer = r->header_in->last;
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001268
1269 } else {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001270 r->discarded_buffer = ngx_palloc(c->pool,
Igor Sysoev6253ca12003-05-27 12:18:54 +00001271 clcf->discarded_buffer_size);
Igor Sysoevd581fd52003-05-13 16:02:32 +00001272 if (r->discarded_buffer) {
1273 ngx_http_close_request(r, 0);
1274 ngx_http_close_connection(c);
1275 return;
1276 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001277 }
1278 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001279
Igor Sysoevdc479b42003-03-20 16:09:44 +00001280 do {
Igor Sysoev239baac2003-06-11 15:28:34 +00001281 n = ngx_recv(c, r->discarded_buffer, clcf->discarded_buffer_size);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001282
Igor Sysoevdc479b42003-03-20 16:09:44 +00001283 ngx_log_debug(c->log, "lingering read: %d" _ n);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001284
Igor Sysoevdc479b42003-03-20 16:09:44 +00001285 if (n == NGX_ERROR || n == 0) {
Igor Sysoevd581fd52003-05-13 16:02:32 +00001286 ngx_http_close_request(r, 0);
1287 ngx_http_close_connection(c);
1288 return;
Igor Sysoevdc479b42003-03-20 16:09:44 +00001289 }
1290
1291 } while (rev->ready);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001292
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001293 timer *= 1000;
Igor Sysoev6253ca12003-05-27 12:18:54 +00001294 if (timer > clcf->lingering_timeout) {
1295 timer = clcf->lingering_timeout;
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001296 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001297
Igor Sysoevdc479b42003-03-20 16:09:44 +00001298 ngx_add_timer(rev, timer);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001299
Igor Sysoevd581fd52003-05-13 16:02:32 +00001300 return;
Igor Sysoev1af7c822002-09-13 14:47:42 +00001301}
1302
Igor Sysoev2b542382002-08-20 14:48:28 +00001303
Igor Sysoev6a1cc902003-05-22 15:23:47 +00001304static void ngx_http_empty_handler(ngx_event_t *wev)
1305{
Igor Sysoev0a280a32003-10-12 16:49:16 +00001306 ngx_log_debug(wev->log, "http EMPTY handler");
Igor Sysoev6a1cc902003-05-22 15:23:47 +00001307
1308 return;
1309}
1310
1311
Igor Sysoev1342d9c2003-10-09 07:00:45 +00001312int ngx_http_send_last(ngx_http_request_t *r)
1313{
Igor Sysoev419f9ac2003-10-21 16:49:56 +00001314 ngx_hunk_t *h;
1315 ngx_chain_t out;
Igor Sysoev1342d9c2003-10-09 07:00:45 +00001316
1317 ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
1318 h->type = NGX_HUNK_LAST;
Igor Sysoev419f9ac2003-10-21 16:49:56 +00001319 out.hunk = h;
1320 out.next = NULL;
Igor Sysoev1342d9c2003-10-09 07:00:45 +00001321
Igor Sysoev419f9ac2003-10-21 16:49:56 +00001322 return ngx_http_output_filter(r, &out);
Igor Sysoev1342d9c2003-10-09 07:00:45 +00001323}
1324
1325
Igor Sysoevd581fd52003-05-13 16:02:32 +00001326void ngx_http_close_request(ngx_http_request_t *r, int error)
1327{
1328 ngx_http_log_ctx_t *ctx;
1329
1330 ngx_log_debug(r->connection->log, "close http request");
1331
1332 if (r->pool == NULL) {
1333 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
Igor Sysoev6ddfbf02003-05-15 15:42:53 +00001334 "http request already closed");
Igor Sysoevd581fd52003-05-13 16:02:32 +00001335 return;
1336 }
1337
1338 if (error) {
1339 r->headers_out.status = error;
1340 }
1341
1342 ngx_http_log_handler(r);
1343
1344 if (r->file.fd != NGX_INVALID_FILE) {
1345 if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) {
1346 ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
1347 ngx_close_file_n " \"%s\" failed", r->file.name.data);
1348 }
1349 }
1350
1351 /* ctx->url was allocated from r->pool */
Igor Sysoev0a280a32003-10-12 16:49:16 +00001352 ctx = r->connection->log->data;
Igor Sysoevd581fd52003-05-13 16:02:32 +00001353 ctx->url = NULL;
1354
1355 ngx_destroy_pool(r->pool);
Igor Sysoevb3e73d82003-10-10 15:10:50 +00001356
Igor Sysoevb3e73d82003-10-10 15:10:50 +00001357 return;
Igor Sysoevd581fd52003-05-13 16:02:32 +00001358}
1359
1360
1361void ngx_http_close_connection(ngx_connection_t *c)
Igor Sysoev6b863e32003-05-12 15:52:24 +00001362{
1363 ngx_log_debug(c->log, "close connection: %d" _ c->fd);
1364
Igor Sysoevd581fd52003-05-13 16:02:32 +00001365 if (c->pool == NULL) {
Igor Sysoev6b863e32003-05-12 15:52:24 +00001366 ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
1367 return;
1368 }
1369
1370 if (c->read->timer_set) {
1371 ngx_del_timer(c->read);
Igor Sysoev6b863e32003-05-12 15:52:24 +00001372 }
1373
Igor Sysoev6b863e32003-05-12 15:52:24 +00001374 if (c->write->timer_set) {
1375 ngx_del_timer(c->write);
Igor Sysoev6b863e32003-05-12 15:52:24 +00001376 }
1377
Igor Sysoev6253ca12003-05-27 12:18:54 +00001378 if (ngx_del_conn) {
Igor Sysoev6a1cc902003-05-22 15:23:47 +00001379 ngx_del_conn(c);
1380
1381 } else {
1382 if (c->read->active) {
1383 ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
1384 }
1385
1386 if (c->write->active) {
1387 ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
1388 }
Igor Sysoev6b863e32003-05-12 15:52:24 +00001389 }
1390
1391 if (ngx_close_socket(c->fd) == -1) {
1392 ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno,
1393 ngx_close_socket_n " failed");
1394 }
1395
1396 c->fd = -1;
1397
1398 ngx_destroy_pool(c->pool);
Igor Sysoevb3e73d82003-10-10 15:10:50 +00001399
1400 return;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +00001401}
1402
1403
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001404static void ngx_http_client_error(ngx_http_request_t *r,
1405 int client_error, int error)
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001406{
1407 ngx_http_log_ctx_t *ctx;
1408
1409 ctx = r->connection->log->data;
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001410
1411 if (error == NGX_HTTP_REQUEST_TIME_OUT) {
1412 ngx_log_error(NGX_LOG_INFO, r->connection->log, NGX_ETIMEDOUT,
1413 "client timed out");
1414 ngx_http_close_request(r, error);
1415 ngx_http_close_connection(r->connection);
1416 return;
1417 }
1418
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001419 r->connection->log->handler = NULL;
1420
1421 if (ctx->url) {
1422 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001423 client_header_errors[client_error - NGX_HTTP_CLIENT_ERROR],
1424 ctx->client, ctx->url);
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001425
1426 } else {
1427 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
Igor Sysoev10fc9ef2003-10-27 08:53:49 +00001428 client_header_errors[client_error - NGX_HTTP_CLIENT_ERROR],
1429 ctx->client);
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001430 }
1431
1432 r->connection->log->handler = ngx_http_log_error;
Igor Sysoev0a280a32003-10-12 16:49:16 +00001433
1434 ngx_http_finalize_request(r, error);
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001435}
1436
1437
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001438static size_t ngx_http_log_error(void *data, char *buf, size_t len)
1439{
1440 ngx_http_log_ctx_t *ctx = (ngx_http_log_ctx_t *) data;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +00001441
Igor Sysoev7578ec92003-06-02 15:24:30 +00001442 if (ctx->action && ctx->url) {
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001443 return ngx_snprintf(buf, len, " while %s, client: %s, URL: %s",
1444 ctx->action, ctx->client, ctx->url);
Igor Sysoev7578ec92003-06-02 15:24:30 +00001445
1446 } else if (ctx->action == NULL && ctx->url) {
1447 return ngx_snprintf(buf, len, ", client: %s, URL: %s",
1448 ctx->client, ctx->url);
1449
Igor Sysoevdc479b42003-03-20 16:09:44 +00001450 } else {
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001451 return ngx_snprintf(buf, len, " while %s, client: %s",
1452 ctx->action, ctx->client);
Igor Sysoevdc479b42003-03-20 16:09:44 +00001453 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00001454}