# HG changeset patch # User Igor Sysoev # Date 1047415093 0 # Node ID 5a7d1aaa16183b2b7a0dda8f611650e72dfe33de # Parent 4876cd4a36bbbfe47b9dfd421cf1fa1653eb939e nginx-0.0.1-2003-03-11-23:38:13 import diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -206,7 +206,7 @@ static int ngx_conf_read_token(ngx_conf_ cf->args->nelts = 0; h = cf->conf_file->hunk; - start = h->pos.mem; + start = h->pos; #if 0 ngx_log_debug(cf->log, "TOKEN START"); @@ -214,31 +214,31 @@ ngx_log_debug(cf->log, "TOKEN START"); for ( ;; ) { - if (h->pos.mem >= h->last.mem) { + if (h->pos >= h->last) { if (cf->conf_file->file.offset >= ngx_file_size(cf->conf_file->file.info)) { return NGX_CONF_FILE_DONE; } - if (h->pos.mem - start) { - ngx_memcpy(h->start, start, h->pos.mem - start); + if (h->pos - start) { + ngx_memcpy(h->start, start, h->pos - start); } n = ngx_read_file(&cf->conf_file->file, - h->start + (h->pos.mem - start), - h->end - (h->start + (h->pos.mem - start)), + h->start + (h->pos - start), + h->end - (h->start + (h->pos - start)), cf->conf_file->file.offset); if (n == NGX_ERROR) { return NGX_ERROR; } - h->pos.mem = h->start + (h->pos.mem - start); + h->pos = h->start + (h->pos - start); start = h->start; - h->last.mem = h->pos.mem + n; + h->last = h->pos + n; } - ch = *h->pos.mem++; + ch = *h->pos++; #if 0 ngx_log_debug(cf->log, "%d:%d:%d:%d:%d '%c'" _ @@ -282,7 +282,7 @@ ngx_log_debug(cf->log, "%d:%d:%d:%d:%d ' continue; } - start = h->pos.mem - 1; + start = h->pos - 1; switch (ch) { @@ -363,11 +363,11 @@ ngx_log_debug(cf->log, "%d:%d:%d:%d:%d ' if (found) { ngx_test_null(word, ngx_push_array(cf->args), NGX_ERROR); ngx_test_null(word->data, - ngx_palloc(cf->pool, h->pos.mem - start + 1), + ngx_palloc(cf->pool, h->pos - start + 1), NGX_ERROR); for (dst = word->data, src = start, len = 0; - src < h->pos.mem - 1; + src < h->pos - 1; len++) { if (*src == '\\') { diff --git a/src/core/ngx_hunk.c b/src/core/ngx_hunk.c --- a/src/core/ngx_hunk.c +++ b/src/core/ngx_hunk.c @@ -10,16 +10,14 @@ ngx_hunk_t *ngx_create_temp_hunk(ngx_poo ngx_test_null(h, ngx_palloc(pool, sizeof(ngx_hunk_t)), NULL); -#if !(HAVE_OFFSET_EQUAL_PTR) - h->pos.file = h->last.file = 0; -#endif + ngx_test_null(h->pre_start, ngx_palloc(pool, size + before + after), NULL); - ngx_test_null(h->pre_start, ngx_palloc(pool, size + before + after), NULL); - h->start = h->pos.mem = h->last.mem = h->pre_start + before; - h->end = h->last.mem + size; + h->start = h->pos = h->last = h->pre_start + before; + h->file_pos = h->file_last = 0; + h->end = h->last + size; h->post_end = h->end + after; - h->type = NGX_HUNK_TEMP; + h->type = NGX_HUNK_TEMP|NGX_HUNK_IN_MEMORY; h->tag = 0; h->file = NULL; @@ -32,26 +30,24 @@ ngx_hunk_t *ngx_create_hunk_before(ngx_p ngx_test_null(h, ngx_palloc(pool, sizeof(ngx_hunk_t)), NULL); -#if !(HAVE_OFFSET_EQUAL_PTR) - h->pos.file = h->last.file = 0; -#endif - - if (hunk->type & NGX_HUNK_TEMP && hunk->pos.mem - hunk->pre_start >= size) { + if (hunk->type & NGX_HUNK_TEMP && hunk->pos - hunk->pre_start >= size) { /* keep hunk->start unchanged - used in restore */ h->pre_start = hunk->pre_start; - h->end = h->post_end = hunk->pre_start = hunk->pos.mem; - h->start = h->pos.mem = h->last.mem = h->end - size; + h->end = h->post_end = hunk->pre_start = hunk->pos; + h->start = h->pos = h->last = h->end - size; + h->file_pos = h->file_last = 0; - h->type = NGX_HUNK_TEMP; + h->type = NGX_HUNK_TEMP|NGX_HUNK_IN_MEMORY; h->tag = 0; h->file = NULL; } else { ngx_test_null(h->pre_start, ngx_palloc(pool, size), NULL); - h->start = h->pos.mem = h->last.mem = h->pre_start; + h->start = h->pos = h->last = h->pre_start; h->end = h->post_end = h->start + size; + h->file_pos = h->file_last = 0; - h->type = NGX_HUNK_TEMP; + h->type = NGX_HUNK_TEMP|NGX_HUNK_IN_MEMORY; h->tag = 0; h->file = NULL; } @@ -65,27 +61,26 @@ ngx_hunk_t *ngx_create_hunk_after(ngx_po ngx_test_null(h, ngx_palloc(pool, sizeof(ngx_hunk_t)), NULL); -#if !(HAVE_OFFSET_EQUAL_PTR) - h->pos.file = h->last.file = 0; -#endif - if (hunk->type & NGX_HUNK_TEMP - && hunk->last.mem == hunk->end + && hunk->last == hunk->end && hunk->post_end - hunk->end >= size) { h->post_end = hunk->post_end; - h->pre_start = h->start = h->pos.mem = h->last.mem = hunk->post_end = - hunk->last.mem; - h->type = NGX_HUNK_TEMP; + h->pre_start = h->start = h->pos = h->last = hunk->post_end = + hunk->last; + h->file_pos = h->file_last = 0; + + h->type = NGX_HUNK_TEMP|NGX_HUNK_IN_MEMORY; h->tag = 0; h->file = NULL; } else { ngx_test_null(h->pre_start, ngx_palloc(pool, size), NULL); - h->start = h->pos.mem = h->last.mem = h->pre_start; + h->start = h->pos = h->last = h->pre_start; h->end = h->post_end = h->start + size; + h->file_pos = h->file_last = 0; - h->type = NGX_HUNK_TEMP; + h->type = NGX_HUNK_TEMP|NGX_HUNK_IN_MEMORY; h->tag = 0; h->file = NULL; } diff --git a/src/core/ngx_hunk.h b/src/core/ngx_hunk.h --- a/src/core/ngx_hunk.h +++ b/src/core/ngx_hunk.h @@ -10,34 +10,34 @@ /* hunk type */ -/* temp means that hunk's content can be changed */ -/* other type means that hunk's content can not be changed */ -#define NGX_HUNK_TEMP 0x0001 -#define NGX_HUNK_MEMORY 0x0002 -#define NGX_HUNK_MMAP 0x0004 -#define NGX_HUNK_FILE 0x0008 +/* the hunk is in memory */ +#define NGX_HUNK_IN_MEMORY 0x0001 +/* the hunk's content can be changed */ +#define NGX_HUNK_TEMP 0x0002 +/* the hunk's content is in cache and can not be changed */ +#define NGX_HUNK_MEMORY 0x0004 +/* the hunk's content is mmap()ed and can not be changed */ +#define NGX_HUNK_MMAP 0x0008 + +#define NGX_HUNK_RECYCLED 0x0010 + +/* the hunk is in file */ +#define NGX_HUNK_FILE 0x0100 /* hunk flags */ /* in thread state flush means to write the hunk completely before return */ /* in event state flush means to start to write the hunk */ -#define NGX_HUNK_FLUSH 0x0100 +#define NGX_HUNK_FLUSH 0x1000 /* last hunk */ -#define NGX_HUNK_LAST 0x0200 -#if 0 -/* can be used with NGX_HUNK_LAST only */ -#define NGX_HUNK_SHUTDOWN 0x0400 / -#endif +#define NGX_HUNK_LAST 0x2000 -#define NGX_HUNK_RECYCLED 0x0800 - - -#define NGX_HUNK_IN_MEMORY (NGX_HUNK_TEMP|NGX_HUNK_MEMORY|NGX_HUNK_MMAP) typedef struct ngx_hunk_s ngx_hunk_t; struct ngx_hunk_s { +#if 0 union { char *mem; /* start of current data */ off_t file; @@ -46,6 +46,13 @@ struct ngx_hunk_s { char *mem; /* end of current data */ off_t file; } last; +#endif + + char *pos; + char *last; + off_t file_pos; + off_t file_last; + int type; char *start; /* start of hunk */ char *end; /* end of hunk */ @@ -67,6 +74,10 @@ struct ngx_chain_s { #define NGX_CHAIN_ERROR (ngx_chain_t *) NGX_ERROR +#define ngx_hunk_in_memory_only(h) \ + ((h->type & (NGX_HUNK_IN_MEMORY|NGX_HUNK_FILE)) == NGX_HUNK_IN_MEMORY) + + ngx_hunk_t *ngx_create_temp_hunk(ngx_pool_t *pool, int size, int before, int after); diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -12,6 +12,7 @@ typedef struct { #define ngx_string(str) { sizeof(str) - 1, str } +#define ngx_null_string { 0, NULL } #if (WIN32) diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -74,12 +74,17 @@ int ngx_kqueue_init(int max_connections, ngx_event_flags = NGX_HAVE_LEVEL_EVENT |NGX_HAVE_ONESHOT_EVENT + #if (HAVE_CLEAR_EVENT) |NGX_HAVE_CLEAR_EVENT +#else + |NGX_USE_LEVEL_EVENT #endif + #if (HAVE_LOWAT_EVENT) |NGX_HAVE_LOWAT_EVENT #endif + |NGX_HAVE_KQUEUE_EVENT; ngx_write_chain_proc = ngx_freebsd_write_chain; diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -56,7 +56,6 @@ struct ngx_event_s { /* otherwise: */ /* accept: 1 if accept many, 0 otherwise */ - unsigned level:1; unsigned oneshot:1; #if 0 @@ -73,6 +72,7 @@ struct ngx_event_s { unsigned process:1; unsigned read_discarded:1; + unsigned ignore_econnreset:1; unsigned unexpected_eof:1; #if (HAVE_DEFERRED_ACCEPT) @@ -149,7 +149,7 @@ typedef struct { #define NGX_HAVE_LEVEL_EVENT 1 /* Event filter is deleted after notification - select, poll, kqueue. - Using /dev/poll, epoll it can be implemented with additional syscall */ + Using /dev/poll it can be implemented with additional syscall */ #define NGX_HAVE_ONESHOT_EVENT 2 /* Event filter notifies only changes and initial level - kqueue */ @@ -159,21 +159,24 @@ typedef struct { #define NGX_HAVE_KQUEUE_EVENT 8 /* Event filter supports low water mark - kqueue's NOTE_LOWAT, - early kqueue implementations have no NOTE_LOWAT so we need separate flag */ -#define NGX_HAVE_LOWAT_EVENT 16 + early kqueue implementations have no NOTE_LOWAT so we need a separate flag */ +#define NGX_HAVE_LOWAT_EVENT 0x00000010 /* Event filter notifies only changes (edges) but not initial level - epoll */ -#define NGX_HAVE_EDGE_EVENT 32 +#define NGX_HAVE_EDGE_EVENT 0x00000020 /* No need to add or delete event filters - rt signals */ -#define NGX_HAVE_SIGIO_EVENT 64 +#define NGX_HAVE_SIGIO_EVENT 0x00000040 /* No need to add or delete event filters - overlapped, aio_read, aioread */ -#define NGX_HAVE_AIO_EVENT 128 +#define NGX_HAVE_AIO_EVENT 0x00000080 -/* Need to add socket or halde only once - i/o completion port. - It also requires to set HAVE_AIO_EVENT and NGX_HAVE_AIO_EVENT */ -#define NGX_HAVE_IOCP_EVENT 256 +/* Need to add socket or handle only once - i/o completion port. + It also requires HAVE_AIO_EVENT and NGX_HAVE_AIO_EVENT to be set */ +#define NGX_HAVE_IOCP_EVENT 0x00000100 + + +#define NGX_USE_LEVEL_EVENT 0x00010000 /* Event filter is deleted before closing file. Has no meaning diff --git a/src/event/ngx_event_close.c b/src/event/ngx_event_close.c --- a/src/event/ngx_event_close.c +++ b/src/event/ngx_event_close.c @@ -13,15 +13,20 @@ int ngx_event_close_connection(ngx_event int rc; ngx_connection_t *c = (ngx_connection_t *) ev->data; - ngx_log_debug(c->log, "CLOSE: %d" _ c->fd); + ngx_log_debug(c->log, "close connection: %d" _ c->fd); ngx_assert((c->fd != -1), return NGX_ERROR, c->log, "ngx_event_close: already closed"); - ngx_destroy_pool(c->pool); + if (c->read->timer_set) { + ngx_del_timer(c->read); + c->read->timer_set = 0; + } - ngx_del_timer(c->read); - ngx_del_timer(c->write); + if (c->write->timer_set) { + ngx_del_timer(c->write); + c->write->timer_set = 0; + } ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT); ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT); @@ -32,5 +37,7 @@ int ngx_event_close_connection(ngx_event c->fd = -1; + ngx_destroy_pool(c->pool); + return rc; } diff --git a/src/event/ngx_event_recv.c b/src/event/ngx_event_recv.c --- a/src/event/ngx_event_recv.c +++ b/src/event/ngx_event_recv.c @@ -10,23 +10,34 @@ ssize_t ngx_event_recv_core(ngx_connecti { int n; ngx_err_t err; + ngx_event_t *ev; - if (c->read->timedout) { + ev = c->read; + + if (ev->timedout) { ngx_set_socket_errno(NGX_ETIMEDOUT); ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, "recv() failed"); return NGX_ERROR; } #if (HAVE_KQUEUE) - ngx_log_debug(c->log, "ngx_event_recv: eof:%d, avail:%d, err:%d" _ - c->read->eof _ c->read->available _ c->read->error); + if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) { + ngx_log_debug(c->log, "ngx_event_recv: eof:%d, avail:%d, err:%d" _ + ev->eof _ ev->available _ ev->error); + } #endif #if (USE_KQUEUE) - if (c->read->eof && c->read->available == 0) { - if (c->read->error) { - ngx_log_error(NGX_LOG_ERR, c->log, c->read->error, + if (ev->eof && ev->available == 0) { + if (ev->error) { + ngx_set_socket_errno(ev->error); + + if (ev->error == NGX_ECONNRESET && ev->ignore_econnreset) { + return 0; + } + + ngx_log_error(NGX_LOG_ERR, c->log, ev->error, "recv() failed"); return NGX_ERROR; } @@ -36,10 +47,16 @@ ssize_t ngx_event_recv_core(ngx_connecti #elif (HAVE_KQUEUE) - if (ngx_event_type == NGX_HAVE_KQUEUE_EVENT) { - if (c->read->eof && c->read->available == 0) { - if (c->read->error) { - ngx_log_error(NGX_LOG_ERR, c->log, c->read->error, + if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) { + if (ev->eof && ev->available == 0) { + if (ev->error) { + ngx_set_socket_errno(ev->error); + + if (ev->error == NGX_ECONNRESET && ev->ignore_econnreset) { + return 0; + } + + ngx_log_error(NGX_LOG_ERR, c->log, ev->error, "recv() failed"); return NGX_ERROR; } @@ -55,6 +72,10 @@ ssize_t ngx_event_recv_core(ngx_connecti if (n == -1) { err = ngx_socket_errno; + if (ev->error == NGX_ECONNRESET && ev->ignore_econnreset) { + return 0; + } + if (err == NGX_EAGAIN) { ngx_log_error(NGX_LOG_INFO, c->log, err, "recv() returns EAGAIN"); return NGX_AGAIN; @@ -66,12 +87,12 @@ ssize_t ngx_event_recv_core(ngx_connecti #if (USE_KQUEUE) - c->read->available -= n; + ev->available -= n; #elif (HAVE_KQUEUE) - if (ngx_event_type == NGX_HAVE_KQUEUE_EVENT) { - c->read->available -= n; + if (ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) { + ev->available -= n; } #endif diff --git a/src/http/modules/ngx_http_event_proxy_handler.c b/src/http/modules/ngx_http_event_proxy_handler.c --- a/src/http/modules/ngx_http_event_proxy_handler.c +++ b/src/http/modules/ngx_http_event_proxy_handler.c @@ -4,12 +4,53 @@ #include #include #include +#include #include + #include +#include +#include #include #include -ngx_http_module_t ngx_http_proxy_module_ctx; + +static ngx_command_t ngx_http_proxy_commands[] = { + + {ngx_string("proxy_large_header"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, large_header)}, + + {ngx_null_string, 0, NULL, 0, 0} +}; + + +static ngx_http_module_t ngx_http_proxy_module_ctx = { + NGX_HTTP_MODULE, + + NULL, /* create server config */ + NULL, /* init server config */ + NULL, /* create location config */ + NULL, /* merge location config */ + + NULL, /* translate handler */ + + NULL, /* output header filter */ + NULL, /* next output header filter */ + NULL, /* output body filter */ + NULL /* next output body filter */ +}; + + +ngx_module_t ngx_http_proxy_module = { + 0, /* module index */ + &ngx_http_proxy_module_ctx, /* module context */ + ngx_http_proxy_commands, /* module directives */ + NGX_HTTP_MODULE_TYPE, /* module type */ + NULL /* init module */ +}; + static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_request_t *r); @@ -18,6 +59,7 @@ static int ngx_http_proxy_connect(ngx_ht char *addr_text); static int ngx_http_proxy_send_request(ngx_event_t *ev); +static int ngx_http_proxy_init_response(ngx_event_t *ev); static int ngx_http_proxy_read_response_header(ngx_event_t *ev); static int ngx_http_proxy_process_status_line(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p); @@ -45,12 +87,13 @@ int ngx_http_proxy_handler(ngx_http_requ if (p == NULL) { ngx_http_create_ctx(r, p, ngx_http_proxy_module_ctx, - sizeof(ngx_http_proxy_ctx_t)); + sizeof(ngx_http_proxy_ctx_t), + NGX_HTTP_INTERNAL_SERVER_ERROR); } chain = ngx_http_proxy_create_request(r); if (chain == NULL) { - return NGX_ERROR; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } p->out = chain; @@ -74,8 +117,13 @@ static ngx_chain_t *ngx_http_proxy_creat /* 2 is for "\r\n" after request line and 2 is for "\r\n" at the header end */ + + /* STUB: "method p->url HTTP/1.0" length */ + len = r->request_line.len + 2 + 2; + /* TODO: Host length */ + /* "Connection: close\r\n" */ len += sizeof(conn_close) - 1; @@ -98,12 +146,16 @@ static ngx_chain_t *ngx_http_proxy_creat ngx_test_null(hunk, ngx_create_temp_hunk(r->pool, len, 0, 0), NULL); ngx_add_hunk_to_chain(chain, hunk, r->pool, NULL); - ngx_memcpy(hunk->last.mem, r->request_line.data, r->request_line.len); - hunk->last.mem += r->request_line.len; - *(hunk->last.mem++) = CR; *(hunk->last.mem++) = LF; + /* STUB: "method p->url HTTP/1.0" */ - ngx_memcpy(hunk->last.mem, conn_close, sizeof(conn_close) - 1); - hunk->last.mem += sizeof(conn_close) - 1; + ngx_memcpy(hunk->last, r->request_line.data, r->request_line.len); + hunk->last += r->request_line.len; + *(hunk->last++) = CR; *(hunk->last++) = LF; + + /* TODO: Host header */ + + ngx_memcpy(hunk->last, conn_close, sizeof(conn_close) - 1); + hunk->last += sizeof(conn_close) - 1; for (i = 0; i < r->headers_in.headers->nelts; i++) { if (&header[i] == r->headers_in.host) { @@ -114,25 +166,25 @@ static ngx_chain_t *ngx_http_proxy_creat continue; } - ngx_memcpy(hunk->last.mem, header[i].key.data, header[i].key.len); - hunk->last.mem += header[i].key.len; + ngx_memcpy(hunk->last, header[i].key.data, header[i].key.len); + hunk->last += header[i].key.len; - *(hunk->last.mem++) = ':'; *(hunk->last.mem++) = ' '; + *(hunk->last++) = ':'; *(hunk->last++) = ' '; - ngx_memcpy(hunk->last.mem, header[i].value.data, header[i].value.len); - hunk->last.mem += header[i].value.len; + ngx_memcpy(hunk->last, header[i].value.data, header[i].value.len); + hunk->last += header[i].value.len; - *(hunk->last.mem++) = CR; *(hunk->last.mem++) = LF; + *(hunk->last++) = CR; *(hunk->last++) = LF; ngx_log_debug(r->connection->log, "proxy: '%s: %s'" _ header[i].key.data _ header[i].value.data); } /* add "\r\n" at the header end */ - *(hunk->last.mem++) = CR; *(hunk->last.mem++) = LF; + *(hunk->last++) = CR; *(hunk->last++) = LF; - /* STUB */ *(hunk->last.mem++) = '\0'; - ngx_log_debug(r->connection->log, "PROXY:\n'%s'" _ hunk->pos.mem); + /* STUB */ *(hunk->last++) = '\0'; + ngx_log_debug(r->connection->log, "PROXY:\n'%s'" _ hunk->pos); return chain; } @@ -142,7 +194,7 @@ static int ngx_http_proxy_connect(ngx_ht struct sockaddr_in *addr, char *addr_text) { - int rc; + int rc, event; ngx_err_t err; ngx_socket_t s; ngx_event_t *rev, *wev; @@ -157,7 +209,7 @@ static int ngx_http_proxy_connect(ngx_ht if (s == -1) { ngx_log_error(NGX_LOG_ALERT, c->log, ngx_socket_errno, ngx_socket_n " failed"); - return NGX_ERROR; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } #if 0 @@ -172,7 +224,7 @@ static int ngx_http_proxy_connect(ngx_ht ngx_close_socket_n " failed"); } - return NGX_ERROR; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } } #endif @@ -186,7 +238,7 @@ static int ngx_http_proxy_connect(ngx_ht ngx_close_socket_n " failed"); } - return NGX_ERROR; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } rc = connect(s, (struct sockaddr *) addr, sizeof(struct sockaddr_in)); @@ -201,7 +253,7 @@ static int ngx_http_proxy_connect(ngx_ht ngx_close_socket_n " failed"); } - return NGX_ERROR; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } } @@ -226,21 +278,48 @@ static int ngx_http_proxy_connect(ngx_ht ngx_test_null(pc->pool, ngx_create_pool(/* STUB */ 1024 /**/, pc->log), - NGX_ERROR); + NGX_HTTP_INTERNAL_SERVER_ERROR); wev->event_handler = ngx_http_proxy_send_request; - rev->event_handler = ngx_http_proxy_read_response_header; + rev->event_handler = ngx_http_proxy_init_response; -#if (HAVE_CLEAR_EVENT) +#if (USE_KQUEUE) + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_CLEAR_EVENT) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + #else - if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) != NGX_OK) { -#endif - return NGX_ERROR; + +#if (HAVE_CLEAR_EVENT) /* kqueue */ + + if (ngx_event_flags & NGX_HAVE_CLEAR_EVENT) { + event = NGX_CLEAR_EVENT; + + } else { + event = NGX_LEVEL_EVENT; } +#else /* select, poll, /dev/poll */ + + event = NGX_LEVEL_EVENT; + +#endif + + if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + +#endif /* USE_KQUEUE */ + + /* TODO: aio, iocp */ + + /* The connection is in a progress */ if (rc == -1) { - return ngx_add_event(wev, NGX_WRITE_EVENT, NGX_ONESHOT_EVENT); + /* TODO: oneshot */ + if (ngx_add_event(wev, NGX_WRITE_EVENT, NGX_ONESHOT_EVENT) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } } wev->write = 1; @@ -262,7 +341,7 @@ static int ngx_http_proxy_send_request(n p = (ngx_http_proxy_ctx_t *) ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); - chain = ngx_event_write(c, p->out, 0); + chain = ngx_write_chain(c, p->out, 0); if (chain == (ngx_chain_t *) -1) { return NGX_ERROR; } @@ -273,7 +352,7 @@ static int ngx_http_proxy_send_request(n } -static int ngx_http_proxy_read_response_header(ngx_event_t *ev) +static int ngx_http_proxy_init_response(ngx_event_t *ev) { int n; ngx_hunk_t **ph; @@ -281,48 +360,126 @@ static int ngx_http_proxy_read_response_ ngx_http_request_t *r; ngx_http_proxy_ctx_t *p; + c = (ngx_connection_t *) ev->data; + r = (ngx_http_request_t *) c->data; + if (ev->timedout) { - return NGX_ERROR; + return ngx_http_proxy_error(r, p, NGX_HTTP_GATEWAY_TIME_OUT); } + p = (ngx_http_proxy_ctx_t *) + ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); + + ngx_test_null(p->header_in, + ngx_create_temp_hunk(r->pool, + /* STUB */ 1024 /**/, 0, 0), + ngx_http_proxy_error(r, p, NGX_HTTP_INTERNAL_SERVER_ERROR)); + + p->header_in->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; + + ngx_test_null(p->headers_in, + ngx_palloc(r->pool, sizeof(ngx_http_proxy_headers_in_t)), + ngx_http_proxy_error(r, p, NGX_HTTP_INTERNAL_SERVER_ERROR)); + + ngx_init_array(p->hunks, r->pool, + /* STUB */ 10 /**/, + sizeof(ngx_hunk_t *), + ngx_http_proxy_error(r, p, NGX_HTTP_INTERNAL_SERVER_ERROR)); + + ngx_test_null(ph, ngx_push_array(&p->hunks), NGX_ERROR); + *ph = p->header_in; + + p->state_handler = ngx_http_proxy_process_status_line; + + return ngx_http_proxy_read_response_header(ev); +} + + +static int ngx_http_proxy_read_response_header(ngx_event_t *ev) +{ + int n; + ngx_hunk_t **ph; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_proxy_ctx_t *p; + ngx_http_proxy_loc_conf_t *lcf; + c = (ngx_connection_t *) ev->data; r = (ngx_http_request_t *) c->data; p = (ngx_http_proxy_ctx_t *) - ngx_http_get_module_ctx(r, ngx_http_proxy_module_ctx); - - if (p->header_in == NULL) { - ngx_test_null(p->header_in, - ngx_create_temp_hunk(r->pool, - /* STUB */ 1024 /**/, 0, 0), - NGX_ERROR); - - p->header_in->type = NGX_HUNK_MEMORY; + ngx_http_get_module_ctx(r, ngx_http_proxy_module); - ngx_test_null(p->headers_in, - ngx_palloc(r->pool, sizeof(ngx_http_proxy_headers_in_t)), - NGX_ERROR); - - ngx_init_array(p->hunks, r->pool, - /* STUB */ 10 /**/, - sizeof(ngx_hunk_t *), - NGX_ERROR); - - ngx_test_null(ph, ngx_push_array(&p->hunks), NGX_ERROR); - *ph = p->header_in; - - p->state_handler = ngx_http_proxy_process_status_line; + if (ev->timedout) { + return ngx_http_proxy_error(r, p, NGX_HTTP_GATEWAY_TIME_OUT); } - n = ngx_event_recv(c, p->header_in->last.mem, - p->header_in->end - p->header_in->last.mem); + lcf = (ngx_http_proxy_loc_conf_t *) + ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + +#if 0 + + do { + n = ngx_event_recv(c, p->header_in->last, + p->header_in->end - p->header_in->last; + + if (n == NGX_AGAIN) { + if (ev->timer_set) { + ngx_del_timer(ev); + } else { + ev->timer_set = 1; + } + + ngx_add_timer(ev, lcf->timeout); + return NGX_AGAIN; + } + + if (n == NGX_ERROR) { + ngx_http_proxy_close_request(r, p); + return ngx_http_error(r, NGX_HTTP_BAD_GATEWAY); + } + + ngx_log_debug(c->log, "http proxy read %d" _ n); + + if (n == 0) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client has prematurely closed connection"); + ngx_http_proxy_close_request(r, p); + } + + p->header_in->last += n; + + if (lcf->large_header && p->header_in->end == p->header_in->last) { + again = 1; + } else { + again = 0; + } + + + + +#if (HAVE_AIO_EVENT) /* aio, iocp */ + + if (ngx_event_flags & NGX_HAVE_AIO_EVENT) { + again = 1; + } + +#endif + + } while (rc == NGX_AGAIN && again); + +#endif + + n = ngx_event_recv(c, p->header_in->last, + p->header_in->end - p->header_in->last); ngx_log_debug(c->log, "READ:%d" _ n); - p->header_in->last.mem += n; + p->header_in->last += n; /* STUB */ - *p->header_in->last.mem = '\0'; - ngx_log_debug(c->log, "PROXY:\n'%s'" _ p->header_in->pos.mem); + *p->header_in->last = '\0'; + ngx_log_debug(c->log, "PROXY:\n'%s'" _ p->header_in->pos); /**/ if (n == 0) { @@ -355,13 +512,14 @@ static int ngx_http_proxy_read_response_ #endif ev->event_handler = ngx_http_proxy_read_response_body; - if (p->header_in->end - p->header_in->last.mem == 0) { + if (p->header_in->end - p->header_in->last == 0) { return ngx_http_proxy_read_response_body(ev); } return NGX_WAITING; } + static int ngx_http_proxy_process_status_line(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p) { @@ -380,7 +538,7 @@ static int ngx_http_proxy_process_status p->state_handler = NULL; } - if (p->header_in->last.mem >= p->header_in->end) { + if (p->header_in->last >= p->header_in->end) { rc = NGX_HTTP_PARSE_TOO_LONG_STATUS_LINE; } else if (rc == NGX_AGAIN) { @@ -390,6 +548,7 @@ static int ngx_http_proxy_process_status /* STUB */ return NGX_ERROR; } + #if 0 static int ngx_http_proxy_process_response_header(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p) @@ -398,6 +557,7 @@ static int ngx_http_proxy_process_respon } #endif + static int ngx_http_proxy_read_response_body(ngx_event_t *ev) { int n; @@ -419,7 +579,7 @@ static int ngx_http_proxy_read_response_ if (p->hunks.nelts > 0) { h = ((ngx_hunk_t **) p->hunks.elts)[p->hunks.nelts - 1]; - left = h->end - h->last.mem; + left = h->end - h->last; } else { h = NULL; @@ -453,13 +613,13 @@ static int ngx_http_proxy_read_response_ /* STUB */ 4096 /**/, 0, 0), NGX_ERROR); - h->type = NGX_HUNK_MEMORY; + h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; *ph = h; } if (h != NULL) { - buf = h->last.mem; - size = h->end - h->last.mem; + buf = h->last; + size = h->end - h->last; } else { buf = (char *) &buf; @@ -478,12 +638,12 @@ static int ngx_http_proxy_read_response_ return NGX_ERROR; } - h->last.mem += n; - left = h->end - h->last.mem; + h->last += n; + left = h->end - h->last; /* STUB */ - *h->last.mem = '\0'; - ngx_log_debug(c->log, "PROXY:\n'%s'" _ h->pos.mem); + *h->last = '\0'; + ngx_log_debug(c->log, "PROXY:\n'%s'" _ h->pos); /**/ } while (n > 0 && left == 0); @@ -503,6 +663,7 @@ static int ngx_http_proxy_read_response_ /* STUB */ return NGX_WAITING; } + static int ngx_http_proxy_write_to_client(ngx_event_t *ev) { int rc; @@ -536,6 +697,15 @@ static int ngx_http_proxy_write_to_clien } +static int ngx_http_proxy_error(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p, + int error) +{ + ngx_event_close_connection(p->connection->read); + + return ngx_http_error(r, error); +} + + static int ngx_read_http_proxy_status_line(ngx_http_proxy_ctx_t *ctx) { char ch; @@ -554,21 +724,16 @@ static int ngx_read_http_proxy_status_li } state; state = ctx->state; - p = ctx->header_in->pos.mem; - - while (p < ctx->header_in->last.mem && state < sw_done) { - ch = *p++; + p = ctx->header_in->pos; -#if 0 -fprintf(stderr, "state: %d, pos: %x, end: %x, char: '%c', status: %d\n", - state, p, ctx->header_in->last.mem, ch, ctx->status); -#endif + while (p < ctx->header_in->last && state < sw_done) { + ch = *p++; switch (state) { /* "HTTP/" */ case sw_start: - if (p + 3 >= ctx->header_in->last.mem) { + if (p + 3 >= ctx->header_in->last) { return NGX_AGAIN; } @@ -684,7 +849,7 @@ fprintf(stderr, "state: %d, pos: %x, end } } - ctx->header_in->pos.mem = p; + ctx->header_in->pos = p; if (state == sw_done) { if (ctx->request_end == NULL) { diff --git a/src/http/modules/ngx_http_event_proxy_handler.h b/src/http/modules/ngx_http_event_proxy_handler.h --- a/src/http/modules/ngx_http_event_proxy_handler.h +++ b/src/http/modules/ngx_http_event_proxy_handler.h @@ -14,6 +14,12 @@ typedef struct { int dummy; } ngx_http_proxy_headers_in_t; + +typedef struct { + int large_header; +} ngx_http_proxy_loc_conf_t; + + typedef struct ngx_http_proxy_ctx_s ngx_http_proxy_ctx_t; struct ngx_http_proxy_ctx_s { @@ -24,6 +30,7 @@ struct ngx_http_proxy_ctx_s { int hunk_n; + ngx_connection_t *connection; ngx_http_proxy_headers_in_t *headers_in; ngx_hunk_t *header_in; @@ -36,7 +43,11 @@ struct ngx_http_proxy_ctx_s { }; -extern ngx_http_module_t ngx_http_proxy_module; +extern ngx_module_t ngx_http_proxy_module; + + +static int ngx_http_proxy_error(ngx_http_request_t *r, ngx_http_proxy_ctx_t *p, + int error); #endif /* _NGX_HTTP_PROXY_HANDLER_H_INCLUDED_ */ diff --git a/src/http/modules/ngx_http_static_handler.c b/src/http/modules/ngx_http_static_handler.c --- a/src/http/modules/ngx_http_static_handler.c +++ b/src/http/modules/ngx_http_static_handler.c @@ -144,8 +144,8 @@ int ngx_http_static_handler(ngx_http_req #if 1 h->type = NGX_HUNK_FILE|NGX_HUNK_LAST; - h->pos.file = 0; - h->last.file = ngx_file_size(r->file.info); + h->file_pos = 0; + h->file_last = ngx_file_size(r->file.info); h->file->fd = r->file.fd; h->file->log = r->connection->log; diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -27,11 +27,6 @@ int ngx_http_large_client_header = 1; int ngx_http_url_in_error_log = 1; -/* STUB: per location */ -int ngx_http_lingering_timeout = 5000; -int ngx_http_lingering_time = 30; -/**/ - ngx_array_t ngx_http_index_handlers; diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -47,29 +47,17 @@ #define NGX_HTTP_NOT_FOUND 404 #define NGX_HTTP_REQUEST_URI_TOO_LARGE 414 #define NGX_HTTP_INTERNAL_SERVER_ERROR 500 +#define NGX_HTTP_NOT_IMPLEMENTED 501 +#define NGX_HTTP_BAD_GATEWAY 502 +#define NGX_HTTP_SERVICE_UNAVAILABLE 503 +#define NGX_HTTP_GATEWAY_TIME_OUT 504 + #define NGX_HTTP_STATIC_HANDLER 0 #define NGX_HTTP_DIRECTORY_HANDLER 1 - -typedef struct { - char *doc_root; - size_t doc_root_len; - - size_t connection_pool_size; - size_t request_pool_size; - - size_t header_buffer_size; - size_t discarded_buffer_size; - - ngx_msec_t header_timeout; - ngx_msec_t lingering_timeout; - time_t lingering_time; -} ngx_http_server_t; - - typedef struct { size_t len; char *data; @@ -232,9 +220,9 @@ typedef struct { #define ngx_http_get_module_loc_conf(r, module) r->loc_conf[module.index] #define ngx_http_get_module_ctx(r, module) r->ctx[module.index] -#define ngx_http_create_ctx(r, cx, module, size) \ +#define ngx_http_create_ctx(r, cx, module, size, error) \ do { \ - ngx_test_null(cx, ngx_pcalloc(r->pool, size), NGX_ERROR); \ + ngx_test_null(cx, ngx_pcalloc(r->pool, size), error); \ r->ctx[module.index] = cx; \ } while (0) @@ -279,9 +267,6 @@ extern int ngx_http_client_header_buffe extern int ngx_http_large_client_header; extern int ngx_http_discarded_buffer_size; -extern int ngx_http_lingering_timeout; -extern int ngx_http_lingering_time; - extern int ngx_http_url_in_error_log; extern ngx_array_t ngx_http_index_handlers; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -96,6 +96,18 @@ static ngx_command_t ngx_http_core_comm NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, send_timeout)}, + {ngx_string("lingering_time"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_time_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, lingering_time)}, + + {ngx_string("lingering_timeout"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_time_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, lingering_timeout)}, + {ngx_string(""), 0, NULL, 0, 0} }; @@ -138,7 +150,7 @@ int ngx_http_handler(ngx_http_request_t r->connection->unexpected_eof = 0; r->lingering_close = 1; - r->keepalive = 1; + r->keepalive = 0; #if 1 r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY; @@ -264,6 +276,11 @@ ngx_log_debug(r->connection->log, "trans } } +#if 0 + /* STUB */ r->handler = ngx_http_proxy_handler; + return NGX_OK; +#endif + if (r->uri.data[r->uri.len - 1] == '/') { r->handler = ngx_http_core_index_handler; return NGX_OK; @@ -504,44 +521,38 @@ int ngx_http_error(ngx_http_request_t *r int ngx_http_close_request(ngx_http_request_t *r) { + ngx_connection_t *c; ngx_http_log_ctx_t *ctx; - ngx_log_debug(r->connection->log, "CLOSE#: %d" _ r->file.fd); + c = r->connection; ngx_http_log_handler(r); - ngx_assert((r->file.fd != NGX_INVALID_FILE), /* void */ ; , - r->connection->log, "file already closed"); - if (r->file.fd != NGX_INVALID_FILE) { if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno, ngx_close_file_n " failed"); } } -/* - if (r->logging) - ngx_http_log_request(r); -*/ - - ctx = (ngx_http_log_ctx_t *) r->connection->log->data; - /* ctx->url was allocated from r->pool */ + ctx = (ngx_http_log_ctx_t *) c->log->data; ctx->url = NULL; ngx_destroy_pool(r->pool); - ngx_log_debug(r->connection->log, "http closed"); - - if (r->connection->read->timer_set) { - ngx_del_timer(r->connection->read); + if (c->read->timer_set) { + ngx_del_timer(c->read); + c->read->timer_set = 0; } - if (r->connection->write->timer_set) { - ngx_del_timer(r->connection->write); + if (c->write->timer_set) { + ngx_del_timer(c->write); + c->write->timer_set = 0; } + ngx_log_debug(c->log, "http closed"); + return NGX_DONE; } @@ -780,7 +791,7 @@ static void *ngx_http_core_create_loc_co lcf->send_timeout = 10; lcf->discarded_buffer_size = 1500; - lcf->lingering_time = 30; + lcf->lingering_time = 30000; lcf->lingering_timeout = 5000; /* @@ -809,8 +820,8 @@ static char *ngx_set_listen(ngx_conf_t * args = (ngx_str_t *) cf->args->elts; ls->port = atoi(args[1].data); - if (ls->port < 0) { - return "port must be greater or equal to zero"; + if (ls->port < 1 || ls->port > 65536) { + return "port must be between 1 and 65535"; } return NGX_CONF_OK; diff --git a/src/http/ngx_http_event.c b/src/http/ngx_http_event.c --- a/src/http/ngx_http_event.c +++ b/src/http/ngx_http_event.c @@ -130,7 +130,6 @@ int ngx_http_init_connection(ngx_connect /* select, poll, /dev/poll */ - ev->level = 1; return ngx_add_event(ev, NGX_READ_EVENT, NGX_LEVEL_EVENT); #endif /* USE_KQUEUE */ @@ -190,7 +189,7 @@ static int ngx_http_init_request(ngx_eve static int ngx_http_process_request_header(ngx_event_t *ev) { - int n, rc; + int n, rc, again; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_log_ctx_t *ctx; @@ -200,18 +199,22 @@ static int ngx_http_process_request_head ngx_log_debug(ev->log, "http process request"); -#if (HAVE_AIO_EVENT) do { -#endif if (r->header_read) { + if (r->header_in->end - r->header_in->last == 0) { + again = 1; + } else { + again = 0; + } + r->header_read = 0; ngx_log_debug(ev->log, "http preread %d" _ - r->header_in->last.mem - r->header_in->pos.mem); + r->header_in->last - r->header_in->pos); } else { - n = ngx_event_recv(c, r->header_in->last.mem, - r->header_in->end - r->header_in->last.mem); + n = ngx_event_recv(c, r->header_in->last, + r->header_in->end - r->header_in->last); if (n == NGX_AGAIN) { if (!r->header_timeout_set) { @@ -228,8 +231,9 @@ static int ngx_http_process_request_head return NGX_AGAIN; } - if (n == NGX_ERROR) + if (n == NGX_ERROR) { return ngx_http_close_request(r); + } ngx_log_debug(ev->log, "http read %d" _ n); @@ -239,7 +243,14 @@ static int ngx_http_process_request_head return ngx_http_close_request(r); } - r->header_in->last.mem += n; + r->header_in->last += n; + + if (ngx_http_large_client_header + && r->header_in->end == r->header_in->last) { + again = 1; + } else { + again = 0; + } } /* the state_handlers are called in the following order: @@ -250,16 +261,22 @@ static int ngx_http_process_request_head /* state_handlers return NGX_OK when the whole header done */ rc = (r->state_handler)(r); - if (rc == NGX_ERROR) + if (rc == NGX_ERROR) { return rc; + } - } while (rc == NGX_AGAIN - && r->header_in->pos.mem < r->header_in->last.mem); + } while (rc == NGX_AGAIN && r->header_in->pos < r->header_in->last); #if (HAVE_AIO_EVENT) /* aio, iocp */ - } while (rc == NGX_AGAIN && ngx_event_flags & NGX_HAVE_AIO_EVENT); + + if (ngx_event_flags & NGX_HAVE_AIO_EVENT) { + again = 1; + } + #endif + } while (rc == NGX_AGAIN && again); + if (rc == NGX_OK) { /* HTTP header done */ @@ -308,7 +325,7 @@ static int ngx_http_process_request_line ngx_http_close_request(r)); ngx_cpystrn(r->uri.data, r->uri_start, r->uri.len + 1); - /* if the large client headers is enabled then + /* if the large client headers are enabled then we need to copy a request line */ r->request_line.len = r->request_end - r->request_start; @@ -376,12 +393,12 @@ static int ngx_http_process_request_line /* NGX_AGAIN: a request line parsing is still not complete */ - if (r->header_in->last.mem == r->header_in->end) { + if (r->header_in->last == r->header_in->end) { /* If it's a pipelined request and a request line is not complete then we need to copy it to the start of r->header_in hunk. - We need to copy it here only if the large client header - is enabled otherwise a request line had been already copied + We need to copy it here only if the large client headers + are enabled otherwise a request line had been already copied to the start of r->header_in hunk in ngx_http_set_keepalive() */ if (ngx_http_large_client_header) { @@ -394,10 +411,10 @@ static int ngx_http_process_request_line } ngx_memcpy(r->header_in->start, r->request_start, - r->header_in->last.mem - r->request_start); + r->header_in->last - r->request_start); - r->header_in->pos.mem -= offset; - r->header_in->last.mem -= offset; + r->header_in->pos -= offset; + r->header_in->last -= offset; r->request_start = r->header_in->start; r->request_end -= offset; r->uri_start -= offset; @@ -437,7 +454,7 @@ static int ngx_http_process_request_head return NGX_AGAIN; - /* the whole header has been parsed successfully */ + /* a whole header has been parsed successfully */ } else if (rc == NGX_HTTP_PARSE_HEADER_DONE) { ngx_log_debug(r->connection->log, "HTTP header done"); @@ -468,9 +485,9 @@ static int ngx_http_process_request_head /* NGX_AGAIN: a header line parsing is still not complete */ - if (r->header_in->last.mem == r->header_in->end) { + if (r->header_in->last == r->header_in->end) { - /* if the large client header is enabled then + /* if the large client headers are enabled then we need to compact r->header_in hunk */ if (ngx_http_large_client_header) { @@ -483,10 +500,10 @@ static int ngx_http_process_request_head } ngx_memcpy(r->header_in->start, r->header_name_start, - r->header_in->last.mem - r->header_name_start); + r->header_in->last - r->header_name_start); - r->header_in->last.mem -= offset; - r->header_in->pos.mem -= offset; + r->header_in->last -= offset; + r->header_in->pos -= offset; r->header_name_start = r->header_in->start; r->header_name_end -= offset; r->header_start -= offset; @@ -512,7 +529,7 @@ static int ngx_http_process_request_head ngx_test_null(h, ngx_push_table(r->headers_in.headers), NGX_ERROR); - /* if large client header is enabled then + /* if large client headers are enabled then we need to copy header name and value */ h->key.len = r->header_name_end - r->header_name_start; @@ -631,13 +648,11 @@ static int ngx_http_event_request_handle } else { event = NGX_LEVEL_EVENT; - wev->level = 1; } #else /* select, poll, /dev/poll */ event = NGX_LEVEL_EVENT; - wev->level = 1; #endif @@ -751,11 +766,11 @@ static int ngx_http_block_read(ngx_event #else - if (ev->level) { /* select, poll, /dev/poll */ + if (ngx_event_flags & NGX_USE_LEVEL_EVENT) { /* select, poll, /dev/poll */ ev->blocked = 1; return ngx_del_event(ev, NGX_READ_EVENT, 0); - } else { /* kqueue, epoll */ + } else { /* kqueue, epoll */ return NGX_OK; } @@ -831,7 +846,7 @@ static int ngx_http_read_discarded_body( static int ngx_http_set_keepalive(ngx_http_request_t *r) { - int len; + int len, blocked; ngx_hunk_t *h; ngx_event_t *rev, *wev; ngx_connection_t *c; @@ -841,33 +856,37 @@ static int ngx_http_set_keepalive(ngx_ht rev = c->read; wev = c->write; - if (rev->blocked && rev->level) { + ctx = (ngx_http_log_ctx_t *) c->log->data; + ctx->action = "closing request"; + ngx_http_close_request(r); + + if (rev->blocked && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) { return NGX_ERROR; } + blocked = 1; rev->blocked = 0; - } - ctx = (ngx_http_log_ctx_t *) c->log->data; - ctx->action = "closing request"; - ngx_http_close_request(r); + } else { + blocked = 0; + } h = c->buffer; /* pipelined request */ - if (h->pos.mem < h->last.mem) { + if (h->pos < h->last) { /* We do not know here whether pipelined request is complete - so we need to copy it to the start of c->buffer if the large - client header is not enabled. This copy should be rare - because clients that support pipelined requests (Mozilla 1.x, - Opera 6.x) are still rare */ + so if large client headers are not enabled + we need to copy the data to the start of c->buffer. + This copy should be rare because clients that support + pipelined requests (Mozilla 1.x, Opera 6.x) are still rare */ if (!ngx_http_large_client_header) { - len = h->last.mem - h->pos.mem; - ngx_memcpy(h->start, h->pos.mem, len); - h->pos.mem = h->start; - h->last.mem = h->start + len; + len = h->last - h->pos; + ngx_memcpy(h->start, h->pos, len); + h->pos = h->start; + h->last = h->start + len; } c->pipeline = 1; @@ -877,10 +896,10 @@ static int ngx_http_set_keepalive(ngx_ht c->pipeline = 0; - h->pos.mem = h->last.mem = h->start; + h->pos = h->last = h->start; rev->event_handler = ngx_http_keepalive_handler; - if (wev->active && wev->level) { + if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } @@ -890,7 +909,13 @@ static int ngx_http_set_keepalive(ngx_ht #if (HAVE_AIO_EVENT) /* aio, iocp */ - if (ngx_event_flags & NGX_HAVE_AIO_EVENT) { + if ((ngx_event_flags & NGX_HAVE_AIO_EVENT) || blocked) { + return ngx_http_keepalive_handler(rev); + } + +#else + + if (blocked) { return ngx_http_keepalive_handler(rev); } @@ -913,11 +938,13 @@ static int ngx_http_keepalive_handler(ng if (ev->timedout) return NGX_DONE; - /* TODO: MSIE closes keepalive connection with ECONNRESET - so we need to handle here this error - 1) in INFO (not ERR) level, 2) with time elapsed */ - n = ngx_event_recv(c, c->buffer->last.mem, - c->buffer->end - c->buffer->last.mem); + /* MSIE closes keepalive connection with RST flag + so we ignore ECONNRESET here */ + + ev->ignore_econnreset = 1; + ngx_set_socket_errno(0); + n = ngx_event_recv(c, c->buffer->last, c->buffer->end - c->buffer->last); + ev->ignore_econnreset = 0; if (n == NGX_AGAIN || n == NGX_ERROR) return n; @@ -926,12 +953,12 @@ static int ngx_http_keepalive_handler(ng ev->log->handler = NULL; if (n == 0) { - ngx_log_error(NGX_LOG_INFO, ev->log, 0, + ngx_log_error(NGX_LOG_INFO, ev->log, ngx_socket_errno, "client %s closed keepalive connection", ctx->client); return NGX_DONE; } - c->buffer->last.mem += n; + c->buffer->last += n; ev->log->handler = ngx_http_log_error; ctx->action = "reading client request line"; @@ -941,57 +968,67 @@ static int ngx_http_keepalive_handler(ng static int ngx_http_set_lingering_close(ngx_http_request_t *r) { - ngx_event_t *ev; - ngx_connection_t *c; + int blocked; + ngx_event_t *rev, *wev; + ngx_connection_t *c; ngx_http_core_loc_conf_t *lcf; c = r->connection; - ev = r->connection->read; + rev = c->read; + wev = c->write; lcf = (ngx_http_core_loc_conf_t *) ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx); - r->lingering_time = ngx_time() + lcf->lingering_time; + r->lingering_time = ngx_time() + lcf->lingering_time / 1000; r->connection->read->event_handler = ngx_http_lingering_close_handler; - if (ev->timer_set) { - ngx_del_timer(ev); + if (rev->timer_set) { + ngx_del_timer(rev); } else { - ev->timer_set = 1; + rev->timer_set = 1; } - ngx_add_timer(ev, lcf->lingering_timeout); + ngx_add_timer(rev, lcf->lingering_timeout); - if (ev->blocked) { - if (ngx_event_flags & NGX_HAVE_LEVEL_EVENT) { - if (ngx_add_event(ev, NGX_READ_EVENT, NGX_LEVEL_EVENT) - == NGX_ERROR) { - return ngx_http_close_request(r); - } + if (rev->blocked && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { + if (ngx_add_event(rev, NGX_READ_EVENT, NGX_LEVEL_EVENT) == NGX_ERROR) { + return ngx_http_close_request(r); + } + blocked = 1; + rev->blocked = 0; + + } else { + blocked = 0; + } + + if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { + if (ngx_del_event(wev, NGX_WRITE_EVENT, 0) == NGX_ERROR) { + return ngx_http_close_request(r); } } - if (ngx_shutdown_socket(r->connection->fd, NGX_WRITE_SHUTDOWN) == -1) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_socket_errno, + if (ngx_shutdown_socket(c->fd, NGX_WRITE_SHUTDOWN) == -1) { + ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, ngx_shutdown_socket_n " failed"); return ngx_http_close_request(r); } #if (HAVE_AIO_EVENT) /* aio, iocp */ - if (ngx_event_flags & NGX_HAVE_AIO_EVENT) { - return ngx_http_lingering_close_handler(ev); + + if ((ngx_event_flags & NGX_HAVE_AIO_EVENT) || blocked) { + return ngx_http_lingering_close_handler(rev); } + +#else + + if (blocked) { + return ngx_http_lingering_close_handler(rev); + } + #endif -#if (HAVE_CLEAR_EVENT) /* kqueue */ || (HAVE_EDGE_EVENT) /* epoll */ - if (ngx_event_flags & (NGX_HAVE_CLEAR_EVENT|NGX_HAVE_EDGE_EVENT)) { - return NGX_OK; - } -#endif - - /* select, poll, /dev/poll */ - - return ngx_del_event(c->write, NGX_WRITE_EVENT, 0); + return NGX_OK; } @@ -1021,9 +1058,14 @@ static int ngx_http_lingering_close_hand ngx_http_get_module_loc_conf(r, ngx_http_core_module_ctx); if (r->discarded_buffer == NULL) { - if ((size_t)(r->header_in->end - r->header_in->last.mem) + + /* TODO: r->header_in->start (if large headers are enabled) + or the end of parsed header (otherwise) + instead of r->header_in->last */ + + if ((size_t)(r->header_in->end - r->header_in->last) >= lcf->discarded_buffer_size) { - r->discarded_buffer = r->header_in->last.mem; + r->discarded_buffer = r->header_in->last; } else { ngx_test_null(r->discarded_buffer, diff --git a/src/http/ngx_http_header_filter.c b/src/http/ngx_http_header_filter.c --- a/src/http/ngx_http_header_filter.c +++ b/src/http/ngx_http_header_filter.c @@ -48,22 +48,37 @@ static char server_string[] = "Server: " static ngx_str_t http_codes[] = { ngx_string("200 OK"), -#if 0 - { 6, "200 OK" }, -#endif + + ngx_string("301 Moved Permanently"), + ngx_string("302 Moved Temporarily"), + ngx_null_string, /* 303 */ + ngx_string("304 Not Modified"), - { 21, "301 Moved Permanently" }, - { 21, "302 Moved Temporarily" }, - { 0, NULL }, - { 16, "304 Not Modified" }, + ngx_string("400 Bad Request"), + ngx_null_string, /* 401 */ + ngx_null_string, /* 402 */ + ngx_string("403 Forbidden"), + ngx_string("404 Not Found"), + ngx_null_string, /* 405 */ + ngx_null_string, /* 406 */ + ngx_null_string, /* 407 */ + ngx_string("408 Request Time-out"), + ngx_null_string, /* 409 */ + ngx_null_string, /* 410 */ + ngx_string("411 Length Required"), + ngx_null_string, /* 412 */ + ngx_string("413 Request Entity Too Large"), + ngx_null_string, /* "414 Request-URI Too Large" but we never send it + because we treat such requests as HTTP/0.9 requests + and send only the body without the header */ + ngx_null_string, /* 415 */ + ngx_string("416 Requested Range Not Satisfiable"), - { 15, "400 Bad Request" }, - { 0, NULL }, - { 0, NULL }, - { 13, "403 Forbidden" }, - { 13, "404 Not Found" }, - - { 25, "500 Internal Server Error" } + ngx_string("500 Internal Server Error"), + ngx_string("501 Method Not Implemented"), + ngx_string("502 Bad Gateway"), + ngx_string("503 Service Temporarily Unavailable"), + ngx_string("504 Gateway Time-out") }; @@ -124,7 +139,7 @@ static int ngx_http_header_filter(ngx_ht } else { status = r->headers_out.status - - NGX_HTTP_INTERNAL_SERVER_ERROR + 1 + 4 + 5; + - NGX_HTTP_INTERNAL_SERVER_ERROR + 1 + 4 + 17; } len += http_codes[status].len; @@ -181,49 +196,49 @@ static int ngx_http_header_filter(ngx_ht ngx_test_null(h, ngx_create_temp_hunk(r->pool, len, 0, 64), NGX_ERROR); /* "HTTP/1.x " */ - ngx_memcpy(h->last.mem, "HTTP/1.1 ", 9); - h->last.mem += 9; + ngx_memcpy(h->last, "HTTP/1.1 ", 9); + h->last += 9; /* status line */ if (r->headers_out.status_line.len) { - ngx_memcpy(h->last.mem, r->headers_out.status_line.data, + ngx_memcpy(h->last, r->headers_out.status_line.data, r->headers_out.status_line.len); - h->last.mem += r->headers_out.status_line.len; + h->last += r->headers_out.status_line.len; } else { - ngx_memcpy(h->last.mem, http_codes[status].data, + ngx_memcpy(h->last, http_codes[status].data, http_codes[status].len); - h->last.mem += http_codes[status].len; + h->last += http_codes[status].len; } - *(h->last.mem++) = CR; *(h->last.mem++) = LF; + *(h->last++) = CR; *(h->last++) = LF; if (!(r->headers_out.server && r->headers_out.server->key.len)) { - ngx_memcpy(h->last.mem, server_string, sizeof(server_string) - 1); - h->last.mem += sizeof(server_string) - 1; + ngx_memcpy(h->last, server_string, sizeof(server_string) - 1); + h->last += sizeof(server_string) - 1; } if (!(r->headers_out.date && r->headers_out.date->key.len)) { - ngx_memcpy(h->last.mem, "Date: ", 6); - h->last.mem += 6; - h->last.mem += ngx_http_get_time(h->last.mem, time(NULL)); - *(h->last.mem++) = CR; *(h->last.mem++) = LF; + ngx_memcpy(h->last, "Date: ", 6); + h->last += 6; + h->last += ngx_http_get_time(h->last, time(NULL)); + *(h->last++) = CR; *(h->last++) = LF; } /* 2^64 is 20 characters */ if (r->headers_out.content_length >= 0) { - h->last.mem += ngx_snprintf(h->last.mem, 49, + h->last += ngx_snprintf(h->last, 49, "Content-Length: " OFF_FMT CRLF, r->headers_out.content_length); } #if 0 if (r->headers_out.content_type.len) { - ngx_memcpy(h->last.mem, "Content-Type: ", 14); - h->last.mem += 14; - ngx_memcpy(h->last.mem, r->headers_out.content_type.data, + ngx_memcpy(h->last, "Content-Type: ", 14); + h->last += 14; + ngx_memcpy(h->last, r->headers_out.content_type.data, r->headers_out.content_type.len); - h->last.mem += r->headers_out.content_type.len; - *(h->last.mem++) = CR; *(h->last.mem++) = LF; + h->last += r->headers_out.content_type.len; + *(h->last++) = CR; *(h->last++) = LF; } #endif @@ -231,20 +246,20 @@ static int ngx_http_header_filter(ngx_ht && r->headers_out.last_modified->key.len) && r->headers_out.last_modified_time != -1) { - ngx_memcpy(h->last.mem, "Last-Modified: ", 15); - h->last.mem += 15; - h->last.mem += ngx_http_get_time(h->last.mem, + ngx_memcpy(h->last, "Last-Modified: ", 15); + h->last += 15; + h->last += ngx_http_get_time(h->last, r->headers_out.last_modified_time); - *(h->last.mem++) = CR; *(h->last.mem++) = LF; + *(h->last++) = CR; *(h->last++) = LF; } if (r->keepalive == 0) { - ngx_memcpy(h->last.mem, "Connection: close" CRLF, 19); - h->last.mem += 19; + ngx_memcpy(h->last, "Connection: close" CRLF, 19); + h->last += 19; } else { - ngx_memcpy(h->last.mem, "Connection: keep-alive" CRLF, 24); - h->last.mem += 24; + ngx_memcpy(h->last, "Connection: keep-alive" CRLF, 24); + h->last += 24; } for (i = 0; i < r->headers_out.headers->nelts; i++) { @@ -252,22 +267,22 @@ static int ngx_http_header_filter(ngx_ht continue; } - ngx_memcpy(h->last.mem, header[i].key.data, header[i].key.len); - h->last.mem += header[i].key.len; - *(h->last.mem++) = ':' ; *(h->last.mem++) = ' ' ; + ngx_memcpy(h->last, header[i].key.data, header[i].key.len); + h->last += header[i].key.len; + *(h->last++) = ':' ; *(h->last++) = ' ' ; - ngx_memcpy(h->last.mem, header[i].value.data, header[i].value.len); - h->last.mem += header[i].value.len; - *(h->last.mem++) = CR; *(h->last.mem++) = LF; + ngx_memcpy(h->last, header[i].value.data, header[i].value.len); + h->last += header[i].value.len; + *(h->last++) = CR; *(h->last++) = LF; } /* STUB */ - *(h->last.mem) = '\0'; - ngx_log_debug(r->connection->log, "%s\n" _ h->pos.mem); + *(h->last) = '\0'; + ngx_log_debug(r->connection->log, "%s\n" _ h->pos); /**/ /* end of HTTP header */ - *(h->last.mem++) = CR; *(h->last.mem++) = LF; + *(h->last++) = CR; *(h->last++) = LF; if (r->header_only) { h->type |= NGX_HUNK_LAST; diff --git a/src/http/ngx_http_output_filter.c b/src/http/ngx_http_output_filter.c --- a/src/http/ngx_http_output_filter.c +++ b/src/http/ngx_http_output_filter.c @@ -26,7 +26,7 @@ static ngx_command_t ngx_http_output_fi NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_output_filter_conf_t, hunk_size)}, - {ngx_string(""), 0, NULL, 0, 0} + {ngx_null_string, 0, NULL, 0, 0} }; @@ -63,8 +63,8 @@ ngx_module_t ngx_http_output_filter_mod #define need_to_copy(r, hunk) \ (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY) \ && (hunk->type & NGX_HUNK_FILE)) \ - || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP) \ - && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP)))) + || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP) \ + && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP)))) int ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk) @@ -81,7 +81,7 @@ int ngx_http_output_filter(ngx_http_requ if (ctx == NULL) { ngx_http_create_ctx(r, ctx, ngx_http_output_filter_module, - sizeof(ngx_http_output_filter_ctx_t)); + sizeof(ngx_http_output_filter_ctx_t), NGX_ERROR); } /* the short path for the case when the chain ctx->incoming is empty @@ -124,7 +124,12 @@ int ngx_http_output_filter(ngx_http_requ ngx_http_output_filter_module); if (hunk->type & NGX_HUNK_LAST) { - size = hunk->last.mem - hunk->pos.mem; + if (hunk->type & NGX_HUNK_IN_MEMORY) { + size = hunk->last - hunk->pos; + } else { + size = hunk->file_last - hunk->file_pos; + } + if (size > conf->hunk_size) { size = conf->hunk_size; } @@ -140,7 +145,7 @@ int ngx_http_output_filter(ngx_http_requ /* our hunk is still busy */ - } else if (ctx->hunk->pos.mem < ctx->hunk->last.mem) { + } else if (ctx->hunk->pos < ctx->hunk->last) { rc = next_filter(r, NULL); if (rc == NGX_ERROR || rc == NGX_AGAIN) { @@ -149,7 +154,7 @@ int ngx_http_output_filter(ngx_http_requ /* NGX_OK */ /* set our hunk free */ - ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start; + ctx->hunk->pos = ctx->hunk->last = ctx->hunk->start; } #if (NGX_SUPPRESS_WARN) @@ -209,11 +214,20 @@ int ngx_http_output_filter(ngx_http_requ /* NGX_OK */ /* set our hunk free */ - ctx->hunk->pos.mem = ctx->hunk->last.mem = ctx->hunk->start; + ctx->hunk->pos = ctx->hunk->last = ctx->hunk->start; + + /* repeat until we will have copied the whole first hunk from + the chain ctx->incoming */ - /* repeat until we will have copied the whole first hunk from - the chain ctx->incoming */ - } while (ctx->incoming->hunk->pos.mem < ctx->incoming->hunk->last.mem); + if (ctx->incoming->hunk->type & NGX_HUNK_IN_MEMORY) { + size = ctx->incoming->hunk->last - ctx->incoming->hunk->pos; + + } else { + size = ctx->incoming->hunk->file_last + - ctx->incoming->hunk->file_pos; + } + + } while (size); /* delete the completed hunk from the incoming chain */ ctx->incoming = ctx->incoming->next; @@ -229,13 +243,31 @@ static int ngx_http_output_filter_copy_h { ssize_t n, size; - size = src->last.mem - src->pos.mem; - if (size > (dst->end - dst->pos.mem)) { - size = dst->end - dst->pos.mem; + if (src->type & NGX_HUNK_IN_MEMORY) { + size = src->last - src->pos; + } else { + size = src->file_last - src->file_pos; + } + + if (size > (dst->end - dst->pos)) { + size = dst->end - dst->pos; } - if (src->type & NGX_HUNK_FILE) { - n = ngx_read_file(src->file, dst->pos.mem, size, src->pos.file); + if (src->type & NGX_HUNK_IN_MEMORY) { + ngx_memcpy(src->pos, dst->pos, size); + src->pos += size; + dst->last += size; + + if (src->type & NGX_HUNK_FILE) { + src->file_pos += n; + } + + if (src->type & NGX_HUNK_LAST && src->pos == src->last) { + dst->type |= NGX_HUNK_LAST; + } + + } else { + n = ngx_read_file(src->file, dst->pos, size, src->file_pos); if (n == NGX_ERROR) { return n; @@ -256,17 +288,12 @@ static int ngx_http_output_filter_copy_h } } - src->pos.mem += n; - dst->last.mem += n; + src->file_pos += n; + dst->last += n; - } else { - ngx_memcpy(src->pos.mem, dst->pos.mem, size); - src->pos.mem += size; - dst->last.mem += size; - } - - if (src->type & NGX_HUNK_LAST && src->pos.mem == src->last.mem) { - dst->type |= NGX_HUNK_LAST; + if (src->type & NGX_HUNK_LAST && src->file_pos == src->file_last) { + dst->type |= NGX_HUNK_LAST; + } } return NGX_OK; diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -25,15 +25,10 @@ int ngx_read_http_request_line(ngx_http_ } state; state = r->state; - p = r->header_in->pos.mem; - - while (p < r->header_in->last.mem && state < sw_done) { - ch = *p++; + p = r->header_in->pos; -/* -printf("\nstate: %d, pos: %x, end: %x, char: '%c' buf: %s", - state, p, r->header_in->last, ch, p); -*/ + while (p < r->header_in->last && state < sw_done) { + ch = *p++; /* GCC 2.95.2 and VC 6.0 compile this switch as jump table */ @@ -45,7 +40,7 @@ printf("\nstate: %d, pos: %x, end: %x, c switch (ch) { case 'G': - if (p + 1 >= r->header_in->last.mem) { + if (p + 1 >= r->header_in->last) { return NGX_AGAIN; } @@ -58,7 +53,7 @@ printf("\nstate: %d, pos: %x, end: %x, c break; case 'H': - if (p + 2 >= r->header_in->last.mem) { + if (p + 2 >= r->header_in->last) { return NGX_AGAIN; } @@ -71,7 +66,7 @@ printf("\nstate: %d, pos: %x, end: %x, c break; case 'P': - if (p + 2 >= r->header_in->last.mem) { + if (p + 2 >= r->header_in->last) { return NGX_AGAIN; } @@ -228,9 +223,9 @@ printf("\nstate: %d, pos: %x, end: %x, c /* "TTP/" */ case sw_http_version: - if (p + 2 >= r->header_in->last.mem) { + if (p + 2 >= r->header_in->last) { r->state = sw_http_version; - r->header_in->pos.mem = p - 1; + r->header_in->pos = p - 1; return NGX_AGAIN; } @@ -309,7 +304,7 @@ printf("\nstate: %d, pos: %x, end: %x, c } } - r->header_in->pos.mem = p; + r->header_in->pos = p; if (state == sw_done) { if (r->request_end == NULL) { @@ -348,15 +343,10 @@ int ngx_read_http_header_line(ngx_http_r } state; state = r->state; - p = h->pos.mem; - - while (p < h->last.mem && state < sw_done) { - ch = *p++; + p = h->pos; -/* -printf("\nstate: %d, pos: %x, end: %x, char: '%c' buf: %s", - state, p, h->last.mem, ch, p); -*/ + while (p < h->last && state < sw_done) { + ch = *p++; switch (state) { @@ -495,7 +485,7 @@ printf("\nstate: %d, pos: %x, end: %x, c } } - h->pos.mem = p; + h->pos = p; if (state == sw_done) { r->state = sw_start; diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -39,6 +39,14 @@ static char error_404_page[] = ; +static char error_414_page[] = +"" CRLF +"414 Request-URI Too Large" CRLF +"" CRLF +"

