diff options
author | Igor Sysoev <igor@sysoev.ru> | 2005-05-12 14:58:06 +0000 |
---|---|---|
committer | Igor Sysoev <igor@sysoev.ru> | 2005-05-12 14:58:06 +0000 |
commit | 899b44eab259f32af5c6e3da342f430c654528ce (patch) | |
tree | 23fb5dfbc9219030f9e102db5a2ce44e98c0a9d0 /src/http/ngx_http_upstream.c | |
parent | 22157ce9d570452b2d77f0fe7e510e6b0e4d05c2 (diff) | |
download | nginx-release-0.1.29.tar.gz nginx-release-0.1.29.zip |
nginx-0.1.29-RELEASE importrelease-0.1.29
*) Feature: the ngx_http_ssi_module supports "include virtual" command.
*) Feature: the ngx_http_ssi_module supports the condition command like
'if expr="$NAME"' and "else" and "endif" commands. Only one nested
level is supported.
*) Feature: the ngx_http_ssi_module supports the DATE_LOCAL and
DATE_GMT variables and "config timefmt" command.
*) Feature: the "ssi_ignore_recycled_buffers" directive.
*) Bugfix: the "echo" command did not show the default value for the
empty QUERY_STRING variable.
*) Change: the ngx_http_proxy_module was rewritten.
*) Feature: the "proxy_redirect", "proxy_pass_request_headers",
"proxy_pass_request_body", and "proxy_method" directives.
*) Feature: the "proxy_set_header" directive. The "proxy_x_var" was
canceled and must be replaced with the proxy_set_header directive.
*) Change: the "proxy_preserve_host" is canceled and must be replaced
with the "proxy_set_header Host $host" and the "proxy_redirect off"
directives, the "proxy_set_header Host $host:$proxy_port" directive
and the appropriate proxy_redirect directives.
*) Change: the "proxy_set_x_real_ip" is canceled and must be replaced
with the "proxy_set_header X-Real-IP $remote_addr" directive.
*) Change: the "proxy_add_x_forwarded_for" is canceled and must be
replaced with
the "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for"
directive.
*) Change: the "proxy_set_x_url" is canceled and must be replaced with
the "proxy_set_header X-URL http://$host:$server_port$request_uri"
directive.
*) Feature: the "fastcgi_param" directive.
*) Change: the "fastcgi_root", "fastcgi_set_var" and "fastcgi_params"
directive are canceled and must be replaced with the fastcgi_param
directives.
*) Feature: the "index" directive can use the variables.
*) Feature: the "index" directive can be used at http and server levels.
*) Change: the last index only in the "index" directive can be absolute.
*) Feature: the "rewrite" directive can use the variables.
*) Feature: the "internal" directive.
*) Feature: the CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR,
SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME,
REQUEST_METHOD, REQUEST_URI, and REMOTE_USER variables.
*) Change: nginx now passes the invalid lines in a client request
headers or a backend response header.
*) Bugfix: if the backend did not transfer response for a long time and
the "send_timeout" was less than "proxy_read_timeout", then nginx
returned the 408 response.
*) Bugfix: the segmentation fault was occurred if the backend sent an
invalid line in response header; the bug had appeared in 0.1.26.
*) Bugfix: the segmentation fault may occurred in FastCGI fault
tolerance configuration.
*) Bugfix: the "expires" directive did not remove the previous
"Expires" and "Cache-Control" headers.
*) Bugfix: nginx did not take into account trailing dot in "Host"
header line.
*) Bugfix: the ngx_http_auth_module did not work under Linux.
*) Bugfix: the rewrite directive worked incorrectly, if the arguments
were in a request.
*) Bugfix: nginx could not be built on MacOS X.
Diffstat (limited to 'src/http/ngx_http_upstream.c')
-rw-r--r-- | src/http/ngx_http_upstream.c | 707 |
1 files changed, 617 insertions, 90 deletions
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 3dab5c39d..f766d7d05 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -6,14 +6,17 @@ #include <ngx_config.h> #include <ngx_core.h> -#include <ngx_http.h> #include <ngx_event_connect.h> +#include <ngx_http.h> -static void ngx_http_upstream_check_broken_connection(ngx_event_t *ev); +static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r); +static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r); +static void ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, + ngx_event_t *ev); static void ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u); -static void ngx_http_upstream_reinit(ngx_http_request_t *r, +static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u); static void ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u); @@ -21,6 +24,7 @@ static void ngx_http_upstream_send_request_handler(ngx_event_t *wev); static void ngx_http_upstream_process_header(ngx_event_t *rev); static void ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u); +static void ngx_http_upstream_process_downstream(ngx_http_request_t *r); static void ngx_http_upstream_process_body(ngx_event_t *ev); static void ngx_http_upstream_dummy_handler(ngx_event_t *wev); static void ngx_http_upstream_next(ngx_http_request_t *r, @@ -28,19 +32,125 @@ static void ngx_http_upstream_next(ngx_http_request_t *r, static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t rc); +static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t + ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_copy_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t + ngx_http_upstream_conditional_copy_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t + ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +#if (NGX_HTTP_GZIP) +static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); +#endif + static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r, uintptr_t data); static u_char *ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); +static u_char *ngx_http_upstream_log_error(ngx_http_request_t *r, u_char *buf, + size_t len); static ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf); +static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf); +static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf); + + +ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = { + + { ngx_string("Status"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, status), + /* STUB */ ngx_http_upstream_ignore_header_line, 0 }, + + { ngx_string("Content-Type"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, content_type), + ngx_http_upstream_copy_content_type, 0 }, + + { ngx_string("Content-Length"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, content_length), + ngx_http_upstream_copy_content_length, 0 }, + + { ngx_string("Date"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, date), + ngx_http_upstream_conditional_copy_header_line, + offsetof(ngx_http_upstream_conf_t, pass_date) }, + + { ngx_string("Server"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, server), + ngx_http_upstream_conditional_copy_header_line, + offsetof(ngx_http_upstream_conf_t, pass_server) }, + + { ngx_string("Location"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_rewrite_location, 0 }, + + { ngx_string("Refresh"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_rewrite_refresh, 0 }, + + { ngx_string("Cache-Control"), + ngx_http_upstream_process_multi_header_lines, + offsetof(ngx_http_upstream_headers_in_t, cache_control), + ngx_http_upstream_copy_multi_header_lines, + offsetof(ngx_http_headers_out_t, cache_control) }, + + { ngx_string("Connection"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_ignore_header_line, 0 }, + + { ngx_string("X-Pad"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_ignore_header_line, 0 }, + + { ngx_string("X-Powered-By"), + ngx_http_upstream_ignore_header_line, 0, + ngx_http_upstream_conditional_copy_header_line, + offsetof(ngx_http_upstream_conf_t, pass_x_powered_by) }, + + { ngx_string("X-Accel-Expires"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, x_accel_expires), + ngx_http_upstream_conditional_copy_header_line, + offsetof(ngx_http_upstream_conf_t, pass_x_accel_expires) }, + +#if (NGX_HTTP_GZIP) + { ngx_string("Content-Encoding"), + ngx_http_upstream_process_header_line, + offsetof(ngx_http_upstream_headers_in_t, content_encoding), + ngx_http_upstream_copy_content_encoding, 0 }, +#endif + + { ngx_null_string, NULL, 0, NULL, 0 } +}; ngx_http_module_t ngx_http_upstream_module_ctx = { - ngx_http_upstream_add_log_formats, /* pre conf */ - - NULL, /* create main configuration */ - NULL, /* init main configuration */ + ngx_http_upstream_add_log_formats, /* preconfiguration */ + NULL, /* postconfiguration */ + + ngx_http_upstream_create_main_conf, /* create main configuration */ + ngx_http_core_init_main_conf, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ @@ -51,7 +161,7 @@ ngx_http_module_t ngx_http_upstream_module_ctx = { ngx_module_t ngx_http_upstream_module = { - NGX_MODULE, + NGX_MODULE_V1, &ngx_http_upstream_module_ctx, /* module context */ NULL, /* module directives */ NGX_HTTP_MODULE, /* module type */ @@ -77,8 +187,9 @@ char *ngx_http_upstream_header_errors[] = { void ngx_http_upstream_init(ngx_http_request_t *r) { - ngx_connection_t *c; - ngx_http_upstream_t *u; + ngx_connection_t *c; + ngx_http_upstream_t *u; + ngx_http_core_loc_conf_t *clcf; c = r->connection; @@ -89,11 +200,11 @@ ngx_http_upstream_init(ngx_http_request_t *r) ngx_del_timer(c->read); } - c->read->event_handler = ngx_http_upstream_check_broken_connection; + r->read_event_handler = ngx_http_upstream_rd_check_broken_connection; if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { - c->write->event_handler = ngx_http_upstream_check_broken_connection; + r->write_event_handler = ngx_http_upstream_wr_check_broken_connection; if (!c->write->active) { if (ngx_add_event(c->write, NGX_WRITE_EVENT, @@ -107,7 +218,14 @@ ngx_http_upstream_init(ngx_http_request_t *r) u = r->upstream; - u->method = r->method; + u->request_bufs = r->request_body->bufs; + + if (u->conf->method == NGX_CONF_UNSET_UINT) { + u->method = r->method; + + } else { + u->method = u->conf->method; + } if (u->create_request(r) == NGX_ERROR) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -115,14 +233,15 @@ ngx_http_upstream_init(ngx_http_request_t *r) } u->peer.log = r->connection->log; - u->saved_log_ctx = r->connection->log->data; - u->saved_log_handler = r->connection->log->handler; - r->connection->log->data = u->log_ctx; - r->connection->log->handler = u->log_handler; + u->saved_log_handler = r->log_handler; + r->log_handler = ngx_http_upstream_log_error; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); u->output.sendfile = r->connection->sendfile; u->output.pool = r->pool; u->output.bufs.num = 1; + u->output.bufs.size = clcf->client_body_buffer_size; u->output.output_filter = ngx_chain_writer; u->output.filter_ctx = &u->writer; @@ -148,20 +267,33 @@ ngx_http_upstream_init(ngx_http_request_t *r) static void -ngx_http_upstream_check_broken_connection(ngx_event_t *ev) +ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r) +{ + ngx_http_upstream_check_broken_connection(r, r->connection->read); +} + + +static void +ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r) +{ + ngx_http_upstream_check_broken_connection(r, r->connection->write); +} + + +static void +ngx_http_upstream_check_broken_connection(ngx_http_request_t *r, + ngx_event_t *ev) { int n; char buf[1]; ngx_err_t err; ngx_connection_t *c; - ngx_http_request_t *r; ngx_http_upstream_t *u; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, "http upstream check client, write event:%d", ev->write); - c = ev->data; - r = c->data; + c = r->connection; u = r->upstream; if (u->peer.connection == NULL) { @@ -296,8 +428,8 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) c = u->peer.connection; c->data = r; - c->write->event_handler = ngx_http_upstream_send_request_handler; - c->read->event_handler = ngx_http_upstream_process_header; + c->write->handler = ngx_http_upstream_send_request_handler; + c->read->handler = ngx_http_upstream_process_header; c->sendfile = r->connection->sendfile; @@ -312,11 +444,20 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) u->writer.limit = 0; if (u->request_sent) { - ngx_http_upstream_reinit(r, u); + if (ngx_http_upstream_reinit(r, u) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } } - if (r->request_body->buf) { - if (r->request_body->temp_file) { + if (r->request_body) { + if (r->request_body->temp_file && r->main == NULL) { + + /* + * the r->request_body->buf can be reused for one request only, + * the subrequests should allocate their own temporay bufs + */ u->output.free = ngx_alloc_chain_link(r->pool); if (u->output.free == NULL) { @@ -332,9 +473,6 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) r->request_body->buf->pos = r->request_body->buf->start; r->request_body->buf->last = r->request_body->buf->start; r->request_body->buf->tag = u->output.tag; - - } else { - r->request_body->buf->pos = r->request_body->buf->start; } } @@ -351,29 +489,51 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) } -static void +static ngx_int_t ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u) { ngx_chain_t *cl; - if (u->reinit_request(r) == NGX_ERROR) { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + if (u->reinit_request(r) != NGX_OK) { + return NGX_ERROR; + } + + ngx_memzero(&r->upstream->headers_in, + sizeof(ngx_http_upstream_headers_in_t)); + + if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 8, + sizeof(ngx_table_elt_t)) != NGX_OK) + { + return NGX_ERROR; } /* reinit the request chain */ - for (cl = r->request_body->bufs; cl; cl = cl->next) { + for (cl = u->request_bufs; cl; cl = cl->next) { cl->buf->pos = cl->buf->start; cl->buf->file_pos = 0; } - /* reinit the ngx_output_chain() context */ + /* reinit the subrequest's ngx_output_chain() context */ + + if (r->request_body) { + if (r->request_body->temp_file && r->main && u->output.buf) { + + u->output.free = ngx_alloc_chain_link(r->pool); + if (u->output.free == NULL) { + return NGX_ERROR; + } + + u->output.free->buf = u->output.buf; + u->output.free->next = NULL; + + u->output.buf->pos = u->output.buf->start; + u->output.buf->last = u->output.buf->start; + } + } u->output.buf = NULL; u->output.in = NULL; - u->output.free = NULL; u->output.busy = NULL; /* reinit u->header_in buffer */ @@ -388,20 +548,22 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u) u->header_in.last = u->header_in.start; } #else + u->header_in.pos = u->header_in.start; u->header_in.last = u->header_in.start; + #endif /* add one more state */ u->state = ngx_array_push(&u->states); if (u->state == NULL) { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; + return NGX_ERROR; } ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); + + return NGX_OK; } @@ -433,8 +595,7 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) c->log->action = "sending request to upstream"; - rc = ngx_output_chain(&u->output, - u->request_sent ? NULL : r->request_body->bufs); + rc = ngx_output_chain(&u->output, u->request_sent ? NULL : u->request_bufs); u->request_sent = 1; @@ -494,9 +655,9 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u) } #endif - c->write->event_handler = ngx_http_upstream_dummy_handler; + c->write->handler = ngx_http_upstream_dummy_handler; - if (ngx_handle_level_write_event(c->write) == NGX_ERROR) { + if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -575,6 +736,14 @@ ngx_http_upstream_process_header(ngx_event_t *rev) u->header_in.tag = u->output.tag; + if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 8, + sizeof(ngx_table_elt_t)) == NGX_ERROR) + { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + #if 0 if (u->cache) { u->header_in.pos += u->cache->ctx.header_size; @@ -631,7 +800,7 @@ ngx_http_upstream_process_header(ngx_event_t *rev) ngx_add_timer(rev, u->read_timeout); #endif - if (u->header_in.last == u->header_in.end) { + if (u->header_in.pos == u->header_in.end) { ngx_log_error(NGX_LOG_ERR, rev->log, 0, "upstream sent too big header"); @@ -661,6 +830,38 @@ ngx_http_upstream_process_header(ngx_event_t *rev) /* rc == NGX_OK */ + if (r->headers_out.status == NGX_HTTP_INTERNAL_SERVER_ERROR) { + + if (u->peer.tries > 1 + && (u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_HTTP_500)) + { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_500); + return; + } + +#if (NGX_HTTP_CACHE) + + if (u->peer.tries == 0 + && u->stale + && (u->conf->use_stale & NGX_HTTP_UPSTREAM_FT_HTTP_500)) + { + ngx_http_upstream_finalize_request(r, u, + ngx_http_send_cached_response(r)); + return; + } + +#endif + } + + if (r->headers_out.status == NGX_HTTP_NOT_FOUND + && u->peer.tries > 1 + && u->conf->next_upstream & NGX_HTTP_UPSTREAM_FT_HTTP_404) + { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_404); + return; + } + + if (r->headers_out.status >= NGX_HTTP_BAD_REQUEST && u->conf->redirect_errors && r->err_ctx == NULL) @@ -687,11 +888,55 @@ ngx_http_upstream_process_header(ngx_event_t *rev) static void ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ngx_int_t rc; - ngx_event_pipe_t *p; - ngx_http_core_loc_conf_t *clcf; + ngx_int_t rc; + ngx_uint_t i, key; + ngx_list_part_t *part; + ngx_table_elt_t *h; + ngx_event_pipe_t *p; + ngx_http_core_loc_conf_t *clcf; + ngx_http_upstream_header_t *hh; + ngx_http_upstream_main_conf_t *umcf; + + umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + hh = (ngx_http_upstream_header_t *) umcf->headers_in_hash.buckets; + + part = &r->upstream->headers_in.headers.part; + h = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + h = part->elts; + i = 0; + } + + key = h[i].hash % umcf->headers_in_hash.hash_size; + + if (hh[key].name.len == h[i].key.len + && ngx_strcasecmp(hh[key].name.data, h[i].key.data) == 0) + { + if (hh[key].copy_handler(r, &h[i], hh[key].conf) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } - rc = u->send_header(r); + continue; + } + + if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + + rc = ngx_http_send_header(r); if (rc == NGX_ERROR || rc > NGX_OK) { ngx_http_upstream_finalize_request(r, u, rc); @@ -820,20 +1065,27 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) p->send_timeout = clcf->send_timeout; p->send_lowat = clcf->send_lowat; - u->peer.connection->read->event_handler = ngx_http_upstream_process_body; - r->connection->write->event_handler = ngx_http_upstream_process_body; + u->peer.connection->read->handler = ngx_http_upstream_process_body; + r->write_event_handler = ngx_http_upstream_process_downstream; ngx_http_upstream_process_body(u->peer.connection->read); } static void +ngx_http_upstream_process_downstream(ngx_http_request_t *r) +{ + ngx_http_upstream_process_body(r->connection->write); +} + + +static void ngx_http_upstream_process_body(ngx_event_t *ev) { + ngx_event_pipe_t *p; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_upstream_t *u; - ngx_event_pipe_t *p; c = ev->data; r = c->data; @@ -1046,11 +1298,6 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, rc = 0; } - if (u->saved_log_ctx) { - r->connection->log->data = u->saved_log_ctx; - r->connection->log->handler = u->saved_log_handler; - } - if (u->pipe.temp_file) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http upstream temp fd: %d", @@ -1065,15 +1312,7 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, } #endif - if (u->pipe.temp_file) { - r->file.fd = u->pipe.temp_file->file.fd; - -#if 0 - } else if (u->cache) { - r->file.fd = u->cache->ctx.file.fd; -#endif - } - + r->log_handler = u->saved_log_handler; r->connection->log->action = "sending to client"; if (rc == 0 && r->main == NULL) { @@ -1084,6 +1323,260 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t **ph; + + ph = (ngx_table_elt_t **) ((char *) &r->upstream->headers_in + offset); + + if (*ph == NULL) { + *ph = h; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_process_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_array_t *pa; + ngx_table_elt_t **ph; + + pa = (ngx_array_t *) ((char *) &r->upstream->headers_in + offset); + + if (pa->elts == NULL) { + if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) + { + return NGX_ERROR; + } + } + + ph = ngx_array_push(pa); + if (ph == NULL) { + return NGX_ERROR; + } + + *ph = h; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_ignore_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_copy_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_conditional_copy_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_flag_t *f; + ngx_table_elt_t *ho; + + f = (ngx_flag_t *) ((char *) r->upstream->conf + offset); + + if (*f == 0) { + return NGX_OK; + } + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_copy_multi_header_lines(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_array_t *pa; + ngx_table_elt_t *ho, **ph; + + pa = (ngx_array_t *) ((char *) &r->headers_out + offset); + + if (pa->elts == NULL) { + if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) + { + return NGX_ERROR; + } + } + + ph = ngx_array_push(pa); + if (ph == NULL) { + return NGX_ERROR; + } + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + *ph = ho; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + r->headers_out.content_type = h->value; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_copy_content_length(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + r->headers_out.content_length = ho; + r->headers_out.content_length_n = ngx_atoof(h->value.data, h->value.len); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_int_t rc; + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + if (r->upstream->rewrite_redirect) { + rc = r->upstream->rewrite_redirect(r, ho, 0); + + if (rc == NGX_OK) { + r->headers_out.location = ho; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "rewritten location: \"%V\"", &ho->value); + } + + return rc; + } + + /* + * we do not set r->headers_out.location here to avoid the handling + * the local redirects without a host name by ngx_http_header_filter() + */ + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + u_char *p; + ngx_int_t rc; + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + if (r->upstream->rewrite_redirect) { + + p = (u_char *) ngx_strstr(ho->value.data, "url="); + + if (p) { + rc = r->upstream->rewrite_redirect(r, ho, p + 4 - ho->value.data); + + } else { + return NGX_OK; + } + +#if (NGX_DEBUG) + if (rc == NGX_OK) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "rewritten refresh: \"%V\"", &ho->value); + } +#endif + + return rc; + } + + return NGX_OK; +} + + +#if (NGX_HTTP_GZIP) + +static ngx_int_t +ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset) +{ + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + r->headers_out.content_encoding = ho; + + return NGX_OK; +} + +#endif + + static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r, uintptr_t data) { @@ -1131,51 +1624,45 @@ ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf, } -u_char * -ngx_http_upstream_log_error(ngx_log_t *log, u_char *buf, size_t len) +static u_char * +ngx_http_upstream_log_error(ngx_http_request_t *r, u_char *buf, size_t len) { u_char *p; uintptr_t escape; - ngx_http_log_ctx_t *ctx; - ngx_http_request_t *r; ngx_http_upstream_t *u; ngx_peer_connection_t *peer; - ctx = log->data; - r = ctx->request; u = r->upstream; peer = &u->peer; p = ngx_snprintf(buf, len, - " while %s, client: %V, server: %V, URL: \"%V\"," + ", server: %V, URL: \"%V\"," " upstream: %V%V%s%V", - log->action, - &r->connection->addr_text, &r->server_name, &r->unparsed_uri, - &u->schema0, + &u->conf->schema, &peer->peers->peer[peer->cur_peer].name, peer->peers->peer[peer->cur_peer].uri_separator, - &u->uri0); + &u->conf->uri); len -= p - buf; buf = p; if (r->quoted_uri) { - escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location0->len, - r->uri.len - u->location0->len, + escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->conf->location->len, + r->uri.len - u->conf->location->len, NGX_ESCAPE_URI); } else { escape = 0; } if (escape) { - if (len >= r->uri.len - u->location0->len + escape) { + if (len >= r->uri.len - u->conf->location->len + escape) { - ngx_escape_uri(buf, r->uri.data + u->location0->len, - r->uri.len - u->location0->len, NGX_ESCAPE_URI); + ngx_escape_uri(buf, r->uri.data + u->conf->location->len, + r->uri.len - u->conf->location->len, NGX_ESCAPE_URI); - buf += r->uri.len - u->location0->len + escape; - len -= r->uri.len - u->location0->len + escape; + buf += r->uri.len - u->conf->location->len + escape; + len -= r->uri.len - u->conf->location->len + escape; if (r->args.len) { p = ngx_snprintf(buf, len, "?%V", &r->args); @@ -1186,19 +1673,19 @@ ngx_http_upstream_log_error(ngx_log_t *log, u_char *buf, size_t len) return ngx_http_log_error_info(r, buf, len); } - p = ngx_palloc(r->pool, r->uri.len - u->location0->len + escape); + p = ngx_palloc(r->pool, r->uri.len - u->conf->location->len + escape); if (p == NULL) { return buf; } - ngx_escape_uri(p, r->uri.data + u->location0->len, - r->uri.len - u->location0->len, NGX_ESCAPE_URI); + ngx_escape_uri(p, r->uri.data + u->conf->location->len, + r->uri.len - u->conf->location->len, NGX_ESCAPE_URI); - p = ngx_cpymem(buf, p, r->uri.len - u->location0->len + escape); + p = ngx_cpymem(buf, p, r->uri.len - u->conf->location->len + escape); } else { - p = ngx_cpymem(buf, r->uri.data + u->location0->len, - r->uri.len - u->location0->len); + p = ngx_cpymem(buf, r->uri.data + u->conf->location->len, + r->uri.len - u->conf->location->len); } len -= p - buf; @@ -1232,3 +1719,43 @@ ngx_http_upstream_add_log_formats(ngx_conf_t *cf) return NGX_OK; } + + +static void * +ngx_http_upstream_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_upstream_main_conf_t *umcf; + + umcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_main_conf_t)); + if (umcf == NULL) { + return NULL; + } + + return umcf; +} + + +static char * +ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_http_upstream_main_conf_t *umcf = conf; + + umcf->headers_in_hash.max_size = 100; + umcf->headers_in_hash.bucket_limit = 1; + umcf->headers_in_hash.bucket_size = sizeof(ngx_http_upstream_header_t); + umcf->headers_in_hash.name = "upstream_headers_in"; + + if (ngx_hash_init(&umcf->headers_in_hash, cf->pool, + ngx_http_upstream_headers_in, 0) != NGX_OK) + { + return NGX_CONF_ERROR; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "http upstream headers_in hash size: %ui, " + "max buckets per entry: %ui", + umcf->headers_in_hash.hash_size, + umcf->headers_in_hash.min_buckets); + + return NGX_CONF_OK; +} |