# HG changeset patch # User Igor Sysoev # Date 1065682845 0 # Node ID cb77c084acdb254c8afec2f1acfcbd112353371c # Parent 656d468f4ead3d38acc68d299615cdec05ad69ad nginx-0.0.1-2003-10-09-11:00:45 import 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 @@ -75,6 +75,14 @@ typedef struct { #define ngx_hunk_in_memory_only(h) \ ((h->type & (NGX_HUNK_IN_MEMORY|NGX_HUNK_FILE)) == NGX_HUNK_IN_MEMORY) +/* + ((h->type & (NGX_HUNK_TEMP|NGX_HUNK_MEMORY|NGX_HUNK_MMAP|NGX_HUNK_FILE)) \ + == (h->type & (NGX_HUNK_TEMP|NGX_HUNK_MEMORY|NGX_HUNK_MMAP))) + +*/ + +#define ngx_hunk_special(h) \ + (h->type == (h->type & (NGX_HUNK_FLUSH|NGX_HUNK_LAST))) ngx_hunk_t *ngx_create_temp_hunk(ngx_pool_t *pool, int size, diff --git a/src/http/modules/ngx_http_not_modified_filter.c b/src/http/modules/ngx_http_not_modified_filter.c --- a/src/http/modules/ngx_http_not_modified_filter.c +++ b/src/http/modules/ngx_http_not_modified_filter.c @@ -39,7 +39,7 @@ static int ngx_http_not_modified_header_ if (r->headers_out.status != NGX_HTTP_OK || r->headers_in.if_modified_since == NULL - || r->headers_out.last_modified_time == NULL) + || r->headers_out.last_modified_time == -1) { return next_header_filter(r); } @@ -50,7 +50,7 @@ static int ngx_http_not_modified_header_ ngx_log_debug(r->connection->log, "%d %d" _ ims _ r->headers_out.last_modified_time); - /* I think that the date equality is correcter */ + /* I think that the equality of the dates is correcter */ if (ims != NGX_ERROR && ims == r->headers_out.last_modified_time) { r->headers_out.status = NGX_HTTP_NOT_MODIFIED; 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 @@ -118,6 +118,7 @@ int ngx_http_static_handler(ngx_http_req } /* we need to allocate all before the header would be sent */ + ngx_test_null(h, ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)), NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -132,18 +133,28 @@ int ngx_http_static_handler(ngx_http_req } if (r->header_only) { + ngx_http_finalize_request(r, rc); + +#if 0 if (rc == NGX_AGAIN) { ngx_http_set_write_handler(r); } else { ngx_http_finalize_request(r, 0); } +#endif return NGX_OK; } - h->type = NGX_HUNK_FILE|NGX_HUNK_LAST; +#if 0 + h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST; +#else + h->type = NGX_HUNK_FILE; +#endif + + h->file_pos = 0; h->file_last = ngx_file_size(r->file.info); @@ -152,6 +163,9 @@ int ngx_http_static_handler(ngx_http_req rc = ngx_http_output_filter(r, h); + ngx_http_finalize_request(r, rc); + +#if 0 if (r->main == NULL) { if (rc == NGX_AGAIN) { ngx_http_set_write_handler(r); @@ -160,6 +174,7 @@ int ngx_http_static_handler(ngx_http_req ngx_http_finalize_request(r, 0); } } +#endif return NGX_OK; } 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 @@ -54,6 +54,7 @@ void ngx_http_finalize_request(ngx_http_ void ngx_http_set_write_handler(ngx_http_request_t *r); +int ngx_http_send_last(ngx_http_request_t *r); void ngx_http_close_request(ngx_http_request_t *r, int error); void ngx_http_close_connection(ngx_connection_t *c); 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 @@ -72,10 +72,11 @@ ngx_module_t ngx_http_output_filter_mod #define ngx_next_filter (*ngx_http_top_body_filter) #define need_to_copy(r, hunk) \ - (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY) \ - && (hunk->type & NGX_HUNK_IN_MEMORY) == 0) \ - || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP) \ - && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP)))) + (!ngx_hunk_special(hunk) \ + && (((r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY) \ + && (hunk->type & NGX_HUNK_IN_MEMORY) == 0) \ + || ((r->filter & NGX_HTTP_FILTER_NEED_TEMP) \ + && (hunk->type & (NGX_HUNK_MEMORY|NGX_HUNK_MMAP))))) @@ -201,6 +202,8 @@ int ngx_http_output_filter(ngx_http_requ *ctx->last_out = ce; ctx->last_out = &ce->next; ctx->hunk = NULL; + + break; } if (ctx->out == NULL && last != NGX_NONE) { diff --git a/src/http/ngx_http_event.c b/src/http/ngx_http_request.c rename from src/http/ngx_http_event.c rename to src/http/ngx_http_request.c --- a/src/http/ngx_http_event.c +++ b/src/http/ngx_http_request.c @@ -785,6 +785,10 @@ void ngx_http_finalize_request(ngx_http_ int rc; ngx_event_t *rev, *wev; + if (r->main) { + return; + } + rc = error; if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -813,9 +817,25 @@ void ngx_http_finalize_request(ngx_http_ return; } +#if 1 + return; +#endif + } else if (rc == NGX_ERROR) { r->keepalive = 0; r->lingering_close = 0; + + } else { + if (ngx_http_send_last(r) == NGX_ERROR) { + ngx_http_close_request(r, 0); + ngx_http_close_connection(r->connection); + return; + } + + if (rc == NGX_AGAIN) { + ngx_http_set_write_handler(r); + return; + } } rev = r->connection->read; @@ -840,6 +860,8 @@ void ngx_http_finalize_request(ngx_http_ ngx_http_close_request(r, 0); ngx_http_close_connection(r->connection); } + + return; } @@ -887,6 +909,8 @@ void ngx_http_set_write_handler(ngx_http ngx_http_close_request(r, 0); ngx_http_close_connection(r->connection); } + + return; } @@ -951,6 +975,8 @@ static void ngx_http_writer(ngx_event_t ngx_http_close_request(r, 0); ngx_http_close_connection(r->connection); } + + return; } @@ -1046,6 +1072,8 @@ static void ngx_http_read_discarded_body ngx_http_close_request(r, rc); ngx_http_close_connection(c); } + + return; } @@ -1385,6 +1413,17 @@ static void ngx_http_empty_handler(ngx_e } +int ngx_http_send_last(ngx_http_request_t *r) +{ + ngx_hunk_t *h; + + ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR); + h->type = NGX_HUNK_LAST; + + return ngx_http_output_filter(r, h); +} + + void ngx_http_close_request(ngx_http_request_t *r, int error) { ngx_http_log_ctx_t *ctx; 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 @@ -199,15 +199,19 @@ int ngx_http_special_response_handler(ng } rc = ngx_http_send_header(r); + if (rc == NGX_ERROR) { return NGX_ERROR; } if (r->header_only) { + ngx_http_finalize_request(r, rc); +#if 0 if (rc == NGX_AGAIN) { ngx_http_set_write_handler(r); return NGX_AGAIN; } +#endif return NGX_OK; } @@ -248,12 +252,16 @@ int ngx_http_special_response_handler(ng rc = ngx_http_output_filter(r, h); + ngx_http_finalize_request(r, rc); + +#if 0 if (r->main == NULL) { if (rc == NGX_AGAIN) { ngx_http_set_write_handler(r); return NGX_AGAIN; } } +#endif return NGX_OK; 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 @@ -130,14 +130,16 @@ int ngx_http_write_filter(ngx_http_reque last _ flush _ size); #endif - /* avoid the output if there is no last hunk, no flush point and - size of the hunks is smaller then "buffer_output" */ + /* + * avoid the output if there is no last hunk, no flush point and + * size of the hunks is smaller then "buffer_output" + */ if (!last && flush == 0 && size < conf->buffer_output) { return NGX_OK; } - if (r->connection->write->delayed) { + if (!r->connection->write->ready || r->connection->write->delayed) { return NGX_AGAIN; } diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -93,26 +93,30 @@ int ngx_os_init(ngx_log_t *log) #if (HAVE_FREEBSD_SENDFILE) - /* The determination of the sendfile() nbytes bug is complex enough. - There're two sendfile() syscalls: a new 393 has no bug while - an old 336 has the bug in some versions and has not in others. - Besides libc_r wrapper also emulates the bug in some versions. - There's no way to say exactly if a given FreeBSD version has bug. - Here is the algorithm that works at least for RELEASEs - and for syscalls only (not libc_r wrapper). */ - - /* detect the new sendfile() version available at the compile time - to allow an old binary to run correctly on an updated FreeBSD system. */ + /* + * The determination of the sendfile() nbytes bug is complex enough. + * There're two sendfile() syscalls: a new 393 has no bug while + * an old 336 has the bug in some versions and has not in others. + * Besides libc_r wrapper also emulates the bug in some versions. + * There's no way to say exactly if a given FreeBSD version has the bug. + * Here is the algorithm that works at least for RELEASEs + * and for syscalls only (not libc_r wrapper). + * + * We detect the new sendfile() version available at the compile time + * to allow an old binary to run correctly on an updated FreeBSD system. + */ #if (__FreeBSD__ == 4 && __FreeBSD_version >= 460102) \ || __FreeBSD_version == 460002 || __FreeBSD_version >= 500039 /* a new syscall without the bug */ + ngx_freebsd_sendfile_nbytes_bug = 0; #else /* an old syscall that can have the bug */ + ngx_freebsd_sendfile_nbytes_bug = 1; #endif diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -1,23 +1,24 @@ #include #include +#include #include /* - sendfile() often sends 4K pages over ethernet in 3 packets: 2x1460 and 1176 - or in 6 packets: 5x1460 and 892. Besides although sendfile() allows - to pass the header and the trailer it never sends the header or the trailer - with the part of the file in one packet. So we use TCP_NOPUSH (similar - to Linux's TCP_CORK) to postpone the sending - it not only sends the header - and the first part of the file in one packet but also sends 4K pages - in the full packets. - - Until FreeBSD 4.5 the turning TCP_NOPUSH off does not not flush - the pending data that less than MSS and the data sent with 5 second delay. - So we use TCP_NOPUSH on FreeBSD prior to 4.5 only if the connection - is not needed not keepalive. -*/ + * sendfile() often sends 4K pages over ethernet in 3 packets: 2x1460 and 1176 + * or in 6 packets: 5x1460 and 892. Besides although sendfile() allows + * to pass the header and the trailer it never sends the header or the trailer + * with the part of the file in one packet. So we use TCP_NOPUSH (similar + * to Linux's TCP_CORK) to postpone the sending - it not only sends the header + * and the first part of the file in one packet but also sends 4K pages + * in the full packets. + * + * Until FreeBSD 4.5 the turning TCP_NOPUSH off does not not flush + * the pending data that less than MSS and the data sent with 5 second delay. + * So we use TCP_NOPUSH on FreeBSD prior to 4.5 only if the connection + * is not needed to be keepalive. + */ ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in) @@ -47,12 +48,23 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( NGX_CHAIN_ERROR); /* create the header iovec */ - if (ngx_hunk_in_memory_only(ce->hunk)) { + +#if 0 + if (ngx_hunk_in_memory_only(ce->hunk) || ngx_hunk_special(ce->hunk)) { +#endif prev = NULL; iov = NULL; /* create the iovec and coalesce the neighbouring chain entries */ - while (ce && ngx_hunk_in_memory_only(ce->hunk)) { + + for ( /* void */; ce; ce = ce->next) { + if (ngx_hunk_special(ce->hunk)) { + continue; + } + + if (!ngx_hunk_in_memory_only(ce->hunk)) { + break; + } if (prev == ce->hunk->pos) { iov->iov_len += ce->hunk->last - ce->hunk->pos; @@ -67,24 +79,39 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( } hsize += ce->hunk->last - ce->hunk->pos; - - ce = ce->next; } +#if 0 } +#endif /* 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 && ngx_hunk_in_memory_only(ce->hunk)) { + +#if 0 + if (ce + && (ngx_hunk_in_memory_only(ce->hunk) + || ngx_hunk_special(ce->hunk))) + { +#endif prev = NULL; iov = NULL; /* create the iovec and coalesce the neighbouring chain entries */ - while (ce && ngx_hunk_in_memory_only(ce->hunk)) { + + for ( /* void */; ce; ce = ce->next) { + if (ngx_hunk_special(ce->hunk)) { + continue; + } + + if (!ngx_hunk_in_memory_only(ce->hunk)) { + break; + } if (prev == ce->hunk->pos) { iov->iov_len += ce->hunk->last - ce->hunk->pos; @@ -97,10 +124,10 @@ ngx_chain_t *ngx_freebsd_sendfile_chain( iov->iov_len = ce->hunk->last - ce->hunk->pos; prev = ce->hunk->last; } - - ce = ce->next; } +#if 0 } +#endif tail = ce; @@ -155,28 +182,36 @@ ngx_log_debug(c->log, "NOPUSH"); #endif } else { - rc = writev(c->fd, (struct iovec *) header.elts, header.nelts); + if (hsize) { + rc = writev(c->fd, (struct iovec *) header.elts, header.nelts); - if (rc == -1) { - err = ngx_errno; - if (err == NGX_EAGAIN) { - ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN"); + if (rc == -1) { + err = ngx_errno; + if (err == NGX_EAGAIN) { + ngx_log_error(NGX_LOG_INFO, c->log, err, + "writev() EAGAIN"); - } else if (err == NGX_EINTR) { - eintr = 1; - ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EINTR"); + } else if (err == NGX_EINTR) { + eintr = 1; + ngx_log_error(NGX_LOG_INFO, c->log, err, + "writev() EINTR"); - } else { - ngx_log_error(NGX_LOG_CRIT, c->log, err, "writev() failed"); - return NGX_CHAIN_ERROR; + } else { + ngx_log_error(NGX_LOG_CRIT, c->log, err, + "writev() failed"); + return NGX_CHAIN_ERROR; + } } - } - sent = rc > 0 ? rc : 0; + sent = rc > 0 ? rc : 0; #if (NGX_DEBUG_WRITE_CHAIN) - ngx_log_debug(c->log, "writev: %qd" _ sent); + ngx_log_debug(c->log, "writev: %qd" _ sent); #endif + + } else { + sent = 0; + } } c->sent += sent; @@ -221,5 +256,9 @@ ngx_log_debug(c->log, "NOPUSH"); } while ((tail && tail == ce) || eintr); + if (ce) { + c->write->ready = 0; + } + return ce; }