blob: fa17f7248fa5d06dcb476fc198b54e8e50bd4683 [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>
4#include <ngx_string.h>
Igor Sysoeva58e3ca2002-09-02 14:48:24 +00005#include <ngx_files.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00006#include <ngx_log.h>
7#include <ngx_alloc.h>
Igor Sysoeva0bb31f2002-12-02 16:09:40 +00008#include <ngx_array.h>
9#include <ngx_table.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000010#include <ngx_hunk.h>
11#include <ngx_connection.h>
Igor Sysoevfcce8d52003-01-23 18:47:54 +000012#include <ngx_event.h>
13#include <ngx_event_timer.h>
Igor Sysoev42feecb2002-12-15 06:25:09 +000014#include <ngx_inet.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000015#include <ngx_http.h>
Igor Sysoeve0268b92002-09-11 15:18:33 +000016#include <ngx_http_config.h>
Igor Sysoev4e9393a2003-01-09 05:36:00 +000017#include <ngx_http_core_module.h>
Igor Sysoev73009772003-02-06 17:21:13 +000018#include <ngx_http_output_filter.h>
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000019
Igor Sysoeva58e3ca2002-09-02 14:48:24 +000020
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000021static int ngx_http_init_request(ngx_event_t *ev);
Igor Sysoevb0869052002-12-10 18:05:12 +000022static int ngx_http_process_request_header(ngx_event_t *ev);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000023
Igor Sysoev016b8522002-08-29 16:59:54 +000024static int ngx_http_process_request_line(ngx_http_request_t *r);
Igor Sysoevb0869052002-12-10 18:05:12 +000025static int ngx_http_process_request_headers(ngx_http_request_t *r);
Igor Sysoeva58e3ca2002-09-02 14:48:24 +000026static int ngx_http_process_request_header_line(ngx_http_request_t *r);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000027
Igor Sysoev42feecb2002-12-15 06:25:09 +000028static int ngx_http_event_request_handler(ngx_http_request_t *r);
Igor Sysoeva58e3ca2002-09-02 14:48:24 +000029
30static int ngx_http_writer(ngx_event_t *ev);
Igor Sysoev42feecb2002-12-15 06:25:09 +000031static int ngx_http_block_read(ngx_event_t *ev);
32static int ngx_http_read_discarded_body(ngx_event_t *ev);
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +000033static int ngx_http_set_keepalive(ngx_http_request_t *r);
Igor Sysoev1af7c822002-09-13 14:47:42 +000034static int ngx_http_keepalive_handler(ngx_event_t *ev);
Igor Sysoev42feecb2002-12-15 06:25:09 +000035static int ngx_http_set_lingering_close(ngx_http_request_t *r);
36static int ngx_http_lingering_close_handler(ngx_event_t *ev);
Igor Sysoev3a40d482002-09-12 14:42:29 +000037
Igor Sysoev2ba1ee02002-10-04 17:58:04 +000038static int ngx_http_close_connection(ngx_event_t *ev);
Igor Sysoev3d062ad2003-03-05 06:37:42 +000039static int ngx_http_header_parse_error(ngx_http_request_t *r,
40 int parse_err, int err);
Igor Sysoev0ad17c02002-08-26 15:18:19 +000041static size_t ngx_http_log_error(void *data, char *buf, size_t len);
42
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000043
Igor Sysoev0ad17c02002-08-26 15:18:19 +000044
Igor Sysoev016b8522002-08-29 16:59:54 +000045static char *header_errors[] = {
46 "client %s sent invalid method",
47 "client %s sent invalid request",
Igor Sysoev1af7c822002-09-13 14:47:42 +000048 "client %s sent too long URI",
Igor Sysoev6a644c62003-03-04 06:33:48 +000049 "client %s sent HEAD method in HTTP/0.9 request",
50
51 "client %s sent invalid header, URL: %s",
52 "client %s sent too long header line, URL: %s",
53 "client %s sent HTTP/1.1 request without \"Host\" header, URL: %s"
Igor Sysoev016b8522002-08-29 16:59:54 +000054};
55
56
Igor Sysoev6a644c62003-03-04 06:33:48 +000057
Igor Sysoeva0bb31f2002-12-02 16:09:40 +000058static ngx_http_header_t headers_in[] = {
59 { 4, "Host", offsetof(ngx_http_headers_in_t, host) },
60 { 10, "Connection", offsetof(ngx_http_headers_in_t, connection) },
Igor Sysoev42feecb2002-12-15 06:25:09 +000061 { 17, "If-Modified-Since",
62 offsetof(ngx_http_headers_in_t,if_modified_since) },
Igor Sysoeva0bb31f2002-12-02 16:09:40 +000063
64 { 10, "User-Agent", offsetof(ngx_http_headers_in_t, user_agent) },
65
66 { 0, NULL, 0 }
67};
68
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000069
70int ngx_http_init_connection(ngx_connection_t *c)
71{
Igor Sysoev0ad17c02002-08-26 15:18:19 +000072 ngx_event_t *ev;
Igor Sysoev0ad17c02002-08-26 15:18:19 +000073 ngx_http_log_ctx_t *ctx;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000074
75 ev = c->read;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000076 ev->event_handler = ngx_http_init_request;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +000077
Igor Sysoev2ba1ee02002-10-04 17:58:04 +000078 ev->close_handler = ngx_http_close_connection;
79 c->write->close_handler = ngx_http_close_connection;
80
Igor Sysoev4e9393a2003-01-09 05:36:00 +000081 ngx_test_null(c->addr_text.data, ngx_palloc(c->pool, c->addr_text_max_len),
Igor Sysoev0ad17c02002-08-26 15:18:19 +000082 NGX_ERROR);
Igor Sysoevb0869052002-12-10 18:05:12 +000083
Igor Sysoev86de4cb2003-01-30 07:28:09 +000084 c->addr_text.len = ngx_sock_ntop(c->family, c->sockaddr,
Igor Sysoev4e9393a2003-01-09 05:36:00 +000085 c->addr_text.data, c->addr_text_max_len);
Igor Sysoev86de4cb2003-01-30 07:28:09 +000086
87 if (c->addr_text.len == 0) {
88 return NGX_ERROR;
89 }
Igor Sysoev0ad17c02002-08-26 15:18:19 +000090
91 ngx_test_null(ctx, ngx_pcalloc(c->pool, sizeof(ngx_http_log_ctx_t)),
92 NGX_ERROR);
Igor Sysoevb0869052002-12-10 18:05:12 +000093 ctx->client = c->addr_text.data;
Igor Sysoev0ad17c02002-08-26 15:18:19 +000094 ctx->action = "reading client request line";
95 c->log->data = ctx;
96 c->log->handler = ngx_http_log_error;
97
Igor Sysoev6de5c2c2002-08-06 16:39:45 +000098#if (HAVE_DEFERRED_ACCEPT)
Igor Sysoev73009772003-02-06 17:21:13 +000099
Igor Sysoev016b8522002-08-29 16:59:54 +0000100 if (ev->ready) {
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000101 return ngx_http_init_request(ev);
Igor Sysoev016b8522002-08-29 16:59:54 +0000102 }
Igor Sysoev73009772003-02-06 17:21:13 +0000103
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000104#endif
Igor Sysoev9b25d692003-01-26 21:08:14 +0000105
106 ngx_add_timer(ev, c->post_accept_timeout);
107 ev->timer_set = 1;
108
109#if (USE_KQUEUE)
110
111 return ngx_add_event(ev, NGX_READ_EVENT, NGX_CLEAR_EVENT);
112
113#else
114
Igor Sysoev73009772003-02-06 17:21:13 +0000115#if (HAVE_CLEAR_EVENT) /* kqueue */
116
Igor Sysoev9b25d692003-01-26 21:08:14 +0000117 if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
118 return ngx_add_event(ev, NGX_READ_EVENT, NGX_CLEAR_EVENT);
119 }
Igor Sysoev73009772003-02-06 17:21:13 +0000120
Igor Sysoev9b25d692003-01-26 21:08:14 +0000121#endif
122
Igor Sysoev6a644c62003-03-04 06:33:48 +0000123#if (HAVE_EDGE_EVENT) /* epoll */ || (HAVE_AIO_EVENT) /* aio, iocp */
Igor Sysoev73009772003-02-06 17:21:13 +0000124
Igor Sysoev6a644c62003-03-04 06:33:48 +0000125 if (ngx_event_flags & (NGX_HAVE_EDGE_EVENT|NGX_HAVE_AIO_EVENT)) {
Igor Sysoev9b25d692003-01-26 21:08:14 +0000126 return ngx_http_init_request(ev);
127 }
Igor Sysoev73009772003-02-06 17:21:13 +0000128
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000129#endif
Igor Sysoev73009772003-02-06 17:21:13 +0000130
131 /* select, poll, /dev/poll */
Igor Sysoev9b25d692003-01-26 21:08:14 +0000132
133 return ngx_add_event(ev, NGX_READ_EVENT, NGX_LEVEL_EVENT);
134
135#endif /* USE_KQUEUE */
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000136}
137
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000138
Igor Sysoev1af7c822002-09-13 14:47:42 +0000139static int ngx_http_init_request(ngx_event_t *ev)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000140{
Igor Sysoev86de4cb2003-01-30 07:28:09 +0000141 ngx_connection_t *c;
142 ngx_http_request_t *r;
143 ngx_http_conf_ctx_t *ctx;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000144
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000145 c = (ngx_connection_t *) ev->data;
Igor Sysoevad22e012003-01-15 07:02:27 +0000146 c->sent = 0;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000147
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000148 ngx_test_null(r, ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)),
149 NGX_ERROR);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000150
151 c->data = r;
152 r->connection = c;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000153 r->file.fd = NGX_INVALID_FILE;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000154
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000155 if (c->buffer == NULL) {
156 ngx_test_null(c->buffer,
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000157 ngx_create_temp_hunk(c->pool,
158 ngx_http_client_header_buffer_size,
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000159 0, 0),
160 NGX_ERROR);
161 } else {
162 r->header_read = 1;
163 }
164
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000165 r->pipeline = c->pipeline;
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000166 r->header_in = c->buffer;
167
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000168 ngx_test_null(r->pool, ngx_create_pool(ngx_http_request_pool_size, ev->log),
Igor Sysoev016b8522002-08-29 16:59:54 +0000169 ngx_http_close_request(r));
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000170
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000171 ngx_test_null(r->ctx,
172 ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module),
Igor Sysoeve0268b92002-09-11 15:18:33 +0000173 ngx_http_close_request(r));
174
Igor Sysoev86de4cb2003-01-30 07:28:09 +0000175 ctx = (ngx_http_conf_ctx_t *) c->ctx;
176 r->srv_conf = ctx->srv_conf;
177 r->loc_conf = ctx->loc_conf;
178
Igor Sysoev42feecb2002-12-15 06:25:09 +0000179 r->headers_out.headers = ngx_create_table(r->pool, 10);
180 r->headers_out.content_length = -1;
181 r->headers_out.last_modified_time = -1;
182
Igor Sysoevb0869052002-12-10 18:05:12 +0000183 ev->event_handler = ngx_http_process_request_header;
Igor Sysoev016b8522002-08-29 16:59:54 +0000184 r->state_handler = ngx_http_process_request_line;
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000185
Igor Sysoevb0869052002-12-10 18:05:12 +0000186 return ngx_http_process_request_header(ev);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000187}
188
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000189
Igor Sysoevb0869052002-12-10 18:05:12 +0000190static int ngx_http_process_request_header(ngx_event_t *ev)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000191{
Igor Sysoevb7387572003-03-11 20:38:13 +0000192 int n, rc, again;
Igor Sysoev9b25d692003-01-26 21:08:14 +0000193 ngx_connection_t *c;
194 ngx_http_request_t *r;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000195 ngx_http_log_ctx_t *ctx;
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000196
197 c = (ngx_connection_t *) ev->data;
198 r = (ngx_http_request_t *) c->data;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000199
200 ngx_log_debug(ev->log, "http process request");
201
Igor Sysoev016b8522002-08-29 16:59:54 +0000202 do {
Igor Sysoev016b8522002-08-29 16:59:54 +0000203
Igor Sysoev73009772003-02-06 17:21:13 +0000204 if (r->header_read) {
Igor Sysoevb7387572003-03-11 20:38:13 +0000205 if (r->header_in->end - r->header_in->last == 0) {
206 again = 1;
207 } else {
208 again = 0;
209 }
210
Igor Sysoev73009772003-02-06 17:21:13 +0000211 r->header_read = 0;
212 ngx_log_debug(ev->log, "http preread %d" _
Igor Sysoevb7387572003-03-11 20:38:13 +0000213 r->header_in->last - r->header_in->pos);
Igor Sysoev016b8522002-08-29 16:59:54 +0000214
Igor Sysoev73009772003-02-06 17:21:13 +0000215 } else {
Igor Sysoevb7387572003-03-11 20:38:13 +0000216 n = ngx_event_recv(c, r->header_in->last,
217 r->header_in->end - r->header_in->last);
Igor Sysoev73009772003-02-06 17:21:13 +0000218
219 if (n == NGX_AGAIN) {
220 if (!r->header_timeout_set) {
221
222 if (ev->timer_set) {
223 ngx_del_timer(ev);
224 } else {
225 ev->timer_set = 1;
226 }
227
228 ngx_add_timer(ev, ngx_http_client_header_timeout);
229 r->header_timeout_set = 1;
230 }
231 return NGX_AGAIN;
232 }
233
Igor Sysoevb7387572003-03-11 20:38:13 +0000234 if (n == NGX_ERROR) {
Igor Sysoev73009772003-02-06 17:21:13 +0000235 return ngx_http_close_request(r);
Igor Sysoevb7387572003-03-11 20:38:13 +0000236 }
Igor Sysoev73009772003-02-06 17:21:13 +0000237
238 ngx_log_debug(ev->log, "http read %d" _ n);
239
240 if (n == 0) {
241 ngx_log_error(NGX_LOG_INFO, c->log, 0,
242 "client has prematurely closed connection");
243 return ngx_http_close_request(r);
244 }
245
Igor Sysoevb7387572003-03-11 20:38:13 +0000246 r->header_in->last += n;
247
248 if (ngx_http_large_client_header
249 && r->header_in->end == r->header_in->last) {
250 again = 1;
251 } else {
252 again = 0;
253 }
Igor Sysoev73009772003-02-06 17:21:13 +0000254 }
255
Igor Sysoev0dad6292003-03-05 17:30:51 +0000256 /* the state_handlers are called in the following order:
Igor Sysoev73009772003-02-06 17:21:13 +0000257 ngx_http_process_request_line(r)
258 ngx_http_process_request_headers(r) */
259
260 do {
Igor Sysoev0dad6292003-03-05 17:30:51 +0000261 /* state_handlers return NGX_OK when the whole header done */
Igor Sysoev73009772003-02-06 17:21:13 +0000262 rc = (r->state_handler)(r);
263
Igor Sysoevb7387572003-03-11 20:38:13 +0000264 if (rc == NGX_ERROR) {
Igor Sysoev73009772003-02-06 17:21:13 +0000265 return rc;
Igor Sysoevb7387572003-03-11 20:38:13 +0000266 }
Igor Sysoev73009772003-02-06 17:21:13 +0000267
Igor Sysoevb7387572003-03-11 20:38:13 +0000268 } while (rc == NGX_AGAIN && r->header_in->pos < r->header_in->last);
Igor Sysoev73009772003-02-06 17:21:13 +0000269
270#if (HAVE_AIO_EVENT) /* aio, iocp */
Igor Sysoevb7387572003-03-11 20:38:13 +0000271
272 if (ngx_event_flags & NGX_HAVE_AIO_EVENT) {
273 again = 1;
274 }
275
Igor Sysoev73009772003-02-06 17:21:13 +0000276#endif
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000277
Igor Sysoevb7387572003-03-11 20:38:13 +0000278 } while (rc == NGX_AGAIN && again);
279
Igor Sysoev830c4ce2003-01-24 16:09:40 +0000280 if (rc == NGX_OK) {
281 /* HTTP header done */
Igor Sysoev016b8522002-08-29 16:59:54 +0000282
Igor Sysoev9b25d692003-01-26 21:08:14 +0000283 if (ev->timer_set) {
Igor Sysoev830c4ce2003-01-24 16:09:40 +0000284 ngx_del_timer(ev);
Igor Sysoev9b25d692003-01-26 21:08:14 +0000285 ev->timer_set = 0;
Igor Sysoev830c4ce2003-01-24 16:09:40 +0000286 }
287
Igor Sysoev42feecb2002-12-15 06:25:09 +0000288 return ngx_http_event_request_handler(r);
Igor Sysoev830c4ce2003-01-24 16:09:40 +0000289
Igor Sysoev9b25d692003-01-26 21:08:14 +0000290 } else { /* NGX_AGAIN */
Igor Sysoev830c4ce2003-01-24 16:09:40 +0000291
Igor Sysoev9b25d692003-01-26 21:08:14 +0000292 if (!r->header_timeout_set) {
293
294 if (ev->timer_set) {
295 ngx_del_timer(ev);
296 } else {
297 ev->timer_set = 1;
298 }
299
Igor Sysoev830c4ce2003-01-24 16:09:40 +0000300 ngx_add_timer(ev, ngx_http_client_header_timeout);
Igor Sysoev9b25d692003-01-26 21:08:14 +0000301 r->header_timeout_set = 1;
Igor Sysoev830c4ce2003-01-24 16:09:40 +0000302 }
303
Igor Sysoevb0869052002-12-10 18:05:12 +0000304 return rc;
Igor Sysoev830c4ce2003-01-24 16:09:40 +0000305 }
Igor Sysoev016b8522002-08-29 16:59:54 +0000306}
307
Igor Sysoev1af7c822002-09-13 14:47:42 +0000308
Igor Sysoev016b8522002-08-29 16:59:54 +0000309static int ngx_http_process_request_line(ngx_http_request_t *r)
310{
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000311 int rc, offset;
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000312 ngx_connection_t *c;
Igor Sysoev016b8522002-08-29 16:59:54 +0000313 ngx_http_log_ctx_t *ctx;
314
315 rc = ngx_read_http_request_line(r);
316
Igor Sysoev2ba1ee02002-10-04 17:58:04 +0000317 c = r->connection;
318
Igor Sysoev0dad6292003-03-05 17:30:51 +0000319 /* a request line has been parsed successfully */
Igor Sysoev016b8522002-08-29 16:59:54 +0000320 if (rc == NGX_OK) {
Igor Sysoev6a644c62003-03-04 06:33:48 +0000321 /* copy URI */
Igor Sysoev42feecb2002-12-15 06:25:09 +0000322 r->uri.len = (r->args_start ? r->args_start - 1 : r->uri_end)
323 - r->uri_start;
Igor Sysoevb0869052002-12-10 18:05:12 +0000324 ngx_test_null(r->uri.data, ngx_palloc(r->pool, r->uri.len + 1),
Igor Sysoev016b8522002-08-29 16:59:54 +0000325 ngx_http_close_request(r));
Igor Sysoevb0869052002-12-10 18:05:12 +0000326 ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1);
Igor Sysoev016b8522002-08-29 16:59:54 +0000327
Igor Sysoevb7387572003-03-11 20:38:13 +0000328 /* if the large client headers are enabled then
Igor Sysoev0dad6292003-03-05 17:30:51 +0000329 we need to copy a request line */
Igor Sysoev2d0d9092002-12-03 15:45:38 +0000330
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000331 r->request_line.len = r->request_end - r->request_start;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000332 if (ngx_http_large_client_header) {
333 ngx_test_null(r->request_line.data,
334 ngx_palloc(r->pool, r->request_line.len + 1),
335 ngx_http_close_request(r));
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000336 ngx_cpystrn(r->request_line.data, r->request_start,
Igor Sysoev6a644c62003-03-04 06:33:48 +0000337 r->request_line.len + 1);
338
339 } else {
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000340 r->request_line.data = r->request_start;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000341 r->request_line.data[r->request_line.len] = '\0';
342 }
343
344 /* copy URI extention if it exists */
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000345 if (r->uri_ext) {
Igor Sysoev42feecb2002-12-15 06:25:09 +0000346 r->exten.len = (r->args_start ? r->args_start - 1 : r->uri_end)
347 - r->uri_ext;
Igor Sysoevb0869052002-12-10 18:05:12 +0000348 ngx_test_null(r->exten.data,
349 ngx_palloc(r->pool, r->exten.len + 1),
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000350 ngx_http_close_request(r));
Igor Sysoevb0869052002-12-10 18:05:12 +0000351 ngx_cpystrn(r->exten.data, r->uri_ext, r->exten.len + 1);
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000352 }
353
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000354#if 1
355 if (r->exten.data == NULL) {
356 r->exten.data = "";
357 }
358 ngx_log_debug(r->connection->log, "HTTP: %d, %d, '%s', '%s'" _
Igor Sysoevb0869052002-12-10 18:05:12 +0000359 r->method _ r->http_version _
360 r->uri.data _ r->exten.data);
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000361 if (r->exten.data[0] == '\0') {
362 r->exten.data = NULL;
363 }
Igor Sysoev295bb632002-12-23 18:22:18 +0000364#endif
Igor Sysoev016b8522002-08-29 16:59:54 +0000365
Igor Sysoev6a644c62003-03-04 06:33:48 +0000366 ctx = r->connection->log->data;
367 if (ngx_http_url_in_error_log) {
368 ngx_test_null(ctx->url,
369 ngx_palloc(r->pool, r->uri_end - r->uri_start + 1),
370 ngx_http_close_request(r));
371 ngx_cpystrn(ctx->url, r->uri_start, r->uri_end - r->uri_start + 1);
372 }
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000373
Igor Sysoev0dad6292003-03-05 17:30:51 +0000374 /* if we need to parse the headers then return NGX_AGAIN
375 becuase of HTTP/0.9 has no headers so return NGX_OK */
376
377 if (r->http_version == NGX_HTTP_VERSION_9) {
378 r->state_handler = NULL;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000379 return NGX_OK;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000380 }
Igor Sysoev1af7c822002-09-13 14:47:42 +0000381
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000382 r->headers_in.headers = ngx_create_table(r->pool, 10);
383
Igor Sysoevb0869052002-12-10 18:05:12 +0000384 r->state_handler = ngx_http_process_request_headers;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000385 ctx->action = "reading client request headers";
Igor Sysoev016b8522002-08-29 16:59:54 +0000386
Igor Sysoevb0869052002-12-10 18:05:12 +0000387 return NGX_AGAIN;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000388
389 /* there was error while a request line parsing */
390 } else if (rc != NGX_AGAIN) {
391 return ngx_http_header_parse_error(r, rc, NGX_HTTP_BAD_REQUEST);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000392 }
393
Igor Sysoev0dad6292003-03-05 17:30:51 +0000394 /* NGX_AGAIN: a request line parsing is still not complete */
395
Igor Sysoevb7387572003-03-11 20:38:13 +0000396 if (r->header_in->last == r->header_in->end) {
Igor Sysoev1af7c822002-09-13 14:47:42 +0000397
Igor Sysoev0dad6292003-03-05 17:30:51 +0000398 /* If it's a pipelined request and a request line is not complete
399 then we need to copy it to the start of r->header_in hunk.
Igor Sysoevb7387572003-03-11 20:38:13 +0000400 We need to copy it here only if the large client headers
401 are enabled otherwise a request line had been already copied
Igor Sysoev0dad6292003-03-05 17:30:51 +0000402 to the start of r->header_in hunk in ngx_http_set_keepalive() */
403
404 if (ngx_http_large_client_header) {
405 offset = r->request_start - r->header_in->start;
406
407 if (offset == 0) {
408 return ngx_http_header_parse_error(r,
409 NGX_HTTP_PARSE_TOO_LONG_URI,
410 NGX_HTTP_REQUEST_URI_TOO_LARGE);
411 }
412
413 ngx_memcpy(r->header_in->start, r->request_start,
Igor Sysoevb7387572003-03-11 20:38:13 +0000414 r->header_in->last - r->request_start);
Igor Sysoev0dad6292003-03-05 17:30:51 +0000415
Igor Sysoevb7387572003-03-11 20:38:13 +0000416 r->header_in->pos -= offset;
417 r->header_in->last -= offset;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000418 r->request_start = r->header_in->start;
419 r->request_end -= offset;
420 r->uri_start -= offset;
421 r->uri_end -= offset;
422 if (r->uri_ext) {
423 r->uri_ext -= offset;
424 }
425 if (r->args_start) {
426 r->args_start -= offset;
427 }
428
429 } else {
430 return ngx_http_header_parse_error(r,
431 NGX_HTTP_PARSE_TOO_LONG_URI,
432 NGX_HTTP_REQUEST_URI_TOO_LARGE);
433 }
Igor Sysoev1af7c822002-09-13 14:47:42 +0000434 }
435
Igor Sysoev0dad6292003-03-05 17:30:51 +0000436 return NGX_AGAIN;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000437}
438
Igor Sysoev1af7c822002-09-13 14:47:42 +0000439
Igor Sysoevb0869052002-12-10 18:05:12 +0000440static int ngx_http_process_request_headers(ngx_http_request_t *r)
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000441{
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000442 int rc, offset;
Igor Sysoev73009772003-02-06 17:21:13 +0000443 size_t len;
Igor Sysoev016b8522002-08-29 16:59:54 +0000444 ngx_http_log_ctx_t *ctx;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000445
Igor Sysoev016b8522002-08-29 16:59:54 +0000446 for ( ;; ) {
Igor Sysoevb0869052002-12-10 18:05:12 +0000447 rc = ngx_read_http_header_line(r, r->header_in);
Igor Sysoev016b8522002-08-29 16:59:54 +0000448
Igor Sysoev0dad6292003-03-05 17:30:51 +0000449 /* a header line has been parsed successfully */
450 if (rc == NGX_OK) {
Igor Sysoeva19a85e2003-01-28 15:56:37 +0000451 if (ngx_http_process_request_header_line(r) == NGX_ERROR) {
Igor Sysoev6a644c62003-03-04 06:33:48 +0000452 return ngx_http_error(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
Igor Sysoeva19a85e2003-01-28 15:56:37 +0000453 }
454
455 return NGX_AGAIN;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000456
Igor Sysoevb7387572003-03-11 20:38:13 +0000457 /* a whole header has been parsed successfully */
Igor Sysoev1af7c822002-09-13 14:47:42 +0000458 } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000459 ngx_log_debug(r->connection->log, "HTTP header done");
Igor Sysoev42feecb2002-12-15 06:25:09 +0000460
Igor Sysoeva19a85e2003-01-28 15:56:37 +0000461 if (r->headers_in.host) {
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000462 for (len = 0; len < r->headers_in.host->value.len; len++) {
463 if (r->headers_in.host->value.data[len] == ':') {
464 break;
465 }
466 }
467 r->headers_in.host_name_len = len;
Igor Sysoeva19a85e2003-01-28 15:56:37 +0000468
Igor Sysoev42feecb2002-12-15 06:25:09 +0000469 } else {
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000470 if (r->http_version > NGX_HTTP_VERSION_10) {
471 return ngx_http_header_parse_error(r,
472 NGX_HTTP_PARSE_NO_HOST_HEADER,
473 NGX_HTTP_BAD_REQUEST);
474 }
475 r->headers_in.host_name_len = 0;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000476 }
Igor Sysoev016b8522002-08-29 16:59:54 +0000477
Igor Sysoev0dad6292003-03-05 17:30:51 +0000478 r->state_handler = NULL;
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000479 return NGX_OK;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000480
Igor Sysoev0dad6292003-03-05 17:30:51 +0000481 /* there was error while a header line parsing */
482 } else if (rc != NGX_AGAIN) {
483 return ngx_http_header_parse_error(r, rc, NGX_HTTP_BAD_REQUEST);
484 }
485
486 /* NGX_AGAIN: a header line parsing is still not complete */
487
Igor Sysoevb7387572003-03-11 20:38:13 +0000488 if (r->header_in->last == r->header_in->end) {
Igor Sysoev0dad6292003-03-05 17:30:51 +0000489
Igor Sysoevb7387572003-03-11 20:38:13 +0000490 /* if the large client headers are enabled then
Igor Sysoev0dad6292003-03-05 17:30:51 +0000491 we need to compact r->header_in hunk */
492
493 if (ngx_http_large_client_header) {
494 offset = r->header_name_start - r->header_in->start;
495
496 if (offset == 0) {
497 return ngx_http_header_parse_error(r,
498 NGX_HTTP_PARSE_TOO_LONG_HEADER,
499 NGX_HTTP_BAD_REQUEST);
500 }
501
502 ngx_memcpy(r->header_in->start, r->header_name_start,
Igor Sysoevb7387572003-03-11 20:38:13 +0000503 r->header_in->last - r->header_name_start);
Igor Sysoev0dad6292003-03-05 17:30:51 +0000504
Igor Sysoevb7387572003-03-11 20:38:13 +0000505 r->header_in->last -= offset;
506 r->header_in->pos -= offset;
Igor Sysoev0dad6292003-03-05 17:30:51 +0000507 r->header_name_start = r->header_in->start;
508 r->header_name_end -= offset;
509 r->header_start -= offset;
510 r->header_end -= offset;
511
512 } else {
513 return ngx_http_header_parse_error(r,
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000514 NGX_HTTP_PARSE_TOO_LONG_HEADER,
515 NGX_HTTP_BAD_REQUEST);
Igor Sysoev0dad6292003-03-05 17:30:51 +0000516 }
Igor Sysoeva19a85e2003-01-28 15:56:37 +0000517
Igor Sysoev016b8522002-08-29 16:59:54 +0000518 }
Igor Sysoev0dad6292003-03-05 17:30:51 +0000519
520 return NGX_AGAIN;
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000521 }
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000522}
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000523
Igor Sysoev1af7c822002-09-13 14:47:42 +0000524
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000525static int ngx_http_process_request_header_line(ngx_http_request_t *r)
526{
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000527 int i;
528 ngx_table_elt_t *h;
529
Igor Sysoev2d0d9092002-12-03 15:45:38 +0000530 ngx_test_null(h, ngx_push_table(r->headers_in.headers), NGX_ERROR);
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000531
Igor Sysoevb7387572003-03-11 20:38:13 +0000532 /* if large client headers are enabled then
Igor Sysoev6a644c62003-03-04 06:33:48 +0000533 we need to copy header name and value */
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000534
Igor Sysoev6a644c62003-03-04 06:33:48 +0000535 h->key.len = r->header_name_end - r->header_name_start;
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000536 h->value.len = r->header_end - r->header_start;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000537
538 if (ngx_http_large_client_header) {
539 ngx_test_null(h->key.data, ngx_palloc(r->pool, h->key.len + 1),
540 NGX_ERROR);
541 ngx_test_null(h->value.data, ngx_palloc(r->pool, h->value.len + 1),
542 NGX_ERROR);
543 ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
544 ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
545
546 } else {
547 h->key.data = r->header_name_start;
548 h->key.data[h->key.len] = '\0';
549 h->value.data = r->header_start;
550 h->value.data[h->value.len] = '\0';
551 }
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000552
553 for (i = 0; headers_in[i].len != 0; i++) {
Igor Sysoeva19a85e2003-01-28 15:56:37 +0000554 if (headers_in[i].len != h->key.len) {
555 continue;
556 }
557
558 if (ngx_strcasecmp(headers_in[i].data, h->key.data) == 0) {
559 *((ngx_table_elt_t **)
560 ((char *) &r->headers_in + headers_in[i].offset)) = h;
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000561 }
562 }
563
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000564 ngx_log_debug(r->connection->log, "HTTP header: '%s: %s'" _
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000565 h->key.data _ h->value.data);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +0000566
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000567 return NGX_OK;
568}
569
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000570
Igor Sysoev42feecb2002-12-15 06:25:09 +0000571static int ngx_http_event_request_handler(ngx_http_request_t *r)
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000572{
Igor Sysoev6a644c62003-03-04 06:33:48 +0000573 int rc, event;
574 ngx_msec_t timeout;
575 ngx_event_t *rev, *wev;
576 ngx_http_log_ctx_t *ctx;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000577
Igor Sysoev9b25d692003-01-26 21:08:14 +0000578 rev = r->connection->read;
579 wev = r->connection->write;
580
581 if (rev->timer_set) {
582 ngx_del_timer(rev);
583 rev->timer_set = 0;
584 }
Igor Sysoevb0869052002-12-10 18:05:12 +0000585
Igor Sysoev9b25d692003-01-26 21:08:14 +0000586 rev->event_handler = ngx_http_block_read;
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000587
Igor Sysoev6a644c62003-03-04 06:33:48 +0000588 ctx = r->connection->log->data;
589 ctx->action = "processing client request";
590
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000591 rc = ngx_http_handler(r);
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000592
Igor Sysoevef259d12002-12-06 16:32:33 +0000593 /* handler is still busy */
Igor Sysoev6ed07e42002-12-05 16:21:24 +0000594 if (rc == NGX_WAITING)
595 return rc;
596
Igor Sysoev73009772003-02-06 17:21:13 +0000597 /* handler has done its work but transfer is still not completed */
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000598 if (rc == NGX_AGAIN) {
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000599
Igor Sysoev6a644c62003-03-04 06:33:48 +0000600 /* STUB: timeouts should be reworked */
Igor Sysoev96f83772002-09-07 10:14:25 +0000601 if (r->connection->sent > 0) {
Igor Sysoev73009772003-02-06 17:21:13 +0000602 ngx_log_debug(r->connection->log, "sent: " OFF_FMT _
Igor Sysoev96f83772002-09-07 10:14:25 +0000603 r->connection->sent);
604 timeout = (ngx_msec_t) (r->connection->sent * 10);
605 ngx_log_debug(r->connection->log, "timeout: %d" _ timeout);
Igor Sysoev9b25d692003-01-26 21:08:14 +0000606 ngx_add_timer(wev, timeout);
Igor Sysoev96f83772002-09-07 10:14:25 +0000607
608 } else {
Igor Sysoev9b25d692003-01-26 21:08:14 +0000609 ngx_add_timer(wev, 10000);
Igor Sysoev96f83772002-09-07 10:14:25 +0000610 }
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000611
Igor Sysoev9b25d692003-01-26 21:08:14 +0000612 wev->event_handler = ngx_http_writer;
Igor Sysoev73009772003-02-06 17:21:13 +0000613
614#if (USE_KQUEUE)
615
Igor Sysoev6a644c62003-03-04 06:33:48 +0000616#if (HAVE_LOWAT_EVENT) /* kqueue's NOTE_LOWAT */
617 wev->lowat = /* STUB */ NGX_LOWAT;
618#endif
619
Igor Sysoev73009772003-02-06 17:21:13 +0000620 if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_CLEAR_EVENT) == NGX_ERROR) {
621 return ngx_http_close_request(r);
622 }
623
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000624 return rc;
Igor Sysoev73009772003-02-06 17:21:13 +0000625
626#else
627
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000628#if (HAVE_AIO_EVENT) || (HAVE_EDGE_EVENT) /* aio, iocp, epoll */
Igor Sysoev73009772003-02-06 17:21:13 +0000629
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000630 if (ngx_event_flags & (NGX_HAVE_AIO_EVENT|NGX_HAVE_EDGE_EVENT)) {
Igor Sysoev73009772003-02-06 17:21:13 +0000631 return rc;
632 }
633
634#endif
635
Igor Sysoev6a644c62003-03-04 06:33:48 +0000636#if (HAVE_LOWAT_EVENT) /* kqueue's NOTE_LOWAT */
637
638 if (ngx_event_flags & NGX_HAVE_LOWAT_EVENT) {
639 wev->lowat = /* STUB */ NGX_LOWAT;
640 }
641
642#endif
643
Igor Sysoev73009772003-02-06 17:21:13 +0000644#if (HAVE_CLEAR_EVENT) /* kqueue */
645
646 if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) {
647 event = NGX_CLEAR_EVENT;
648
649 } else {
Igor Sysoev73009772003-02-06 17:21:13 +0000650 event = NGX_LEVEL_EVENT;
Igor Sysoev73009772003-02-06 17:21:13 +0000651 }
652
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000653#else /* select, poll, /dev/poll */
Igor Sysoev73009772003-02-06 17:21:13 +0000654
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000655 event = NGX_LEVEL_EVENT;
Igor Sysoev73009772003-02-06 17:21:13 +0000656
657#endif
658
659 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) == NGX_ERROR) {
660 return ngx_http_close_request(r);
661 }
662
663 return rc;
664
665
666#endif /* USE_KQUEUE */
667
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000668 }
669
670 if (rc == NGX_ERROR) {
671 /* log http request */
672 return ngx_http_close_request(r);
673 }
674
675 if (rc >= NGX_HTTP_SPECIAL_RESPONSE)
676 return ngx_http_special_response(r, rc);
677
678 /* rc == NGX_OK */
679
Igor Sysoev6a644c62003-03-04 06:33:48 +0000680 if (r->keepalive == 0) {
Igor Sysoev3a40d482002-09-12 14:42:29 +0000681 if (r->lingering_close) {
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000682 return ngx_http_set_lingering_close(r);
683
Igor Sysoev3a40d482002-09-12 14:42:29 +0000684 } else {
685 return ngx_http_close_request(r);
686 }
687 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000688
689 /* keepalive */
690
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000691 return ngx_http_set_keepalive(r);
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000692}
693
Igor Sysoevb0869052002-12-10 18:05:12 +0000694
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000695static int ngx_http_writer(ngx_event_t *ev)
696{
697 int rc;
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000698 ngx_msec_t timeout;
699 ngx_connection_t *c;
700 ngx_http_request_t *r;
701 ngx_http_core_loc_conf_t *conf;
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000702
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000703 c = (ngx_connection_t *) ev->data;
704 r = (ngx_http_request_t *) c->data;
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000705
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000706 rc = ngx_http_output_filter(r, NULL);
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000707
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000708 ngx_log_debug(ev->log, "output filter in writer: %d" _ rc);
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000709
710 if (rc == NGX_AGAIN) {
711
Igor Sysoev6a644c62003-03-04 06:33:48 +0000712 /* STUB: timeouts should be reworked */
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000713 if (c->sent > 0) {
Igor Sysoeva0bb31f2002-12-02 16:09:40 +0000714 conf = (ngx_http_core_loc_conf_t *)
Igor Sysoev207ed5a2002-12-26 16:26:23 +0000715 ngx_http_get_module_loc_conf(r->main ? r->main : r,
716 ngx_http_core_module_ctx);
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000717
718 timeout = (ngx_msec_t) (c->sent * conf->send_timeout);
719
Igor Sysoev73009772003-02-06 17:21:13 +0000720 ngx_log_debug(ev->log, "sent: " OFF_FMT _ c->sent);
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000721 ngx_log_debug(ev->log, "timeout: %d" _ timeout);
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000722
Igor Sysoev9b25d692003-01-26 21:08:14 +0000723 if (ev->timer_set) {
724 ngx_del_timer(ev);
725 } else {
726 ev->timer_set = 1;
727 }
728
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000729 ngx_add_timer(ev, timeout);
730 }
731
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000732 return rc;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +0000733 }
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000734
735 if (rc == NGX_ERROR)
736 return rc;
737
738 /* rc == NGX_OK */
739
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000740 ngx_log_debug(ev->log, "http writer done");
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000741
Igor Sysoev6a644c62003-03-04 06:33:48 +0000742 if (r->keepalive == 0) {
Igor Sysoev3a40d482002-09-12 14:42:29 +0000743 if (r->lingering_close) {
Igor Sysoev3a17f242002-12-24 17:30:59 +0000744 return ngx_http_set_lingering_close(r);
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000745
Igor Sysoev3a40d482002-09-12 14:42:29 +0000746 } else {
747 return ngx_http_close_request(r);
748 }
749 }
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000750
Igor Sysoev3a40d482002-09-12 14:42:29 +0000751 /* keepalive */
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000752
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000753 return ngx_http_set_keepalive(r);
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000754}
755
Igor Sysoevb0869052002-12-10 18:05:12 +0000756
Igor Sysoev42feecb2002-12-15 06:25:09 +0000757static int ngx_http_block_read(ngx_event_t *ev)
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000758{
Igor Sysoev42feecb2002-12-15 06:25:09 +0000759 ngx_log_debug(ev->log, "http read blocked");
760
Igor Sysoev73009772003-02-06 17:21:13 +0000761 /* aio does not call this handler */
762
763#if (USE_KQUEUE)
764
765 return NGX_OK;
766
767#else
768
Igor Sysoevb7387572003-03-11 20:38:13 +0000769 if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { /* select, poll, /dev/poll */
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000770 ev->blocked = 1;
771 return ngx_del_event(ev, NGX_READ_EVENT, 0);
Igor Sysoev73009772003-02-06 17:21:13 +0000772
Igor Sysoevb7387572003-03-11 20:38:13 +0000773 } else { /* kqueue, epoll */
Igor Sysoev73009772003-02-06 17:21:13 +0000774 return NGX_OK;
775 }
776
Igor Sysoev73009772003-02-06 17:21:13 +0000777#endif /* USE_KQUEUE */
Igor Sysoev42feecb2002-12-15 06:25:09 +0000778}
779
780
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000781/* TODO */
Igor Sysoev42feecb2002-12-15 06:25:09 +0000782int ngx_http_discard_body(ngx_http_request_t *r)
783{
Igor Sysoev9b25d692003-01-26 21:08:14 +0000784 ngx_event_t *ev;
785
786 ev = r->connection->read;
787
Igor Sysoev42feecb2002-12-15 06:25:09 +0000788 ngx_log_debug(r->connection->log, "set discard body");
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000789
Igor Sysoev9b25d692003-01-26 21:08:14 +0000790 if (ev->timer_set) {
791 ngx_del_timer(ev);
792 ev->timer_set = 0;
793 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000794
Igor Sysoev73009772003-02-06 17:21:13 +0000795 if (r->client_content_length) {
Igor Sysoev9b25d692003-01-26 21:08:14 +0000796 ev->event_handler = ngx_http_read_discarded_body;
Igor Sysoev73009772003-02-06 17:21:13 +0000797 /* if blocked - read */
798 /* else add timer */
799 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000800
801 return NGX_OK;
802}
803
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000804
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000805/* TODO */
Igor Sysoev42feecb2002-12-15 06:25:09 +0000806static int ngx_http_read_discarded_body(ngx_event_t *ev)
807{
808 size_t size;
809 ssize_t n;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000810 ngx_connection_t *c;
811 ngx_http_request_t *r;
812 ngx_http_core_loc_conf_t *lcf;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000813
814 ngx_log_debug(ev->log, "http read discarded body");
815
816 if (ev->timedout)
817 return NGX_ERROR;
818
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000819 c = (ngx_connection_t *) ev->data;
820 r = (ngx_http_request_t *) c->data;
821
822 lcf = (ngx_http_core_loc_conf_t *)
823 ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx);
824
Igor Sysoev42feecb2002-12-15 06:25:09 +0000825 if (r->discarded_buffer == NULL)
826 ngx_test_null(r->discarded_buffer,
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000827 ngx_palloc(r->pool, lcf->discarded_buffer_size),
Igor Sysoev42feecb2002-12-15 06:25:09 +0000828 NGX_ERROR);
829
830 size = r->client_content_length;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000831 if (size > lcf->discarded_buffer_size)
832 size = lcf->discarded_buffer_size;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000833
834 n = ngx_event_recv(c, r->discarded_buffer, size);
835 if (n == NGX_ERROR)
836 return NGX_ERROR;
837
838 if (n == NGX_AGAIN)
839 return NGX_OK;
840
841 r->client_content_length -= n;
842 /* XXX: what if r->client_content_length == 0 ? */
843 return NGX_OK;
844}
845
846
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000847static int ngx_http_set_keepalive(ngx_http_request_t *r)
848{
Igor Sysoevb7387572003-03-11 20:38:13 +0000849 int len, blocked;
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000850 ngx_hunk_t *h;
851 ngx_event_t *rev, *wev;
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000852 ngx_connection_t *c;
Igor Sysoev6a644c62003-03-04 06:33:48 +0000853 ngx_http_log_ctx_t *ctx;
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000854
855 c = (ngx_connection_t *) r->connection;
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000856 rev = c->read;
857 wev = c->write;
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000858
Igor Sysoev6a644c62003-03-04 06:33:48 +0000859 ctx = (ngx_http_log_ctx_t *) c->log->data;
860 ctx->action = "closing request";
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000861 ngx_http_close_request(r);
862
Igor Sysoevb7387572003-03-11 20:38:13 +0000863 if (rev->blocked && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
864 if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) {
865 return NGX_ERROR;
866 }
867 blocked = 1;
868 rev->blocked = 0;
869
870 } else {
871 blocked = 0;
872 }
873
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000874 h = c->buffer;
875
876 /* pipelined request */
Igor Sysoevb7387572003-03-11 20:38:13 +0000877 if (h->pos < h->last) {
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000878
Igor Sysoev0dad6292003-03-05 17:30:51 +0000879 /* We do not know here whether pipelined request is complete
Igor Sysoevb7387572003-03-11 20:38:13 +0000880 so if large client headers are not enabled
881 we need to copy the data to the start of c->buffer.
882 This copy should be rare because clients that support
883 pipelined requests (Mozilla 1.x, Opera 6.x) are still rare */
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000884
885 if (!ngx_http_large_client_header) {
Igor Sysoevb7387572003-03-11 20:38:13 +0000886 len = h->last - h->pos;
887 ngx_memcpy(h->start, h->pos, len);
888 h->pos = h->start;
889 h->last = h->start + len;
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000890 }
891
892 c->pipeline = 1;
893 ctx->action = "reading client pipelined request line";
894 return ngx_http_init_request(rev);
895 }
896
897 c->pipeline = 0;
898
Igor Sysoevb7387572003-03-11 20:38:13 +0000899 h->pos = h->last = h->start;
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000900 rev->event_handler = ngx_http_keepalive_handler;
901
Igor Sysoevb7387572003-03-11 20:38:13 +0000902 if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000903 if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
904 return NGX_ERROR;
905 }
906 }
907
Igor Sysoev6a644c62003-03-04 06:33:48 +0000908 ctx->action = "keepalive";
909
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000910#if (HAVE_AIO_EVENT) /* aio, iocp */
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000911
Igor Sysoevb7387572003-03-11 20:38:13 +0000912 if ((ngx_event_flags & NGX_HAVE_AIO_EVENT) || blocked) {
913 return ngx_http_keepalive_handler(rev);
914 }
915
916#else
917
918 if (blocked) {
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000919 return ngx_http_keepalive_handler(rev);
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000920 }
Igor Sysoev3d062ad2003-03-05 06:37:42 +0000921
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000922#endif
923
924 return NGX_OK;
925}
926
927
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000928static int ngx_http_keepalive_handler(ngx_event_t *ev)
929{
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000930 ssize_t n;
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000931 ngx_connection_t *c;
932 ngx_http_log_ctx_t *ctx;
933
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000934 c = (ngx_connection_t *) ev->data;
935
Igor Sysoev42feecb2002-12-15 06:25:09 +0000936 ngx_log_debug(ev->log, "http keepalive handler");
Igor Sysoev1af7c822002-09-13 14:47:42 +0000937
938 if (ev->timedout)
939 return NGX_DONE;
940
Igor Sysoevb7387572003-03-11 20:38:13 +0000941 /* MSIE closes keepalive connection with RST flag
942 so we ignore ECONNRESET here */
943
944 ev->ignore_econnreset = 1;
945 ngx_set_socket_errno(0);
946 n = ngx_event_recv(c, c->buffer->last, c->buffer->end - c->buffer->last);
947 ev->ignore_econnreset = 0;
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000948
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000949 if (n == NGX_AGAIN || n == NGX_ERROR)
950 return n;
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000951
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000952 ctx = (ngx_http_log_ctx_t *) ev->log->data;
953 ev->log->handler = NULL;
954
955 if (n == 0) {
Igor Sysoevb7387572003-03-11 20:38:13 +0000956 ngx_log_error(NGX_LOG_INFO, ev->log, ngx_socket_errno,
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000957 "client %s closed keepalive connection", ctx->client);
958 return NGX_DONE;
959 }
960
Igor Sysoevb7387572003-03-11 20:38:13 +0000961 c->buffer->last += n;
Igor Sysoev682bf8e2002-09-16 15:01:44 +0000962 ev->log->handler = ngx_http_log_error;
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000963 ctx->action = "reading client request line";
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000964
965 return ngx_http_init_request(ev);
966}
967
Igor Sysoev0ad17c02002-08-26 15:18:19 +0000968
Igor Sysoev42feecb2002-12-15 06:25:09 +0000969static int ngx_http_set_lingering_close(ngx_http_request_t *r)
Igor Sysoev1af7c822002-09-13 14:47:42 +0000970{
Igor Sysoevb7387572003-03-11 20:38:13 +0000971 int blocked;
972 ngx_event_t *rev, *wev;
973 ngx_connection_t *c;
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000974 ngx_http_core_loc_conf_t *lcf;
975
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +0000976 c = r->connection;
Igor Sysoevb7387572003-03-11 20:38:13 +0000977 rev = c->read;
978 wev = c->write;
Igor Sysoev9b25d692003-01-26 21:08:14 +0000979
Igor Sysoev4e9393a2003-01-09 05:36:00 +0000980 lcf = (ngx_http_core_loc_conf_t *)
981 ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx);
982
Igor Sysoevb7387572003-03-11 20:38:13 +0000983 r->lingering_time = ngx_time() + lcf->lingering_time / 1000;
Igor Sysoev42feecb2002-12-15 06:25:09 +0000984 r->connection->read->event_handler = ngx_http_lingering_close_handler;
985
Igor Sysoevb7387572003-03-11 20:38:13 +0000986 if (rev->timer_set) {
987 ngx_del_timer(rev);
Igor Sysoev9b25d692003-01-26 21:08:14 +0000988 } else {
Igor Sysoevb7387572003-03-11 20:38:13 +0000989 rev->timer_set = 1;
Igor Sysoev9b25d692003-01-26 21:08:14 +0000990 }
Igor Sysoev42feecb2002-12-15 06:25:09 +0000991
Igor Sysoevb7387572003-03-11 20:38:13 +0000992 ngx_add_timer(rev, lcf->lingering_timeout);
Igor Sysoev9b25d692003-01-26 21:08:14 +0000993
Igor Sysoevb7387572003-03-11 20:38:13 +0000994 if (rev->blocked && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
995 if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) {
996 return ngx_http_close_request(r);
997 }
998 blocked = 1;
999 rev->blocked = 0;
1000
1001 } else {
1002 blocked = 0;
1003 }
1004
1005 if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) {
1006 if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) {
1007 return ngx_http_close_request(r);
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001008 }
Igor Sysoev42feecb2002-12-15 06:25:09 +00001009 }
1010
Igor Sysoevb7387572003-03-11 20:38:13 +00001011 if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) {
1012 ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
Igor Sysoev42feecb2002-12-15 06:25:09 +00001013 ngx_shutdown_socket_n " failed");
1014 return ngx_http_close_request(r);
1015 }
1016
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001017#if (HAVE_AIO_EVENT) /* aio, iocp */
Igor Sysoevb7387572003-03-11 20:38:13 +00001018
1019 if ((ngx_event_flags & NGX_HAVE_AIO_EVENT) || blocked) {
1020 return ngx_http_lingering_close_handler(rev);
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001021 }
Igor Sysoevb7387572003-03-11 20:38:13 +00001022
1023#else
1024
1025 if (blocked) {
1026 return ngx_http_lingering_close_handler(rev);
1027 }
1028
Igor Sysoev1e7ec9d2003-02-11 07:14:40 +00001029#endif
1030
Igor Sysoevb7387572003-03-11 20:38:13 +00001031 return NGX_OK;
Igor Sysoev42feecb2002-12-15 06:25:09 +00001032}
1033
1034
1035static int ngx_http_lingering_close_handler(ngx_event_t *ev)
1036{
1037 ssize_t n;
1038 ngx_msec_t timer;
Igor Sysoev1af7c822002-09-13 14:47:42 +00001039 ngx_connection_t *c;
1040 ngx_http_request_t *r;
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001041 ngx_http_core_loc_conf_t *lcf;
Igor Sysoev1af7c822002-09-13 14:47:42 +00001042
Igor Sysoev42feecb2002-12-15 06:25:09 +00001043 ngx_log_debug(ev->log, "http lingering close handler");
Igor Sysoev1af7c822002-09-13 14:47:42 +00001044
Igor Sysoev86de4cb2003-01-30 07:28:09 +00001045 c = (ngx_connection_t *) ev->data;
1046 r = (ngx_http_request_t *) c->data;
1047
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001048 if (ev->timedout) {
1049 return ngx_http_close_request(r);
1050 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001051
Igor Sysoev1af7c822002-09-13 14:47:42 +00001052 timer = r->lingering_time - ngx_time();
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001053 if (timer <= 0) {
1054 return ngx_http_close_request(r);
1055 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001056
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001057 lcf = (ngx_http_core_loc_conf_t *)
1058 ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx);
1059
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001060 if (r->discarded_buffer == NULL) {
Igor Sysoevb7387572003-03-11 20:38:13 +00001061
1062 /* TODO: r->header_in->start (if large headers are enabled)
1063 or the end of parsed header (otherwise)
1064 instead of r->header_in->last */
1065
1066 if ((size_t)(r->header_in->end - r->header_in->last)
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001067 >= lcf->discarded_buffer_size) {
Igor Sysoevb7387572003-03-11 20:38:13 +00001068 r->discarded_buffer = r->header_in->last;
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001069
1070 } else {
1071 ngx_test_null(r->discarded_buffer,
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001072 ngx_palloc(c->pool, lcf->discarded_buffer_size),
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001073 ngx_http_close_request(r));
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001074 }
1075 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001076
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001077 n = ngx_event_recv(c, r->discarded_buffer, lcf->discarded_buffer_size);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001078
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001079 ngx_log_debug(ev->log, "lingering read: %d" _ n);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001080
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001081 if (n == NGX_ERROR || n == 0) {
1082 return ngx_http_close_request(r);
1083 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001084
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001085 timer *= 1000;
Igor Sysoev4e9393a2003-01-09 05:36:00 +00001086 if (timer > lcf->lingering_timeout) {
1087 timer = lcf->lingering_timeout;
Igor Sysoev0d2bda52002-12-24 07:09:57 +00001088 }
Igor Sysoev1af7c822002-09-13 14:47:42 +00001089
Igor Sysoev9b25d692003-01-26 21:08:14 +00001090 if (ev->timer_set) {
1091 ngx_del_timer(ev);
1092 } else {
1093 ev->timer_set = 1;
1094 }
Igor Sysoev682bf8e2002-09-16 15:01:44 +00001095 ngx_add_timer(ev, timer);
Igor Sysoev1af7c822002-09-13 14:47:42 +00001096
1097 return NGX_OK;
1098}
1099
Igor Sysoev2b542382002-08-20 14:48:28 +00001100
Igor Sysoev2ba1ee02002-10-04 17:58:04 +00001101static int ngx_http_close_connection(ngx_event_t *ev)
1102{
Igor Sysoev2ba1ee02002-10-04 17:58:04 +00001103 return ngx_event_close_connection(ev);
1104}
1105
1106
Igor Sysoev3d062ad2003-03-05 06:37:42 +00001107static int ngx_http_header_parse_error(ngx_http_request_t *r,
1108 int parse_err, int err)
1109{
1110 ngx_http_log_ctx_t *ctx;
1111
1112 ctx = r->connection->log->data;
1113 r->connection->log->handler = NULL;
1114
1115 if (ctx->url) {
1116 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1117 header_errors[parse_err - NGX_HTTP_PARSE_INVALID_METHOD],
1118 ctx->client, ctx->url);
1119
1120 } else {
1121 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1122 header_errors[parse_err - NGX_HTTP_PARSE_INVALID_METHOD],
1123 ctx->client);
1124 }
1125
1126 r->connection->log->handler = ngx_http_log_error;
1127
1128 return ngx_http_error(r, err);
1129}
1130
1131
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001132static size_t ngx_http_log_error(void *data, char *buf, size_t len)
1133{
1134 ngx_http_log_ctx_t *ctx = (ngx_http_log_ctx_t *) data;
Igor Sysoeva58e3ca2002-09-02 14:48:24 +00001135
Igor Sysoev0ad17c02002-08-26 15:18:19 +00001136 if (ctx->url)
1137 return ngx_snprintf(buf, len, " while %s, client: %s, URL: %s",
1138 ctx->action, ctx->client, ctx->url);
1139 else
1140 return ngx_snprintf(buf, len, " while %s, client: %s",
1141 ctx->action, ctx->client);
Igor Sysoev6de5c2c2002-08-06 16:39:45 +00001142}