# HG changeset patch # User Igor Sysoev # Date 1066754996 0 # Node ID c71aeb75c07119e065fc5ea67031634d9363d549 # Parent fb48bf4fea1c134f1cd6141750323f480a31058b nginx-0.0.1-2003-10-21-20:49:56 import diff -r fb48bf4fea1c -r c71aeb75c071 src/core/ngx_hunk.c --- a/src/core/ngx_hunk.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/core/ngx_hunk.c Tue Oct 21 16:49:56 2003 +0000 @@ -147,18 +147,6 @@ if (ngx_hunk_size((*busy)->hunk) > 0) { break; } -#if 0 - if ((*busy)->hunk->type & NGX_HUNK_IN_MEMORY) { - if ((*busy)->hunk->pos != (*busy)->hunk->last) { - break; - } - - } else { - if ((*busy)->hunk->file_pos != (*busy)->hunk->file_last) { - break; - } - } -#endif #if (HAVE_WRITE_ZEROCOPY) if ((*busy)->hunk->type & NGX_HUNK_ZEROCOPY_BUSY) { diff -r fb48bf4fea1c -r c71aeb75c071 src/event/ngx_event_pipe.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/event/ngx_event_pipe.c Tue Oct 21 16:49:56 2003 +0000 @@ -0,0 +1,606 @@ + +#include +#include +#include +#include + + +static int ngx_event_pipe_read_upstream(ngx_event_pipe_t *p); +static int ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p); + +static int ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p); +ngx_inline static void ngx_remove_shadow_links(ngx_hunk_t *hunk); +ngx_inline static void ngx_remove_shadow_free_raw_hunk(ngx_chain_t **free, + ngx_hunk_t *h); +ngx_inline static void ngx_add_after_partially_filled_hunk(ngx_chain_t **chain, + ngx_chain_t *ce); +static int ngx_drain_chains(ngx_event_pipe_t *p); + + +int ngx_event_pipe(ngx_event_pipe_t *p, int do_write) +{ + for ( ;; ) { + if (do_write) { + if (ngx_event_pipe_write_to_downstream(p) == NGX_ABORT) { + return NGX_ABORT; + } + } + + p->read = 0; + + if (ngx_event_pipe_read_upstream(p) == NGX_ABORT) { + return NGX_ABORT; + } + + if (!p->read) { + break; + } + + do_write = 1; + } + + if (ngx_handle_read_event(p->upstream->read) == NGX_ERROR) { + return NGX_ABORT; + } + + if (ngx_handle_write_event(p->downstream->write, + /* TODO: lowat */ 0) == NGX_ERROR) { + return NGX_ABORT; + } + + return NGX_OK; +} + + +int ngx_event_pipe_read_upstream(ngx_event_pipe_t *p) +{ + int n, rc, size; + ngx_hunk_t *h; + ngx_chain_t *chain, *ce, *te; + + if (p->upstream_eof || p->upstream_error || p->upstream_done) { + return NGX_OK; + } + + ngx_log_debug(p->log, "read upstream: %d" _ p->upstream->read->ready); + + for ( ;; ) { + + if (p->upstream_eof || p->upstream_error || p->upstream_done) { + break; + } + + if (p->preread_hunks == NULL && !p->upstream->read->ready) { + break; + } + + if (p->preread_hunks) { + + /* use the pre-read hunks if they exist */ + + p->read = 1; + chain = p->preread_hunks; + p->preread_hunks = NULL; + n = p->preread_size; + + ngx_log_debug(p->log, "preread: %d" _ n); + + } else { + +#if (HAVE_KQUEUE) + + /* + * kqueue notifies about the end of file or a pending error. + * This test allows not to allocate a hunk on these conditions + * and not to call ngx_recv_chain(). + */ + + if (ngx_event_flags == NGX_HAVE_KQUEUE_EVENT) { + + if (p->upstream->read->error) { + ngx_log_error(NGX_LOG_ERR, p->log, p->upstream->read->error, + "readv() failed"); + p->upstream_error = 1; + + break; + + } else if (p->upstream->read->eof + && p->upstream->read->available == 0) { + p->upstream_eof = 1; + p->read = 1; + + break; + } + } +#endif + + if (p->free_raw_hunks) { + + /* use the free hunks if they exist */ + + chain = p->free_raw_hunks; + p->free_raw_hunks = NULL; + + } else if (p->hunks < p->bufs.num) { + + /* allocate a new hunk if it's still allowed */ + + ngx_test_null(h, ngx_create_temp_hunk(p->pool, + p->bufs.size, 0, 0), + NGX_ABORT); + p->hunks++; + + ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT); + chain = te; + + } else if (!p->cachable && p->downstream->write->ready) { + + /* + * if the hunks are not needed to be saved in a cache and + * a downstream is ready then write the hunks to a downstream + */ + + ngx_log_debug(p->log, "downstream ready"); + + break; + + } else if (p->cachable || p->temp_offset < p->max_temp_file_size) { + + /* + * if it's allowed then save some hunks from r->in + * to a temporary file, and add them to a r->out chain + */ + + rc = ngx_event_pipe_write_chain_to_temp_file(p); + + ngx_log_debug(p->log, "temp offset: %d" _ p->temp_offset); + + if (rc == NGX_AGAIN) { + if (ngx_event_flags & NGX_USE_LEVEL_EVENT + && p->upstream->read->active + && p->upstream->read->ready) + { + if (ngx_del_event(p->upstream->read, NGX_READ_EVENT, 0) + == NGX_ERROR) + { + return NGX_ABORT; + } + } + } + + if (rc != NGX_OK) { + return rc; + } + + chain = p->free_raw_hunks; + p->free_raw_hunks = NULL; + + } else { + + /* if there're no hunks to read in then disable a level event */ + + ngx_log_debug(p->log, "no hunks to read in"); + + break; + } + + n = ngx_recv_chain(p->upstream, chain); + + ngx_log_debug(p->log, "recv_chain: %d" _ n); + + p->free_raw_hunks = chain; + + if (n == NGX_ERROR) { + p->upstream_error = 1; + return NGX_ERROR; + } + + if (n == NGX_AGAIN) { + break; + } + + p->read = 1; + + if (n == 0) { + p->upstream_eof = 1; + break; + } + } + + ce = chain; + + while (ce && n > 0) { + + ngx_remove_shadow_links(ce->hunk); + + size = ce->hunk->end - ce->hunk->last; + + if (n >= size) { + ce->hunk->last = ce->hunk->end; + + if (p->input_filter(p, ce->hunk) == NGX_ERROR) { + return NGX_ABORT; + } + + n -= size; + ce = ce->next; + + } else { + ce->hunk->last += n; + n = 0; + } + } + + p->free_raw_hunks = ce; + } + + if ((p->upstream_eof || p->upstream_error) && p->free_raw_hunks) { + if (p->input_filter(p, p->free_raw_hunks->hunk) == NGX_ERROR) { + return NGX_ABORT; + } + + /* TODO: p->free_raw_hunk->next can be free()ed */ + p->free_raw_hunks = p->free_raw_hunks->next; + } + + if (p->cachable && p->in) { + if (ngx_event_pipe_write_chain_to_temp_file(p) == NGX_ABORT) { + return NGX_ABORT; + } + } + + return NGX_OK; +} + + +int ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p) +{ + size_t busy_len; + ngx_hunk_t *h; + ngx_chain_t *out, **le, *ce, *te; + + ngx_log_debug(p->log, "write downstream: %d" _ p->downstream->write->ready); + + for ( ;; ) { + if (p->downstream_error) { + return ngx_drain_chains(p); + } + + if ((p->upstream_eof || p->upstream_error || p->upstream_done) + && p->out == NULL && p->in == NULL) + { + p->downstream_done = 1; + break; + } + + if (!p->downstream->write->ready) { + break; + } + + busy_len = 0; + + if (!(p->upstream_eof || p->upstream_error || p->upstream_done)) { + /* calculate p->busy_len */ + for (ce = p->busy; ce; ce = ce->next) { + busy_len += ngx_hunk_size(ce->hunk); + } + } + + out = NULL; + le = NULL; + + for ( ;; ) { + if (p->out) { + ce = p->out; + + if (!(p->upstream_eof || p->upstream_error || p->upstream_done) + && (busy_len + ngx_hunk_size(ce->hunk) > p->max_busy_len)) + { + break; + } + + p->out = p->out->next; + ngx_remove_shadow_free_raw_hunk(&p->free_raw_hunks, ce->hunk); + + } else if (!p->cachable && p->in) { + ce = p->in; + + if (!(p->upstream_eof || p->upstream_error || p->upstream_done) + && (busy_len + ngx_hunk_size(ce->hunk) > p->max_busy_len)) + { + break; + } + + p->in = p->in->next; + + } else { + break; + } + + busy_len += ngx_hunk_size(ce->hunk); + ce->next = NULL; + ngx_chain_add_ce(out, le, ce); + } + + if (out == NULL) { + break; + } + + if (p->output_filter(p->output_ctx, out) == NGX_ERROR) { + p->downstream_error = 1; + continue; + } + + ngx_chain_update_chains(&p->free, &p->busy, &out); + + /* add the free shadow raw hunks to p->free_raw_hunks */ + + for (ce = p->free; ce; ce = ce->next) { + if (ce->hunk->type & NGX_HUNK_LAST_SHADOW) { + h = ce->hunk->shadow; + /* THINK NEEDED ??? */ h->pos = h->last = h->start; + h->shadow = NULL; + ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT); + ngx_add_after_partially_filled_hunk(&p->free_raw_hunks, te); + + ce->hunk->type &= ~NGX_HUNK_LAST_SHADOW; + } + ce->hunk->shadow = NULL; + } + } + + return NGX_OK; +} + + +static int ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p) +{ + int rc, size, hunk_size; + ngx_hunk_t *h; + ngx_chain_t *ce, *te, *next, *out, **le, **last_free; + + ngx_log_debug(p->log, "write to file"); + + if (p->temp_file->fd == NGX_INVALID_FILE) { + rc = ngx_create_temp_file(p->temp_file, p->temp_path, p->pool, + p->cachable); + + if (rc == NGX_ERROR) { + return NGX_ABORT; + } + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + + if (!p->cachable && p->temp_file_warn) { + ngx_log_error(NGX_LOG_WARN, p->log, 0, p->temp_file_warn); + } + } + + out = p->in; + + if (!p->cachable) { + + size = 0; + ce = p->in; + le = NULL; + +ngx_log_debug(p->log, "offset: %d" _ p->temp_offset); + + do { + hunk_size = ce->hunk->last - ce->hunk->pos; + +ngx_log_debug(p->log, "hunk size: %d" _ hunk_size); + + if ((size + hunk_size > p->temp_file_write_size) + || (p->temp_offset + hunk_size > p->max_temp_file_size)) + { + break; + } + + size += hunk_size; + le = &ce->next; + ce = ce->next; + + } while (ce); + +ngx_log_debug(p->log, "size: %d" _ size); + + if (ce) { + p->in = ce; + *le = NULL; + + } else { + p->in = NULL; + p->last_in = &p->in; + } + + } else { + p->in = NULL; + p->last_in = &p->in; + } + + if (ngx_write_chain_to_file(p->temp_file, out, p->temp_offset, + p->pool) == NGX_ERROR) { + return NGX_ABORT; + } + + for (last_free = &p->free_raw_hunks; + *last_free != NULL; + last_free = &(*last_free)->next) + { + /* void */ + } + + for (ce = out; ce; ce = next) { + next = ce->next; + ce->next = NULL; + + h = ce->hunk; + h->type |= NGX_HUNK_FILE; + h->file = p->temp_file; + h->file_pos = p->temp_offset; + p->temp_offset += h->last - h->pos; + h->file_last = p->temp_offset; + + ngx_chain_add_ce(p->out, p->last_out, ce); + + if (h->type & NGX_HUNK_LAST_SHADOW) { + h->shadow->last = h->shadow->pos = h->shadow->start; + ngx_alloc_ce_and_set_hunk(te, h->shadow, p->pool, NGX_ABORT); + *last_free = te; + last_free = &te->next; + } + } + + return NGX_OK; +} + + +/* the copy input filter */ + +int ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_hunk_t *hunk) +{ + ngx_hunk_t *h; + ngx_chain_t *ce; + + if (hunk->pos == hunk->last) { + return NGX_OK; + } + + if (p->free) { + h = p->free->hunk; + p->free = p->free->next; + + } else { + ngx_test_null(h, ngx_alloc_hunk(p->pool), NGX_ERROR); + } + + ngx_memcpy(h, hunk, sizeof(ngx_hunk_t)); + h->shadow = hunk; + h->type |= NGX_HUNK_LAST_SHADOW|NGX_HUNK_RECYCLED; + hunk->shadow = h; + + ngx_alloc_ce_and_set_hunk(ce, h, p->pool, NGX_ERROR); + ngx_chain_add_ce(p->in, p->last_in, ce); + + return NGX_OK; +} + + +ngx_inline static void ngx_remove_shadow_links(ngx_hunk_t *hunk) +{ + ngx_hunk_t *h, *next; + + if (hunk->shadow == NULL) { + return; + } + + h = hunk->shadow; + + while (!(h->type & NGX_HUNK_LAST_SHADOW)) { + next = h->shadow; + h->type &= ~(NGX_HUNK_TEMP|NGX_HUNK_IN_MEMORY|NGX_HUNK_RECYCLED); + h->shadow = NULL; + h = next; + } + + h->type &= ~(NGX_HUNK_TEMP + |NGX_HUNK_IN_MEMORY + |NGX_HUNK_RECYCLED + |NGX_HUNK_LAST_SHADOW); + h->shadow = NULL; + + hunk->shadow = NULL; +} + + +ngx_inline static void ngx_remove_shadow_free_raw_hunk(ngx_chain_t **free, + ngx_hunk_t *h) +{ + ngx_hunk_t *s; + ngx_chain_t *ce, **le; + + if (h->shadow == NULL) { + return; + } + + for (s = h->shadow; !(s->type & NGX_HUNK_LAST_SHADOW); s = s->shadow) { + /* void */ + } + + le = free; + + for (ce = *free ; ce; ce = ce->next) { + if (ce->hunk == s) { + *le = ce->next; + break; + } + + if (ce->hunk->shadow) { + break; + } + + le = &ce->next; + } +} + + +ngx_inline static void ngx_add_after_partially_filled_hunk(ngx_chain_t **chain, + ngx_chain_t *ce) +{ + if (*chain == NULL) { + *chain = ce; + return; + } + + if ((*chain)->hunk->pos != (*chain)->hunk->last) { + ce->next = (*chain)->next; + (*chain)->next = ce; + + } else { + ce->next = (*chain); + (*chain) = ce; + } +} + + +static int ngx_drain_chains(ngx_event_pipe_t *p) +{ + ngx_hunk_t *h; + ngx_chain_t *ce, *te; + + for ( ;; ) { + if (p->busy) { + ce = p->busy; + + } else if (p->out) { + ce = p->out; + + } else if (p->in) { + ce = p->in; + + } else { + return NGX_OK; + } + + while (ce) { + if (ce->hunk->type & NGX_HUNK_LAST_SHADOW) { + h = ce->hunk->shadow; + /* THINK NEEDED ??? */ h->pos = h->last = h->start; + h->shadow = NULL; + ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT); + ngx_add_after_partially_filled_hunk(&p->free_raw_hunks, te); + + ce->hunk->type &= ~NGX_HUNK_LAST_SHADOW; + } + + ce->hunk->shadow = NULL; + te = ce->next; + ce->next = p->free; + p->free = ce; + ce = te; + } + } +} diff -r fb48bf4fea1c -r c71aeb75c071 src/event/ngx_event_pipe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/event/ngx_event_pipe.h Tue Oct 21 16:49:56 2003 +0000 @@ -0,0 +1,75 @@ +#ifndef _NGX_EVENT_PIPE_H_INCLUDED_ +#define _NGX_EVENT_PIPE_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct ngx_event_pipe_s ngx_event_pipe_t; + +typedef int (*ngx_event_pipe_input_filter_pt)(ngx_event_pipe_t *p, + ngx_hunk_t *hunk); +typedef int (*ngx_event_pipe_output_filter_pt)(void *data, ngx_chain_t *chain); + + +struct ngx_event_pipe_s { + ngx_chain_t *free_raw_hunks; + ngx_chain_t *in; + ngx_chain_t **last_in; + + ngx_chain_t *out; + ngx_chain_t **last_out; + + ngx_chain_t *free; + ngx_chain_t *busy; + + /* + * the input filter i.e. that moves HTTP/1.1 chunks + * from the raw hunks to an incoming chain + */ + + ngx_event_pipe_input_filter_pt input_filter; + void *input_ctx; + + ngx_event_pipe_output_filter_pt output_filter; + void *output_ctx; + + unsigned read:1; + unsigned cachable:1; + unsigned upstream_done:1; + unsigned upstream_eof:1; + unsigned upstream_error:1; + unsigned downstream_done:1; + unsigned downstream_error:1; + + int hunks; + ngx_bufs_t bufs; + + size_t max_busy_len; + + off_t temp_offset; + off_t max_temp_file_size; + int temp_file_write_size; + + ngx_connection_t *upstream; + ngx_connection_t *downstream; + + ngx_pool_t *pool; + ngx_log_t *log; + + ngx_chain_t *preread_hunks; + int preread_size; + + ngx_file_t *temp_file; + ngx_path_t *temp_path; + char *temp_file_warn; +}; + + +int ngx_event_pipe(ngx_event_pipe_t *p, int do_write); +int ngx_event_pipe_copy_input_filter(ngx_event_pipe_t *p, ngx_hunk_t *hunk); + + +#endif /* _NGX_EVENT_PIPE_H_INCLUDED_ */ diff -r fb48bf4fea1c -r c71aeb75c071 src/event/ngx_event_proxy.c --- a/src/event/ngx_event_proxy.c Tue Oct 21 07:47:21 2003 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,607 +0,0 @@ - -#include -#include -#include -#include - -static int ngx_event_proxy_write_chain_to_temp_file(ngx_event_proxy_t *p); -ngx_inline static void ngx_remove_shadow_links(ngx_hunk_t *hunk); -ngx_inline static void ngx_remove_shadow_free_raw_hunk(ngx_chain_t **free, - ngx_hunk_t *h); -ngx_inline static void ngx_add_after_partially_filled_hunk(ngx_chain_t **chain, - ngx_chain_t *ce); -static int ngx_drain_chains(ngx_event_proxy_t *p); - - -int ngx_event_proxy(ngx_event_proxy_t *p, int do_write) -{ - for ( ;; ) { - if (do_write) { - if (ngx_event_proxy_write_to_downstream(p) == NGX_ABORT) { - return NGX_ABORT; - } - } - - p->read = 0; - - if (ngx_event_proxy_read_upstream(p) == NGX_ABORT) { - return NGX_ABORT; - } - - if (!p->read) { - break; - } - - do_write = 1; - } - - if (ngx_handle_read_event(p->upstream->read) == NGX_ERROR) { - return NGX_ABORT; - } - - if (ngx_handle_write_event(p->downstream->write, - /* TODO: lowat */ 0) == NGX_ERROR) { - return NGX_ABORT; - } - - return NGX_OK; -} - - -int ngx_event_proxy_read_upstream(ngx_event_proxy_t *p) -{ - int n, rc, size; - ngx_hunk_t *h; - ngx_chain_t *chain, *ce, *te; - - if (p->upstream_eof || p->upstream_error || p->upstream_done) { - return NGX_OK; - } - - ngx_log_debug(p->log, "read upstream: %d" _ p->upstream->read->ready); - - for ( ;; ) { - - if (p->upstream_eof || p->upstream_error || p->upstream_done) { - break; - } - - if (p->preread_hunks == NULL && !p->upstream->read->ready) { - break; - } - - if (p->preread_hunks) { - - /* use the pre-read hunks if they exist */ - - p->read = 1; - chain = p->preread_hunks; - p->preread_hunks = NULL; - n = p->preread_size; - - ngx_log_debug(p->log, "preread: %d" _ n); - - } else { - -#if (HAVE_KQUEUE) - - /* - * kqueue notifies about the end of file or a pending error. - * This test allows not to allocate a hunk on these conditions - * and not to call ngx_recv_chain(). - */ - - if (ngx_event_flags == NGX_HAVE_KQUEUE_EVENT) { - - if (p->upstream->read->error) { - ngx_log_error(NGX_LOG_ERR, p->log, p->upstream->read->error, - "readv() failed"); - p->upstream_error = 1; - - break; - - } else if (p->upstream->read->eof - && p->upstream->read->available == 0) { - p->upstream_eof = 1; - p->read = 1; - - break; - } - } -#endif - - if (p->free_raw_hunks) { - - /* use the free hunks if they exist */ - - chain = p->free_raw_hunks; - p->free_raw_hunks = NULL; -ngx_log_debug(p->log, "FREE: %08X:%d" _ chain->hunk->pos _ chain->hunk->end - chain->hunk->last); - - } else if (p->hunks < p->bufs.num) { - - /* allocate a new hunk if it's still allowed */ - - ngx_test_null(h, ngx_create_temp_hunk(p->pool, - p->bufs.size, 0, 0), - NGX_ABORT); - p->hunks++; - - ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT); - chain = te; - - } else if (!p->cachable && p->downstream->write->ready) { - - /* - * If the hunks are not needed to be saved in a cache and - * a downstream is ready then write the hunks to a downstream. - */ - - ngx_log_debug(p->log, "downstream ready"); - - break; - - } else if (p->temp_offset < p->max_temp_file_size) { - - /* - * If it's allowed then save some hunks from r->in - * to a temporary file, and add them to a r->out chain. - */ - - rc = ngx_event_proxy_write_chain_to_temp_file(p); - - ngx_log_debug(p->log, "temp offset: %d" _ p->temp_offset); - - if (rc == NGX_AGAIN) { - if (ngx_event_flags & NGX_USE_LEVEL_EVENT - && p->upstream->read->active - && p->upstream->read->ready) - { - if (ngx_del_event(p->upstream->read, NGX_READ_EVENT, 0) - == NGX_ERROR) - { - return NGX_ABORT; - } - } - } - - if (rc != NGX_OK) { - return rc; - } - - chain = p->free_raw_hunks; - p->free_raw_hunks = NULL; - - } else { - - /* if there're no hunks to read in then disable a level event */ - - ngx_log_debug(p->log, "no hunks to read in"); - - break; - } - - n = ngx_recv_chain(p->upstream, chain); - - ngx_log_debug(p->log, "recv_chain: %d" _ n); - - p->free_raw_hunks = chain; - - if (n == NGX_ERROR) { - p->upstream_error = 1; - return NGX_ERROR; - } - - if (n == NGX_AGAIN) { - break; - } - - p->read = 1; - - if (n == 0) { - p->upstream_eof = 1; - break; - } - } - - ce = chain; - - while (ce && n > 0) { - - ngx_remove_shadow_links(ce->hunk); - - size = ce->hunk->end - ce->hunk->last; - - if (n >= size) { - ce->hunk->last = ce->hunk->end; - - if (p->input_filter(p, ce->hunk) == NGX_ERROR) { - return NGX_ABORT; - } - - n -= size; - ce = ce->next; - - } else { -ngx_log_debug(p->log, "PART: %08X:%d:%d" _ ce->hunk->pos _ ce->hunk->last - ce->hunk->pos _ n); - ce->hunk->last += n; -ngx_log_debug(p->log, "PART: %08X:%d" _ ce->hunk->pos _ ce->hunk->end - ce->hunk->last); - n = 0; - } - } - - p->free_raw_hunks = ce; - } - - if ((p->upstream_eof || p->upstream_error) && p->free_raw_hunks) { - if (p->input_filter(p, p->free_raw_hunks->hunk) == NGX_ERROR) { - return NGX_ABORT; - } - - /* TODO: p->free_raw_hunk->next can be free()ed */ - p->free_raw_hunks = p->free_raw_hunks->next; - } - - if (p->cachable && p->in) { - if (ngx_event_proxy_write_chain_to_temp_file(p) == NGX_ABORT) { - return NGX_ABORT; - } - } - - return NGX_OK; -} - - -int ngx_event_proxy_write_to_downstream(ngx_event_proxy_t *p) -{ - size_t busy_len; - ngx_hunk_t *h; - ngx_chain_t *out, *ce, *te; - - ngx_log_debug(p->log, "write downstream: %d" _ p->downstream->write->ready); - - for ( ;; ) { - if (p->downstream_error) { - return ngx_drain_chains(p); - } - - if ((p->upstream_eof || p->upstream_error || p->upstream_done) - && p->out == NULL && p->in == NULL) - { - p->downstream_done = 1; - break; - } - - if (!p->downstream->write->ready) { - break; - } - - busy_len = 0; - - if (!(p->upstream_eof || p->upstream_error || p->upstream_done)) { - /* calculate p->busy_len */ - for (ce = p->busy; ce; ce = ce->next) { - busy_len += ngx_hunk_size(ce->hunk); - } - } - - - if (p->out) { - out = p->out; - - if (!(p->upstream_eof || p->upstream_error || p->upstream_done) - && (busy_len + ngx_hunk_size(out->hunk) > p->max_busy_len)) - { - break; - } - - p->out = p->out->next; - ngx_remove_shadow_free_raw_hunk(&p->free_raw_hunks, out->hunk); - - } else if (!p->cachable && p->in) { - out = p->in; - - if (!(p->upstream_eof || p->upstream_error || p->upstream_done) - && (busy_len + ngx_hunk_size(out->hunk) > p->max_busy_len)) - { - break; - } - - p->in = p->in->next; - - } else { - break; - } - - out->next = NULL; - - - if (p->output_filter(p->output_ctx, out->hunk) == NGX_ERROR) { - p->downstream_error = 1; - continue; - } - - ngx_chain_update_chains(&p->free, &p->busy, &out); - - /* add the free shadow raw hunks to p->free_raw_hunks */ - - for (ce = p->free; ce; ce = ce->next) { -ngx_log_debug(p->log, "SHADOW %08X" _ ce->hunk->shadow); - if (ce->hunk->type & NGX_HUNK_LAST_SHADOW) { - h = ce->hunk->shadow; - /* THINK NEEDED ??? */ h->pos = h->last = h->start; - h->shadow = NULL; - ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT); - ngx_add_after_partially_filled_hunk(&p->free_raw_hunks, te); - -ngx_log_debug(p->log, "RAW %08X" _ h->pos); - - ce->hunk->type &= ~NGX_HUNK_LAST_SHADOW; - } - ce->hunk->shadow = NULL; - } - } - - ngx_log_debug(p->log, "STATE %d:%d:%d:%X:%X" _ - p->upstream_eof _ - p->upstream_error _ - p->upstream_done _ - p->in _ - p->out - ); - - return NGX_OK; -} - - -static int ngx_event_proxy_write_chain_to_temp_file(ngx_event_proxy_t *p) -{ - int rc, size, hunk_size; - ngx_hunk_t *h; - ngx_chain_t *ce, *te, *next, *in, **le, **last_free; - - ngx_log_debug(p->log, "write to file"); - - if (p->temp_file->fd == NGX_INVALID_FILE) { - rc = ngx_create_temp_file(p->temp_file, p->temp_path, p->pool, - p->cachable); - - if (rc == NGX_ERROR) { - return NGX_ABORT; - } - - if (rc == NGX_AGAIN) { - return NGX_AGAIN; - } - - if (!p->cachable && p->temp_file_warn) { - ngx_log_error(NGX_LOG_WARN, p->log, 0, p->temp_file_warn); - } - } - - if (!p->cachable) { - - size = 0; - ce = p->in; - le = NULL; - -ngx_log_debug(p->log, "offset: %d" _ p->temp_offset); - - do { - hunk_size = ce->hunk->last - ce->hunk->pos; - -ngx_log_debug(p->log, "hunk size: %d" _ hunk_size); - - if ((size + hunk_size > p->temp_file_write_size) - || (p->temp_offset + hunk_size > p->max_temp_file_size)) - { - break; - } - - size += hunk_size; - le = &ce->next; - ce = ce->next; - - } while (ce); - -ngx_log_debug(p->log, "size: %d" _ size); - - if (ce) { - in = ce; - *le = NULL; - - } else { - in = NULL; - p->last_in = &p->in; - } - - } else { - in = NULL; - p->last_in = &p->in; - } - - if (ngx_write_chain_to_file(p->temp_file, p->in, p->temp_offset, - p->pool) == NGX_ERROR) { - return NGX_ABORT; - } - - for (last_free = &p->free_raw_hunks; - *last_free != NULL; - last_free = &(*last_free)->next) - { - /* void */ - } - - for (ce = p->in; ce; ce = next) { - next = ce->next; - ce->next = NULL; - - h = ce->hunk; - h->type |= NGX_HUNK_FILE; - h->file = p->temp_file; - h->file_pos = p->temp_offset; - p->temp_offset += h->last - h->pos; - h->file_last = p->temp_offset; - - ngx_chain_add_ce(p->out, p->last_out, ce); - - if (h->type & NGX_HUNK_LAST_SHADOW) { - h->shadow->last = h->shadow->pos = h->shadow->start; - ngx_alloc_ce_and_set_hunk(te, h->shadow, p->pool, NGX_ABORT); - *last_free = te; - last_free = &te->next; - } - } - - p->in = in; - - return NGX_OK; -} - - -/* the copy input filter */ - -int ngx_event_proxy_copy_input_filter(ngx_event_proxy_t *p, ngx_hunk_t *hunk) -{ - ngx_hunk_t *h; - ngx_chain_t *ce; - - if (hunk->pos == hunk->last) { - return NGX_OK; - } - - if (p->free) { - h = p->free->hunk; - p->free = p->free->next; - - } else { - ngx_test_null(h, ngx_alloc_hunk(p->pool), NGX_ERROR); - } - - ngx_memcpy(h, hunk, sizeof(ngx_hunk_t)); - h->shadow = hunk; - h->type |= NGX_HUNK_LAST_SHADOW|NGX_HUNK_RECYCLED; - hunk->shadow = h; - - ngx_alloc_ce_and_set_hunk(ce, h, p->pool, NGX_ERROR); - ngx_chain_add_ce(p->in, p->last_in, ce); - - return NGX_OK; -} - - -ngx_inline static void ngx_remove_shadow_links(ngx_hunk_t *hunk) -{ - ngx_hunk_t *h, *next; - - if (hunk->shadow == NULL) { - return; - } - - h = hunk->shadow; - - while (!(h->type & NGX_HUNK_LAST_SHADOW)) { - next = h->shadow; - h->type &= ~(NGX_HUNK_TEMP|NGX_HUNK_IN_MEMORY|NGX_HUNK_RECYCLED); - h->shadow = NULL; - h = next; - } - - h->type &= ~(NGX_HUNK_TEMP - |NGX_HUNK_IN_MEMORY - |NGX_HUNK_RECYCLED - |NGX_HUNK_LAST_SHADOW); - h->shadow = NULL; - - hunk->shadow = NULL; -} - - -ngx_inline static void ngx_remove_shadow_free_raw_hunk(ngx_chain_t **free, - ngx_hunk_t *h) -{ - ngx_hunk_t *s; - ngx_chain_t *ce, **le; - - if (h->shadow == NULL) { - return; - } - - for (s = h->shadow; !(s->type & NGX_HUNK_LAST_SHADOW); s = s->shadow) { - /* void */ - } - - le = free; - - for (ce = *free ; ce; ce = ce->next) { - if (ce->hunk == s) { - *le = ce->next; - break; - } - - if (ce->hunk->shadow) { - break; - } - - le = &ce->next; - } -} - - -ngx_inline static void ngx_add_after_partially_filled_hunk(ngx_chain_t **chain, - ngx_chain_t *ce) -{ - if (*chain == NULL) { - *chain = ce; - return; - } - - if ((*chain)->hunk->pos != (*chain)->hunk->last) { - ce->next = (*chain)->next; - (*chain)->next = ce; - - } else { - ce->next = (*chain); - (*chain) = ce; - } -} - - -static int ngx_drain_chains(ngx_event_proxy_t *p) -{ - ngx_hunk_t *h; - ngx_chain_t *ce, *te; - - for ( ;; ) { - if (p->busy) { - ce = p->busy; - - } else if (p->out) { - ce = p->out; - - } else if (p->in) { - ce = p->in; - - } else { - return NGX_OK; - } - - while (ce) { - if (ce->hunk->type & NGX_HUNK_LAST_SHADOW) { - h = ce->hunk->shadow; - /* THINK NEEDED ??? */ h->pos = h->last = h->start; - h->shadow = NULL; - ngx_alloc_ce_and_set_hunk(te, h, p->pool, NGX_ABORT); - ngx_add_after_partially_filled_hunk(&p->free_raw_hunks, te); - - ce->hunk->type &= ~NGX_HUNK_LAST_SHADOW; - } - - ce->hunk->shadow = NULL; - te = ce->next; - ce->next = p->free; - p->free = ce; - ce = te; - } - } -} diff -r fb48bf4fea1c -r c71aeb75c071 src/event/ngx_event_proxy.h --- a/src/event/ngx_event_proxy.h Tue Oct 21 07:47:21 2003 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -#ifndef _NGX_EVENT_PROXY_H_INCLUDED_ -#define _NGX_EVENT_PROXY_H_INCLUDED_ - - -#include -#include -#include - - -typedef struct ngx_event_proxy_s ngx_event_proxy_t; - -typedef int (*ngx_event_proxy_input_filter_pt)(ngx_event_proxy_t *p, - ngx_hunk_t *hunk); -typedef int (*ngx_event_proxy_output_filter_pt)(void *data, ngx_hunk_t *hunk); - - -struct ngx_event_proxy_s { - ngx_chain_t *free_raw_hunks; - ngx_chain_t *in; - ngx_chain_t **last_in; - - ngx_chain_t *out; - ngx_chain_t **last_out; - - ngx_chain_t *free; - ngx_chain_t *busy; - - /* - * the input filter i.e. that moves HTTP/1.1 chunks - * from the raw hunks to an incoming chain - */ - - ngx_event_proxy_input_filter_pt input_filter; - void *input_ctx; - - ngx_event_proxy_output_filter_pt output_filter; - void *output_ctx; - - unsigned read:1; - unsigned cachable:1; - unsigned upstream_done:1; - unsigned upstream_eof:1; - unsigned upstream_error:1; - unsigned downstream_done:1; - unsigned downstream_error:1; - - int hunks; - ngx_bufs_t bufs; - - size_t max_busy_len; - - off_t temp_offset; - off_t max_temp_file_size; - int temp_file_write_size; - - ngx_connection_t *upstream; - ngx_connection_t *downstream; - - ngx_pool_t *pool; - ngx_log_t *log; - - ngx_chain_t *preread_hunks; - int preread_size; - - ngx_file_t *temp_file; - ngx_path_t *temp_path; - char *temp_file_warn; -}; - - -int ngx_event_proxy(ngx_event_proxy_t *p, int do_write); -int ngx_event_proxy_copy_input_filter(ngx_event_proxy_t *p, ngx_hunk_t *hunk); - -/* STUB */ -int ngx_event_proxy_read_upstream(ngx_event_proxy_t *p); -int ngx_event_proxy_write_to_downstream(ngx_event_proxy_t *p); - - -#endif /* _NGX_EVENT_PROXY_H_INCLUDED_ */ diff -r fb48bf4fea1c -r c71aeb75c071 src/http/modules/ngx_http_chunked_filter.c --- a/src/http/modules/ngx_http_chunked_filter.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/modules/ngx_http_chunked_filter.c Tue Oct 21 16:49:56 2003 +0000 @@ -39,7 +39,7 @@ return next_header_filter(r); } - if (r->headers_out.content_length == -1) { + if (r->headers_out.content_length_n == -1) { if (r->http_version < NGX_HTTP_VERSION_11) { r->keepalive = 0; diff -r fb48bf4fea1c -r c71aeb75c071 src/http/modules/ngx_http_gzip_filter.c --- a/src/http/modules/ngx_http_gzip_filter.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/modules/ngx_http_gzip_filter.c Tue Oct 21 16:49:56 2003 +0000 @@ -157,8 +157,9 @@ r->headers_out.content_encoding->value.len = 4; r->headers_out.content_encoding->value.data = "gzip"; - ctx->length = r->headers_out.content_length; - r->headers_out.content_length = -1; + ctx->length = r->headers_out.content_length_n; + r->headers_out.content_length_n = -1; + r->headers_out.content_length = NULL; r->filter |= NGX_HTTP_FILTER_NEED_IN_MEMORY; return next_header_filter(r); diff -r fb48bf4fea1c -r c71aeb75c071 src/http/modules/ngx_http_not_modified_filter.c --- a/src/http/modules/ngx_http_not_modified_filter.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/modules/ngx_http_not_modified_filter.c Tue Oct 21 16:49:56 2003 +0000 @@ -54,7 +54,8 @@ if (ims != NGX_ERROR && ims == r->headers_out.last_modified_time) { r->headers_out.status = NGX_HTTP_NOT_MODIFIED; - r->headers_out.content_length = -1; + r->headers_out.content_length_n = -1; + r->headers_out.content_length = NULL; r->headers_out.content_type->key.len = 0; r->headers_out.content_type = NULL; r->headers_out.accept_ranges->key.len = 0; diff -r fb48bf4fea1c -r c71aeb75c071 src/http/modules/ngx_http_range_filter.c --- a/src/http/modules/ngx_http_range_filter.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/modules/ngx_http_range_filter.c Tue Oct 21 16:49:56 2003 +0000 @@ -49,7 +49,7 @@ if (r->main || r->http_version < NGX_HTTP_VERSION_10 || r->headers_out.status != NGX_HTTP_OK - || r->headers_out.content_length == -1 + || r->headers_out.content_length_n == -1 /* STUB: we currently support ranges for file hunks only */ || r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY) { @@ -103,7 +103,7 @@ break; } - if (start >= r->headers_out.content_length) { + if (start >= r->headers_out.content_length_n) { rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; break; } @@ -114,7 +114,7 @@ ngx_test_null(range, ngx_push_array(&r->headers_out.ranges), NGX_ERROR); range->start = start; - range->end = r->headers_out.content_length; + range->end = r->headers_out.content_length_n; if (*p++ == ',') { continue; @@ -139,7 +139,7 @@ break; } - if (end >= r->headers_out.content_length || start >= end) { + if (end >= r->headers_out.content_length_n || start >= end) { rc = NGX_HTTP_RANGE_NOT_SATISFIABLE; break; } @@ -170,9 +170,10 @@ r->headers_out.content_range->value.len = ngx_snprintf(r->headers_out.content_range->value.data, 8 + 20 + 1, "bytes */" OFF_FMT, - r->headers_out.content_length); + r->headers_out.content_length_n); - r->headers_out.content_length = -1; + r->headers_out.content_length_n = -1; + r->headers_out.content_length = NULL; return rc; @@ -193,9 +194,9 @@ 6 + 20 + 1 + 20 + 1 + 20 + 1, "bytes " OFF_FMT "-" OFF_FMT "/" OFF_FMT, range->start, range->end - 1, - r->headers_out.content_length); + r->headers_out.content_length_n); - r->headers_out.content_length = range->end - range->start; + r->headers_out.content_length_n = range->end - range->start; } else { @@ -267,13 +268,14 @@ 20 + 1 + 20 + 1 + 20 + 5, OFF_FMT "-" OFF_FMT "/" OFF_FMT CRLF CRLF, range[i].start, range[i].end - 1, - r->headers_out.content_length); + r->headers_out.content_length_n); len += ctx->boundary_header.len + range[i].content_range.len + (size_t) (range[i].end - range[i].start); } - r->headers_out.content_length = len; + r->headers_out.content_length_n = len; + r->headers_out.content_length = NULL; } } diff -r fb48bf4fea1c -r c71aeb75c071 src/http/modules/ngx_http_static_handler.c --- a/src/http/modules/ngx_http_static_handler.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/modules/ngx_http_static_handler.c Tue Oct 21 16:49:56 2003 +0000 @@ -191,6 +191,7 @@ ngx_log_e level; ngx_err_t err; ngx_hunk_t *h; + ngx_chain_t out; ngx_http_type_t *type; ngx_http_log_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; @@ -257,7 +258,7 @@ #endif r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length = ngx_file_size(r->file.info); + r->headers_out.content_length_n = ngx_file_size(r->file.info); r->headers_out.last_modified_time = ngx_file_mtime(r->file.info); ngx_test_null(r->headers_out.content_type, @@ -317,7 +318,10 @@ h->file->fd = r->file.fd; h->file->log = r->connection->log; - return ngx_http_output_filter(r, h); + out.hunk = h; + out.next = NULL; + + return ngx_http_output_filter(r, &out); } diff -r fb48bf4fea1c -r c71aeb75c071 src/http/modules/proxy/ngx_http_proxy_handler.c --- a/src/http/modules/proxy/ngx_http_proxy_handler.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/modules/proxy/ngx_http_proxy_handler.c Tue Oct 21 16:49:56 2003 +0000 @@ -2,8 +2,8 @@ #include #include #include -/* STUB */ #include -/* STUB */ #include +#include +#include #include #include @@ -632,12 +632,13 @@ { int rc, i; ngx_table_elt_t *ch, *ph; - ngx_event_proxy_t *ep; + ngx_event_pipe_t *ep; ngx_http_request_t *r; r = p->request; - r->headers_out.content_length = -1; + r->headers_out.content_length_n = -1; + r->headers_out.content_length = NULL; /* copy an upstream header to r->headers_out */ @@ -655,13 +656,6 @@ } } - if (&ph[i] == p->headers_in.content_length) { - r->headers_out.content_length = - ngx_atoi(p->headers_in.content_length->value.data, - p->headers_in.content_length->value.len); - continue; - } - ch = ngx_push_table(r->headers_out.headers); if (ch == NULL) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -675,6 +669,14 @@ r->headers_out.content_type->key.len = 0; continue; } + + if (&ph[i] == p->headers_in.content_length) { + r->headers_out.content_length_n = + ngx_atoi(p->headers_in.content_length->value.data, + p->headers_in.content_length->value.len); + r->headers_out.content_length = ch; + continue; + } } /* STUB */ @@ -700,14 +702,14 @@ p->header_sent = 1; - ep = ngx_pcalloc(r->pool, sizeof(ngx_event_proxy_t)); + ep = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); if (ep == NULL) { ngx_http_proxy_finalize_request(p, 0); return; } - ep->input_filter = ngx_event_proxy_copy_input_filter; - ep->output_filter = (ngx_event_proxy_output_filter_pt) + ep->input_filter = ngx_event_pipe_copy_input_filter; + ep->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter; ep->output_ctx = r; ep->bufs = p->lcf->bufs; @@ -743,14 +745,17 @@ ep->preread_size = p->header_in->last - p->header_in->pos; /* - * event_proxy would do p->header_in->last += ep->preread_size - * as these bytes were read. + * event_pipe would do p->header_in->last += ep->preread_size + * as though these bytes were read. */ p->header_in->last = p->header_in->pos; - /* STUB */ ep->cachable = 0; + /* STUB */ ep->cachable = 1; +#if 0 + ep->max_temp_file_size = 1000000000; +#endif - p->event_proxy = ep; + p->event_pipe = ep; #if 0 lcx = p->log->data; @@ -771,7 +776,7 @@ ngx_connection_t *c; ngx_http_request_t *r; ngx_http_proxy_ctx_t *p; - ngx_event_proxy_t *ep; + ngx_event_pipe_t *ep; c = ev->data; @@ -786,7 +791,7 @@ r = p->request; } - ep = p->event_proxy; + ep = p->event_pipe; if (ev->timedout) { if (ev->write) { @@ -797,7 +802,7 @@ } } else { - if (ngx_event_proxy(ep, ev->write) == NGX_ABORT) { + if (ngx_event_pipe(ep, ev->write) == NGX_ABORT) { ngx_http_proxy_finalize_request(p, 0); return; } @@ -1159,14 +1164,14 @@ conf->bufs.num = 10; conf->bufs.size = 4096; - conf->max_busy_len = 8192 + 4096; + conf->max_busy_len = 8192; /* CHECK in _init conf->max_temp_size >= conf->bufs.size !!! */ conf->max_temp_file_size = 4096 * 6; - conf->temp_file_write_size = 4096 * 2; + conf->temp_file_write_size = 4096 * 1; ngx_test_null(conf->temp_path, ngx_pcalloc(cf->pool, sizeof(ngx_path_t)), NULL); diff -r fb48bf4fea1c -r c71aeb75c071 src/http/modules/proxy/ngx_http_proxy_handler.h --- a/src/http/modules/proxy/ngx_http_proxy_handler.h Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/modules/proxy/ngx_http_proxy_handler.h Tue Oct 21 16:49:56 2003 +0000 @@ -48,6 +48,8 @@ ngx_table_elt_t *last_modified; ngx_table_elt_t *accept_ranges; + off_t content_length_n; + ngx_table_t *headers; } ngx_http_proxy_headers_in_t; @@ -74,7 +76,7 @@ int location_len; ngx_str_t host_header; - ngx_event_proxy_t *event_proxy; + ngx_event_pipe_t *event_pipe; unsigned accel:1; unsigned cachable:1; diff -r fb48bf4fea1c -r c71aeb75c071 src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/ngx_http_core_module.c Tue Oct 21 16:49:56 2003 +0000 @@ -130,13 +130,6 @@ offsetof(ngx_http_core_loc_conf_t, doc_root), NULL}, - {ngx_string("sendfile"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_core_loc_conf_t, sendfile), - NULL}, - {ngx_string("send_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -207,15 +200,22 @@ lcx = r->connection->log->data; lcx->action = NULL; - /* STUB */ - r->keepalive = 1; - if (r->headers_in.connection) { - if (r->headers_in.connection->value.len == 5 - && ngx_strcasecmp(r->headers_in.connection->value.data, "close") - == 0) - { + switch (r->headers_in.connection_type) { + case 0: + if (r->http_version > NGX_HTTP_VERSION_10) { + r->keepalive = 1; + } else { r->keepalive = 0; } + break; + + case NGX_HTTP_CONNECTION_CLOSE: + r->keepalive = 0; + break; + + case NGX_HTTP_CONNECTION_KEEP_ALIVE: + r->keepalive = 1; + break; } #if 0 @@ -331,9 +331,10 @@ int ngx_http_find_location_config(ngx_http_request_t *r) { - int i, rc; - ngx_http_core_loc_conf_t *clcf, **clcfp; - ngx_http_core_srv_conf_t *cscf; + int i, rc; + ngx_http_core_loc_conf_t *clcf, **clcfp; + ngx_http_core_srv_conf_t *cscf; + ngx_http_write_filter_conf_t *wcf; cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); @@ -363,12 +364,14 @@ } } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + wcf = ngx_http_get_module_loc_conf(r, ngx_http_write_filter_module); - if (!(ngx_io.flags & NGX_IO_SENDFILE) || !clcf->sendfile) { + if (!(ngx_io.flags & NGX_IO_SENDFILE) || !wcf->sendfile) { r->filter = NGX_HTTP_FILTER_NEED_IN_MEMORY; } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + if (clcf->handler) { /* * if the location already has content handler then skip @@ -825,8 +828,6 @@ */ - lcf->sendfile = NGX_CONF_UNSET; - lcf->send_timeout = NGX_CONF_UNSET; lcf->discarded_buffer_size = NGX_CONF_UNSET; lcf->keepalive_timeout = NGX_CONF_UNSET; @@ -895,7 +896,6 @@ ngx_conf_merge_str_value(conf->default_type, prev->default_type, "text/plain"); - ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 10000); ngx_conf_merge_size_value(conf->discarded_buffer_size, prev->discarded_buffer_size, 1500); diff -r fb48bf4fea1c -r c71aeb75c071 src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/ngx_http_core_module.h Tue Oct 21 16:49:56 2003 +0000 @@ -110,7 +110,6 @@ ngx_array_t *types; ngx_str_t default_type; - int sendfile; /* sendfile */ ngx_msec_t send_timeout; /* send_timeout */ ssize_t send_lowat; /* send_lowat */ ssize_t discarded_buffer_size; /* discarded_buffer_size */ diff -r fb48bf4fea1c -r c71aeb75c071 src/http/ngx_http_filter.h --- a/src/http/ngx_http_filter.h Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/ngx_http_filter.h Tue Oct 21 16:49:56 2003 +0000 @@ -7,12 +7,20 @@ #define NGX_HTTP_FILTER_NEED_TEMP 4 -int ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk); +typedef struct { + ssize_t buffer_output; + int sendfile; +} ngx_http_write_filter_conf_t; + + +int ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in); int ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in); extern int (*ngx_http_top_header_filter) (ngx_http_request_t *r); extern int (*ngx_http_top_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch); +extern ngx_module_t ngx_http_write_filter_module; + #endif /* _NGX_HTTP_FILTER_H_INCLUDED_ */ diff -r fb48bf4fea1c -r c71aeb75c071 src/http/ngx_http_header_filter.c --- a/src/http/ngx_http_header_filter.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/ngx_http_header_filter.c Tue Oct 21 16:49:56 2003 +0000 @@ -159,9 +159,11 @@ len += 15 + r->headers_out.content_range->value.len + 2; } - if (r->headers_out.content_length >= 0) { - /* "Content-Length: ... \r\n", 2^64 is 20 characters */ - len += 48; + if (r->headers_out.content_length == NULL) { + if (r->headers_out.content_length_n >= 0) { + /* "Content-Length: ... \r\n", 2^64 is 20 characters */ + len += 48; + } } if (r->headers_out.content_type && r->headers_out.content_type->value.len) { @@ -260,11 +262,13 @@ *(h->last++) = CR; *(h->last++) = LF; } - /* 2^64 is 20 characters */ - if (r->headers_out.content_length >= 0) { - h->last += ngx_snprintf(h->last, 49, - "Content-Length: " OFF_FMT CRLF, - r->headers_out.content_length); + if (r->headers_out.content_length == NULL) { + /* 2^64 is 20 characters */ + if (r->headers_out.content_length_n >= 0) { + h->last += ngx_snprintf(h->last, 49, + "Content-Length: " OFF_FMT CRLF, + r->headers_out.content_length_n); + } } if (r->headers_out.content_type && r->headers_out.content_type->value.len) { diff -r fb48bf4fea1c -r c71aeb75c071 src/http/ngx_http_output_filter.c --- a/src/http/ngx_http_output_filter.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/ngx_http_output_filter.c Tue Oct 21 16:49:56 2003 +0000 @@ -84,11 +84,11 @@ -int ngx_http_output_filter(ngx_http_request_t *r, ngx_hunk_t *hunk) +int ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in) { int rc, last; ssize_t size; - ngx_chain_t out, *ce, **le; + ngx_chain_t *ce; ngx_http_output_filter_ctx_t *ctx; ngx_http_output_filter_conf_t *conf; @@ -103,33 +103,27 @@ /* * the short path for the case when the chain ctx->in is empty - * and there's no hunk or the hunk does not require the copy + * and the incoming chain is empty too or it has the single hunk + * that does not require the copy */ if (ctx->in == NULL) { - if (hunk == NULL) { - return ngx_next_filter(r, NULL); + if (in == NULL) { + return ngx_next_filter(r, in); } - if (!need_to_copy(r, hunk)) { - out.hunk = hunk; - out.next = NULL; - return ngx_next_filter(r, &out); + if (in->next == NULL && (!need_to_copy(r, in->hunk))) { + return ngx_next_filter(r, in); } } /* add the incoming hunk to the chain ctx->in */ - if (hunk) { - le = &ctx->in; - - for (ce = ctx->in; ce; ce = ce->next) { - le = &ce->next; + if (in) { + if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { + return NGX_ERROR; } - - ngx_add_hunk_to_chain(ce, hunk, r->pool, NGX_ERROR); - *le = ce; } conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, diff -r fb48bf4fea1c -r c71aeb75c071 src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/ngx_http_request.c Tue Oct 21 16:49:56 2003 +0000 @@ -9,6 +9,7 @@ static void ngx_http_process_request_line(ngx_event_t *rev); static void ngx_http_process_request_headers(ngx_event_t *rev); static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); +static int ngx_http_process_request_header(ngx_http_request_t *r); static void ngx_http_set_write_handler(ngx_http_request_t *r); @@ -256,7 +257,8 @@ r->file.fd = NGX_INVALID_FILE; r->headers_in.content_length_n = -1; - r->headers_out.content_length = -1; + r->headers_in.keep_alive_n = -1; + r->headers_out.content_length_n = -1; r->headers_out.last_modified_time = -1; rev->event_handler = ngx_http_process_request_line; @@ -503,14 +505,11 @@ static void ngx_http_process_request_headers(ngx_event_t *rev) { int rc, i, offset; - size_t len; ssize_t n; ngx_table_elt_t *h; ngx_connection_t *c; ngx_http_request_t *r; - ngx_http_server_name_t *name; ngx_http_core_srv_conf_t *cscf; - ngx_http_core_loc_conf_t *clcf; c = rev->data; r = c->data; @@ -604,59 +603,11 @@ ngx_log_debug(r->connection->log, "HTTP header done"); - if (r->headers_in.host) { - for (len = 0; len < r->headers_in.host->value.len; len++) { - if (r->headers_in.host->value.data[len] == ':') { - break; - } - } - r->headers_in.host_name_len = len; - - /* find the name based server configuration */ - - name = r->virtual_names->elts; - for (i = 0; i < r->virtual_names->nelts; i++) { - if (r->headers_in.host_name_len != name[i].name.len) { - continue; - } - - if (ngx_strncasecmp(r->headers_in.host->value.data, - name[i].name.data, - r->headers_in.host_name_len) == 0) - { - r->srv_conf = name[i].core_srv_conf->ctx->srv_conf; - r->loc_conf = name[i].core_srv_conf->ctx->loc_conf; + rc = ngx_http_process_request_header(r); - clcf = ngx_http_get_module_loc_conf(r, - ngx_http_core_module); - c->log->file = clcf->err_log->file; - c->log->log_level = clcf->err_log->log_level; - - break; - } - } - - } else { - if (r->http_version > NGX_HTTP_VERSION_10) { - ngx_http_header_parse_error(r, - NGX_HTTP_PARSE_NO_HOST_HEADER, - NGX_HTTP_BAD_REQUEST); - return; - } - r->headers_in.host_name_len = 0; - } - - if (r->headers_in.content_length) { - r->headers_in.content_length_n = - ngx_atoi(r->headers_in.content_length->value.data, - r->headers_in.content_length->value.len); - - if (r->headers_in.content_length_n == NGX_ERROR) { - ngx_http_header_parse_error(r, - NGX_HTTP_PARSE_INVALID_CL_HEADER, - NGX_HTTP_BAD_REQUEST); - return; - } + if (rc != NGX_OK) { + ngx_http_header_parse_error(r, rc, NGX_HTTP_BAD_REQUEST); + return; } if (r->header_timeout_set) { @@ -766,6 +717,86 @@ } +static int ngx_http_process_request_header(ngx_http_request_t *r) +{ + int i; + size_t len; + ngx_http_server_name_t *name; + ngx_http_core_loc_conf_t *clcf; + + if (r->headers_in.host) { + for (len = 0; len < r->headers_in.host->value.len; len++) { + if (r->headers_in.host->value.data[len] == ':') { + break; + } + } + r->headers_in.host_name_len = len; + + /* find the name based server configuration */ + + name = r->virtual_names->elts; + for (i = 0; i < r->virtual_names->nelts; i++) { + if (r->headers_in.host_name_len != name[i].name.len) { + continue; + } + + if (ngx_strncasecmp(r->headers_in.host->value.data, + name[i].name.data, + r->headers_in.host_name_len) == 0) + { + r->srv_conf = name[i].core_srv_conf->ctx->srv_conf; + r->loc_conf = name[i].core_srv_conf->ctx->loc_conf; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + r->connection->log->file = clcf->err_log->file; + r->connection->log->log_level = clcf->err_log->log_level; + + break; + } + } + + } else { + if (r->http_version > NGX_HTTP_VERSION_10) { + return NGX_HTTP_PARSE_NO_HOST_HEADER; + } + r->headers_in.host_name_len = 0; + } + + if (r->headers_in.content_length) { + r->headers_in.content_length_n = + ngx_atoi(r->headers_in.content_length->value.data, + r->headers_in.content_length->value.len); + + if (r->headers_in.content_length_n == NGX_ERROR) { + return NGX_HTTP_PARSE_INVALID_CL_HEADER; + } + } + + if (r->headers_in.connection) { + if (r->headers_in.connection->value.len == 5 + && ngx_strcasecmp(r->headers_in.connection->value.data, "close") + == 0) + { + r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE; + + } else if (r->headers_in.connection->value.len == 10 + && ngx_strcasecmp(r->headers_in.connection->value.data, + "keep-alive") == 0) + { + r->headers_in.connection_type = NGX_HTTP_CONNECTION_KEEP_ALIVE; + + if (r->headers_in.keep_alive) { + r->headers_in.keep_alive_n = + ngx_atoi(r->headers_in.keep_alive->value.data, + r->headers_in.keep_alive->value.len); + } + } + } + + return NGX_OK; +} + + void ngx_http_finalize_request(ngx_http_request_t *r, int rc) { ngx_log_debug(r->connection->log, "finalize http request"); @@ -1283,12 +1314,15 @@ int ngx_http_send_last(ngx_http_request_t *r) { - ngx_hunk_t *h; + ngx_hunk_t *h; + ngx_chain_t out; ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR); h->type = NGX_HUNK_LAST; + out.hunk = h; + out.next = NULL; - return ngx_http_output_filter(r, h); + return ngx_http_output_filter(r, &out); } diff -r fb48bf4fea1c -r c71aeb75c071 src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/ngx_http_request.h Tue Oct 21 16:49:56 2003 +0000 @@ -10,11 +10,11 @@ #define NGX_HTTP_HEAD 2 #define NGX_HTTP_POST 3 -#define NGX_HTTP_CONN_CLOSE 0 -#define NGX_HTTP_CONN_KEEP_ALIVE 1 +#define NGX_HTTP_CONNECTION_CLOSE 1 +#define NGX_HTTP_CONNECTION_KEEP_ALIVE 2 -#define NGX_NONE 1 +#define NGX_NONE 1 #define NGX_HTTP_PARSE_HEADER_DONE 1 @@ -63,9 +63,6 @@ typedef struct { - size_t host_name_len; - ssize_t content_length_n; - ngx_table_elt_t *host; ngx_table_elt_t *connection; ngx_table_elt_t *if_modified_since; @@ -77,6 +74,11 @@ ngx_table_elt_t *user_agent; ngx_table_elt_t *keep_alive; + size_t host_name_len; + ssize_t content_length_n; + size_t connection_type; + ssize_t keep_alive_n; + ngx_table_t *headers; } ngx_http_headers_in_t; @@ -107,6 +109,7 @@ ngx_table_elt_t *server; ngx_table_elt_t *date; ngx_table_elt_t *content_type; + ngx_table_elt_t *content_length; ngx_table_elt_t *content_encoding; ngx_table_elt_t *location; ngx_table_elt_t *last_modified; @@ -118,7 +121,7 @@ ngx_table_t *headers; - off_t content_length; + off_t content_length_n; char *etag; time_t date_time; time_t last_modified_time; diff -r fb48bf4fea1c -r c71aeb75c071 src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/ngx_http_special_response.c Tue Oct 21 16:49:56 2003 +0000 @@ -152,8 +152,9 @@ int ngx_http_special_response_handler(ngx_http_request_t *r, int error) { - int err, rc; - ngx_hunk_t *h; + int err, rc; + ngx_hunk_t *h; + ngx_chain_t *out, **le, *ce; r->headers_out.status = error; @@ -189,9 +190,9 @@ } if (error_pages[err].len) { - r->headers_out.content_length = error_pages[err].len - + sizeof(error_tail) - 1 - + sizeof(msie_stub) - 1; + r->headers_out.content_length_n = error_pages[err].len + + sizeof(error_tail) - 1 + + sizeof(msie_stub) - 1; ngx_test_null(r->headers_out.content_type, ngx_push_table(r->headers_out.headers), @@ -203,7 +204,8 @@ r->headers_out.content_type->value.data = "text/html"; } else { - r->headers_out.content_length = -1; + r->headers_out.content_length_n = -1; + r->headers_out.content_length = NULL; } rc = ngx_http_send_header(r); @@ -216,41 +218,42 @@ return NGX_OK; } + out = NULL; + le = NULL; + ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR); - h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; h->pos = error_pages[err].data; h->last = error_pages[err].data + error_pages[err].len; - if (ngx_http_output_filter(r, h) == NGX_ERROR) { - return NGX_ERROR; - } + ngx_alloc_ce_and_set_hunk(ce, h, r->pool, NGX_ERROR); + ngx_chain_add_ce(out, le, ce); + ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR); - h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; h->pos = error_tail; h->last = error_tail + sizeof(error_tail) - 1; + ngx_alloc_ce_and_set_hunk(ce, h, r->pool, NGX_ERROR); + ngx_chain_add_ce(out, le, ce); + if (/* STUB: "msie_padding on/off" */ 1 && r->http_version >= NGX_HTTP_VERSION_10 && error >= NGX_HTTP_BAD_REQUEST && error != NGX_HTTP_REQUEST_URI_TOO_LARGE ) { - - if (ngx_http_output_filter(r, h) == NGX_ERROR) { - return NGX_ERROR; - } - ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR); - h->type = NGX_HUNK_MEMORY|NGX_HUNK_IN_MEMORY; h->pos = msie_stub; h->last = msie_stub + sizeof(msie_stub) - 1; + + ngx_alloc_ce_and_set_hunk(ce, h, r->pool, NGX_ERROR); + ngx_chain_add_ce(out, le, ce); } h->type |= NGX_HUNK_LAST; - return ngx_http_output_filter(r, h); + return ngx_http_output_filter(r, out); } diff -r fb48bf4fea1c -r c71aeb75c071 src/http/ngx_http_write_filter.c --- a/src/http/ngx_http_write_filter.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/http/ngx_http_write_filter.c Tue Oct 21 16:49:56 2003 +0000 @@ -6,11 +6,6 @@ typedef struct { - ssize_t buffer_output; -} ngx_http_write_filter_conf_t; - - -typedef struct { ngx_chain_t *out; } ngx_http_write_filter_ctx_t; @@ -23,6 +18,13 @@ static ngx_command_t ngx_http_write_filter_commands[] = { + {ngx_string("sendfile"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_write_filter_conf_t, sendfile), + NULL}, + {ngx_string("buffer_output"), NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -81,36 +83,7 @@ for (ce = ctx->out; ce; ce = ce->next) { le = &ce->next; - 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; - } - - if (ce->hunk->type & NGX_HUNK_LAST) { - last = 1; - } - } - - /* add the new chain to the existent one */ - - for (/* void */; in; in = in->next) { - ngx_test_null(ce, ngx_alloc_chain_entry(r->pool), NGX_ERROR); - - ce->hunk = in->hunk; - ce->next = NULL; - *le = ce; - le = &ce->next; - - 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; - } + size += ngx_hunk_size(ce->hunk); if (ce->hunk->type & (NGX_HUNK_FLUSH|NGX_HUNK_RECYCLED)) { flush = size; @@ -124,6 +97,31 @@ conf = ngx_http_get_module_loc_conf(r->main ? r->main : r, ngx_http_write_filter_module); + /* add the new chain to the existent one */ + + for (/* void */; in; in = in->next) { + ngx_test_null(ce, ngx_alloc_chain_entry(r->pool), NGX_ERROR); + + ce->hunk = in->hunk; + ce->next = NULL; + *le = ce; + le = &ce->next; + + if (!(ngx_io.flags & NGX_IO_SENDFILE) || !conf->sendfile) { + ce->hunk->type &= ~NGX_HUNK_FILE; + } + + size += ngx_hunk_size(ce->hunk); + + if (ce->hunk->type & (NGX_HUNK_FLUSH|NGX_HUNK_RECYCLED)) { + flush = size; + } + + if (ce->hunk->type & NGX_HUNK_LAST) { + last = 1; + } + } + #if (NGX_DEBUG_WRITE_FILTER) ngx_log_debug(r->connection->log, "write filter: last:%d flush:%qd size:%qd" _ @@ -176,6 +174,7 @@ NULL); conf->buffer_output = NGX_CONF_UNSET; + conf->sendfile = NGX_CONF_UNSET; return conf; } @@ -188,6 +187,7 @@ ngx_http_write_filter_conf_t *conf = child; ngx_conf_merge_size_value(conf->buffer_output, prev->buffer_output, 1460); + ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0); return NULL; } diff -r fb48bf4fea1c -r c71aeb75c071 src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c Tue Oct 21 07:47:21 2003 +0000 +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c Tue Oct 21 16:49:56 2003 +0000 @@ -154,6 +154,11 @@ hdtr.trailers = (struct iovec *) trailer.elts; hdtr.trl_cnt = trailer.nelts; + /* + * the old sendfile() "nbytes bug": + * http://www.freebsd.org/cgi/query-pr.cgi?pr=33771 + */ + if (ngx_freebsd_sendfile_nbytes_bug == 0) { hsize = 0; } @@ -194,7 +199,6 @@ if (rc == -1) { err = ngx_errno; if (err == NGX_EAGAIN) { - eagain = 1; ngx_log_error(NGX_LOG_INFO, c->log, err, "writev() EAGAIN"); } else if (err == NGX_EINTR) { @@ -256,6 +260,11 @@ in = ce; if (eagain) { + /* + * sendfile() can return EAGAIN even if it has sent + * a whole file part and successive sendfile() would + * return EAGAIN right away and would not send anything. + */ c->write->ready = 0; break; }