# HG changeset patch # User Igor Sysoev # Date 1029432026 0 # Node ID d220029ac7f3531d6d84c32c82026fc299e3a361 # Parent 4eff17414a4378feaba42876e0d3a6a50646cdee nginx-0.0.1-2002-08-15-21:20:26 import diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -25,7 +25,7 @@ int ngx_http_init_connection(void *data) int ngx_max_conn = 512; struct sockaddr_in ngx_addr = {0, AF_INET, 0, 0, 0}; - +int ngx_backlog = 0; ngx_pool_t ngx_pool; ngx_log_t ngx_log; @@ -35,10 +35,12 @@ ngx_server_t ngx_server; int main(int argc, char *const *argv) { char addr_text[22]; - ngx_socket_t fd; + ngx_socket_t s; ngx_listen_t ls; + int reuseaddr = 1; #if (WIN32) WSADATA wsd; + unsigned long nb = 1; #endif @@ -61,16 +63,45 @@ int main(int argc, char *const *argv) "WSAStartup failed"); #endif + /* for each listening socket */ + s = socket(AF_INET, SOCK_STREAM, 0); + if (s == -1) + ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno, + "socket failed"); + + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, + (const void *) &reuseaddr, sizeof(int)) == -1) + ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno, + "setsockopt (SO_REUSEADDR) failed"); + +#if (WIN32) + if (ioctlsocket(s, FIONBIO, &nb) == -1) + ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno, + "ioctlsocket (FIONBIO) failed"); +#else + if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) + ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno, + "fcntl (O_NONBLOCK) failed"); +#endif + ngx_snprintf(ngx_cpystrn(addr_text, inet_ntoa(ngx_addr.sin_addr), 16), 7, ":%d", ntohs(ngx_addr.sin_port)); - fd = ngx_listen((struct sockaddr *) &ngx_addr, -1, &ngx_log, addr_text); + + if (bind(s, (struct sockaddr *) &ngx_addr, + sizeof(struct sockaddr_in)) == -1) + ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno, + "bind to %s failed", addr_text); + + if (listen(s, ngx_backlog) == -1) + ngx_log_error(NGX_LOG_EMERG, &(ngx_log), ngx_socket_errno, + "listen to %s failed", addr_text); ngx_server.buff_size = 1024; ngx_server.handler = ngx_http_init_connection; /* daemon */ - ls.fd = fd; + ls.fd = s; ls.server = &ngx_server; ls.log = &ngx_log; diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -48,8 +48,10 @@ #include #include #include +#include #include #include +#include #include #include #include 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 @@ -8,12 +8,12 @@ ngx_hunk_t *ngx_get_hunk(ngx_pool_t *poo ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t)); #ifndef OFF_EQUAL_PTR - h->pos.f = h->last.f = 0; + h->pos.file = h->last.file = 0; #endif h->pre_start = ngx_palloc(pool, size + before + after); - h->start = h->pos.p = h->last.p = h->pre_start + before; - h->end = h->last.p + size; + h->start = h->pos.mem = h->last.mem = h->pre_start + before; + h->end = h->last.mem + size; h->post_end = h->end + after; h->type = NGX_HUNK_TEMP; @@ -28,21 +28,22 @@ ngx_hunk_t *ngx_get_hunk_before(ngx_pool ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t)); #ifndef OFF_EQUAL_PTR - h->pos.f = h->last.f = 0; + h->pos.file = h->last.file = 0; #endif - if (hunk->type & NGX_HUNK_TEMP && hunk->pos.p - hunk->pre_start >= size) { + if (hunk->type & NGX_HUNK_TEMP && hunk->pos.mem - 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.p; - h->start = h->pos.p = h->last.p = h->end - size; + h->end = h->post_end = hunk->pre_start = hunk->pos.mem; + h->start = h->pos.mem = h->last.mem = h->end - size; h->type = NGX_HUNK_TEMP; h->tag = 0; h->fd = (ngx_file_t) -1; } else { - h->pre_start = h->start = h->pos.p = h->last.p = ngx_palloc(pool, size); + h->pre_start = h->start = h->pos.mem = h->last.mem + = ngx_palloc(pool, size); h->end = h->post_end = h->start + size; h->type = NGX_HUNK_TEMP; @@ -58,22 +59,23 @@ ngx_hunk_t *ngx_get_hunk_after(ngx_pool_ ngx_hunk_t *h = ngx_palloc(pool, sizeof(ngx_hunk_t)); #ifndef OFF_EQUAL_PTR - h->pos.f = h->last.f = 0; + h->pos.file = h->last.file = 0; #endif if (hunk->type & NGX_HUNK_TEMP - && hunk->last.p == hunk->end + && hunk->last.mem == hunk->end && hunk->post_end - hunk->end >= size) { h->post_end = hunk->post_end; - h->pre_start = h->start = h->pos.p = h->last.p = hunk->post_end = - hunk->last.p; + h->pre_start = h->start = h->pos.mem = h->last.mem = hunk->post_end = + hunk->last.mem; h->type = NGX_HUNK_TEMP; h->tag = 0; h->fd = (ngx_file_t) -1; } else { - h->pre_start = h->start = h->pos.p = h->last.p = ngx_palloc(pool, size); + h->pre_start = h->start = h->pos.mem = h->last.mem = + ngx_palloc(pool, size); h->end = h->post_end = h->start + size; h->type = NGX_HUNK_TEMP; 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 @@ -7,33 +7,39 @@ #include -/* type */ +/* 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 -#define NGX_HUNK_FLUSH 0x0010 -/* in thread state flush means to write the hunk completely before return - in event-driven state flush means to start to write the hunk */ -#define NGX_HUNK_LAST 0x0020 + +/* hunk flags */ -#define NGX_HUNK_IN_MEMORY (NGX_HUNK_TEMP | NGX_HUNK_MEMORY | NGX_HUNK_MMAP ) -#define NGX_HUNK_TYPE 0x0ffff +/* 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 +/* last hunk */ +#define NGX_HUNK_LAST 0x0200 +/* can be used with NGX_HUNK_LAST only */ +#define NGX_HUNK_SHUTDOWN 0x0400 -/* flags */ -#define NGX_HUNK_SHUTDOWN 0x10000 -/* can be used with NGX_HUNK_LAST only */ + +#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 { union { - char *p; /* start of current data */ - off_t f; + char *mem; /* start of current data */ + off_t file; } pos; union { - char *p; /* end of current data */ - off_t f; + char *mem; /* end of current data */ + off_t file; } last; int type; char *start; /* start of hunk */ diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -45,6 +45,7 @@ void ngx_log_error_core(int level, ngx_l len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1, " [%s] (%d)", err_levels[level], err); + else len += ngx_snprintf(errstr + len, sizeof(errstr) - len - 1, " [%s] (%X)", err_levels[level], err); diff --git a/src/event/modules/ngx_overlapped_module.c b/src/event/modules/ngx_overlapped_module.c --- a/src/event/modules/ngx_overlapped_module.c +++ b/src/event/modules/ngx_overlapped_module.c @@ -1,17 +1,41 @@ + + + event = WSACreateEvent(void); + WSAEventSelect(s, event, FD_ACCEPT); + int ngx_overlapped_process_events(ngx_log_t *log) { if (acceptex) - event = SleepEx(timer, 1); + n = SleepEx(timer, 1); else - event = WSAWaitForMultipleEvents(n_events, events, 0, timer, 1); + n = WSAWaitForMultipleEvents(nevents, events, 0, timer, 1); + + if (n == WSA_WAIT_TIMEOUT) + close some event; + + if (n == WSA_IO_COMPLETION) + again - if (event == WSA_IO_COMPLETION) - look ready array + /* try it with AcceptEx() on NT to detect connected sockets */ + if (!acceptex) { + WSAEnumNetworkEvents( + sockets[n - WSA_WAIT_EVENT_0], + events[n - WSA_WAIT_EVENT_0], + net_events); + + if (net_events.lNetworkEvents & FD_ACCEPT) { + if (net_events.iErrorCode[FD_ACCEPT_BIT] != 0) + accept error + again + + ngx_event_accept(); OR post AcceptEx(); + } + } } void CALLBACK overlapped_completion_procedure(DWORD error, DWORD nbytes, LPWSAOVERLAPPED overlapped, DWORD flags) { - push overlapped; + run event handler } 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 @@ -16,8 +16,8 @@ struct ngx_event_s { void *context; char *action; - ngx_event_t *prev; /* queue in select(), poll() */ - ngx_event_t *next; + ngx_event_t *prev; /* queue in select(), poll(), mutex(), */ + ngx_event_t *next; /* aio_read(), aio_write() */ int (*timer_handler)(ngx_event_t *ev); ngx_event_t *timer_prev; @@ -52,7 +52,7 @@ struct ngx_event_s { #endif #if (HAVE_KQUEUE) unsigned eof:1; - int errno; + int error; #endif }; @@ -70,12 +70,20 @@ typedef struct { int (*add)(ngx_event_t *ev, int event, u_int flags); int (*del)(ngx_event_t *ev, int event); int (*process)(ngx_log_t *log); + int (*read)(ngx_event_t *ev, char *buf, size_t size); /* - int (*read)(ngx_event_t *ev, char *buf, size_t size); int (*write)(ngx_event_t *ev, char *buf, size_t size); */ } ngx_event_actions_t; +/* + +NGX_LEVEL_EVENT (default) select, poll, kqueue + requires to read whole data +NGX_ONESHOT_EVENT kqueue +NGX_CLEAR_EVENT kqueue + +*/ #if (HAVE_KQUEUE) @@ -99,15 +107,21 @@ typedef struct { #if (USE_KQUEUE) + #define ngx_init_events ngx_kqueue_init #define ngx_process_events ngx_kqueue_process_events #define ngx_add_event ngx_kqueue_add_event #define ngx_del_event ngx_kqueue_del_event +#define ngx_event_recv ngx_event_recv_core + #else + #define ngx_init_events (ngx_event_init[ngx_event_type]) #define ngx_process_events ngx_event_actions.process #define ngx_add_event ngx_event_actions.add #define ngx_del_event ngx_event_actions.del +#define ngx_event_recv ngx_event_recv_core + #endif diff --git a/src/event/ngx_event_mutex.c b/src/event/ngx_event_mutex.c new file mode 100644 --- /dev/null +++ b/src/event/ngx_event_mutex.c @@ -0,0 +1,14 @@ + +spinlock_max depend on CPU number and mutex type. + 1 CPU 1 + ngx_malloc_mutex 1000 ? + + +int ngx_event_mutex_trylock(ngx_mutex_t *mtx) +{ + for(i = mtx->spinlock_max; i; i--) + if (trylock(mtx->lock)) + return 1; + + return 0; +} diff --git a/src/event/ngx_event_read.c b/src/event/ngx_event_recv.c rename from src/event/ngx_event_read.c rename to src/event/ngx_event_recv.c --- a/src/event/ngx_event_read.c +++ b/src/event/ngx_event_recv.c @@ -2,23 +2,28 @@ #include #include #include +#include #include -int ngx_event_recv(ngx_connection_t *c, char *buf, size_t size) +int ngx_event_recv_core(ngx_event_t *ev, char *buf, size_t size) { - int n; - ngx_err_t err; - ngx_event_t *ev = c->read; + int n; + ngx_err_t err; + ngx_connection_t *c; + + c = (ngx_connection_t *) ev->data; #if (HAVE_KQUEUE) + ngx_log_debug(ev->log, "ngx_event_recv: eof:%d, avail:%d, err:%d" _ + ev->eof _ ev->available _ ev->error); #if !(USE_KQUEUE) if (ngx_event_type == NGX_KQUEUE_EVENT) #endif if (ev->eof && ev->available == 0) { if (ev->error) { ngx_log_error(NGX_LOG_ERR, ev->log, ev->error, - "ngx_event_recv: recv failed while %s", - ev->log->action); + "ngx_event_recv: recv failed while %s", + ev->log->action); return -1; } @@ -27,7 +32,7 @@ int ngx_event_recv(ngx_connection_t *c, } #endif - n = recv(c->fd, buf, size, 0); + n = ngx_recv(c->fd, buf, size, 0); if (n == -1) { err = ngx_socket_errno; diff --git a/src/event/ngx_event_write.c b/src/event/ngx_event_write.c --- a/src/event/ngx_event_write.c +++ b/src/event/ngx_event_write.c @@ -10,8 +10,8 @@ #include -ngx_chain_t *ngx_event_writer(ngx_connection_t *cn, ngx_chain_t *in, - off_t flush) +ngx_chain_t *ngx_event_write(ngx_connection_t *cn, ngx_chain_t *in, + off_t flush) { int rc; char *last; @@ -34,25 +34,21 @@ ngx_chain_t *ngx_event_writer(ngx_connec header->nelts = 0; trailer->nelts = 0; - if (ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH)) { + if (ch->hunk->type & NGX_HUNK_IN_MEMORY) { last = NULL; iov = NULL; - while (ch - && (ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH))) + while (ch && (ch->hunk->type & NGX_HUNK_IN_MEMORY)) { - if (ch->hunk->type & NGX_HUNK_FLUSH) - continue; - - if (last == ch->hunk->pos.p) { - iov->ngx_iov_len += ch->hunk->last.p - ch->hunk->pos.p; + if (last == ch->hunk->pos.mem) { + iov->ngx_iov_len += ch->hunk->last.mem - ch->hunk->pos.mem; } else { ngx_test_null(iov, ngx_push_array(header), (ngx_chain_t *) -1); - iov->ngx_iov_base = ch->hunk->pos.p; - iov->ngx_iov_len = ch->hunk->last.p - ch->hunk->pos.p; - last = ch->hunk->last.p; + iov->ngx_iov_base = ch->hunk->pos.mem; + iov->ngx_iov_len = ch->hunk->last.mem - ch->hunk->pos.mem; + last = ch->hunk->last.mem; } ch = ch->next; @@ -70,25 +66,23 @@ ngx_chain_t *ngx_event_writer(ngx_connec &sent); } else { #endif - if (ch && ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH)) { + if (ch && ch->hunk->type & NGX_HUNK_IN_MEMORY) { last = NULL; iov = NULL; - while (ch - && (ch->hunk->type & (NGX_HUNK_IN_MEMORY | NGX_HUNK_FLUSH))) - { - if (ch->hunk->type & NGX_HUNK_FLUSH) - continue; + while (ch && (ch->hunk->type & NGX_HUNK_IN_MEMORY)) { - if (last == ch->hunk->pos.p) { - iov->ngx_iov_len += ch->hunk->last.p - ch->hunk->pos.p; + if (last == ch->hunk->pos.mem) { + iov->ngx_iov_len += + ch->hunk->last.mem - ch->hunk->pos.mem; } else { ngx_test_null(iov, ngx_push_array(trailer), (ngx_chain_t *) -1); - iov->ngx_iov_base = ch->hunk->pos.p; - iov->ngx_iov_len = ch->hunk->last.p - ch->hunk->pos.p; - last = ch->hunk->last.p; + iov->ngx_iov_base = ch->hunk->pos.mem; + iov->ngx_iov_len = + ch->hunk->last.mem - ch->hunk->pos.mem; + last = ch->hunk->last.mem; } ch = ch->next; @@ -98,8 +92,8 @@ ngx_chain_t *ngx_event_writer(ngx_connec if (file) { rc = ngx_sendfile(cn->fd, (ngx_iovec_t *) header->elts, header->nelts, - file->fd, file->pos.f, - (size_t) (file->last.f - file->pos.f), + file->fd, file->pos.file, + (size_t) (file->last.file - file->pos.file), (ngx_iovec_t *) trailer->elts, trailer->nelts, &sent, cn->log); } else { @@ -117,17 +111,18 @@ ngx_chain_t *ngx_event_writer(ngx_connec flush -= sent; for (ch = in; ch && !(ch->hunk->type & NGX_HUNK_LAST); ch = ch->next) { - if (sent >= ch->hunk->last.f - ch->hunk->pos.f) { - sent -= ch->hunk->last.f - ch->hunk->pos.f; - ch->hunk->last.f = ch->hunk->pos.f; + if (sent >= ch->hunk->last.file - ch->hunk->pos.file) { + sent -= ch->hunk->last.file - ch->hunk->pos.file; + ch->hunk->last.file = ch->hunk->pos.file; continue; } - ch->hunk->pos.f += sent; + ch->hunk->pos.file += sent; break; } - } while (flush > 0); + /* flush hunks if threaded state */ + } while (cn->write->context && flush > 0); ngx_destroy_array(trailer); ngx_destroy_array(header); diff --git a/src/http/modules/ngx_http_header_filter.c b/src/http/modules/ngx_http_header_filter.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_header_filter.c @@ -0,0 +1,55 @@ + + +typedef struct { + int len; + char *line; +} line; + + +static line http_codes[] = { + { 6, "200 OK" } +}; + + + + +int ngx_http_header_filter(ngx_http_request_t *r) +{ + int status; + ngx_hunk_t *h; + + ngx_test_null(h, ngx_get_hunk(r->pool, 1024, 0, 64), NGX_HTTP_FILTER_ERROR); + + status = r->headers_out->status - GX_HTTP_OK; + + ngx_memcpy(h->pos.mem, "HTTP/1.0 ", 9); + h->pos.mem += 9; + ngx_memcpy(h->pos.mem, http_codes[status].line, http_codes[status].len); + h->pos.mem += http_codes[status].len; + *(h->pos.mem++) = CR; *(h->pos.mem++) = LF; + + memcpy(h->pos.mem, "Date: ", 6); + h->pos.mem += 6; + h->pos.mem += ngx_http_get_time(h->pos.mem, time()); + *(h->pos.mem++) = CR; *(h->pos.mem++) = LF; + + /* 2^64 is 20 characters */ + if (r->headers_out->content_length) + h->pos.mem += ngx_snprintf(h->pos.mem, 49, "Content-Length: %d" CRLF, + r->headers_out->content_length); + + /* check */ + + memcpy(h->pos.mem, "Server: ", 8); + h->pos.mem += 8; + if (r->headers_out->server) { + h->pos.mem = ngx_cpystrn(h->pos.mem, r->headers_out->server, + h->last.mem - h->pos.mem); + check space + } else { + ngx_memcpy(h->pos.mem, NGINX_VER, sizeof(NGINX_VER)); + h->pos.mem += sizeof(NGINX_VER); + } + *(h->pos.mem++) = CR; *(h->pos.mem++) = LF; + +} diff --git a/src/http/modules/ngx_http_index_handler.c b/src/http/modules/ngx_http_index_handler.c --- a/src/http/modules/ngx_http_index_handler.c +++ b/src/http/modules/ngx_http_index_handler.c @@ -20,10 +20,11 @@ int ngx_http_index_handler(ngx_http_requ ngx_get_module_loc_conf(r, &ngx_http_index_handler_module); index_len = (*(r->uri_end - 1) == '/') ? cf->max_index_len : 0; - name = ngx_palloc(r->pool, r->uri_end - r->uri_start + index_len - + r->server->doc_root_len); - if (name == NULL) - return NGX_ERROR; + + ngx_test_null(name, + ngx_palloc(r->pool, r->uri_end - r->uri_start + index_len + + r->server->doc_root_len), + NGX_HTTP_INTERNAL_SERVER_ERROR); loc = ngx_cpystrn(name, r->server->doc_root, r->server->doc_root_len); file = ngx_cpystrn(loc, r->uri_start, r->uri_end - r->uri_start + 1); @@ -39,7 +40,7 @@ int ngx_http_index_handler(ngx_http_requ if (err == NGX_ENOENT) return NGX_HTTP_NOT_FOUND; else - return NGX_ERROR; + return NGX_HTTP_INTERNAL_SERVER_ERROR; } if (ngx_is_dir(r->stat)) { diff --git a/src/http/modules/ngx_http_static_handler.c b/src/http/modules/ngx_http_static_handler.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_static_handler.c @@ -0,0 +1,101 @@ + +#include + +#include +#include +#include + +#include + +int ngx_http_static_handler(ngx_http_request_t *r) +{ + int index_len, err, i; + char *name, *loc, *file + ngx_file_t fd; + + ngx_http_header_out_t out; + ngx_http_event_static_handler_loc_conf_t *cf; + + cf = (ngx_http_event_static_handler_loc_conf_t *) + ngx_get_module_loc_conf(r, &ngx_http_event_static_handler_module); + + ngx_assert(r->fd, return NGX_HTTP_INTERNAL_SERVER_ERROR, + r->connection->log, "ngx_http_static_handler: no file"); + + out.status = NGX_HTTP_OK; + out.content_length = r->stat.sb_size; + out.last_modified = r->stat.sb_mtime; + + /* */ + out.content_type = "text/html"; + + rc = ngx_send_http_header(&out); + if (r->header_only) + return rc; + + /* NGX_HTTP_INTERNAL_SERVER_ERROR is too late */ + + ngx_test_null(h, ngx_create_hunk(r->pool), NGX_HTTP_INTERNAL_SERVER_ERROR); + h->type = NGX_HUNK_FILE | NGX_HUNK_LAST; + h->fd = r->fd; + h->pos.file = 0; + h->end.file = r->stat.sb_size; + + ngx_test_null(ch, ngx_create_chain(r->pool), + NGX_HTTP_INTERNAL_SERVER_ERROR); + ch->hunk = h; + ch->next = NULL; + + return ngx_http_filter(ch); +} + +/* + +static void *ngx_create_index_config() +{ + ngx_http_index_handler_loc_conf_t *cf; + + ngx_check_null(cf, ngx_alloc(p, sizeof(ngx_http_index_handler_loc_conf)), + NULL); + + cf->indices = ngx_create_array(p, sizeof(ngx_http_index_t), 5); + if (cf->indices == NULL) + return NULL; + + cf->max_index_len = 0; + + return cf; +} + +static void *ngx_merge_index_config() +{ + if (p->indices->nelts > 0) { + + copy and check dups + + if (c->max_index_len < c->max_index_len) + c->max_index_len < c->max_index_len); + } +} + +static void *ngx_set_index() +{ + if (*conf == NULL) { + cf = ngx_create_index_conf(); + if (cf == NULL) + return "can not create config"; + } + + while (args) { + index = ngx_push_array(cf->indices); + index->name = arg; + index->len = ngx_strlen(arg) + 1; + + if (cf->max_index_len < index->len) + cf->max_index_len = index->len; + } + + *conf = cf; +} + +*/ 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 @@ -23,6 +23,13 @@ typedef struct { + void *ctx; /* STUB */ +} ngx_http_module_t; + +/* STUB */ +#define ngx_get_module_ctx(r, module) (module)->ctx + +typedef struct { char *buff; char *pos; char *last; 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 @@ -38,10 +38,7 @@ int ngx_http_init_connection(ngx_connect ngx_event_t *ev; ev = c->read; -/* ev->event_handler = ngx_http_init_request; -*/ - ev->event_handler = NULL; ev->log->action = "reading client request line"; ngx_log_debug(ev->log, "ngx_http_init_connection: entered"); @@ -62,8 +59,6 @@ int ngx_http_init_connection(ngx_connect #endif } -#if 0 - int ngx_http_init_request(ngx_event_t *ev) { ngx_connection_t *c = (ngx_connection_t *) ev->data; @@ -71,11 +66,13 @@ int ngx_http_init_request(ngx_event_t *e ngx_log_debug(ev->log, "ngx_http_init_request: entered"); + ngx_test_null(c->pool, ngx_create_pool(16384, ev->log), -1); ngx_test_null(r, ngx_pcalloc(c->pool, sizeof(ngx_http_request_t)), -1); c->data = r; r->connection = c; + ngx_test_null(r->pool, ngx_create_pool(16384, ev->log), -1); ngx_test_null(r->buff, ngx_palloc(r->pool, sizeof(ngx_buff_t)), -1); ngx_test_null(r->buff->buff, ngx_pcalloc(r->pool, sizeof(c->server->buff_size)), -1); @@ -99,33 +96,15 @@ int ngx_http_process_request(ngx_event_t ngx_log_debug(ev->log, "http process request"); - ngx_log_debug(ev->log, "http: eof:%d, avail:%d", ev->eof, ev->available); + n = ngx_event_recv(ev, r->buff->last, r->buff->end - r->buff->last); - if (ev->eof && ev->available == 0) { - if (ev->err_no) - ngx_log_error(NGX_LOG_ERR, ev->log, ev->err_no, - "ngx_http_process_request: " - "read failed while %s", ev->action); - - return -1; - } - - if ((n = read(c->fd, r->buff->last, r->buff->end - r->buff->last)) == -1) { + if (n == -2) + return 0; - if (errno == NGX_EWOULDBLOCK) { - ngx_log_error(NGX_LOG_INFO, ev->log, errno, - "ngx_http_process_request: " - "EAGAIN while %s", ev->action); - return 0; - } + if (n == -1) + return -1; - ngx_log_error(NGX_LOG_ERR, ev->log, errno, - "ngx_http_process_request: " - "read failed while %s", ev->action); - return -1; - } - - ngx_log_debug(ev->log, "http read %d", n); + ngx_log_debug(ev->log, "http read %d" _ n); if (n == 0) { if (ev->unexpected_eof) { @@ -138,8 +117,6 @@ int ngx_http_process_request(ngx_event_t return ngx_http_close_request(ev); } - n == r->buff->end - r->buff->last; - if (!ev->read_discarded) { r->buff->last += n; @@ -168,8 +145,8 @@ static int ngx_process_http_request_line if ((n = ngx_read_http_request_line(r)) == 1) { *r->uri_end = '\0'; - ngx_log_debug(r->connection->log, "HTTP: %d, %d, %s", - r->method, r->http_version, r->uri_start); + ngx_log_debug(r->connection->log, "HTTP: %d, %d, %s" _ + r->method _ r->http_version _ r->uri_start); r->state_handler = ngx_process_http_request_header; r->connection->read->action = "reading client request headers"; } @@ -184,8 +161,8 @@ static int ngx_process_http_request_head while ((n = ngx_read_http_header_line(r)) == 1) { *r->header_name_end = '\0'; *r->header_end = '\0'; - ngx_log_debug(r->connection->log, "HTTP header: '%s: %s'", - r->header_name_start, r->header_start); + ngx_log_debug(r->connection->log, "HTTP header: '%s: %s'" _ + r->header_name_start _ r->header_start); } if (n != 2) @@ -203,6 +180,13 @@ static int ngx_process_http_request_head static int ngx_process_http_request(ngx_http_request_t *r) { + return -1; +} + +#if 0 + +static int ngx_process_http_request(ngx_http_request_t *r) +{ int fd; struct stat sb; ngx_http_header_out_t *header_out; @@ -258,6 +242,8 @@ static int ngx_process_http_request(ngx_ return 0; } +#endif + static int ngx_http_close_request(ngx_event_t *ev) { ngx_connection_t *c = (ngx_connection_t *) ev->data; @@ -269,5 +255,3 @@ static int ngx_http_close_request(ngx_ev return ngx_event_close(ev); } - -#endif diff --git a/src/http/ngx_http_filter.h b/src/http/ngx_http_filter.h new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_filter.h @@ -0,0 +1,10 @@ +#ifndef _NGX_HTTP_FILTER_H_INCLUDED_ +#define _NGX_HTTP_FILTER_H_INCLUDED_ + + +#define NGX_HTTP_FILTER_ERROR -1 +#define NGX_HTTP_FILTER_AGAIN 0 +#define NGX_HTTP_FILTER_DONE 1 + + +#endif /* _NGX_HTTP_FILTER_H_INCLUDED_ */ diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_parse.c @@ -0,0 +1,475 @@ + +#include +#include + +int ngx_read_http_request_line(ngx_http_request_t *r) +{ + char ch; + char *buff = r->buff->buff; + char *p = r->buff->pos; + enum { + rl_start = 0, + rl_space_after_method, + rl_spaces_before_uri, + rl_after_slash_in_uri, + rl_check_uri, + rl_uri, + rl_http_09, + rl_http_version, + rl_first_major_digit, + rl_major_digit, + rl_first_minor_digit, + rl_minor_digit, + rl_almost_done, + rl_done + } state = r->state; + + while (p < r->buff->last && state < rl_done) { + ch = *p++; + +/* +printf("\nstate: %d, pos: %x, end: %x, char: '%c' buf: %s", + state, p, r->buff->last, ch, p); +*/ + + /* GCC complie it as jump table */ + + switch (state) { + + /* HTTP methods: GET, HEAD, POST */ + case rl_start: + switch (ch) { + case 'G': + if (p + 1 >= r->buff->last) + return 0; + + if (*p != 'E' || *(p + 1) != 'T') + return NGX_HTTP_INVALID_METHOD; + + r->method = NGX_HTTP_GET; + p += 2; + break; + + case 'H': + if (p + 2 >= r->buff->last) + return 0; + + if (*p != 'E' || *(p + 1) != 'A' || *(p + 2) != 'D') + return NGX_HTTP_INVALID_METHOD; + + r->method = NGX_HTTP_HEAD; + p += 3; + break; + + case 'P': + if (p + 2 >= r->buff->last) + return 0; + + if (*p != 'O' || *(p + 1) != 'S' || *(p + 2) != 'T') + return NGX_HTTP_INVALID_METHOD; + + r->method = NGX_HTTP_POST; + p += 3; + break; + + default: + return NGX_HTTP_INVALID_METHOD; + } + + state = rl_space_after_method; + break; + + /* single space after method */ + case rl_space_after_method: + switch (ch) { + case ' ': + state = rl_spaces_before_uri; + break; + default: + return NGX_HTTP_INVALID_METHOD; + } + break; + + /* space* before URI */ + case rl_spaces_before_uri: + switch (ch) { + case '/': + r->uri_start = p - 1; + state = rl_after_slash_in_uri; + break; + case ' ': + break; + default: + r->unusual_uri = 1; + r->uri_start = p - 1; + state = rl_uri; + break; + } + break; + + /* check dot after slash */ + case rl_after_slash_in_uri: + switch (ch) { + case CR: + r->uri_end = p - 1; + r->http_minor = 9; + state = rl_almost_done; + break; + case LF: + r->uri_end = p - 1; + r->http_minor = 9; + state = rl_done; + break; + case ' ': + r->uri_end = p - 1; + state = rl_http_09; + break; + case '.': + r->complex_uri = 1; + state = rl_uri; + break; + case '/': + r->complex_uri = 1; + state = rl_uri; + break; + case '?': + r->args_start = p; + state = rl_uri; + break; + default: + state = rl_check_uri; + break; + } + break; + + /* check slash in URI */ + case rl_check_uri: + switch (ch) { + case CR: + r->uri_end = p - 1; + r->http_minor = 9; + state = rl_almost_done; + break; + case LF: + r->uri_end = p - 1; + r->http_minor = 9; + state = rl_done; + break; + case ' ': + r->uri_end = p - 1; + state = rl_http_09; + break; + case '.': + r->uri_ext = p; + break; + case '/': + r->uri_ext = NULL; + state = rl_after_slash_in_uri; + break; + case '?': + r->args_start = p; + state = rl_uri; + break; + } + break; + + /* URI */ + case rl_uri: + switch (ch) { + case CR: + r->uri_end = p - 1; + r->http_minor = 9; + state = rl_almost_done; + break; + case LF: + r->uri_end = p - 1; + r->http_minor = 9; + state = rl_done; + break; + case ' ': + r->uri_end = p - 1; + state = rl_http_09; + break; + } + break; + + /* space+ after URI */ + case rl_http_09: + switch (ch) { + case ' ': + break; + case CR: + r->http_minor = 9; + state = rl_almost_done; + break; + case LF: + r->http_minor = 9; + state = rl_done; + break; + case 'H': + state = rl_http_version; + break; + default: + return NGX_HTTP_INVALID_REQUEST; + } + break; + + /* TTP/ */ + case rl_http_version: + if (p + 2 >= r->buff->last) { + r->state = rl_http_version; + r->buff->pos = p - 1; + return 0; + } + + if (ch != 'T' || *p != 'T' || *(p + 1) != 'P' || *(p + 2) != '/') + return NGX_HTTP_INVALID_REQUEST; + + p += 3; + state = rl_first_major_digit; + break; + + /* first digit of major HTTP version */ + case rl_first_major_digit: + if (ch < '1' || ch > '9') + return NGX_HTTP_INVALID_REQUEST; + + r->http_major = ch - '0'; + state = rl_major_digit; + break; + + /* major HTTP version or dot */ + case rl_major_digit: + if (ch == '.') { + state = rl_first_minor_digit; + break; + } + + if (ch < '0' || ch > '9') + return NGX_HTTP_INVALID_REQUEST; + + r->http_major = r->http_major * 10 + ch - '0'; + break; + + /* first digit of minor HTTP version */ + case rl_first_minor_digit: + if (ch < '0' || ch > '9') + return NGX_HTTP_INVALID_REQUEST; + + r->http_minor = ch - '0'; + + state = rl_minor_digit; + break; + + /* minor HTTP version or end of request line */ + case rl_minor_digit: + if (ch == CR) { + state = rl_almost_done; + break; + } + + if (ch == LF) { + state = rl_done; + break; + } + + if (ch < '0' || ch > '9') + return NGX_HTTP_INVALID_REQUEST; + + r->http_minor = r->http_minor * 10 + ch - '0'; + break; + + /* end of request line */ + case rl_almost_done: + switch (ch) { + case LF: + state = rl_done; + break; + default: + return NGX_HTTP_INVALID_METHOD; + } + break; + } + } + + r->buff->pos = p; + + if (state == rl_done) { + r->http_version = r->http_major * 1000 + r->http_minor; + r->state = rl_start; + return 1; + } else { + r->state = state; + return 0; + } +} + +int ngx_read_http_header_line(ngx_http_request_t *r) +{ + char c, ch; + char *buff = r->buff->buff; + char *p = r->buff->pos; + enum { + hl_start = 0, + hl_name, + hl_space_before_value, + hl_value, + hl_space_after_value, + hl_almost_done, + header_almost_done, + hl_done, + header_done + } state = r->state; + + while (p < r->buff->last && state < hl_done) { + ch = *p++; + +/* +printf("\nstate: %d, pos: %x, end: %x, char: '%c' buf: %s", + state, p, r->buff->last, ch, p); +*/ + + switch (state) { + + /* first char */ + case hl_start: + switch (ch) { + case CR: + r->header_end = p - 1; + state = header_almost_done; + break; + case LF: + r->header_end = p - 1; + state = header_done; + break; + default: + state = hl_name; + r->header_name_start = p - 1; + + c = ch | 0x20; + if (c >= 'a' && c <= 'z') + break; + + if (ch == '-') + break; + + if (ch >= '0' && ch <= '9') + break; + + return NGX_HTTP_INVALID_HEADER; + + } + break; + + /* header name */ + case hl_name: + c = ch | 0x20; + if (c >= 'a' && c <= 'z') + break; + + if (ch == ':') { + r->header_name_end = p - 1; + state = hl_space_before_value; + break; + } + + if (ch == '-') + break; + + if (ch >= '0' && ch <= '9') + break; + + return NGX_HTTP_INVALID_HEADER; + + /* space* before header value */ + case hl_space_before_value: + switch (ch) { + case ' ': + break; + case CR: + r->header_start = r->header_end = p - 1; + state = hl_almost_done; + break; + case LF: + r->header_start = r->header_end = p - 1; + state = hl_done; + break; + default: + r->header_start = p - 1; + state = hl_value; + break; + } + break; + + /* header value */ + case hl_value: + switch (ch) { + case ' ': + r->header_end = p - 1; + state = hl_space_after_value; + break; + case CR: + r->header_end = p - 1; + state = hl_almost_done; + break; + case LF: + r->header_end = p - 1; + state = hl_done; + break; + } + break; + + /* space* before end of header line */ + case hl_space_after_value: + switch (ch) { + case ' ': + break; + case CR: + state = hl_almost_done; + break; + case LF: + state = hl_done; + break; + default: + state = hl_value; + break; + } + break; + + /* end of header line */ + case hl_almost_done: + switch (ch) { + case LF: + state = hl_done; + break; + default: + return NGX_HTTP_INVALID_HEADER; + } + break; + + /* end of header */ + case header_almost_done: + switch (ch) { + case LF: + state = header_done; + break; + default: + return NGX_HTTP_INVALID_HEADER; + } + break; + } + } + + r->buff->pos = p; + + if (state == hl_done) { + r->state = hl_start; + return 1; + } else if (state == header_done) { + r->state = hl_start; + return 2; + } else { + r->state = state; + return 0; + } +} diff --git a/src/http/ngx_http_write_filter.c b/src/http/ngx_http_write_filter.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_write_filter.c @@ -0,0 +1,82 @@ + +#include + +#include +#include +#include +#include + +#include + + +ngx_http_module_t ngx_http_write_filter_module; + + +/* STUB */ +static ngx_http_write_filter_ctx_t module_ctx; + +void ngx_http_write_filter_init() +{ + module_ctx.buffer_output = 10240; + module_ctx.out = NULL; + + ngx_http_write_filter_module.ctx = &module_ctx; +} +/* */ + + +int ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + int last; + off_t size, flush; + ngx_chain_t *ch, **prev, *chain; + ngx_http_write_filter_ctx_t *ctx; + + ctx = (ngx_http_write_filter_ctx_t *) + ngx_get_module_ctx(r->main ? r->main : r, + &ngx_http_write_filter_module); + size = flush = 0; + last = 0; + prev = &ctx->out; + + /* find size, flush point and last link of saved chain */ + for (ch = ctx->out; ch; ch = ch->next) { + prev = &ch->next; + size += ch->hunk->last.file - ch->hunk->pos.file; + + if (ch->hunk->type & NGX_HUNK_FLUSH) + flush = size; + + if (ch->hunk->type & NGX_HUNK_LAST) + last = 1; + } + + /* add new chain to existent one */ + for (/* void */; in; in = in->next) { + ngx_test_null(ch, ngx_palloc(r->pool, sizeof(ngx_chain_t)), + NGX_HTTP_FILTER_ERROR); + + ch->hunk = in->hunk; + ch->next = NULL; + *prev = ch; + prev = &ch->next; + size += ch->hunk->last.file - ch->hunk->pos.file; + + if (ch->hunk->type & NGX_HUNK_FLUSH) + flush = size; + + if (ch->hunk->type & NGX_HUNK_LAST) + last = 1; + } + + if (flush == 0 && size < ctx->buffer_output) + return NGX_HTTP_FILTER_DONE; + + chain = ngx_event_write(r->connection, ctx->out, flush); + if (chain == (ngx_chain_t *) -1) + return NGX_HTTP_FILTER_ERROR; + + ctx->out = chain; + + return (chain ? NGX_HTTP_FILTER_AGAIN : NGX_HTTP_FILTER_DONE); +} diff --git a/src/http/ngx_http_write_filter.h b/src/http/ngx_http_write_filter.h new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_write_filter.h @@ -0,0 +1,11 @@ +#ifndef _NGX_HTTP_WRITE_FILTER_H_INCLUDED_ +#define _NGX_HTTP_WRITE_FILTER_H_INCLUDED_ + + +typedef struct { + ngx_chain_t *out; + size_t buffer_output; +} ngx_http_write_filter_ctx_t; + + +#endif /* _NGX_HTTP_WRITE_FILTER_H_INCLUDED_ */ diff --git a/src/os/freebsd/ngx_os_thread.c b/src/os/freebsd/ngx_os_thread.c new file mode 100644 --- /dev/null +++ b/src/os/freebsd/ngx_os_thread.c @@ -0,0 +1,64 @@ + +#include + +char *ngx_stacks_start; +char *ngx_stacks_end; +size_t ngx_stack_size; + + +/* handle thread-safe errno */ +static int errno0; /* errno for main thread */ +static int *errnos; + +int *__error() +{ + ngx_tid_t tid = ngx_gettid(); + return tid ? &(errnos[ngx_gettid()]) : &errno0; +} + + +int ngx_create_os_thread(ngx_os_tid_t *tid, void *stack, + int (*func)(void *arg), void *arg, ngx_log_t log) +{ + int id, err; + + id = rfork_thread(RFPROC|RFMEM, stack, func, arg); + err = ngx_errno; + + if (id == -1) + ngx_log_error(NGX_LOG_ERR, log, err, + "ngx_create_os_thread: rfork failed"); + else + *tid = id; + + return err; +} + + +int ngx_create_os_thread_env(int n, size_t size, ngx_log_t log) +{ + char *addr; + + /* create thread stacks */ + addr = mmap(NULL, n * size, PROT_READ|PROT_WRITE, MAP_ANON, -1, NULL); + if (addr == MAP_FAILED) { + ngx_log_error(NGX_LOG_ERR, log, ngx_errno, + "ngx_create_os_thread_stacks: mmap failed"); + return -1; + } + + nxg_stacks_start = addr; + nxg_stacks_end = addr + n * size; + nxg_stack_size = size; + + /* create thread errno array */ + ngx_test_null(errnos, ngx_calloc(n * sizeof(int)), -1); + + /* create thread tid array */ + ngx_test_null(ngx_os_tids, ngx_calloc(n * sizeof(ngx_os_tid_t)), -1); + + /* allow spinlock in malloc() */ + __isthreaded = 1; + + return 0; +} diff --git a/src/os/freebsd/ngx_os_thread.h b/src/os/freebsd/ngx_os_thread.h new file mode 100644 --- /dev/null +++ b/src/os/freebsd/ngx_os_thread.h @@ -0,0 +1,24 @@ +#ifndef _NGX_OS_THREAD_H_INCLUDED_ +#define _NGX_OS_THREAD_H_INCLUDED_ + + +typedef int ngx_os_tid_t; +typedef int ngx_tid_t; + + +extern char *ngx_stacks_start; +extern char *ngx_stacks_end; +extern size_t ngx_stack_size; + + +static inline ngx_tid_t ngx_gettid() +{ + char *sp; + + __asm__ ("mov %%esp,%0" : "=r" (sp)); + return (sp > ngx_stacks_end) ? 0: + (sp - ngx_stacks_start) / ngx_stack_size + 1; +} + + +#endif /* _NGX_OS_THREAD_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_recv.h b/src/os/unix/ngx_recv.h new file mode 100644 --- /dev/null +++ b/src/os/unix/ngx_recv.h @@ -0,0 +1,10 @@ +#ifndef _NGX_RECV_H_INCLUDED_ +#define _NGX_RECV_H_INCLUDED_ + + +#include + +#define ngx_recv(fd, buf, size, flags) recv(fd, buf, size, flags) + + +#endif /* _NGX_RECV_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_time.c b/src/os/unix/ngx_time.c --- a/src/os/unix/ngx_time.c +++ b/src/os/unix/ngx_time.c @@ -17,3 +17,70 @@ u_int ngx_msec(void) return tv.tv_sec * 1000 + tv.tv_usec / 1000; } + +#if 0 + +typedef struct { + int busy; + u_int_64 msec; + time_t sec; + tm; + http_time_len; + http_time[n]; +}; + +volatile *ngx_time_p; + +ngx_time() +{ + p = ngx_time_p; +} + +ngx_update_time() +{ + u_int64 msec; + struct timeval tv; + + gettimeofday(&tv, NULL); + + msec = (unsigned long) tv.tv_sec * 1000 + tv.tv_usec / 1000; + p = ngx_time_p; + + /* minimum can be for example 0, 10, 50 or 100 ms */ + if (tv_sec > p->sec || msec - p->msec >= minimum) { + old_p = p; + /* max_tries < max_slots - 10, + max_slots should be more than max of threads */ + for (/* void */; i < max_tries; i++) { + if (++p >= last_slot) + p = first_slot; + + if (!test_and_set(p->busy) + break; + } + + if (i == max_tries) { + ngx_log_error(); + return; + } + + if (tv_sec > p->sec) { + p->sec = tv.tv.sec; + p->msec = msec; + localtime_r(&tv.tv_sec, tm); + make http stirng; + + } else { + ngx_memcpy(p->sec, old_p->sec, sizeof() - offset_of(, sec)); + p->msec = msec; + } + + /* here can be too seldom and non-critical race condition */ + if (ngx_time_p == old_p) + ngx_time_p = p; + + unlock(p->busy); + } +} + +#endif diff --git a/src/os/win32/ngx_recv.h b/src/os/win32/ngx_recv.h new file mode 100644 --- /dev/null +++ b/src/os/win32/ngx_recv.h @@ -0,0 +1,10 @@ +#ifndef _NGX_RECV_H_INCLUDED_ +#define _NGX_RECV_H_INCLUDED_ + + +#include + +#define ngx_recv(fd, buf, size, flags) recv(fd, buf, size, flags) + + +#endif /* _NGX_RECV_H_INCLUDED_ */