414 Request-URI Too Large

" CRLF +; + + static char error_500_page[] = "" CRLF "500 Internal Server Error" CRLF @@ -58,6 +66,16 @@ static ngx_str_t error_pages[] = { { 0, NULL}, /* 402 */ { sizeof(error_403_page) - 1, error_403_page }, { sizeof(error_404_page) - 1, error_404_page }, + { 0, NULL}, /* 405 */ + { 0, NULL}, /* 406 */ + { 0, NULL}, /* 407 */ + { 0, NULL}, /* 408 */ + { 0, NULL}, /* 409 */ + { 0, NULL}, /* 410 */ + { 0, NULL}, /* 411 */ + { 0, NULL}, /* 412 */ + { 0, NULL}, /* 413 */ + { sizeof(error_414_page) - 1, error_414_page }, { sizeof(error_500_page) - 1, error_500_page } }; @@ -79,7 +97,7 @@ int ngx_http_special_response(ngx_http_r err = error - NGX_HTTP_BAD_REQUEST + 4; else - err = error - NGX_HTTP_INTERNAL_SERVER_ERROR + 4 + 5; + err = error - NGX_HTTP_INTERNAL_SERVER_ERROR + 4 + 15; if (error_pages[err].len == 0) r->headers_out.content_length = -1; @@ -97,9 +115,9 @@ int ngx_http_special_response(ngx_http_r ngx_test_null(message, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), NGX_ERROR); - message->type = NGX_HUNK_MEMORY; - message->pos.mem = error_pages[err].data; - message->last.mem = error_pages[err].data + error_pages[err].len; + message->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; + message->pos = error_pages[err].data; + message->last = error_pages[err].data + error_pages[err].len; if (ngx_http_output_filter(r, message) == NGX_ERROR) { return NGX_ERROR; @@ -107,9 +125,9 @@ int ngx_http_special_response(ngx_http_r ngx_test_null(tail, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), NGX_ERROR); - tail->type = NGX_HUNK_MEMORY|NGX_HUNK_LAST; - tail->pos.mem = error_tail; - tail->last.mem = error_tail + sizeof(error_tail); + tail->type = NGX_HUNK_MEMORY|NGX_HUNK_LAST|NGX_HUNK_IN_MEMORY; + tail->pos = error_tail; + tail->last = error_tail + sizeof(error_tail); return ngx_http_output_filter(r, tail); } diff --git a/src/http/ngx_http_write_filter.c b/src/http/ngx_http_write_filter.c --- a/src/http/ngx_http_write_filter.c +++ b/src/http/ngx_http_write_filter.c @@ -70,7 +70,7 @@ int ngx_http_write_filter(ngx_http_reque ngx_http_write_filter_module); if (ctx == NULL) { ngx_http_create_ctx(r, ctx, ngx_http_write_filter_module, - sizeof(ngx_http_write_filter_ctx_t)); + sizeof(ngx_http_write_filter_ctx_t), NGX_ERROR); } size = flush = 0; @@ -80,14 +80,12 @@ int ngx_http_write_filter(ngx_http_reque /* find the size, the flush point and the last entry of saved chain */ for (ce = ctx->out; ce; ce = ce->next) { le = &ce->next; - size += ce->hunk->last.file - ce->hunk->pos.file; -#if (NGX_DEBUG_WRITE_FILTER) - ngx_log_debug(r->connection->log, "write filter: old chunk: %x " - QX_FMT " " QD_FMT _ - ce->hunk->type _ ce->hunk->pos.file _ - ce->hunk->last.file - ce->hunk->pos.file); -#endif + if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + size += ce->hunk->last - ce->hunk->pos; + } else { + size += ce->hunk->file_last - ce->hunk->file_pos; + } if (ce->hunk->type & (NGX_HUNK_FLUSH|NGX_HUNK_RECYCLED)) { flush = size; @@ -106,14 +104,12 @@ int ngx_http_write_filter(ngx_http_reque ce->next = NULL; *le = ce; le = &ce->next; - size += ce->hunk->last.file - ce->hunk->pos.file; -#if (NGX_DEBUG_WRITE_FILTER) - ngx_log_debug(r->connection->log, "write filter: new hunk: %x " - QX_FMT " " QD_FMT _ - ce->hunk->type _ ce->hunk->pos.file _ - ce->hunk->last.file - ce->hunk->pos.file); -#endif + if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + size += ce->hunk->last - ce->hunk->pos; + } else { + size += ce->hunk->file_last - ce->hunk->file_pos; + } if (ce->hunk->type & (NGX_HUNK_FLUSH|NGX_HUNK_RECYCLED)) { flush = size; diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -14,9 +14,11 @@ typedef int ngx_err_t; #define NGX_EAGAIN EWOULDBLOCK #define NGX_EINPROGRESS EINPROGRESS #define NGX_EADDRINUSE EADDRINUSE +#define NGX_ECONNRESET ECONNRESET #define NGX_ETIMEDOUT ETIMEDOUT #define NGX_ECANCELED ECANCELED + #define ngx_errno errno #define ngx_socket_errno errno #define ngx_set_socket_errno(err) errno = err diff --git a/src/os/unix/ngx_freebsd_write_chain.c b/src/os/unix/ngx_freebsd_write_chain.c --- a/src/os/unix/ngx_freebsd_write_chain.c +++ b/src/os/unix/ngx_freebsd_write_chain.c @@ -15,7 +15,7 @@ ngx_chain_t *ngx_freebsd_write_chain(ngx { int rc; char *prev; - size_t hsize; + size_t hsize, size; off_t sent; struct iovec *iov; struct sf_hdtr hdtr; @@ -32,54 +32,54 @@ ngx_chain_t *ngx_freebsd_write_chain(ngx ngx_init_array(trailer, c->pool, 10, sizeof(struct iovec), NGX_CHAIN_ERROR); /* create the header iovec */ - if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + if (ngx_hunk_in_memory_only(ce->hunk)) { prev = NULL; iov = NULL; /* create the iovec and coalesce the neighbouring chain entries */ - while (ce && (ce->hunk->type & NGX_HUNK_IN_MEMORY)) - { - if (prev == ce->hunk->pos.mem) { - iov->iov_len += ce->hunk->last.mem - ce->hunk->pos.mem; - prev = ce->hunk->last.mem; + while (ce && ngx_hunk_in_memory_only(ce->hunk)) { + + if (prev == ce->hunk->pos) { + iov->iov_len += ce->hunk->last - ce->hunk->pos; + prev = ce->hunk->last; } else { ngx_test_null(iov, ngx_push_array(&header), NGX_CHAIN_ERROR); - iov->iov_base = ce->hunk->pos.mem; - iov->iov_len = ce->hunk->last.mem - ce->hunk->pos.mem; - prev = ce->hunk->last.mem; + iov->iov_base = ce->hunk->pos; + iov->iov_len = ce->hunk->last - ce->hunk->pos; + prev = ce->hunk->last; } #if (HAVE_FREEBSD_SENDFILE_NBYTES_BUG) - hsize += ce->hunk->last.mem - ce->hunk->pos.mem; + hsize += ce->hunk->last - ce->hunk->pos; #endif ce = ce->next; } } - /* TODO: coalesce the neighbouring shadow file hunks */ + /* TODO: coalesce the neighbouring file hunks */ if (ce && (ce->hunk->type & NGX_HUNK_FILE)) { file = ce->hunk; ce = ce->next; } /* create the trailer iovec */ - if (ce && ce->hunk->type & NGX_HUNK_IN_MEMORY) { + if (ce && ngx_hunk_in_memory_only(ce->hunk)) { prev = NULL; iov = NULL; /* create the iovec and coalesce the neighbouring chain entries */ - while (ce && (ce->hunk->type & NGX_HUNK_IN_MEMORY)) { + while (ce && ngx_hunk_in_memory_only(ce->hunk)) { - if (prev == ce->hunk->pos.mem) { - iov->iov_len += ce->hunk->last.mem - ce->hunk->pos.mem; - prev = ce->hunk->last.mem; + if (prev == ce->hunk->pos) { + iov->iov_len += ce->hunk->last - ce->hunk->pos; + prev = ce->hunk->last; } else { ngx_test_null(iov, ngx_push_array(&trailer), NGX_CHAIN_ERROR); - iov->iov_base = ce->hunk->pos.mem; - iov->iov_len = ce->hunk->last.mem - ce->hunk->pos.mem; - prev = ce->hunk->last.mem; + iov->iov_base = ce->hunk->pos; + iov->iov_len = ce->hunk->last - ce->hunk->pos; + prev = ce->hunk->last; } ce = ce->next; @@ -92,8 +92,8 @@ ngx_chain_t *ngx_freebsd_write_chain(ngx hdtr.trailers = (struct iovec *) trailer.elts; hdtr.trl_cnt = trailer.nelts; - rc = sendfile(file->file->fd, c->fd, file->pos.file, - (size_t) (file->last.file - file->pos.file) + hsize, + rc = sendfile(file->file->fd, c->fd, file->file_pos, + (size_t) (file->file_last - file->file_pos) + hsize, &hdtr, &sent, 0); if (rc == -1) { @@ -110,8 +110,8 @@ ngx_chain_t *ngx_freebsd_write_chain(ngx #if (NGX_DEBUG_WRITE_CHAIN) ngx_log_debug(c->log, "sendfile: %d, @%qd %qd:%d" _ - rc _ file->pos.file _ *sent _ - (size_t) (file->last.file - file->pos.file) + hsize); + rc _ file->file_pos _ sent _ + (size_t) (file->file_last - file->file_pos) + hsize); #endif } else { @@ -142,31 +142,33 @@ ngx_chain_t *ngx_freebsd_write_chain(ngx for (ce = in; ce; ce = ce->next) { -#if (NGX_DEBUG_WRITE_CHAIN) - ngx_log_debug(c->log, "write chain: %x %qx %qd" _ - ce->hunk->type _ - ce->hunk->pos.file _ - ce->hunk->last.file - ce->hunk->pos.file); -#endif + if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + size = ce->hunk->last - ce->hunk->pos; + } else { + size = ce->hunk->file_last - ce->hunk->file_pos; + } + + if (sent >= size) { + sent -= size; - if (sent >= ce->hunk->last.file - ce->hunk->pos.file) { - sent -= ce->hunk->last.file - ce->hunk->pos.file; - ce->hunk->pos.file = ce->hunk->last.file; + if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + ce->hunk->pos = ce->hunk->last; + } -#if (NGX_DEBUG_WRITE_CHAIN) - ngx_log_debug(c->log, "write chain done: %qx %qd" _ - ce->hunk->pos.file _ sent); -#endif + if (ce->hunk->type & NGX_HUNK_FILE) { + ce->hunk->file_pos = ce->hunk->file_last; + } + continue; } - ce->hunk->pos.file += sent; + if (ce->hunk->type & NGX_HUNK_IN_MEMORY) { + ce->hunk->pos += sent; + } -#if (NGX_DEBUG_WRITE_CHAIN) - ngx_log_debug(c->log, "write chain rest: %qx %qd" _ - ce->hunk->pos.file _ - ce->hunk->last.file - ce->hunk->pos.file); -#endif + if (ce->hunk->type & NGX_HUNK_FILE) { + ce->hunk->file_pos += sent; + } break; } diff --git a/src/os/win32/ngx_errno.h b/src/os/win32/ngx_errno.h --- a/src/os/win32/ngx_errno.h +++ b/src/os/win32/ngx_errno.h @@ -15,6 +15,7 @@ typedef DWORD ngx_err_t; #define NGX_EAGAIN WSAEWOULDBLOCK #define NGX_EINPROGRESS WSAEINPROGRESS #define NGX_EADDRINUSE WSAEADDRINUSE +#define NGX_ECONNRESET ECONNRESET #define NGX_ETIMEDOUT WSAETIMEDOUT int ngx_strerror_r(ngx_err_t err, char *errstr, size_t size);