diff options
| author | Igor Sysoev <igor@sysoev.ru> | 2005-01-18 13:03:58 +0000 |
|---|---|---|
| committer | Igor Sysoev <igor@sysoev.ru> | 2005-01-18 13:03:58 +0000 |
| commit | 02025fd6bdfa997f521c3b26a08aeba366308e84 (patch) | |
| tree | 44db6ebb4e310f97f4550b7d7d69932636764304 /src/http | |
| parent | 543d02a4427e1833f8f9bdb60e3ff5e9fe2eb21b (diff) | |
| download | nginx-release-0.1.14.tar.gz nginx-release-0.1.14.tar.bz2 | |
nginx-0.1.14-RELEASE importrelease-0.1.14
*) Feature: the autoconfiguration directives:
--http-client-body-temp-path=PATH, --http-proxy-temp-path=PATH, and
--http-fastcgi-temp-path=PATH
*) Change: the directory name for the temporary files with the client
request body is specified by directive client_body_temp_path, by
default it is <prefix>/client_body_temp.
*) Feature: the ngx_http_fastcgi_module and the directives:
fastcgi_pass, fastcgi_root, fastcgi_index, fastcgi_params,
fastcgi_connect_timeout, fastcgi_send_timeout, fastcgi_read_timeout,
fastcgi_send_lowat, fastcgi_header_buffer_size, fastcgi_buffers,
fastcgi_busy_buffers_size, fastcgi_temp_path,
fastcgi_max_temp_file_size, fastcgi_temp_file_write_size,
fastcgi_next_upstream, and fastcgi_x_powered_by.
*) Bugfix: the "[alert] zero size buf" error; the bug had appeared in
0.1.3.
*) Change: the URI must be specified after the host name in the
proxy_pass directive.
*) Change: the %3F symbol in the URI was considered as the argument
string start.
*) Feature: the unix domain sockets support in the
ngx_http_proxy_module.
*) Feature: the ssl_engine and ssl_ciphers directives.
Thanks to Sergey Skvortsov for SSL-accelerator.
Diffstat (limited to 'src/http')
25 files changed, 4422 insertions, 975 deletions
diff --git a/src/http/modules/ngx_http_access_handler.c b/src/http/modules/ngx_http_access_handler.c index 9e5c43c4d..01796897f 100644 --- a/src/http/modules/ngx_http_access_handler.c +++ b/src/http/modules/ngx_http_access_handler.c @@ -80,7 +80,7 @@ ngx_module_t ngx_http_access_module = { static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r) { ngx_uint_t i; - struct sockaddr_in *addr_in; + struct sockaddr_in *sin; ngx_http_access_rule_t *rule; ngx_http_access_loc_conf_t *alcf; @@ -92,16 +92,16 @@ static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r) /* AF_INET only */ - addr_in = (struct sockaddr_in *) r->connection->sockaddr; + sin = (struct sockaddr_in *) r->connection->sockaddr; rule = alcf->rules->elts; for (i = 0; i < alcf->rules->nelts; i++) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "%08XD %08XD %08XD", - addr_in->sin_addr.s_addr, rule[i].mask, rule[i].addr); + sin->sin_addr.s_addr, rule[i].mask, rule[i].addr); - if ((addr_in->sin_addr.s_addr & rule[i].mask) == rule[i].addr) { + if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) { if (rule[i].deny) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "access forbidden by rule"); diff --git a/src/http/modules/ngx_http_fastcgi_handler.c b/src/http/modules/ngx_http_fastcgi_handler.c new file mode 100644 index 000000000..f38646a9b --- /dev/null +++ b/src/http/modules/ngx_http_fastcgi_handler.c @@ -0,0 +1,1968 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> +#include <nginx.h> + + +typedef struct { + ngx_http_upstream_conf_t upstream; + + ngx_peers_t *peers; + + ngx_uint_t params; + + ngx_str_t root; + ngx_str_t index; + + ngx_str_t *location; +} ngx_http_fastcgi_loc_conf_t; + + +typedef struct { + ngx_list_t headers; + + ngx_table_elt_t *status; + + ngx_table_elt_t *content_type; + ngx_table_elt_t *content_length; + ngx_table_elt_t *x_powered_by; + +#if (NGX_HTTP_GZIP) + ngx_table_elt_t *content_encoding; +#endif +} ngx_http_fastcgi_headers_in_t; + + +typedef struct { + ngx_http_fastcgi_headers_in_t headers_in; +} ngx_http_fastcgi_upstream_t; + + +typedef enum { + ngx_http_fastcgi_st_version = 0, + ngx_http_fastcgi_st_type, + ngx_http_fastcgi_st_request_id_hi, + ngx_http_fastcgi_st_request_id_lo, + ngx_http_fastcgi_st_content_length_hi, + ngx_http_fastcgi_st_content_length_lo, + ngx_http_fastcgi_st_padding_length, + ngx_http_fastcgi_st_reserved, + ngx_http_fastcgi_st_data, + ngx_http_fastcgi_st_padding, +} ngx_http_fastcgi_state_e; + + +typedef struct { + ngx_http_fastcgi_state_e state; + u_char *pos; + u_char *last; + ngx_uint_t type; + size_t length; + size_t padding; + + ngx_http_fastcgi_upstream_t *upstream; +} ngx_http_fastcgi_ctx_t; + + +#define NGX_HTTP_FASTCGI_REMOTE_ADDR 0x0002 +#define NGX_HTTP_FASTCGI_REMOTE_USER 0x0004 +#define NGX_HTTP_FASTCGI_SERVER_NAME 0x0008 +#define NGX_HTTP_FASTCGI_SERVER_ADDR 0x0010 +#define NGX_HTTP_FASTCGI_SERVER_PORT 0x0020 +#define NGX_HTTP_FASTCGI_SCRIPT_NAME 0x0040 +#define NGX_HTTP_FASTCGI_AUTH_TYPE 0x0080 +#define NGX_HTTP_FASTCGI_SERVER_PROTOCOL 0x0100 +#define NGX_HTTP_FASTCGI_SERVER_SOFTWARE 0x0200 +#define NGX_HTTP_FASTCGI_GATEWAY_INTERFACE 0x0400 +#define NGX_HTTP_FASTCGI_REQUEST_URI 0x0800 +#define NGX_HTTP_FASTCGI_REDIRECT_STATUS 0x1000 + + +#define NGX_HTTP_FASTCGI_RESPONDER 1 + +#define NGX_HTTP_FASTCGI_BEGIN_REQUEST 1 +#define NGX_HTTP_FASTCGI_ABORT_REQUEST 2 +#define NGX_HTTP_FASTCGI_END_REQUEST 3 +#define NGX_HTTP_FASTCGI_PARAMS 4 +#define NGX_HTTP_FASTCGI_STDIN 5 +#define NGX_HTTP_FASTCGI_STDOUT 6 +#define NGX_HTTP_FASTCGI_STDERR 7 +#define NGX_HTTP_FASTCGI_DATA 8 + + +typedef struct { + u_char version; + u_char type; + u_char request_id_hi; + u_char request_id_lo; + u_char content_length_hi; + u_char content_length_lo; + u_char padding_length; + u_char reserved; +} ngx_http_fastcgi_header_t; + + +typedef struct { + u_char role_hi; + u_char role_lo; + u_char flags; + u_char reserved[5]; +} ngx_http_fastcgi_begin_request_t; + + +static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r); +static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r); +static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r); +static ngx_int_t ngx_http_fastcgi_send_header(ngx_http_request_t *r); +static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, + ngx_buf_t *buf); +static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r, + ngx_http_fastcgi_ctx_t *f); +static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r); +static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, + ngx_int_t rc); + +static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, + void *data); +static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + + +static ngx_str_t ngx_http_fastcgi_methods[] = { + ngx_string("GET"), + ngx_string("HEAD"), + ngx_string("POST") +}; + + +static ngx_http_header_t ngx_http_fastcgi_headers_in[] = { + { ngx_string("Status"), offsetof(ngx_http_fastcgi_headers_in_t, status) }, + + { ngx_string("Content-Type"), + offsetof(ngx_http_fastcgi_headers_in_t, content_type) }, + + { ngx_string("Content-Length"), + offsetof(ngx_http_fastcgi_headers_in_t, content_length) }, + + { ngx_string("X-Powered-By"), + offsetof(ngx_http_fastcgi_headers_in_t, x_powered_by) }, + +#if (NGX_HTTP_GZIP) + { ngx_string("Content-Encoding"), + offsetof(ngx_http_fastcgi_headers_in_t, content_encoding) }, +#endif + + { ngx_null_string, 0 } +}; + + +static ngx_conf_post_t ngx_http_fastcgi_lowat_post = + { ngx_http_fastcgi_lowat_check } ; + +static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = { + { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, + { ngx_string("timeout"), NGX_HTTP_UPSTREAM_FT_TIMEOUT }, + { ngx_string("invalid_header"), NGX_HTTP_UPSTREAM_FT_INVALID_HEADER }, + { ngx_string("http_500"), NGX_HTTP_UPSTREAM_FT_HTTP_500 }, + { ngx_string("http_404"), NGX_HTTP_UPSTREAM_FT_HTTP_404 }, + { ngx_null_string, 0 } +}; + + +static ngx_conf_bitmask_t ngx_http_fastcgi_params_masks[] = { + { ngx_string("remote_addr"), NGX_HTTP_FASTCGI_REMOTE_ADDR }, + { ngx_string("server_port"), NGX_HTTP_FASTCGI_SERVER_PORT }, + { ngx_string("server_addr"), NGX_HTTP_FASTCGI_SERVER_ADDR }, + { ngx_string("server_name"), NGX_HTTP_FASTCGI_SERVER_NAME }, + { ngx_string("script_name"), NGX_HTTP_FASTCGI_SCRIPT_NAME }, + + { ngx_string("server_protocol"), NGX_HTTP_FASTCGI_SERVER_PROTOCOL }, + { ngx_string("server_software"), NGX_HTTP_FASTCGI_SERVER_SOFTWARE }, + { ngx_string("gateway_interface"), NGX_HTTP_FASTCGI_GATEWAY_INTERFACE }, + + { ngx_string("redirect_status"), NGX_HTTP_FASTCGI_REDIRECT_STATUS }, + { ngx_string("request_uri"), NGX_HTTP_FASTCGI_REQUEST_URI }, + + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_fastcgi_commands[] = { + + { ngx_string("fastcgi_pass"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_fastcgi_pass, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("fastcgi_root"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, root), + NULL }, + + { ngx_string("fastcgi_index"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, index), + NULL }, + + { ngx_string("fastcgi_connect_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.connect_timeout), + NULL }, + + { ngx_string("fastcgi_send_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_timeout), + NULL }, + + { ngx_string("fastcgi_send_lowat"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.send_lowat), + &ngx_http_fastcgi_lowat_post }, + + { ngx_string("fastcgi_header_buffer_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.header_buffer_size), + NULL }, + + { ngx_string("fastcgi_x_powered_by"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.x_powered_by), + NULL }, + + { ngx_string("fastcgi_read_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.read_timeout), + NULL }, + + { ngx_string("fastcgi_buffers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, + ngx_conf_set_bufs_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.bufs), + NULL }, + + { ngx_string("fastcgi_busy_buffers_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.busy_buffers_size), + NULL }, + + { ngx_string("fastcgi_temp_path"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, + ngx_conf_set_path_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_path), + (void *) ngx_garbage_collector_temp_handler }, + + { ngx_string("fastcgi_max_temp_file_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_temp_file_size), + NULL }, + + { ngx_string("fastcgi_temp_file_write_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_file_write_size), + NULL }, + + { ngx_string("fastcgi_next_upstream"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.next_upstream), + &ngx_http_fastcgi_next_upstream_masks }, + + { ngx_string("fastcgi_params"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, params), + &ngx_http_fastcgi_params_masks }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_fastcgi_module_ctx = { + NULL, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_fastcgi_create_loc_conf, /* create location configuration */ + ngx_http_fastcgi_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_fastcgi_module = { + NGX_MODULE, + &ngx_http_fastcgi_module_ctx, /* module context */ + ngx_http_fastcgi_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static ngx_int_t ngx_http_fastcgi_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_upstream_t *u; + ngx_http_fastcgi_loc_conf_t *flcf; + + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + if (!(u = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_t)))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + u->peer.log = r->connection->log; + u->peer.log_error = NGX_ERROR_ERR; + u->peer.peers = flcf->peers; + u->peer.tries = flcf->peers->number; +#if (NGX_THREADS) + u->peer.lock = &r->connection->lock; +#endif + + u->output.tag = (ngx_buf_tag_t) &ngx_http_fastcgi_module; + + u->conf = &flcf->upstream; + + u->location = flcf->location; + + u->create_request = ngx_http_fastcgi_create_request; + u->reinit_request = ngx_http_fastcgi_reinit_request; + u->process_header = ngx_http_fastcgi_process_header; + u->send_header = ngx_http_fastcgi_send_header; + u->abort_request = ngx_http_fastcgi_abort_request; + u->finalize_request = ngx_http_fastcgi_finalize_request; + + u->pipe.input_filter = ngx_http_fastcgi_input_filter; + u->pipe.input_ctx = r; + + u->log_ctx = r->connection->log->data; + u->log_handler = ngx_http_upstream_log_error; + + u->schema.len = sizeof("fastcgi://") - 1; + u->schema.data = (u_char *) "fastcgi://"; + u->uri.len = sizeof("/") - 1; + u->uri.data = (u_char *) "/"; + + r->upstream = u; + + rc = ngx_http_read_client_request_body(r, ngx_http_upstream_init); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + return NGX_DONE; +} + + +static ngx_int_t ngx_http_fastcgi_create_request(ngx_http_request_t *r) +{ + u_char ch, *pos, addr_text[INET_ADDRSTRLEN]; + size_t size, len, index, padding, addr_len; + off_t file_pos; + ngx_buf_t *b; + socklen_t slen; + ngx_chain_t *cl, *body; + ngx_uint_t i, n, next; + ngx_list_part_t *part; + ngx_table_elt_t *header; + struct sockaddr_in sin; + ngx_http_fastcgi_header_t *h; + ngx_http_fastcgi_loc_conf_t *flcf; + ngx_http_fastcgi_begin_request_t *br; + + flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module); + + if ((flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) && r->in_addr == 0) { + + slen = sizeof(struct sockaddr_in); + if (getsockname(r->connection->fd, + (struct sockaddr *) &sin, &slen) == -1) + { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, + ngx_socket_errno, "getsockname() failed"); + return NGX_ERROR; + } + + r->in_addr = sin.sin_addr.s_addr; + } + + addr_len = ngx_inet_ntop(r->connection->listening->family, &r->in_addr, + addr_text, INET_ADDRSTRLEN); + if (addr_len == 0) { + return NGX_ERROR; + } + + + if (r->upstream->method) { + len = 1 + 1 + sizeof("REQUEST_METHOD") - 1 + + ngx_http_fastcgi_methods[r->upstream->method - 1].len; + + } else { + len = 1 + ((r->method_name.len - 1 > 127) ? 4 : 1) + + sizeof("REQUEST_METHOD") - 1 + + r->method_name.len - 1; + } + + + index = (r->uri.data[r->uri.len - 1] == '/') ? flcf->index.len : 0; + + len += 1 + ((flcf->root.len + r->uri.len + index > 127) ? 4 : 1) + + sizeof("PATH_TRANSLATED") - 1 + + flcf->root.len + r->uri.len + index; + + if (r->args.len) { + len += 1 + ((r->args.len > 127) ? 4 : 1) + sizeof("QUERY_STRING") - 1 + + r->args.len; + } + + if (r->headers_in.content_length_n > 0) { + len += 1 + ((r->headers_in.content_length->value.len > 127) ? 4 : 1) + + sizeof("CONTENT_LENGTH") - 1 + + r->headers_in.content_length->value.len; + } + + + if (r->headers_in.content_type) { + len += 1 + ((r->headers_in.content_type->value.len > 127) ? 4 : 1) + + sizeof("CONTENT_TYPE") - 1 + + r->headers_in.content_type->value.len; + } + + + if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) { + len += 1 + 1 + sizeof("REDIRECT_STATUS200") - 1; + } + + if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) { + len += 1 + ((r->uri.len > 127) ? 4 : 1) + + sizeof("REQUEST_URI") - 1 + r->uri.len; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) { + len += 1 + ((r->uri.len + index > 127) ? 4 : 1) + + sizeof("SCRIPT_NAME") - 1 + r->uri.len + index ; + } + + if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) { + len += 1 + 1 + sizeof("REMOTE_ADDR") - 1 + r->connection->addr_text.len; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) { + len += 1 + 1 + sizeof("SERVER_NAME") - 1 + r->server_name.len; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) { + len += 1 + 1 + sizeof("SERVER_PORT") - 1 + r->port_text->len - 1; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) { + len += 1 + 1 + sizeof("SERVER_ADDR") - 1 + addr_len; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL + && r->http_protocol.len) + { + len += 1 + ((r->http_protocol.len > 127) ? 4 : 1) + + sizeof("SERVER_PROTOCOL") - 1 + r->http_protocol.len; + } + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) { + len += 1 + 1 + sizeof("SERVER_SOFTWARE") - 1 + sizeof(NGINX_VER) - 1; + } + + if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) { + len += 1 + 1 + sizeof("GATEWAY_INTERFACE") - 1 + sizeof("CGI/1.1") - 1; + } + + + part = &r->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + len += ((header[i].key.len > 127) ? 4 : 1) + + ((header[i].value.len > 127) ? 4 : 1) + + 5 + header[i].key.len + header[i].value.len; + } + + + if (len > 65535) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "fastcgi: the request record is too big"); + return NGX_ERROR; + } + + + padding = 8 - len % 8; + padding = (padding == 8) ? 0 : padding; + + + size = sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t) + + + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ + + len + padding + + sizeof(ngx_http_fastcgi_header_t) /* NGX_HTTP_FASTCGI_PARAMS */ + + + sizeof(ngx_http_fastcgi_header_t); /* NGX_HTTP_FASTCGI_STDIN */ + + + if (!(b = ngx_create_temp_buf(r->pool, size))) { + return NGX_ERROR; + } + + if (!(cl = ngx_alloc_chain_link(r->pool))) { + return NGX_ERROR; + } + + cl->buf = b; + + h = (ngx_http_fastcgi_header_t *) b->pos; + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_BEGIN_REQUEST; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = sizeof(ngx_http_fastcgi_begin_request_t); + h->padding_length = 0; + h->reserved = 0; + + br = (ngx_http_fastcgi_begin_request_t *) + (b->pos + sizeof(ngx_http_fastcgi_header_t)); + br->role_hi = 0; + br->role_lo = NGX_HTTP_FASTCGI_RESPONDER; + br->flags = 0; /* NGX_HTTP_FASTCGI_KEEP_CONN */ + br->reserved[0] = 0; + br->reserved[1] = 0; + br->reserved[2] = 0; + br->reserved[3] = 0; + br->reserved[4] = 0; + + h = (ngx_http_fastcgi_header_t *) + (b->pos + sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t)); + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_PARAMS; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = (u_char) ((len >> 8) & 0xff); + h->content_length_lo = (u_char) (len & 0xff); + h->padding_length = (u_char) padding; + h->reserved = 0; + + b->last = b->pos + sizeof(ngx_http_fastcgi_header_t) + + sizeof(ngx_http_fastcgi_begin_request_t) + + sizeof(ngx_http_fastcgi_header_t); + + + *b->last++ = sizeof("PATH_TRANSLATED") - 1; + + len = flcf->root.len + r->uri.len + index; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "PATH_TRANSLATED", + sizeof("PATH_TRANSLATED") - 1); + b->last = ngx_cpymem(b->last, flcf->root.data, flcf->root.len); + b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); + + if (index) { + b->last = ngx_cpymem(b->last, flcf->index.data, index); + } + + + *b->last++ = sizeof("REQUEST_METHOD") - 1; + + if (r->upstream->method) { + *b->last++ = (u_char) + ngx_http_fastcgi_methods[r->upstream->method - 1].len; + + b->last = ngx_cpymem(b->last, "REQUEST_METHOD", + sizeof("REQUEST_METHOD") - 1); + + b->last = ngx_cpymem(b->last, + ngx_http_fastcgi_methods[r->upstream->method - 1].data, + ngx_http_fastcgi_methods[r->upstream->method - 1].len); + + } else { + len = r->method_name.len - 1; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "REQUEST_METHOD", + sizeof("REQUEST_METHOD") - 1); + b->last = ngx_cpymem(b->last, r->method_name.data, len); + } + + + if (r->args.len) { + *b->last++ = sizeof("QUERY_STRING") - 1; + + len = r->args.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "QUERY_STRING", + sizeof("QUERY_STRING") - 1); + b->last = ngx_cpymem(b->last, r->args.data, len); + } + + + if (r->headers_in.content_length_n > 0) { + *b->last++ = sizeof("CONTENT_LENGTH") - 1; + + len = r->headers_in.content_length->value.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "CONTENT_LENGTH", + sizeof("CONTENT_LENGTH") - 1); + b->last = ngx_cpymem(b->last, r->headers_in.content_length->value.data, + len); + } + + + if (r->headers_in.content_type) { + *b->last++ = sizeof("CONTENT_TYPE") - 1; + + len = r->headers_in.content_type->value.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "CONTENT_TYPE", + sizeof("CONTENT_TYPE") - 1); + b->last = ngx_cpymem(b->last, r->headers_in.content_type->value.data, + len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_REDIRECT_STATUS) { + *b->last++ = sizeof("REDIRECT_STATUS") - 1; + *b->last++ = sizeof("200") - 1; + b->last = ngx_cpymem(b->last, "REDIRECT_STATUS200", + sizeof("REDIRECT_STATUS200") - 1); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_REQUEST_URI) { + *b->last++ = sizeof("REQUEST_URI") - 1; + + len = r->uri.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "REQUEST_URI", sizeof("REQUEST_URI") - 1); + b->last = ngx_cpymem(b->last, r->uri.data, len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SCRIPT_NAME) { + *b->last++ = sizeof("SCRIPT_NAME") - 1; + + len = r->uri.len + index; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "SCRIPT_NAME", sizeof("SCRIPT_NAME") - 1); + b->last = ngx_cpymem(b->last, r->uri.data, r->uri.len); + + if (index) { + b->last = ngx_cpymem(b->last, flcf->index.data, index); + } + } + + + if (flcf->params & NGX_HTTP_FASTCGI_REMOTE_ADDR) { + *b->last++ = sizeof("REMOTE_ADDR") - 1; + *b->last++ = (u_char) (r->connection->addr_text.len); + b->last = ngx_cpymem(b->last, "REMOTE_ADDR", sizeof("REMOTE_ADDR") - 1); + b->last = ngx_cpymem(b->last, r->connection->addr_text.data, + r->connection->addr_text.len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_NAME) { + *b->last++ = sizeof("SERVER_NAME") - 1; + *b->last++ = (u_char) r->server_name.len; + b->last = ngx_cpymem(b->last, "SERVER_NAME", sizeof("SERVER_NAME") - 1); + b->last = ngx_cpymem(b->last, r->server_name.data, r->server_name.len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PORT) { + *b->last++ = sizeof("SERVER_PORT") - 1; + *b->last++ = (u_char) (r->port_text->len - 1); + b->last = ngx_cpymem(b->last, "SERVER_PORT", sizeof("SERVER_PORT") - 1); + b->last = ngx_cpymem(b->last, r->port_text->data + 1, + r->port_text->len - 1); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_ADDR) { + *b->last++ = sizeof("SERVER_ADDR") - 1; + *b->last++ = (u_char) addr_len; + b->last = ngx_cpymem(b->last, "SERVER_ADDR", sizeof("SERVER_ADDR") - 1); + b->last = ngx_cpymem(b->last, addr_text, addr_len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_PROTOCOL + && r->http_protocol.len) + { + *b->last++ = sizeof("SERVER_PROTOCOL") - 1; + + len = r->http_protocol.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "SERVER_PROTOCOL", + sizeof("SERVER_PROTOCOL") - 1); + b->last = ngx_cpymem(b->last, r->http_protocol.data, len); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_SERVER_SOFTWARE) { + *b->last++ = sizeof("SERVER_SOFTWARE") - 1; + *b->last++ = (u_char) (sizeof(NGINX_VER) - 1); + b->last = ngx_cpymem(b->last, "SERVER_SOFTWARE", + sizeof("SERVER_SOFTWARE") - 1); + b->last = ngx_cpymem(b->last, NGINX_VER, sizeof(NGINX_VER) - 1); + } + + + if (flcf->params & NGX_HTTP_FASTCGI_GATEWAY_INTERFACE) { + *b->last++ = sizeof("GATEWAY_INTERFACE") - 1; + *b->last++ = (u_char) (sizeof("CGI/1.1") - 1); + b->last = ngx_cpymem(b->last, "GATEWAY_INTERFACE", + sizeof("GATEWAY_INTERFACE") - 1); + b->last = ngx_cpymem(b->last, "CGI/1.1", sizeof("CGI/1.1") - 1); + } + + + part = &r->headers_in.headers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + len = 5 + header[i].key.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + len = header[i].value.len; + if (len > 127) { + *b->last++ = (u_char) (((len >> 24) & 0x7f) | 0x80); + *b->last++ = (u_char) ((len >> 16) & 0xff); + *b->last++ = (u_char) ((len >> 8) & 0xff); + *b->last++ = (u_char) (len & 0xff); + + } else { + *b->last++ = (u_char) len; + } + + b->last = ngx_cpymem(b->last, "HTTP_", sizeof("HTTP_") - 1); + + for (n = 0; n < header[i].key.len; n++) { + ch = header[i].key.data[n]; + + if (ch >= 'a' && ch <= 'z') { + ch &= ~0x20; + + } else if (ch == '-') { + ch = '_'; + } + + *b->last++ = ch; + } + + b->last = ngx_cpymem(b->last, header[i].value.data, + header[i].value.len); + } + + + if (padding) { + ngx_memzero(b->last, padding); + b->last += padding; + } + + + h = (ngx_http_fastcgi_header_t *) b->last; + b->last += sizeof(ngx_http_fastcgi_header_t); + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_PARAMS; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = 0; + h->padding_length = 0; + h->reserved = 0; + + h = (ngx_http_fastcgi_header_t *) b->last; + b->last += sizeof(ngx_http_fastcgi_header_t); + + body = r->request_body->bufs; + r->request_body->bufs = cl; + +#if (NGX_SUPPRESS_WARN) + file_pos = 0; + pos = NULL; +#endif + + while (body) { + + if (body->buf->in_file) { + file_pos = body->buf->file_pos; + + } else { + pos = body->buf->pos; + } + + next = 0; + + do { + if (!(b = ngx_alloc_buf(r->pool))) { + return NGX_ERROR; + } + + ngx_memcpy(b, body->buf, sizeof(ngx_buf_t)); + + if (body->buf->in_file) { + b->file_pos = file_pos; + file_pos += 32 * 1024; + + if (file_pos > body->buf->file_last) { + file_pos = body->buf->file_last; + next = 1; + } + + b->file_last = file_pos; + len = (ngx_uint_t) (file_pos - b->file_pos); + + } else { + b->pos = pos; + pos += 32 * 1024; + + if (pos > body->buf->last) { + pos = body->buf->last; + next = 1; + } + + b->last = pos; + len = (ngx_uint_t) (pos - b->pos); + } + + padding = 8 - len % 8; + padding = (padding == 8) ? 0 : padding; + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_STDIN; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = (u_char) ((len >> 8) & 0xff); + h->content_length_lo = (u_char) (len & 0xff); + h->padding_length = (u_char) padding; + h->reserved = 0; + + if (!(cl->next = ngx_alloc_chain_link(r->pool))) { + return NGX_ERROR; + } + + cl = cl->next; + cl->buf = b; + + b = ngx_create_temp_buf(r->pool, sizeof(ngx_http_fastcgi_header_t) + + padding); + if (b == NULL) { + return NGX_ERROR; + } + + if (padding) { + ngx_memzero(b->last, padding); + b->last += padding; + } + + h = (ngx_http_fastcgi_header_t *) b->last; + b->last += sizeof(ngx_http_fastcgi_header_t); + + if (!(cl->next = ngx_alloc_chain_link(r->pool))) { + return NGX_ERROR; + } + + cl = cl->next; + cl->buf = b; + + } while (!next); + + body = body->next; + } + + h->version = 1; + h->type = NGX_HTTP_FASTCGI_STDIN; + h->request_id_hi = 0; + h->request_id_lo = 1; + h->content_length_hi = 0; + h->content_length_lo = 0; + h->padding_length = 0; + h->reserved = 0; + + cl->next = NULL; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_fastcgi_reinit_request(ngx_http_request_t *r) +{ + ngx_http_fastcgi_ctx_t *f; + + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + if (f == NULL) { + return NGX_OK; + } + + f->state = ngx_http_fastcgi_st_version; + + ngx_memzero(&f->upstream->headers_in, + sizeof(ngx_http_fastcgi_headers_in_t)); + + if (f->upstream->headers_in.headers.part.elts) { + if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 5, + sizeof(ngx_table_elt_t)) == NGX_ERROR) + { + return NGX_ERROR; + } + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_fastcgi_process_header(ngx_http_request_t *r) +{ + u_char *start, *last; + ngx_str_t *status_line; + ngx_int_t rc, status; + ngx_uint_t i; + ngx_table_elt_t *h; + ngx_http_upstream_t *u; + ngx_http_fastcgi_ctx_t *f; + + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + if (f == NULL) { + if (!(f = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_ctx_t)))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_http_set_ctx(r, f, ngx_http_fastcgi_module); + + f->upstream = ngx_pcalloc(r->pool, sizeof(ngx_http_fastcgi_upstream_t)); + if (f->upstream == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (ngx_list_init(&f->upstream->headers_in.headers, r->pool, 5, + sizeof(ngx_table_elt_t)) == NGX_ERROR) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + } + + u = r->upstream; + + for ( ;; ) { + + if (f->state < ngx_http_fastcgi_st_data) { + + f->pos = u->header_in.pos; + f->last = u->header_in.last; + + rc = ngx_http_fastcgi_process_record(r, f); + + u->header_in.pos = f->pos; + u->header_in.last = f->last; + + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + + if (rc == NGX_ERROR) { + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (f->type != NGX_HTTP_FASTCGI_STDOUT) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unexpected FastCGI record: %d", + f->type); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (f->length == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream closed prematurely FastCGI stdout"); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + } + + if (f->state == ngx_http_fastcgi_st_padding) { + + if (u->header_in.pos + f->padding < u->header_in.last) { + f->state = ngx_http_fastcgi_st_version; + u->header_in.pos += f->padding; + + continue; + } + + if (u->header_in.pos + f->padding == u->header_in.last) { + f->state = ngx_http_fastcgi_st_version; + u->header_in.pos = u->header_in.last; + + return NGX_AGAIN; + } + + f->padding -= u->header_in.last - u->header_in.pos; + u->header_in.pos = u->header_in.last; + + return NGX_AGAIN; + } + + /* f->state == ngx_http_fastcgi_st_data */ + + start = u->header_in.pos; + + if (u->header_in.pos + f->length < u->header_in.last) { + + /* + * set u->header_in.last to the end of the FastCGI record data + * for ngx_http_parse_header_line() + */ + + last = u->header_in.last; + u->header_in.last = u->header_in.pos + f->length; + + } else { + last = NULL; + } + + for ( ;; ) { + + rc = ngx_http_parse_header_line(r, &u->header_in); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi parser: %d", rc); + + if (rc == NGX_AGAIN) { + break; + } + + if (rc == NGX_OK) { + + /* a header line has been parsed successfully */ + + if (!(h = ngx_list_push(&f->upstream->headers_in.headers))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + h->key.len = r->header_name_end - r->header_name_start; + h->value.len = r->header_end - r->header_start; + + h->key.data = ngx_palloc(r->pool, + h->key.len + 1 + h->value.len + 1); + if (h->key.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + h->value.data = h->key.data + h->key.len + 1; + + ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1); + ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1); + + for (i = 0; ngx_http_fastcgi_headers_in[i].name.len != 0; i++) { + if (ngx_http_fastcgi_headers_in[i].name.len != h->key.len) { + continue; + } + + if (ngx_strcasecmp(ngx_http_fastcgi_headers_in[i].name.data, + h->key.data) == 0) + { + *((ngx_table_elt_t **) + ((char *) &f->upstream->headers_in + + ngx_http_fastcgi_headers_in[i].offset)) = h; + break; + } + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi header: \"%V: %V\"", + &h->key, &h->value); + + continue; + } + + if (rc == NGX_HTTP_PARSE_HEADER_DONE) { + + /* a whole header has been parsed successfully */ + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi header done"); + + if (f->upstream->headers_in.status) { + status_line = &f->upstream->headers_in.status->value; + + status = ngx_atoi(status_line->data, 3); + + if (status == NGX_ERROR) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->headers_out.status = status; + r->headers_out.status_line = *status_line; + + } else { + r->headers_out.status = 200; + r->headers_out.status_line.len = sizeof("200 OK") - 1; + r->headers_out.status_line.data = (u_char *) "200 OK"; + } + + u->state->status = r->headers_out.status; +#if 0 + if (u->cachable) { + u->cachable = ngx_http_upstream_is_cachable(r); + } +#endif + + break; + } + + /* there was error while a header line parsing */ + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + ngx_http_upstream_header_errors[rc + - NGX_HTTP_PARSE_HEADER_ERROR]); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + + } + + if (last) { + u->header_in.last = last; + } + + f->length -= u->header_in.pos - start; + + if (rc == NGX_AGAIN) { + if (u->header_in.pos == u->header_in.last) { + return NGX_AGAIN; + } + + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "upstream split a header in FastCGI records"); + + return NGX_HTTP_UPSTREAM_INVALID_HEADER; + } + + if (f->length == 0) { + if (f->padding) { + f->state = ngx_http_fastcgi_st_padding; + } else { + f->state = ngx_http_fastcgi_st_version; + } + } + + return NGX_OK; + } +} + + +static ngx_int_t ngx_http_fastcgi_send_header(ngx_http_request_t *r) +{ + ngx_uint_t i; + ngx_list_part_t *part; + ngx_table_elt_t *ho, *h; + ngx_http_fastcgi_ctx_t *f; + ngx_http_fastcgi_headers_in_t *headers_in; + + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + headers_in = &f->upstream->headers_in; + part = &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; + } + + /* ignore some headers */ + + if (&h[i] == headers_in->status) { + continue; + } + + + if (&h[i] == headers_in->x_powered_by + && !r->upstream->conf->x_powered_by) + { + continue; + } + + + /* "Content-Type" is handled specially */ + + if (&h[i] == headers_in->content_type) { + r->headers_out.content_type = &h[i]; + r->headers_out.content_type->key.len = 0; + continue; + } + + + /* copy some header pointers and set up r->headers_out */ + + if (!(ho = ngx_list_push(&r->headers_out.headers))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + *ho = h[i]; + +#if (NGX_HTTP_GZIP) + if (&h[i] == headers_in->content_encoding) { + r->headers_out.content_encoding = ho; + continue; + } +#endif + + if (&h[i] == headers_in->content_length) { + r->headers_out.content_length = ho; + r->headers_out.content_length_n = ngx_atoi(ho->value.data, + ho->value.len); + continue; + } + } + + return ngx_http_send_header(r); +} + + +static ngx_int_t ngx_http_fastcgi_input_filter(ngx_event_pipe_t *p, + ngx_buf_t *buf) +{ + ngx_int_t rc; + ngx_buf_t *b; + ngx_str_t line; + ngx_chain_t *cl; + ngx_http_request_t *r; + ngx_http_fastcgi_ctx_t *f; + + if (buf->pos == buf->last) { + return NGX_OK; + } + + r = p->input_ctx; + f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module); + + b = NULL; + + f->pos = buf->pos; + f->last = buf->last; + + for ( ;; ) { + if (f->state < ngx_http_fastcgi_st_data) { + + rc = ngx_http_fastcgi_process_record(r, f); + + if (rc == NGX_AGAIN) { + break; + } + + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (f->type == NGX_HTTP_FASTCGI_STDOUT && f->length == 0) { + f->state = ngx_http_fastcgi_st_version; + p->upstream_done = 1; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, + "http fastcgi closed stdout"); + + continue; + } + + if (f->type == NGX_HTTP_FASTCGI_END_REQUEST) { + f->state = ngx_http_fastcgi_st_version; + p->upstream_done = 1; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, p->log, 0, + "http fastcgi sent end request"); + + break; + } + } + + + if (f->state == ngx_http_fastcgi_st_padding) { + + if (f->pos + f->padding < f->last) { + f->state = ngx_http_fastcgi_st_version; + f->pos += f->padding; + + continue; + } + + if (f->pos + f->padding == f->last) { + f->state = ngx_http_fastcgi_st_version; + + break; + } + + f->padding -= f->last - f->pos; + + break; + } + + + /* f->state == ngx_http_fastcgi_st_data */ + + if (f->type == NGX_HTTP_FASTCGI_STDERR) { + + if (f->length) { + line.data = f->pos; + + if (f->pos + f->length <= f->last) { + line.len = f->length; + f->pos += f->length; + + } else { + line.len = f->last - f->pos; + f->length -= f->last - f->pos; + f->pos = f->last; + } + + /* + * TODO: copy split stderr output into buffer, + * clean it up + */ + + ngx_log_error(NGX_LOG_ERR, p->log, 0, + "FastCGI stderr: %V", &line); + + if (f->pos == f->last) { + break; + } + } + + f->state = ngx_http_fastcgi_st_version; + + continue; + } + + + /* f->type == NGX_HTTP_FASTCGI_STDOUT */ + + if (p->free) { + b = p->free->buf; + p->free = p->free->next; + + } else { + if (!(b = ngx_alloc_buf(p->pool))) { + return NGX_ERROR; + } + } + + ngx_memzero(b, sizeof(ngx_buf_t)); + + b->pos = f->pos; + b->shadow = buf; + b->tag = p->tag; + b->temporary = 1; + b->recycled = 1; + buf->shadow = b; + + if (!(cl = ngx_alloc_chain_link(p->pool))) { + return NGX_ERROR; + } + + cl->buf = b; + cl->next = NULL; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); + + ngx_chain_add_link(p->in, p->last_in, cl); + + if (f->pos + f->length < f->last) { + + if (f->padding) { + f->state = ngx_http_fastcgi_st_padding; + } else { + f->state = ngx_http_fastcgi_st_version; + } + + f->pos += f->length; + b->last = f->pos; + + continue; + } + + if (f->pos + f->length == f->last) { + + if (f->padding) { + f->state = ngx_http_fastcgi_st_padding; + } else { + f->state = ngx_http_fastcgi_st_version; + } + + b->last = f->last; + + break; + } + + f->length -= f->last - f->pos; + + b->last = f->last; + + break; + + } + + if (b) { + b->last_shadow = 1; + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_fastcgi_process_record(ngx_http_request_t *r, + ngx_http_fastcgi_ctx_t *f) +{ + u_char ch, *p; + ngx_http_upstream_t *u; + ngx_http_fastcgi_state_e state; + + u = r->upstream; + + state = f->state; + + for (p = f->pos; p < f->last; p++) { + + ch = *p; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi record byte: %02Xd", ch); + + switch (state) { + + case ngx_http_fastcgi_st_version: + if (ch != 1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unsupported FastCGI " + "protocol version: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_type; + break; + + case ngx_http_fastcgi_st_type: + switch (ch) { + case NGX_HTTP_FASTCGI_STDOUT: + case NGX_HTTP_FASTCGI_STDERR: + case NGX_HTTP_FASTCGI_END_REQUEST: + f->type = (ngx_uint_t) ch; + break; + default: + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent invalid FastCGI " + "record type: %d", ch); + return NGX_ERROR; + + } + state = ngx_http_fastcgi_st_request_id_hi; + break; + + /* we support the single request per connection */ + + case ngx_http_fastcgi_st_request_id_hi: + if (ch != 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unexpected FastCGI " + "request id high byte: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_request_id_lo; + break; + + case ngx_http_fastcgi_st_request_id_lo: + if (ch != 1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent unexpected FastCGI " + "request id low byte: %d", ch); + return NGX_ERROR; + } + state = ngx_http_fastcgi_st_content_length_hi; + break; + + case ngx_http_fastcgi_st_content_length_hi: + f->length = ch << 8; + state = ngx_http_fastcgi_st_content_length_lo; + break; + + case ngx_http_fastcgi_st_content_length_lo: + f->length |= (size_t) ch; + state = ngx_http_fastcgi_st_padding_length; + break; + + case ngx_http_fastcgi_st_padding_length: + f->padding = (size_t) ch; + state = ngx_http_fastcgi_st_reserved; + break; + + case ngx_http_fastcgi_st_reserved: + state = ngx_http_fastcgi_st_data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http fastcgi record length: %z", f->length); + + f->pos = p + 1; + f->state = state; + + return NGX_OK; + + /* suppress warning */ + case ngx_http_fastcgi_st_data: + case ngx_http_fastcgi_st_padding: + break; + } + } + + f->pos = p + 1; + f->state = state; + + return NGX_AGAIN; +} + + +static void ngx_http_fastcgi_abort_request(ngx_http_request_t *r) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "abort http fastcgi request"); + + return; +} + + +static void ngx_http_fastcgi_finalize_request(ngx_http_request_t *r, + ngx_int_t rc) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "finalize http fastcgi request"); + + return; +} + + +static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_fastcgi_loc_conf_t *lcf = conf; + + ngx_str_t *value; + ngx_inet_upstream_t inet_upstream; + ngx_http_core_loc_conf_t *clcf; +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_unix_domain_upstream_t unix_upstream; +#endif + + value = cf->args->elts; + + if (ngx_strncasecmp(value[1].data, "unix:", 5) == 0) { + +#if (NGX_HAVE_UNIX_DOMAIN) + + ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); + + unix_upstream.name = value[1]; + unix_upstream.url = value[1]; + + + if (!(lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream))) { + return NGX_CONF_ERROR; + } + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the unix domain sockets are not supported " + "on this platform"); + return NGX_CONF_ERROR; + +#endif + + } else { + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + + inet_upstream.name = value[1]; + inet_upstream.url = value[1]; + + if (!(lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream))) { + return NGX_CONF_ERROR; + } + } + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + lcf->location = &clcf->name; + clcf->handler = ngx_http_fastcgi_handler; + + if (clcf->name.data[clcf->name.len - 1] == '/') { + clcf->auto_redirect = 1; + } + + return NGX_CONF_OK; +} + + +static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, + void *data) +{ +#if (NGX_FREEBSD) + ssize_t *np = data; + + if (*np >= ngx_freebsd_net_inet_tcp_sendspace) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_send_lowat\" must be less than %d " + "(sysctl net.inet.tcp.sendspace)", + ngx_freebsd_net_inet_tcp_sendspace); + + return NGX_CONF_ERROR; + } + +#elif !(NGX_HAVE_SO_SNDLOWAT) + ssize_t *np = data; + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"fastcgi_send_lowat\" is not supported, ignored"); + + *np = 0; + +#endif + + return NGX_CONF_OK; +} + + +static void *ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_fastcgi_loc_conf_t *conf; + + if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_fastcgi_loc_conf_t)))) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->upstream.bufs.num = 0; + * conf->upstream.path = NULL; + * conf->upstream.next_upstream = 0; + * conf->upstream.temp_path = NULL; + * conf->params = 0; + * conf->root.len = 0; + * conf->root.data = NULL; + * conf->index.len = 0; + * conf->index.data = NULL; + * conf->location = NULL; + */ + + conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.send_lowat = NGX_CONF_UNSET_SIZE; + + conf->upstream.header_buffer_size = NGX_CONF_UNSET_SIZE; + conf->upstream.read_timeout = NGX_CONF_UNSET_MSEC; + conf->upstream.busy_buffers_size = NGX_CONF_UNSET_SIZE; + + conf->upstream.max_temp_file_size = NGX_CONF_UNSET_SIZE; + conf->upstream.temp_file_write_size = NGX_CONF_UNSET_SIZE; + + conf->upstream.x_powered_by = NGX_CONF_UNSET; + + /* "fastcgi_cyclic_temp_file" is disabled */ + conf->upstream.cyclic_temp_file = 0; + + return conf; +} + + +static char *ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child) +{ + ngx_http_fastcgi_loc_conf_t *prev = parent; + ngx_http_fastcgi_loc_conf_t *conf = child; + + size_t size; + + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, + prev->upstream.connect_timeout, 60000); + ngx_conf_merge_msec_value(conf->upstream.send_timeout, + prev->upstream.send_timeout, 60000); + ngx_conf_merge_size_value(conf->upstream.send_lowat, + prev->upstream.send_lowat, 0); + + ngx_conf_merge_msec_value(conf->upstream.read_timeout, + prev->upstream.read_timeout, 60000); + + ngx_conf_merge_msec_value(conf->upstream.x_powered_by, + prev->upstream.x_powered_by, 1); + + + ngx_conf_merge_size_value(conf->upstream.header_buffer_size, + prev->upstream.header_buffer_size, + (size_t) ngx_pagesize); + + ngx_conf_merge_bufs_value(conf->upstream.bufs, prev->upstream.bufs, + 8, ngx_pagesize); + + if (conf->upstream.bufs.num < 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "there must be at least 2 \"fastcgi_buffers\""); + return NGX_CONF_ERROR; + } + + + size = conf->upstream.header_buffer_size; + if (size < conf->upstream.bufs.size) { + size = conf->upstream.bufs.size; + } + + + ngx_conf_merge_size_value(conf->upstream.busy_buffers_size, + prev->upstream.busy_buffers_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.busy_buffers_size == NGX_CONF_UNSET_SIZE) { + conf->upstream.busy_buffers_size = 2 * size; + + } else if (conf->upstream.busy_buffers_size < size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_busy_buffers_size\" must be equal or bigger than " + "maximum of the value of \"fastcgi_header_buffer_size\" and " + "one of the \"fastcgi_buffers\""); + + return NGX_CONF_ERROR; + + } else if (conf->upstream.busy_buffers_size + > (conf->upstream.bufs.num - 1) * conf->upstream.bufs.size) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_busy_buffers_size\" must be less than " + "the size of all \"fastcgi_buffers\" minus one buffer"); + + return NGX_CONF_ERROR; + } + + + ngx_conf_merge_size_value(conf->upstream.temp_file_write_size, + prev->upstream.temp_file_write_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.temp_file_write_size == NGX_CONF_UNSET_SIZE) { + conf->upstream.temp_file_write_size = 2 * size; + + } else if (conf->upstream.temp_file_write_size < size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_temp_file_write_size\" must be equal or bigger than " + "maximum of the value of \"fastcgi_header_buffer_size\" and " + "one of the \"fastcgi_buffers\""); + + return NGX_CONF_ERROR; + } + + + ngx_conf_merge_size_value(conf->upstream.max_temp_file_size, + prev->upstream.max_temp_file_size, + NGX_CONF_UNSET_SIZE); + + if (conf->upstream.max_temp_file_size == NGX_CONF_UNSET_SIZE) { + + conf->upstream.max_temp_file_size = 1024 * 1024 * 1024; + + } else if (conf->upstream.max_temp_file_size != 0 + && conf->upstream.max_temp_file_size < size) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_max_temp_file_size\" must be equal to zero to disable " + "the temporary files usage or must be equal or bigger than " + "maximum of the value of \"fastcgi_header_buffer_size\" and " + "one of the \"fastcgi_buffers\""); + + return NGX_CONF_ERROR; + } + + + ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, + prev->upstream.next_upstream, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_UPSTREAM_FT_ERROR + |NGX_HTTP_UPSTREAM_FT_TIMEOUT)); + + ngx_conf_merge_path_value(conf->upstream.temp_path, + prev->upstream.temp_path, + NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0, + ngx_garbage_collector_temp_handler, cf); + + + ngx_conf_merge_bitmask_value(conf->params, prev->params, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_FASTCGI_REMOTE_ADDR + |NGX_HTTP_FASTCGI_REMOTE_USER + |NGX_HTTP_FASTCGI_SERVER_NAME + |NGX_HTTP_FASTCGI_SERVER_PORT + |NGX_HTTP_FASTCGI_SCRIPT_NAME + |NGX_HTTP_FASTCGI_AUTH_TYPE + |NGX_HTTP_FASTCGI_REQUEST_URI + |NGX_HTTP_FASTCGI_REDIRECT_STATUS)); + + ngx_conf_merge_str_value(conf->root, prev->root, ""); + + if (conf->root.len && conf->root.data[conf->root.len - 1] == '/') { + conf->root.len--; + } + + ngx_conf_merge_str_value(conf->index, prev->index, ""); + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_gzip_filter.c b/src/http/modules/ngx_http_gzip_filter.c index b093d582f..0cd1d91df 100644 --- a/src/http/modules/ngx_http_gzip_filter.c +++ b/src/http/modules/ngx_http_gzip_filter.c @@ -80,12 +80,13 @@ static ngx_int_t ngx_http_gzip_proxied(ngx_http_request_t *r, static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size); static void ngx_http_gzip_filter_free(void *opaque, void *address); -static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx); +static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx); static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); + +static ngx_int_t ngx_http_gzip_add_log_formats(ngx_conf_t *cf); -static ngx_int_t ngx_http_gzip_pre_conf(ngx_conf_t *cf); static ngx_int_t ngx_http_gzip_filter_init(ngx_cycle_t *cycle); static void *ngx_http_gzip_create_conf(ngx_conf_t *cf); static char *ngx_http_gzip_merge_conf(ngx_conf_t *cf, @@ -205,7 +206,7 @@ static ngx_command_t ngx_http_gzip_filter_commands[] = { static ngx_http_module_t ngx_http_gzip_filter_module_ctx = { - ngx_http_gzip_pre_conf, /* pre conf */ + ngx_http_gzip_add_log_formats, /* pre conf */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -229,22 +230,23 @@ ngx_module_t ngx_http_gzip_filter_module = { static ngx_http_log_op_name_t ngx_http_gzip_log_fmt_ops[] = { - { ngx_string("gzip_ratio"), NGX_INT32_LEN + 3, ngx_http_gzip_log_ratio }, - { ngx_null_string, 0, NULL } + { ngx_string("gzip_ratio"), NGX_INT32_LEN + 3, + NULL, NULL, ngx_http_gzip_log_ratio }, + { ngx_null_string, 0, NULL, NULL, NULL } }; static u_char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; -#if (NGX_HAVE_LITTLE_ENDIAN) +#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) struct gztrailer { uint32_t crc32; uint32_t zlen; }; -#else /* NGX_HAVE_BIG_ENDIAN */ +#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */ struct gztrailer { u_char crc32[4]; @@ -497,11 +499,13 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, if (rc != Z_OK) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "deflateInit2() failed: %d", rc); - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } if (!(b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } b->memory = 1; @@ -509,7 +513,8 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, b->last = b->pos + 10; if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = b; cl->next = NULL; @@ -522,7 +527,8 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, */ if (ngx_http_next_body_filter(r, cl) == NGX_ERROR) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } ctx->last_out = &ctx->out; @@ -533,7 +539,8 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, if (in) { if (ngx_chain_add_copy(r->pool, &ctx->in, in) == NGX_ERROR) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } } @@ -607,7 +614,8 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, ctx->out_buf = ngx_create_temp_buf(r->pool, conf->bufs.size); if (ctx->out_buf == NULL) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } ctx->out_buf->tag = (ngx_buf_tag_t) @@ -634,7 +642,8 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, if (rc != Z_OK && rc != Z_STREAM_END) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "deflate() failed: %d, %d", ctx->flush, rc); - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } ngx_log_debug5(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -663,7 +672,8 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, /* zlib wants to output some more gzipped data */ if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = ctx->out_buf; cl->next = NULL; @@ -683,7 +693,8 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, ctx->flush = Z_NO_FLUSH; if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = ctx->out_buf; cl->next = NULL; @@ -703,13 +714,15 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, if (rc != Z_OK) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "deflateEnd() failed: %d", rc); - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } ngx_pfree(r->pool, ctx->preallocated); if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = ctx->out_buf; cl->next = NULL; @@ -723,13 +736,15 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, } else { if (!(b = ngx_create_temp_buf(r->pool, 8))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } b->last_buf = 1; if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = b; cl->next = NULL; @@ -739,19 +754,21 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, b->last += 8; } -#if (NGX_HAVE_LITTLE_ENDIAN) +#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) + trailer->crc32 = ctx->crc32; trailer->zlen = ctx->zin; + #else - trailer->crc32[0] = ctx->crc32 & 0xff; - trailer->crc32[1] = (ctx->crc32 >> 8) & 0xff; - trailer->crc32[2] = (ctx->crc32 >> 16) & 0xff; - trailer->crc32[3] = (ctx->crc32 >> 24) & 0xff; - - trailer->zlen[0] = ctx->zin & 0xff; - trailer->zlen[1] = (ctx->zin >> 8) & 0xff; - trailer->zlen[2] = (ctx->zin >> 16) & 0xff; - trailer->zlen[3] = (ctx->zin >> 24) & 0xff; + trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff); + trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff); + trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff); + trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff); + + trailer->zlen[0] = (u_char) (ctx->zin & 0xff); + trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff); + trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff); + trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff); #endif ctx->zstream.avail_in = 0; @@ -764,7 +781,8 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, if (conf->no_buffer && ctx->in == NULL) { if (!(cl = ngx_alloc_chain_link(r->pool))) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } cl->buf = ctx->out_buf; cl->next = NULL; @@ -791,7 +809,8 @@ static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, */ if (last == NGX_ERROR) { - return ngx_http_gzip_error(ctx); + ngx_http_gzip_error(ctx); + return NGX_ERROR; } ngx_chain_update_chains(&ctx->free, &ctx->busy, &ctx->out, @@ -858,7 +877,7 @@ static void ngx_http_gzip_filter_free(void *opaque, void *address) static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { ngx_uint_t zint, zfrac; ngx_http_gzip_ctx_t *ctx; @@ -889,7 +908,7 @@ static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, } -static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) +static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) { deflateEnd(&ctx->zstream); @@ -902,26 +921,24 @@ static int ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) ctx->done = 1; - return NGX_ERROR; + return; } -static ngx_int_t ngx_http_gzip_pre_conf(ngx_conf_t *cf) +static ngx_int_t ngx_http_gzip_add_log_formats(ngx_conf_t *cf) { ngx_http_log_op_name_t *op; for (op = ngx_http_gzip_log_fmt_ops; op->name.len; op++) { /* void */ } - op->op = NULL; - - op = ngx_http_log_fmt_ops; + op->run = NULL; - for (op = ngx_http_log_fmt_ops; op->op; op++) { + for (op = ngx_http_log_fmt_ops; op->run; op++) { if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->op; + op = (ngx_http_log_op_name_t *) op->run; } } - op->op = (ngx_http_log_op_pt) ngx_http_gzip_log_fmt_ops; + op->run = (ngx_http_log_op_run_pt) ngx_http_gzip_log_fmt_ops; return NGX_OK; } @@ -948,14 +965,11 @@ static void *ngx_http_gzip_create_conf(ngx_conf_t *cf) } /* - - set by ngx_pcalloc(): - - conf->bufs.num = 0; - conf->proxied = 0; - - conf->types = NULL; - + * set by ngx_pcalloc(): + * + * conf->bufs.num = 0; + * conf->proxied = 0; + * conf->types = NULL; */ conf->enable = NGX_CONF_UNSET; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index 35ab2c46c..9cb6e171d 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -8,11 +8,15 @@ #include <ngx_core.h> #include <ngx_http.h> +#include <openssl/engine.h> + #define NGX_DEFLAUT_CERTIFICATE "cert.pem" #define NGX_DEFLAUT_CERTIFICATE_KEY "cert.pem" +static void *ngx_http_ssl_create_main_conf(ngx_conf_t *cf); +static char *ngx_http_ssl_init_main_conf(ngx_conf_t *cf, void *conf); static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf); static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); @@ -20,6 +24,13 @@ static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, static ngx_command_t ngx_http_ssl_commands[] = { + { ngx_string("ssl_engine"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_MAIN_CONF_OFFSET, + offsetof(ngx_http_ssl_main_conf_t, engine), + NULL }, + { ngx_string("ssl"), NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -41,6 +52,13 @@ static ngx_command_t ngx_http_ssl_commands[] = { offsetof(ngx_http_ssl_srv_conf_t, certificate_key), NULL }, + { ngx_string("ssl_ciphers"), + NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, ciphers), + NULL }, + ngx_null_command }; @@ -48,8 +66,8 @@ static ngx_command_t ngx_http_ssl_commands[] = { static ngx_http_module_t ngx_http_ssl_module_ctx = { NULL, /* pre conf */ - NULL, /* create main configuration */ - NULL, /* init main configuration */ + ngx_http_ssl_create_main_conf, /* create main configuration */ + ngx_http_ssl_init_main_conf, /* init main configuration */ ngx_http_ssl_create_srv_conf, /* create server configuration */ ngx_http_ssl_merge_srv_conf, /* merge server configuration */ @@ -69,6 +87,56 @@ ngx_module_t ngx_http_ssl_module = { }; +static void *ngx_http_ssl_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_ssl_main_conf_t *mcf; + + if (!(mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_main_conf_t)))) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * mcf->engine.len = 0; + * mcf->engine.data = NULL; + */ + + return mcf; +} + + +static char *ngx_http_ssl_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_http_ssl_main_conf_t *mcf = conf; + + ENGINE *engine; + + if (mcf->engine.len == 0) { + return NGX_CONF_OK; + } + + engine = ENGINE_by_id((const char *) mcf->engine.data); + + if (engine == NULL) { + ngx_ssl_error(NGX_LOG_WARN, cf->log, 0, + "ENGINE_by_id(\"%V\") failed", &mcf->engine); + return NGX_CONF_ERROR; + } + + if (ENGINE_set_default(engine, ENGINE_METHOD_ALL) == 0) { + ngx_ssl_error(NGX_LOG_WARN, cf->log, 0, + "ENGINE_set_default(\"%V\", ENGINE_METHOD_ALL) failed", + &mcf->engine); + return NGX_CONF_ERROR; + } + + ENGINE_free(engine); + + return NGX_CONF_OK; +} + + static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) { ngx_http_ssl_srv_conf_t *scf; @@ -77,6 +145,17 @@ static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf) return NGX_CONF_ERROR; } + /* + * set by ngx_pcalloc(): + * + * scf->certificate.len = 0; + * scf->certificate.data = NULL; + * scf->certificate_key.len = 0; + * scf->certificate_key.data = NULL; + * scf->ciphers.len = 0; + * scf->ciphers.data = NULL; + */ + scf->enable = NGX_CONF_UNSET; return scf; @@ -101,6 +180,9 @@ static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, NGX_DEFLAUT_CERTIFICATE_KEY); + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, ""); + + /* TODO: configure methods */ conf->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); @@ -110,6 +192,16 @@ static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, return NGX_CONF_ERROR; } + if (conf->ciphers.len) { + if (SSL_CTX_set_cipher_list(conf->ssl_ctx, + (const char *) conf->ciphers.data) == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_set_cipher_list(\"%V\") failed", + &conf->ciphers); + } + } + if (SSL_CTX_use_certificate_file(conf->ssl_ctx, (char *) conf->certificate.data, SSL_FILETYPE_PEM) == 0) { diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h index eaca2a6c5..87166877f 100644 --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -14,10 +14,17 @@ typedef struct { + ngx_str_t engine; +} ngx_http_ssl_main_conf_t; + + +typedef struct { ngx_flag_t enable; ngx_str_t certificate; ngx_str_t certificate_key; + ngx_str_t ciphers; + ngx_ssl_ctx_t *ssl_ctx; } ngx_http_ssl_srv_conf_t; diff --git a/src/http/modules/ngx_http_userid_filter.c b/src/http/modules/ngx_http_userid_filter.c index 2385ceed2..aee161b53 100644 --- a/src/http/modules/ngx_http_userid_filter.c +++ b/src/http/modules/ngx_http_userid_filter.c @@ -44,13 +44,17 @@ static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); +static size_t ngx_http_userid_log_uid_got_getlen(ngx_http_request_t *r, + uintptr_t data); static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); +static size_t ngx_http_userid_log_uid_set_getlen(ngx_http_request_t *r, + uintptr_t data); static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); +static ngx_int_t ngx_http_userid_add_log_formats(ngx_conf_t *cf); static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle); -static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf); static void *ngx_http_userid_create_conf(ngx_conf_t *cf); static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -142,7 +146,7 @@ static ngx_command_t ngx_http_userid_commands[] = { ngx_http_module_t ngx_http_userid_filter_module_ctx = { - ngx_http_userid_pre_conf, /* pre conf */ + ngx_http_userid_add_log_formats, /* pre conf */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -166,9 +170,13 @@ ngx_module_t ngx_http_userid_filter_module = { static ngx_http_log_op_name_t ngx_http_userid_log_fmt_ops[] = { - { ngx_string("uid_got"), 0, ngx_http_userid_log_uid_got }, - { ngx_string("uid_set"), 0, ngx_http_userid_log_uid_set }, - { ngx_null_string, 0, NULL } + { ngx_string("uid_got"), 0, NULL, + ngx_http_userid_log_uid_got_getlen, + ngx_http_userid_log_uid_got }, + { ngx_string("uid_set"), 0, NULL, + ngx_http_userid_log_uid_set_getlen, + ngx_http_userid_log_uid_set }, + { ngx_null_string, 0, NULL, NULL, NULL } }; @@ -298,7 +306,7 @@ static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, u_char *cookie, *p; size_t len; socklen_t slen; - struct sockaddr_in addr_in; + struct sockaddr_in sin; ngx_str_t src, dst; ngx_table_elt_t *set_cookie, *p3p; @@ -321,14 +329,13 @@ static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, if (r->in_addr == 0) { slen = sizeof(struct sockaddr_in); if (getsockname(r->connection->fd, - (struct sockaddr *) &addr_in, &slen) == -1) + (struct sockaddr *) &sin, &slen) == -1) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, - ngx_socket_errno, - "getsockname() failed"); + ngx_socket_errno, "getsockname() failed"); } - r->in_addr = addr_in.sin_addr.s_addr; + r->in_addr = sin.sin_addr.s_addr; } ctx->uid_set[0] = htonl(r->in_addr); @@ -352,7 +359,7 @@ static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, len += sizeof(expires) - 1 + 2; } - if (conf->domain.len > 1) { + if (conf->domain.len) { len += conf->domain.len; } @@ -379,7 +386,7 @@ static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, p = ngx_http_cookie_time(p, ngx_time() + conf->expires); } - if (conf->domain.len > 1) { + if (conf->domain.len) { p = ngx_cpymem(p, conf->domain.data, conf->domain.len); } @@ -397,7 +404,7 @@ static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uid cookie: \"%V\"", &set_cookie->value); - if (conf->p3p.len == 1) { + if (conf->p3p.len == 0) { return NGX_OK; } @@ -413,8 +420,8 @@ static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, } -static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, - uintptr_t data) +static size_t ngx_http_userid_log_uid_got_getlen(ngx_http_request_t *r, + uintptr_t data) { ngx_http_userid_ctx_t *ctx; ngx_http_userid_conf_t *conf; @@ -422,20 +429,30 @@ static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); if (ctx == NULL || ctx->uid_got[3] == 0) { - if (buf == NULL) { - return (u_char *) 1; - } + return 1; + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); + + return conf->name.len + 1 + 32; +} + + +static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_http_userid_ctx_t *ctx; + ngx_http_userid_conf_t *conf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); + if (ctx == NULL || ctx->uid_got[3] == 0) { *buf = '-'; return buf + 1; } conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - if (buf == NULL) { - return (u_char *) (conf->name.len + 1 + 32); - } - buf = ngx_cpymem(buf, conf->name.data, conf->name.len); *buf++ = '='; @@ -446,8 +463,8 @@ static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, } -static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, - uintptr_t data) +static size_t ngx_http_userid_log_uid_set_getlen(ngx_http_request_t *r, + uintptr_t data) { ngx_http_userid_ctx_t *ctx; ngx_http_userid_conf_t *conf; @@ -455,20 +472,30 @@ static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); if (ctx == NULL || ctx->uid_set[3] == 0) { - if (buf == NULL) { - return (u_char *) 1; - } + return 1; + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); + + return conf->name.len + 1 + 32; +} + +static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_http_userid_ctx_t *ctx; + ngx_http_userid_conf_t *conf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); + + if (ctx == NULL || ctx->uid_set[3] == 0) { *buf = '-'; return buf + 1; } conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - if (buf == NULL) { - return (u_char *) (conf->name.len + 1 + 32); - } - buf = ngx_cpymem(buf, conf->name.data, conf->name.len); *buf++ = '='; @@ -479,31 +506,29 @@ static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, } -static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle) -{ - ngx_http_next_header_filter = ngx_http_top_header_filter; - ngx_http_top_header_filter = ngx_http_userid_filter; - - return NGX_OK; -} - - -static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf) +static ngx_int_t ngx_http_userid_add_log_formats(ngx_conf_t *cf) { ngx_http_log_op_name_t *op; for (op = ngx_http_userid_log_fmt_ops; op->name.len; op++) { /* void */ } - op->op = NULL; + op->run = NULL; - op = ngx_http_log_fmt_ops; - - for (op = ngx_http_log_fmt_ops; op->op; op++) { + for (op = ngx_http_log_fmt_ops; op->run; op++) { if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->op; + op = (ngx_http_log_op_name_t *) op->run; } } - op->op = (ngx_http_log_op_pt) ngx_http_userid_log_fmt_ops; + op->run = (ngx_http_log_op_run_pt) ngx_http_userid_log_fmt_ops; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_userid_filter; return NGX_OK; } @@ -517,18 +542,18 @@ static void *ngx_http_userid_create_conf(ngx_conf_t *cf) return NGX_CONF_ERROR; } - /* set by ngx_pcalloc(): - - conf->name.len = 0; - conf->name.date = NULL; - conf->domain.len = 0; - conf->domain.date = NULL; - conf->path.len = 0; - conf->path.date = NULL; - conf->p3p.len = 0; - conf->p3p.date = NULL; - - */ + /* + * set by ngx_pcalloc(): + * + * conf->name.len = 0; + * conf->name.date = NULL; + * conf->domain.len = 0; + * conf->domain.date = NULL; + * conf->path.len = 0; + * conf->path.date = NULL; + * conf->p3p.len = 0; + * conf->p3p.date = NULL; + */ conf->enable = NGX_CONF_UNSET; conf->service = NGX_CONF_UNSET; @@ -547,9 +572,9 @@ static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, ngx_conf_merge_value(conf->enable, prev->enable, NGX_HTTP_USERID_OFF); ngx_conf_merge_str_value(conf->name, prev->name, "uid"); - ngx_conf_merge_str_value(conf->domain, prev->domain, "."); + ngx_conf_merge_str_value(conf->domain, prev->domain, ""); ngx_conf_merge_str_value(conf->path, prev->path, "; path=/"); - ngx_conf_merge_str_value(conf->p3p, prev->p3p, "."); + ngx_conf_merge_str_value(conf->p3p, prev->p3p, ""); ngx_conf_merge_value(conf->service, prev->service, NGX_CONF_UNSET); ngx_conf_merge_sec_value(conf->expires, prev->expires, 0); @@ -565,8 +590,8 @@ char *ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data) u_char *p, *new; if (domain->len == 4 && ngx_strcmp(domain->data, "none") == 0) { - domain->len = 1; - domain->data = (u_char *) "."; + domain->len = 0; + domain->data = (u_char *) ""; return NGX_CONF_OK; } @@ -645,8 +670,8 @@ char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data) ngx_str_t *p3p = data; if (p3p->len == 4 && ngx_strcmp(p3p->data, "none") == 0) { - p3p->len = 1; - p3p->data = (u_char *) "."; + p3p->len = 0; + p3p->data = (u_char *) ""; } return NGX_CONF_OK; diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c index 62e348e0a..7a1c03ce3 100644 --- a/src/http/modules/proxy/ngx_http_proxy_handler.c +++ b/src/http/modules/proxy/ngx_http_proxy_handler.c @@ -13,14 +13,20 @@ static ngx_int_t ngx_http_proxy_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_proxy_cache_get(ngx_http_proxy_ctx_t *p); +static size_t ngx_http_proxy_log_proxy_state_getlen(ngx_http_request_t *r, + uintptr_t data); static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r, - u_char *buf, uintptr_t data); + u_char *buf, + ngx_http_log_op_t *op); + +#if 0 static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r, u_char *buf, uintptr_t data); static u_char *ngx_http_proxy_log_reason(ngx_http_request_t *r, u_char *buf, uintptr_t data); +#endif -static ngx_int_t ngx_http_proxy_pre_conf(ngx_conf_t *cf); +static ngx_int_t ngx_http_proxy_add_log_formats(ngx_conf_t *cf); static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); @@ -231,7 +237,6 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, default_expires), NULL }, - { ngx_string("proxy_next_upstream"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, ngx_conf_set_bitmask_slot, @@ -251,7 +256,7 @@ static ngx_command_t ngx_http_proxy_commands[] = { ngx_http_module_t ngx_http_proxy_module_ctx = { - ngx_http_proxy_pre_conf, /* pre conf */ + ngx_http_proxy_add_log_formats, /* pre conf */ NULL, /* create main configuration */ NULL, /* init main configuration */ @@ -270,16 +275,22 @@ ngx_module_t ngx_http_proxy_module = { ngx_http_proxy_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init module */ - NULL /* init child */ + NULL /* init process */ }; static ngx_http_log_op_name_t ngx_http_proxy_log_fmt_ops[] = { - { ngx_string("proxy"), 0, ngx_http_proxy_log_proxy_state }, + { ngx_string("proxy"), 0, NULL, + ngx_http_proxy_log_proxy_state_getlen, + ngx_http_proxy_log_proxy_state }, + +#if 0 { ngx_string("proxy_cache_state"), 0, ngx_http_proxy_log_cache_state }, { ngx_string("proxy_reason"), 0, ngx_http_proxy_log_reason }, - { ngx_null_string, 0, NULL } +#endif + + { ngx_null_string, 0, NULL, NULL, NULL } }; @@ -301,8 +312,12 @@ ngx_http_header_t ngx_http_proxy_headers_in[] = { offsetof(ngx_http_proxy_headers_in_t, content_type) }, { ngx_string("Content-Length"), offsetof(ngx_http_proxy_headers_in_t, content_length) }, + +#if (NGX_HTTP_GZIP) { ngx_string("Content-Encoding"), offsetof(ngx_http_proxy_headers_in_t, content_encoding) }, +#endif + { ngx_string("Last-Modified"), offsetof(ngx_http_proxy_headers_in_t, last_modified) }, { ngx_string("Location"), @@ -779,11 +794,12 @@ u_char *ngx_http_proxy_log_error(void *data, u_char *buf, size_t len) peer = &ctx->proxy->upstream->peer; p = ngx_snprintf(buf, len, - " while %s, client: %V, URL: %V, upstream: %V%V", + " while %s, client: %V, URL: %V, upstream: http://%V%s%V", ctx->proxy->action, &r->connection->addr_text, &r->unparsed_uri, - &peer->peers->peers[peer->cur_peer].addr_port_text, + &peer->peers->peer[peer->cur_peer].name, + ctx->proxy->lcf->upstream->uri_separator, &ctx->proxy->lcf->upstream->uri); len -= p - buf; buf = p; @@ -835,8 +851,24 @@ u_char *ngx_http_proxy_log_error(void *data, u_char *buf, size_t len) } +static size_t ngx_http_proxy_log_proxy_state_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + ngx_http_proxy_ctx_t *p; + + p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module); + + if (p == NULL) { + return 1; + } + + return p->states.nelts * /* STUB */ 100; +} + + static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r, - u_char *buf, uintptr_t data) + u_char *buf, + ngx_http_log_op_t *op) { ngx_uint_t i; ngx_http_proxy_ctx_t *p; @@ -845,21 +877,10 @@ static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r, p = ngx_http_get_module_err_ctx(r, ngx_http_proxy_module); if (p == NULL) { - if (buf == NULL) { - return (u_char *) 1; - } - *buf = '-'; return buf + 1; } - - if (buf == NULL) { - /* find the request line length */ - return (u_char *) (uintptr_t) (p->states.nelts * /* STUB */ 100); - } - - i = 0; state = p->states.elts; @@ -935,6 +956,8 @@ static u_char *ngx_http_proxy_log_proxy_state(ngx_http_request_t *r, } +#if 0 + static u_char *ngx_http_proxy_log_cache_state(ngx_http_request_t *r, u_char *buf, uintptr_t data) { @@ -1014,23 +1037,23 @@ static u_char *ngx_http_proxy_log_reason(ngx_http_request_t *r, u_char *buf, } } +#endif + -static ngx_int_t ngx_http_proxy_pre_conf(ngx_conf_t *cf) +static ngx_int_t ngx_http_proxy_add_log_formats(ngx_conf_t *cf) { ngx_http_log_op_name_t *op; for (op = ngx_http_proxy_log_fmt_ops; op->name.len; op++) { /* void */ } - op->op = NULL; - - op = ngx_http_log_fmt_ops; + op->run = NULL; - for (op = ngx_http_log_fmt_ops; op->op; op++) { + for (op = ngx_http_log_fmt_ops; op->run; op++) { if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->op; + op = (ngx_http_log_op_name_t *) op->run; } } - op->op = (ngx_http_log_op_pt) ngx_http_proxy_log_fmt_ops; + op->run = (ngx_http_log_op_run_pt) ngx_http_proxy_log_fmt_ops; return NGX_OK; } @@ -1044,24 +1067,19 @@ static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) ngx_pcalloc(cf->pool, sizeof(ngx_http_proxy_loc_conf_t)), NGX_CONF_ERROR); - /* set by ngx_pcalloc(): - - conf->bufs.num = 0; - - conf->path = NULL; - - conf->next_upstream = 0; - conf->use_stale = 0; - - conf->upstreams = NULL; - conf->peers = NULL; - - conf->cache_path = NULL; - conf->temp_path = NULL; - - conf->busy_lock = NULL; - - */ + /* + * set by ngx_pcalloc(): + * + * conf->bufs.num = 0; + * conf->path = NULL; + * conf->next_upstream = 0; + * conf->use_stale = 0; + * conf->upstreams = NULL; + * conf->peers = NULL; + * conf->cache_path = NULL; + * conf->temp_path = NULL; + * conf->busy_lock = NULL; + */ conf->connect_timeout = NGX_CONF_UNSET_MSEC; conf->send_timeout = NGX_CONF_UNSET_MSEC; @@ -1210,11 +1228,15 @@ static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, ngx_conf_merge_bitmask_value(conf->use_stale, prev->use_stale, NGX_CONF_BITMASK_SET); +#if 0 ngx_conf_merge_path_value(conf->cache_path, prev->cache_path, - "cache", 1, 2, 0, cf->pool); + NGX_HTTP_PROXY_CACHE_PATH, 1, 2, 0, + ngx_garbage_collector_temp_handler, cf); +#endif ngx_conf_merge_path_value(conf->temp_path, prev->temp_path, - "temp", 1, 2, 0, cf->pool); + NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0, + ngx_garbage_collector_temp_handler, cf); ngx_conf_merge_value(conf->cache, prev->cache, 0); @@ -1256,24 +1278,23 @@ static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, } - static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_proxy_loc_conf_t *lcf = conf; - ngx_uint_t i, len; - char *err; - u_char *host; - in_addr_t addr; - ngx_str_t *value; - struct hostent *h; - ngx_http_core_loc_conf_t *clcf; - + ngx_str_t *value, *url; + ngx_inet_upstream_t inet_upstream; + ngx_http_core_loc_conf_t *clcf; +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_unix_domain_upstream_t unix_upstream; +#endif value = cf->args->elts; - if (ngx_strncasecmp(value[1].data, "http://", 7) != 0) { + url = &value[1]; + + if (ngx_strncasecmp(url->data, "http://", 7) != 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix"); return NGX_CONF_ERROR; } @@ -1284,121 +1305,52 @@ static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd, return NGX_CONF_ERROR; } - lcf->upstream->url.len = value[1].len; - if (!(lcf->upstream->url.data = ngx_palloc(cf->pool, value[1].len + 1))) { - return NGX_CONF_ERROR; - } - - ngx_cpystrn(lcf->upstream->url.data, value[1].data, value[1].len + 1); - - value[1].data += 7; - value[1].len -= 7; - - err = ngx_http_proxy_parse_upstream(&value[1], lcf->upstream); - - if (err) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, err); - return NGX_CONF_ERROR; - } - - if (!(host = ngx_palloc(cf->pool, lcf->upstream->host.len + 1))) { - return NGX_CONF_ERROR; - } - - ngx_cpystrn(host, lcf->upstream->host.data, lcf->upstream->host.len + 1); + if (ngx_strncasecmp(url->data + 7, "unix:", 5) == 0) { - /* AF_INET only */ +#if (NGX_HAVE_UNIX_DOMAIN) - addr = inet_addr((char *) host); + ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); - if (addr == INADDR_NONE) { - h = gethostbyname((char *) host); + unix_upstream.name = *url; + unix_upstream.url.len = url->len - 7; + unix_upstream.url.data = url->data + 7; + unix_upstream.uri_part = 1; - if (h == NULL || h->h_addr_list[0] == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "host %s not found", host); + if (!(lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream))) { return NGX_CONF_ERROR; } - for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } - - /* MP: ngx_shared_palloc() */ - - lcf->peers = ngx_pcalloc(cf->pool, - sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1)); - - if (lcf->peers == NULL) { - return NGX_CONF_ERROR; - } - - lcf->peers->number = i; - - /* STUB */ - lcf->peers->max_fails = 1; - lcf->peers->fail_timeout = 60; - - for (i = 0; h->h_addr_list[i] != NULL; i++) { - lcf->peers->peers[i].host.data = host; - lcf->peers->peers[i].host.len = lcf->upstream->host.len; - lcf->peers->peers[i].addr = *(in_addr_t *)(h->h_addr_list[i]); - lcf->peers->peers[i].port = lcf->upstream->port; + lcf->upstream->host_header.len = sizeof("localhost") - 1; + lcf->upstream->host_header.data = (u_char *) "localhost"; + lcf->upstream->uri = unix_upstream.uri; + lcf->upstream->uri_separator = ":"; + lcf->upstream->default_port = 1; - len = INET_ADDRSTRLEN - 1 + 1 + lcf->upstream->port_text.len; - - lcf->peers->peers[i].addr_port_text.data = - ngx_palloc(cf->pool, len); - if (lcf->peers->peers[i].addr_port_text.data == NULL) { - return NGX_CONF_ERROR; - } - - len = ngx_inet_ntop(AF_INET, - &lcf->peers->peers[i].addr, - lcf->peers->peers[i].addr_port_text.data, - len); - - lcf->peers->peers[i].addr_port_text.data[len++] = ':'; - - ngx_memcpy(lcf->peers->peers[i].addr_port_text.data + len, - lcf->upstream->port_text.data, - lcf->upstream->port_text.len); +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the unix domain sockets are not supported " + "on this platform"); + return NGX_CONF_ERROR; - lcf->peers->peers[i].addr_port_text.len = - len + lcf->upstream->port_text.len; - } +#endif } else { + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); - /* MP: ngx_shared_palloc() */ - - if (!(lcf->peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)))) { - return NGX_CONF_ERROR; - } - - lcf->peers->number = 1; - - lcf->peers->peers[0].host.data = host; - lcf->peers->peers[0].host.len = lcf->upstream->host.len; - lcf->peers->peers[0].addr = addr; - lcf->peers->peers[0].port = lcf->upstream->port; - - len = lcf->upstream->host.len + 1 + lcf->upstream->port_text.len; + inet_upstream.name = *url; + inet_upstream.url.len = url->len - 7; + inet_upstream.url.data = url->data + 7; + inet_upstream.default_port_value = 80; + inet_upstream.uri_part = 1; - lcf->peers->peers[0].addr_port_text.len = len; - - lcf->peers->peers[0].addr_port_text.data = ngx_palloc(cf->pool, len); - if (lcf->peers->peers[0].addr_port_text.data == NULL) { + if (!(lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream))) { return NGX_CONF_ERROR; } - len = lcf->upstream->host.len; - - ngx_memcpy(lcf->peers->peers[0].addr_port_text.data, - lcf->upstream->host.data, len); - - lcf->peers->peers[0].addr_port_text.data[len++] = ':'; - - ngx_memcpy(lcf->peers->peers[0].addr_port_text.data + len, - lcf->upstream->port_text.data, - lcf->upstream->port_text.len); + lcf->upstream->host_header = inet_upstream.host_header; + lcf->upstream->port_text = inet_upstream.port_text; + lcf->upstream->uri = inet_upstream.uri; + lcf->upstream->uri_separator = ""; } clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); @@ -1410,93 +1362,7 @@ static char *ngx_http_proxy_set_pass(ngx_conf_t *cf, ngx_command_t *cmd, clcf->auto_redirect = 1; } - return NULL; -} - - -static char *ngx_http_proxy_parse_upstream(ngx_str_t *url, - ngx_http_proxy_upstream_conf_t *u) -{ - size_t i; - - if (url->data[0] == ':' || url->data[0] == '/') { - return "invalid upstream URL"; - } - - u->host.data = url->data; - u->host_header.data = url->data; - - for (i = 1; i < url->len; i++) { - if (url->data[i] == ':') { - u->port_text.data = &url->data[i] + 1; - u->host.len = i; - } - - if (url->data[i] == '/') { - u->uri.data = &url->data[i]; - u->uri.len = url->len - i; - u->host_header.len = i; - - if (u->host.len == 0) { - u->host.len = i; - } - - if (u->port_text.data == NULL) { - u->default_port = 1; - u->port = htons(80); - u->port_text.len = 2; - u->port_text.data = (u_char *) "80"; - return NULL; - } - - u->port_text.len = &url->data[i] - u->port_text.data; - - if (u->port_text.len > 0) { - u->port = (in_port_t) ngx_atoi(u->port_text.data, - u->port_text.len); - if (u->port > 0) { - - if (u->port == 80) { - u->default_port = 1; - } - - u->port = htons(u->port); - return NULL; - } - } - - return "invalid port in upstream URL"; - } - } - - if (u->host.len == 0) { - u->host.len = i; - } - - u->host_header.len = i; - - u->uri.data = (u_char *) "/"; - u->uri.len = 1; - - if (u->port_text.data == NULL) { - u->default_port = 1; - u->port = htons(80); - u->port_text.len = 2; - u->port_text.data = (u_char *) "80"; - return NULL; - } - - u->port_text.len = &url->data[i] - u->port_text.data; - - if (u->port_text.len > 0) { - u->port = (in_port_t) ngx_atoi(u->port_text.data, u->port_text.len); - if (u->port > 0) { - u->port = htons(u->port); - return NULL; - } - } - - return "invalid port in upstream URL"; + return NGX_CONF_OK; } diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.h b/src/http/modules/proxy/ngx_http_proxy_handler.h index 8ab88ad54..915ca6219 100644 --- a/src/http/modules/proxy/ngx_http_proxy_handler.h +++ b/src/http/modules/proxy/ngx_http_proxy_handler.h @@ -47,6 +47,8 @@ typedef struct { ngx_str_t port_text; ngx_str_t *location; + char *uri_separator; + in_port_t port; unsigned default_port:1; @@ -131,7 +133,11 @@ typedef struct { ngx_table_elt_t *connection; ngx_table_elt_t *content_type; ngx_table_elt_t *content_length; + +#if (NGX_HTTP_GZIP) ngx_table_elt_t *content_encoding; +#endif + ngx_table_elt_t *last_modified; ngx_table_elt_t *location; ngx_table_elt_t *accept_ranges; diff --git a/src/http/modules/proxy/ngx_http_proxy_header.c b/src/http/modules/proxy/ngx_http_proxy_header.c index cd5deeb9e..78ae6530f 100644 --- a/src/http/modules/proxy/ngx_http_proxy_header.c +++ b/src/http/modules/proxy/ngx_http_proxy_header.c @@ -26,12 +26,7 @@ int ngx_http_proxy_copy_header(ngx_http_proxy_ctx_t *p, part = &headers_in->headers.part; h = part->elts; -#if 0 - h = headers_in->headers.elts; - for (i = 0; i < headers_in->headers.nelts; i++) { -#endif - - for (i = 0 ; /* void */; i++) { + for (i = 0; /* void */; i++) { if (i >= part->nelts) { if (part->next == NULL) { @@ -113,10 +108,12 @@ int ngx_http_proxy_copy_header(ngx_http_proxy_ctx_t *p, continue; } +#if (NGX_HTTP_GZIP) if (&h[i] == headers_in->content_encoding) { r->headers_out.content_encoding = ho; continue; } +#endif if (&h[i] == headers_in->last_modified) { r->headers_out.last_modified = ho; @@ -169,7 +166,8 @@ static int ngx_http_proxy_rewrite_location_header(ngx_http_proxy_ctx_t *p, return NGX_ERROR; } - if (uc->url.len > loc->value.len + if (p->lcf->preserve_host + || uc->url.len > loc->value.len || ngx_rstrncmp(loc->value.data, uc->url.data, uc->url.len) != 0) { diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c index 47d2b17df..4dfd4e6d1 100644 --- a/src/http/modules/proxy/ngx_http_proxy_upstream.c +++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c @@ -14,7 +14,7 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p); -static void ngx_http_proxy_init_upstream(void *data); +static void ngx_http_proxy_init_upstream(ngx_http_request_t *r); static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p); static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p); static void ngx_http_proxy_send_request(ngx_http_proxy_ctx_t *p); @@ -53,9 +53,7 @@ static char connection_close_header[] = "Connection: close" CRLF; int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p) { int rc; - ngx_temp_file_t *tf; ngx_http_request_t *r; - ngx_http_request_body_t *rb; ngx_http_proxy_upstream_t *u; r = p->request; @@ -75,36 +73,7 @@ int ngx_http_proxy_request_upstream(ngx_http_proxy_ctx_t *p) u->method = r->method; - if (!(rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - r->request_body = rb; - - if (r->headers_in.content_length_n <= 0) { - ngx_http_proxy_init_upstream(p); - return NGX_DONE; - } - - if (!(tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - - tf->file.fd = NGX_INVALID_FILE; - tf->file.log = r->connection->log; - tf->path = p->lcf->temp_path; - tf->pool = r->pool; - tf->warn = "a client request body is buffered to a temporary file"; - /* tf->persistent = 0; */ - - rb->handler = ngx_http_proxy_init_upstream; - rb->data = p; - /* rb->bufs = NULL; */ - /* rb->buf = NULL; */ - /* rb->rest = 0; */ - - rb->temp_file = tf; - - rc = ngx_http_read_client_request_body(r); + rc = ngx_http_read_client_request_body(r, ngx_http_proxy_init_upstream); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { return rc; @@ -428,17 +397,16 @@ static ngx_chain_t *ngx_http_proxy_create_request(ngx_http_proxy_ctx_t *p) } -static void ngx_http_proxy_init_upstream(void *data) +static void ngx_http_proxy_init_upstream(ngx_http_request_t *r) { - ngx_http_proxy_ctx_t *p = data; ngx_chain_t *cl; - ngx_http_request_t *r; + ngx_http_proxy_ctx_t *p; ngx_output_chain_ctx_t *output; ngx_chain_writer_ctx_t *writer; ngx_http_proxy_log_ctx_t *ctx; - r = p->request; + p = ngx_http_get_module_ctx(r, ngx_http_proxy_module); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http proxy init upstream, client timer: %d", @@ -502,7 +470,7 @@ static void ngx_http_proxy_init_upstream(void *data) output->pool = r->pool; output->bufs.num = 1; output->tag = (ngx_buf_tag_t) &ngx_http_proxy_module; - output->output_filter = (ngx_output_chain_filter_pt) ngx_chain_writer; + output->output_filter = ngx_chain_writer; if (!(writer = ngx_palloc(r->pool, sizeof(ngx_chain_writer_ctx_t)))) { ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -700,7 +668,7 @@ static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p) } p->state->peer = - &p->upstream->peer.peers->peers[p->upstream->peer.cur_peer].addr_port_text; + &p->upstream->peer.peers->peer[p->upstream->peer.cur_peer].name; if (rc == NGX_CONNECT_ERROR) { ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_ERROR); @@ -733,7 +701,7 @@ static void ngx_http_proxy_connect(ngx_http_proxy_ctx_t *p) } if (r->request_body->buf) { - if (r->request_body->temp_file->file.fd != NGX_INVALID_FILE) { + if (r->request_body->temp_file) { if (!(output->free = ngx_alloc_chain_link(r->pool))) { ngx_http_proxy_finalize_request(p, @@ -1347,6 +1315,7 @@ static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p) } ep->preread_bufs->buf = p->header_in; ep->preread_bufs->next = NULL; + p->header_in->recycled = 1; ep->preread_size = p->header_in->last - p->header_in->pos; diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h index 42550aa22..9425e3b36 100644 --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -13,6 +13,7 @@ #include <ngx_garbage_collector.h> typedef struct ngx_http_request_s ngx_http_request_t; +typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t; typedef struct ngx_http_cleanup_s ngx_http_cleanup_t; typedef struct ngx_http_in_addr_s ngx_http_in_addr_t; @@ -22,6 +23,7 @@ typedef struct ngx_http_in_addr_s ngx_http_in_addr_t; /* STUB */ #include <ngx_http_cache.h> +#include <ngx_http_upstream.h> #include <ngx_http_request.h> #include <ngx_http_config.h> #include <ngx_http_busy_lock.h> @@ -33,8 +35,8 @@ typedef struct ngx_http_in_addr_s ngx_http_in_addr_t; #endif -typedef struct { - u_int connection; +struct ngx_http_log_ctx_s { + ngx_uint_t connection; /* * we declare "action" as "char *" because the actions are usually @@ -45,18 +47,23 @@ typedef struct { char *action; ngx_str_t *client; ngx_http_request_t *request; -} ngx_http_log_ctx_t; +}; #define ngx_http_get_module_ctx(r, module) r->ctx[module.ctx_index] #define ngx_http_get_module_err_ctx(r, module) \ (r->err_ctx ? r->err_ctx[module.ctx_index] : r->ctx[module.ctx_index]) +/* STUB */ #define ngx_http_create_ctx(r, cx, module, size, error) \ do { \ ngx_test_null(cx, ngx_pcalloc(r->pool, size), error); \ r->ctx[module.ctx_index] = cx; \ } while (0) +/**/ + +#define ngx_http_set_ctx(r, c, module) \ + r->ctx[module.ctx_index] = c; #define ngx_http_delete_ctx(r, module) \ r->ctx[module.ctx_index] = NULL; @@ -80,7 +87,8 @@ void ngx_http_close_request(ngx_http_request_t *r, int error); void ngx_http_close_connection(ngx_connection_t *c); -ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r); +ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, + ngx_http_client_body_handler_pt post_handler); ngx_int_t ngx_http_send_header(ngx_http_request_t *r); ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, int error); diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 478bb0811..9429ea6db 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -205,6 +205,13 @@ static ngx_command_t ngx_http_core_commands[] = { offsetof(ngx_http_core_loc_conf_t, client_body_timeout), NULL }, + { ngx_string("client_body_temp_path"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, + ngx_conf_set_path_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, client_body_temp_path), + (void *) ngx_garbage_collector_temp_handler }, + { ngx_string("sendfile"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -1288,15 +1295,11 @@ static void *ngx_http_core_create_srv_conf(ngx_conf_t *cf) ngx_test_null(cscf, ngx_pcalloc(cf->pool, sizeof(ngx_http_core_srv_conf_t)), NGX_CONF_ERROR); - /* - - set by ngx_pcalloc(): - - conf->client_large_buffers.num = 0; - - */ - + * + * set by ngx_pcalloc(): + * conf->client_large_buffers.num = 0; + */ ngx_init_array(cscf->locations, cf->pool, 5, sizeof(void *), NGX_CONF_ERROR); @@ -1398,22 +1401,22 @@ static void *ngx_http_core_create_loc_conf(ngx_conf_t *cf) ngx_pcalloc(cf->pool, sizeof(ngx_http_core_loc_conf_t)), NGX_CONF_ERROR); - /* set by ngx_pcalloc(): - - lcf->root.len = 0; - lcf->root.data = NULL; - lcf->types = NULL; - lcf->default_type.len = 0; - lcf->default_type.data = NULL; - lcf->err_log = NULL; - lcf->error_pages = NULL; - - lcf->regex = NULL; - lcf->exact_match = 0; - lcf->auto_redirect = 0; - lcf->alias = 0; - - */ + /* + * set by ngx_pcalloc(): + * + * lcf->root.len = 0; + * lcf->root.data = NULL; + * lcf->types = NULL; + * lcf->default_type.len = 0; + * lcf->default_type.data = NULL; + * lcf->err_log = NULL; + * lcf->error_pages = NULL; + * lcf->client_body_path = NULL; + * lcf->regex = NULL; + * lcf->exact_match = 0; + * lcf->auto_redirect = 0; + * lcf->alias = 0; + */ lcf->client_max_body_size = NGX_CONF_UNSET_SIZE; lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE; @@ -1526,6 +1529,11 @@ static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf, ngx_conf_merge_msec_value(conf->lingering_timeout, prev->lingering_timeout, 5000); + ngx_conf_merge_path_value(conf->client_body_temp_path, + prev->client_body_temp_path, + NGX_HTTP_CLIENT_TEMP_PATH, 0, 0, 0, + ngx_garbage_collector_temp_handler, cf); + ngx_conf_merge_value(conf->reset_timedout_connection, prev->reset_timedout_connection, 0); ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1); @@ -1746,7 +1754,7 @@ static char *ngx_set_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) if (overwrite == NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%V\"", value[i]); + "invalid value \"%V\"", &value[i]); return NGX_CONF_ERROR; } diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 138067d50..eee43bcb0 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -199,6 +199,8 @@ struct ngx_http_core_loc_conf_s { ngx_array_t *error_pages; /* error_page */ + ngx_path_t *client_body_temp_path; /* client_body_temp_path */ + ngx_http_cache_hash_t *open_files; ngx_log_t *err_log; diff --git a/src/http/ngx_http_log_handler.c b/src/http/ngx_http_log_handler.c index 6702c4f77..142010739 100644 --- a/src/http/ngx_http_log_handler.c +++ b/src/http/ngx_http_log_handler.c @@ -11,40 +11,64 @@ static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, - uintptr_t data); -static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); + +static size_t ngx_http_log_request_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); + +static ngx_int_t ngx_http_log_header_in_compile(ngx_http_log_op_t *op, + ngx_str_t *value); +static size_t ngx_http_log_header_in_getlen(ngx_http_request_t *r, + uintptr_t data); static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); +static size_t ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, + u_char *buf, + ngx_http_log_op_t *op); + +static ngx_int_t ngx_http_log_header_out_compile(ngx_http_log_op_t *op, + ngx_str_t *value); +static size_t ngx_http_log_header_out_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); +static size_t ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, + uintptr_t data); +static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, + u_char *buf, + ngx_http_log_op_t *op); + static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, - u_char *buf, uintptr_t data); + u_char *buf, + ngx_http_log_op_t *op); static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, u_char *buf, - uintptr_t data); -static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, - u_char *buf, uintptr_t data); -static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, - uintptr_t data); -static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, u_char *buf, - uintptr_t data); + ngx_http_log_op_t *op); -static ngx_int_t ngx_http_log_pre_conf(ngx_conf_t *cf); +static ngx_table_elt_t *ngx_http_log_unknown_header(ngx_list_t *headers, + ngx_str_t *value); + +static ngx_int_t ngx_http_log_set_formats(ngx_conf_t *cf); static void *ngx_http_log_create_main_conf(ngx_conf_t *cf); static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, @@ -78,7 +102,7 @@ static ngx_command_t ngx_http_log_commands[] = { ngx_http_module_t ngx_http_log_module_ctx = { - ngx_http_log_pre_conf, /* pre conf */ + ngx_http_log_set_formats, /* pre conf */ ngx_http_log_create_main_conf, /* create main configuration */ NULL, /* init main configuration */ @@ -110,28 +134,38 @@ static ngx_str_t ngx_http_combined_fmt = ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = { - { ngx_string("addr"), INET_ADDRSTRLEN - 1, ngx_http_log_addr }, - { ngx_string("conn"), NGX_INT32_LEN, ngx_http_log_connection }, - { ngx_string("pipe"), 1, ngx_http_log_pipe }, + { ngx_string("addr"), INET_ADDRSTRLEN - 1, NULL, NULL, ngx_http_log_addr }, + { ngx_string("conn"), NGX_INT32_LEN, NULL, NULL, ngx_http_log_connection }, + { ngx_string("pipe"), 1, NULL, NULL, ngx_http_log_pipe }, { ngx_string("time"), sizeof("28/Sep/1970:12:00:00") - 1, - ngx_http_log_time }, - { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec }, - { ngx_string("request"), 0, ngx_http_log_request }, - { ngx_string("status"), 3, ngx_http_log_status }, - { ngx_string("length"), NGX_OFF_T_LEN, ngx_http_log_length }, - { ngx_string("apache_length"), NGX_OFF_T_LEN, ngx_http_log_apache_length }, + NULL, NULL, ngx_http_log_time }, + { ngx_string("msec"), NGX_TIME_T_LEN + 4, NULL, NULL, ngx_http_log_msec }, + { ngx_string("status"), 3, NULL, NULL, ngx_http_log_status }, + { ngx_string("length"), NGX_OFF_T_LEN, NULL, NULL, ngx_http_log_length }, + { ngx_string("apache_length"), NGX_OFF_T_LEN, + NULL, NULL, ngx_http_log_apache_length }, { ngx_string("request_length"), NGX_SIZE_T_LEN, - ngx_http_log_request_length }, - { ngx_string("i"), NGX_HTTP_LOG_ARG, ngx_http_log_header_in }, - { ngx_string("o"), NGX_HTTP_LOG_ARG, ngx_http_log_header_out }, - { ngx_null_string, 0, NULL } + NULL, NULL, ngx_http_log_request_length }, + + { ngx_string("request"), 0, NULL, + ngx_http_log_request_getlen, + ngx_http_log_request }, + + { ngx_string("i"), 0, ngx_http_log_header_in_compile, + ngx_http_log_header_in_getlen, + ngx_http_log_header_in }, + + { ngx_string("o"), 0, ngx_http_log_header_out_compile, + ngx_http_log_header_out_getlen, + ngx_http_log_header_out }, + + { ngx_null_string, 0, NULL, NULL, NULL } }; ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) { ngx_uint_t i, l; - uintptr_t data; u_char *line, *p; size_t len; ngx_http_log_t *log; @@ -157,7 +191,7 @@ ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) op = log[l].ops->elts; for (i = 0; i < log[l].ops->nelts; i++) { if (op[i].len == 0) { - len += (size_t) op[i].op(r, NULL, op[i].data); + len += op[i].getlen(r, op[i].data); } else { len += op[i].len; @@ -177,20 +211,7 @@ ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) p = line; for (i = 0; i < log[l].ops->nelts; i++) { - if (op[i].op == NGX_HTTP_LOG_COPY_SHORT) { - len = op[i].len; - data = op[i].data; - while (len--) { - *p++ = (char) (data & 0xff); - data >>= 8; - } - - } else if (op[i].op == NGX_HTTP_LOG_COPY_LONG) { - p = ngx_cpymem(p, (void *) op[i].data, op[i].len); - - } else { - p = op[i].op(r, p, op[i].data); - } + p = op[i].run(r, p, &op[i]); } #if (NGX_WIN32) @@ -206,8 +227,33 @@ ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) } +static u_char *ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + size_t len; + uintptr_t data; + + len = op->len; + data = op->data; + + while (len--) { + *buf++ = (u_char) (data & 0xff); + data >>= 8; + } + + return buf; +} + + +static u_char *ngx_http_log_copy_long(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + return ngx_cpymem(buf, (u_char *) op->data, op->len); +} + + static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_cpymem(buf, r->connection->addr_text.data, r->connection->addr_text.len); @@ -215,14 +261,14 @@ static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_sprintf(buf, "%ui", r->connection->number); } static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { if (r->pipeline) { *buf = 'p'; @@ -235,7 +281,7 @@ static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_cpymem(buf, ngx_cached_http_log_time.data, ngx_cached_http_log_time.len); @@ -243,7 +289,7 @@ static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { struct timeval tv; @@ -253,20 +299,22 @@ static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, } -static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, - uintptr_t data) +static size_t ngx_http_log_request_getlen(ngx_http_request_t *r, + uintptr_t data) { - if (buf == NULL) { - /* find the request line length */ - return (u_char *) r->request_line.len; - } + return r->request_line.len; +} + +static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ return ngx_cpymem(buf, r->request_line.data, r->request_line.len); } static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_sprintf(buf, "%ui", r->err_status ? r->err_status : r->headers_out.status); @@ -274,294 +322,304 @@ static u_char *ngx_http_log_status(ngx_http_request_t *r, u_char *buf, static u_char *ngx_http_log_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_sprintf(buf, "%O", r->connection->sent); } static u_char *ngx_http_log_apache_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_sprintf(buf, "%O", r->connection->sent - r->header_size); } static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, - uintptr_t data) + ngx_http_log_op_t *op) { return ngx_sprintf(buf, "%z", r->request_length); } -static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, - uintptr_t data) +static ngx_int_t ngx_http_log_header_in_compile(ngx_http_log_op_t *op, + ngx_str_t *value) { - ngx_uint_t i; - ngx_str_t *s; - ngx_table_elt_t *h; - ngx_http_log_op_t *op; - - if (r) { - h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); + ngx_uint_t i; - if (h == NULL) { - - /* no header */ + op->len = 0; - if (buf) { - *buf = '-'; - } + for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) { - return buf + 1; + if (ngx_http_headers_in[i].name.len != value->len) { + continue; } - if (buf == NULL) { - /* find the header length */ - return (u_char *) h->value.len; - } + if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, value->data, + value->len) == 0) + { + op->getlen = ngx_http_log_header_in_getlen; + op->run = ngx_http_log_header_in; + op->data = ngx_http_headers_in[i].offset; - return ngx_cpymem(buf, h->value.data, h->value.len); + return NGX_OK; + } } - /* find an offset while a format string compilation */ + op->getlen = ngx_http_log_unknown_header_in_getlen; + op->run = ngx_http_log_unknown_header_in; + op->data = (uintptr_t) value; - op = (ngx_http_log_op_t *) buf; - s = (ngx_str_t *) data; + return NGX_OK; +} - op->len = 0; - for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) { - if (ngx_http_headers_in[i].name.len != s->len) { - continue; - } +static size_t ngx_http_log_header_in_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + ngx_table_elt_t *h; - if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, s->data, s->len) - == 0) - { - op->op = ngx_http_log_header_in; - op->data = ngx_http_headers_in[i].offset; - return NULL; - } - } + h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); - op->op = ngx_http_log_unknown_header_in; - op->data = (uintptr_t) s; + if (h) { + return h->value.len; + } - return NULL; + return 1; } -static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, - u_char *buf, uintptr_t data) +static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) { - ngx_uint_t i; - ngx_str_t *s; - ngx_list_part_t *part; ngx_table_elt_t *h; - s = (ngx_str_t *) data; + h = *(ngx_table_elt_t **) ((char *) &r->headers_in + op->data); - part = &r->headers_in.headers.part; - h = part->elts; + if (h) { + return ngx_cpymem(buf, h->value.data, h->value.len); + } - for (i = 0; /* void */; i++) { + *buf = '-'; - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } + return buf + 1; +} - part = part->next; - h = part->elts; - i = 0; - } - if (h[i].key.len != s->len) { - continue; - } +static size_t ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + ngx_table_elt_t *h; - if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) { - if (buf == NULL) { - /* find the header length */ - return (u_char *) h[i].value.len; - } + h = ngx_http_log_unknown_header(&r->headers_in.headers, (ngx_str_t *) data); - return ngx_cpymem(buf, h[i].value.data, h[i].value.len); - } + if (h) { + return h->value.len; } - /* no header */ + return 1; +} + - if (buf) { - *buf = '-'; +static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, + u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_table_elt_t *h; + + h = ngx_http_log_unknown_header(&r->headers_in.headers, + (ngx_str_t *) op->data); + + if (h) { + return ngx_cpymem(buf, h->value.data, h->value.len); } + *buf = '-'; + return buf + 1; } -static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, - uintptr_t data) +static ngx_int_t ngx_http_log_header_out_compile(ngx_http_log_op_t *op, + ngx_str_t *value) { - ngx_uint_t i; - ngx_str_t *s; - ngx_table_elt_t *h; - ngx_http_log_op_t *op; + ngx_uint_t i; - if (r) { + op->len = 0; - /* run-time execution */ + for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) { - if (r->http_version < NGX_HTTP_VERSION_10) { - if (buf) { - *buf = '-'; - } + if (ngx_http_headers_out[i].name.len != value->len) { + continue; + } - return buf + 1; + if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, value->data, + value->len) == 0) + { + op->getlen = ngx_http_log_header_out_getlen; + op->run = ngx_http_log_header_out; + op->data = ngx_http_headers_out[i].offset; + + return NGX_OK; } + } - h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data); + if (value->len == sizeof("Connection") - 1 + && ngx_strncasecmp(value->data, "Connection", value->len) == 0) + { + op->len = sizeof("keep-alive") - 1; + op->getlen = NULL; + op->run = ngx_http_log_connection_header_out; + op->data = 0; + return NGX_OK; + } - if (h == NULL) { + if (value->len == sizeof("Transfer-Encoding") - 1 + && ngx_strncasecmp(value->data, "Transfer-Encoding", value->len) == 0) + { + op->len = sizeof("chunked") - 1; + op->getlen = NULL; + op->run = ngx_http_log_transfer_encoding_header_out; + op->data = 0; + return NGX_OK; + } - /* - * No header pointer was found. - * However, some headers: "Date", "Server", "Content-Length", - * and "Last-Modified" have a special handling in the header filter - * but we do not set up their pointers in the filter because - * they are too seldom needed to be logged. - */ + op->getlen = ngx_http_log_unknown_header_out_getlen; + op->run = ngx_http_log_unknown_header_out; + op->data = (uintptr_t) value; - if (data == offsetof(ngx_http_headers_out_t, date)) { - if (buf == NULL) { - return (u_char *) ngx_cached_http_time.len; - } - return ngx_cpymem(buf, ngx_cached_http_time.data, - ngx_cached_http_time.len); - } + return NGX_OK; +} - if (data == offsetof(ngx_http_headers_out_t, server)) { - if (buf == NULL) { - return (u_char *) (sizeof(NGINX_VER) - 1); - } - return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1); - } - if (data == offsetof(ngx_http_headers_out_t, content_length)) { - if (r->headers_out.content_length_n == -1) { - if (buf) { - *buf = '-'; - } - return buf + 1; - } +static size_t ngx_http_log_header_out_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + ngx_table_elt_t *h; - if (buf == NULL) { - return (u_char *) NGX_OFF_T_LEN; - } - return ngx_sprintf(buf, "%O", r->headers_out.content_length_n); - } + h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data); - if (data == offsetof(ngx_http_headers_out_t, last_modified)) { - if (r->headers_out.last_modified_time == -1) { - if (buf) { - *buf = '-'; - } - return buf + 1; - } + if (h) { + return h->value.len; + } - if (buf == NULL) { - return (u_char *) - sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; - } - return ngx_http_time(buf, r->headers_out.last_modified_time); - } + /* + * No header pointer was found. + * However, some headers: "Date", "Server", "Content-Length", + * and "Last-Modified" have a special handling in the header filter + * but we do not set up their pointers in the filter because + * they are too seldom needed to be logged. + */ - if (buf) { - *buf = '-'; - } + if (data == offsetof(ngx_http_headers_out_t, date)) { + return ngx_cached_http_time.len; + } - return buf + 1; + if (data == offsetof(ngx_http_headers_out_t, server)) { + return (sizeof(NGINX_VER) - 1); + } + + if (data == offsetof(ngx_http_headers_out_t, content_length)) { + if (r->headers_out.content_length_n == -1) { + return 1; } - if (buf == NULL) { - /* find the header length */ - return (u_char *) h->value.len; + return NGX_OFF_T_LEN; + } + + if (data == offsetof(ngx_http_headers_out_t, last_modified)) { + if (r->headers_out.last_modified_time == -1) { + return 1; } + return sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; + } + + return 1; +} + + +static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_table_elt_t *h; + + h = *(ngx_table_elt_t **) ((char *) &r->headers_out + op->data); + + if (h) { return ngx_cpymem(buf, h->value.data, h->value.len); } - /* find an offset while a format string compilation */ + /* + * No header pointer was found. + * However, some headers: "Date", "Server", "Content-Length", + * and "Last-Modified" have a special handling in the header filter + * but we do not set up their pointers in the filter because + * they are too seldom needed to be logged. + */ + + if (op->data == offsetof(ngx_http_headers_out_t, date)) { + return ngx_cpymem(buf, ngx_cached_http_time.data, + ngx_cached_http_time.len); + } - op = (ngx_http_log_op_t *) buf; - s = (ngx_str_t *) data; + if (op->data == offsetof(ngx_http_headers_out_t, server)) { + return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1); + } - op->len = 0; + if (op->data == offsetof(ngx_http_headers_out_t, content_length)) { + if (r->headers_out.content_length_n == -1) { + *buf = '-'; - for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) { - if (ngx_http_headers_out[i].name.len != s->len) { - continue; + return buf + 1; } - if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, s->data, s->len) - == 0) - { - op->op = ngx_http_log_header_out; - op->data = ngx_http_headers_out[i].offset; - return NULL; - } + return ngx_sprintf(buf, "%O", r->headers_out.content_length_n); } - if (s->len == sizeof("Connection") - 1 - && ngx_strncasecmp(s->data, "Connection", s->len) == 0) - { - op->op = ngx_http_log_connection_header_out; - op->data = (uintptr_t) NULL; - return NULL; - } + if (op->data == offsetof(ngx_http_headers_out_t, last_modified)) { + if (r->headers_out.last_modified_time == -1) { + *buf = '-'; - if (s->len == sizeof("Transfer-Encoding") - 1 - && ngx_strncasecmp(s->data, "Transfer-Encoding", s->len) == 0) { - op->op = ngx_http_log_transfer_encoding_header_out; - op->data = (uintptr_t) NULL; - return NULL; + return buf + 1; + } + + return ngx_http_time(buf, r->headers_out.last_modified_time); } - op->op = ngx_http_log_unknown_header_out; - op->data = (uintptr_t) s; + *buf = '-'; - return NULL; + return buf + 1; } -static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, - u_char *buf, uintptr_t data) +static size_t ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, + uintptr_t data) { - if (buf == NULL) { - return (u_char *) ((r->keepalive) ? sizeof("keep-alive") - 1: - sizeof("close") - 1); - } + ngx_table_elt_t *h; - if (r->keepalive) { - return ngx_cpymem(buf, "keep-alive", sizeof("keep-alive") - 1); + h = ngx_http_log_unknown_header(&r->headers_out.headers, + (ngx_str_t *) data); - } else { - return ngx_cpymem(buf, "close", sizeof("close") - 1); + if (h) { + return h->value.len; } + + return 1; } -static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, - u_char *buf, - uintptr_t data) +static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, + u_char *buf, + ngx_http_log_op_t *op) { - if (buf == NULL) { - return (u_char *) ((r->chunked) ? sizeof("chunked") - 1 : 1); - } + ngx_table_elt_t *h; - if (r->chunked) { - return ngx_cpymem(buf, "chunked", sizeof("chunked") - 1); + h = ngx_http_log_unknown_header(&r->headers_out.headers, + (ngx_str_t *) op->data); + + if (h) { + return ngx_cpymem(buf, h->value.data, h->value.len); } *buf = '-'; @@ -570,18 +628,14 @@ static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, } -static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, - u_char *buf, - uintptr_t data) +static ngx_table_elt_t *ngx_http_log_unknown_header(ngx_list_t *headers, + ngx_str_t *value) { ngx_uint_t i; - ngx_str_t *s; ngx_list_part_t *part; ngx_table_elt_t *h; - s = (ngx_str_t *) data; - - part = &r->headers_out.headers.part; + part = &headers->part; h = part->elts; for (i = 0; /* void */; i++) { @@ -596,36 +650,52 @@ static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, i = 0; } - if (h[i].key.len != s->len) { + if (h[i].key.len != value->len) { continue; } - if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) { - if (buf == NULL) { - /* find the header length */ - return (u_char *) h[i].value.len; - } - - return ngx_cpymem(buf, h[i].value.data, h[i].value.len); + if (ngx_strncasecmp(h[i].key.data, value->data, value->len) == 0) { + return &h[i]; } } - /* no header */ + return NULL; +} + - if (buf) { - *buf = '-'; +static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, + u_char *buf, + ngx_http_log_op_t *op) +{ + if (r->keepalive) { + return ngx_cpymem(buf, "keep-alive", sizeof("keep-alive") - 1); + + } else { + return ngx_cpymem(buf, "close", sizeof("close") - 1); } +} + + +static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, + u_char *buf, + ngx_http_log_op_t *op) +{ + if (r->chunked) { + return ngx_cpymem(buf, "chunked", sizeof("chunked") - 1); + } + + *buf = '-'; return buf + 1; } -static ngx_int_t ngx_http_log_pre_conf(ngx_conf_t *cf) +static ngx_int_t ngx_http_log_set_formats(ngx_conf_t *cf) { ngx_http_log_op_name_t *op; for (op = ngx_http_log_fmt_ops; op->name.len; op++) { /* void */ } - op->op = NULL; + op->run = NULL; return NGX_OK; } @@ -889,15 +959,15 @@ static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, break; } - for (name = ngx_http_log_fmt_ops; name->op; name++) { + for (name = ngx_http_log_fmt_ops; name->run; name++) { if (name->name.len == 0) { - name = (ngx_http_log_op_name_t *) name->op; + name = (ngx_http_log_op_name_t *) name->run; } if (name->name.len == fname_len && ngx_strncmp(name->name.data, fname, fname_len) == 0) { - if (name->len != NGX_HTTP_LOG_ARG) { + if (name->compile == NULL) { if (arg.len) { fname[fname_len] = '\0'; ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -907,7 +977,8 @@ static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, } op->len = name->len; - op->op = name->op; + op->getlen = name->getlen; + op->run = name->run; op->data = 0; break; @@ -926,7 +997,9 @@ static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, } *a = arg; - name->op(NULL, (u_char *) op, (uintptr_t) a); + if (name->compile(op, a) == NGX_ERROR) { + return NGX_CONF_ERROR; + } break; } @@ -949,9 +1022,10 @@ static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, if (len) { op->len = len; + op->getlen = NULL; if (len <= sizeof(uintptr_t)) { - op->op = NGX_HTTP_LOG_COPY_SHORT; + op->run = ngx_http_log_copy_short; op->data = 0; while (len--) { @@ -960,7 +1034,7 @@ static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd, } } else { - op->op = NGX_HTTP_LOG_COPY_LONG; + op->run = ngx_http_log_copy_long; if (!(p = ngx_palloc(cf->pool, len))) { return NGX_CONF_ERROR; diff --git a/src/http/ngx_http_log_handler.h b/src/http/ngx_http_log_handler.h index 8eb74ba1c..4472ed982 100644 --- a/src/http/ngx_http_log_handler.h +++ b/src/http/ngx_http_log_handler.h @@ -13,49 +13,54 @@ #include <ngx_http.h> -typedef u_char *(*ngx_http_log_op_pt) (ngx_http_request_t *r, u_char *buf, - uintptr_t data); +typedef struct ngx_http_log_op_s ngx_http_log_op_t; -#define NGX_HTTP_LOG_COPY_SHORT (ngx_http_log_op_pt) 0 -#define NGX_HTTP_LOG_COPY_LONG (ngx_http_log_op_pt) -1 +typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); -#define NGX_HTTP_LOG_ARG (u_int) -1 +typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r, + uintptr_t data); +typedef ngx_int_t (*ngx_http_log_op_compile_pt) (ngx_http_log_op_t *op, + ngx_str_t *value); -typedef struct { - size_t len; - ngx_http_log_op_pt op; - uintptr_t data; -} ngx_http_log_op_t; +struct ngx_http_log_op_s { + size_t len; + ngx_http_log_op_getlen_pt getlen; + ngx_http_log_op_run_pt run; + uintptr_t data; +}; typedef struct { - ngx_str_t name; - ngx_array_t *ops; /* array of ngx_http_log_op_t */ + ngx_str_t name; + ngx_array_t *ops; /* array of ngx_http_log_op_t */ } ngx_http_log_fmt_t; typedef struct { - ngx_str_t name; - size_t len; - ngx_http_log_op_pt op; + ngx_str_t name; + size_t len; + ngx_http_log_op_compile_pt compile; + ngx_http_log_op_getlen_pt getlen; + ngx_http_log_op_run_pt run; } ngx_http_log_op_name_t; typedef struct { - ngx_array_t formats; /* array of ngx_http_log_fmt_t */ + ngx_array_t formats; /* array of ngx_http_log_fmt_t */ } ngx_http_log_main_conf_t; typedef struct { - ngx_open_file_t *file; - ngx_array_t *ops; /* array of ngx_http_log_op_t */ + ngx_open_file_t *file; + ngx_array_t *ops; /* array of ngx_http_log_op_t */ } ngx_http_log_t; typedef struct { - ngx_array_t *logs; /* array of ngx_http_log_t */ - ngx_uint_t off; /* unsigned off:1 */ + ngx_array_t *logs; /* array of ngx_http_log_t */ + ngx_uint_t off; /* unsigned off:1 */ } ngx_http_log_loc_conf_t; diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index 77db813ae..b17c2008e 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -34,15 +34,13 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) sw_major_digit, sw_first_minor_digit, sw_minor_digit, - sw_almost_done, - sw_done + sw_almost_done } state; state = r->state; - p = b->pos; - while (p < b->last && state < sw_done) { - ch = *p++; + for (p = b->pos; p < b->last; p++) { + ch = *p; /* gcc 2.95.2 and msvc 6.0 compile this switch as an jump table */ @@ -50,7 +48,7 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) /* HTTP methods: GET, HEAD, POST */ case sw_start: - r->request_start = p - 1; + r->request_start = p; if (ch == CR || ch == LF) { break; @@ -65,19 +63,19 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_method: if (ch == ' ') { - r->method_end = p - 1; + r->method_end = p; m = r->request_start; - if (r->method_end - m == 3) { + if (p - m == 3) { if (m[0] == 'G' && m[1] == 'E' && m[2] == 'T') { r->method = NGX_HTTP_GET; } - } else if (r->method_end - m == 4) { + } else if (p - m == 4) { if (m[0] == 'P' && m[1] == 'O' - && m[2] == 'T' && m[3] == 'T') + && m[2] == 'S' && m[3] == 'T') { r->method = NGX_HTTP_POST; @@ -113,14 +111,14 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_spaces_before_uri: switch (ch) { case '/': - r->uri_start = p - 1; + r->uri_start = p; state = sw_after_slash_in_uri; break; case ' ': break; default: if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { - r->schema_start = p - 1; + r->schema_start = p; state = sw_schema; break; } @@ -131,7 +129,7 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_schema: switch (ch) { case ':': - r->schema_end = p - 1; + r->schema_end = p; state = sw_schema_slash; break; default: @@ -155,7 +153,7 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_schema_slash_slash: switch (ch) { case '/': - r->host_start = p - 1; + r->host_start = p; state = sw_host; break; default: @@ -166,12 +164,12 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_host: switch (ch) { case ':': - r->host_end = p - 1; + r->host_end = p; state = sw_port; break; case '/': - r->host_end = p - 1; - r->uri_start = p - 1; + r->host_end = p; + r->uri_start = p; state = sw_after_slash_in_uri; break; default: @@ -187,8 +185,8 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_port: switch (ch) { case '/': - r->port_end = p - 1; - r->uri_start = p - 1; + r->port_end = p; + r->uri_start = p; state = sw_after_slash_in_uri; break; default: @@ -203,17 +201,16 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_after_slash_in_uri: switch (ch) { case CR: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; state = sw_almost_done; break; case LF: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; - state = sw_done; - break; + goto done; case ' ': - r->uri_end = p - 1; + r->uri_end = p; state = sw_http_09; break; case '.': @@ -233,7 +230,7 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) r->complex_uri = 1; break; case '?': - r->args_start = p; + r->args_start = p + 1; state = sw_uri; break; default: @@ -246,21 +243,20 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_check_uri: switch (ch) { case CR: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; state = sw_almost_done; break; case LF: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; - state = sw_done; - break; + goto done; case ' ': - r->uri_end = p - 1; + r->uri_end = p; state = sw_http_09; break; case '.': - r->uri_ext = p; + r->uri_ext = p + 1; break; #if (NGX_WIN32) case '\\': @@ -277,7 +273,7 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) state = sw_uri; break; case '?': - r->args_start = p; + r->args_start = p + 1; state = sw_uri; break; } @@ -287,17 +283,16 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_uri: switch (ch) { case CR: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; state = sw_almost_done; break; case LF: - r->uri_end = p - 1; + r->uri_end = p; r->http_minor = 9; - state = sw_done; - break; + goto done; case ' ': - r->uri_end = p - 1; + r->uri_end = p; state = sw_http_09; break; } @@ -314,9 +309,9 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) break; case LF: r->http_minor = 9; - state = sw_done; - break; + goto done; case 'H': + r->http_protocol.data = p; state = sw_http_H; break; default: @@ -406,8 +401,7 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) } if (ch == LF) { - state = sw_done; - break; + goto done; } if (ch < '0' || ch > '9') { @@ -419,42 +413,38 @@ ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) /* end of request line */ case sw_almost_done: - r->request_end = p - 2; + r->request_end = p - 1; switch (ch) { case LF: - state = sw_done; - break; + goto done; default: return NGX_HTTP_PARSE_INVALID_REQUEST; } break; - - /* suppress warning */ - case sw_done: - break; } } b->pos = p; + r->state = state; - if (state == sw_done) { - if (r->request_end == NULL) { - r->request_end = p - 1; - } + return NGX_AGAIN; - r->http_version = r->http_major * 1000 + r->http_minor; - r->state = sw_start; +done: - if (r->http_version == 9 && r->method != NGX_HTTP_GET) { - return NGX_HTTP_PARSE_INVALID_09_METHOD; - } + b->pos = p + 1; + + if (r->request_end == NULL) { + r->request_end = p; + } - return NGX_OK; + r->http_version = r->http_major * 1000 + r->http_minor; + r->state = sw_start; - } else { - r->state = state; - return NGX_AGAIN; + if (r->http_version == 9 && r->method != NGX_HTTP_GET) { + return NGX_HTTP_PARSE_INVALID_09_METHOD; } + + return NGX_OK; } @@ -469,16 +459,13 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) sw_space_after_value, sw_almost_done, sw_header_almost_done, - sw_ignore_line, - sw_done, - sw_header_done + sw_ignore_line } state; state = r->state; - p = b->pos; - while (p < b->last && state < sw_done) { - ch = *p++; + for (p = b->pos; p < b->last; p++) { + ch = *p; switch (state) { @@ -486,16 +473,15 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_start: switch (ch) { case CR: - r->header_end = p - 1; + r->header_end = p; state = sw_header_almost_done; break; case LF: - r->header_end = p - 1; - state = sw_header_done; - break; + r->header_end = p; + goto header_done; default: state = sw_name; - r->header_name_start = p - 1; + r->header_name_start = p; c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'z') { @@ -523,7 +509,7 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) } if (ch == ':') { - r->header_name_end = p - 1; + r->header_name_end = p; state = sw_space_before_value; break; } @@ -539,7 +525,7 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) /* IIS may send the duplicate "HTTP/1.1 ..." lines */ if (ch == '/' && r->proxy - && p - r->header_start == 5 + && p - r->header_start == 4 && ngx_strncmp(r->header_start, "HTTP", 4) == 0) { state = sw_ignore_line; @@ -554,15 +540,14 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) case ' ': break; case CR: - r->header_start = r->header_end = p - 1; + r->header_start = r->header_end = p; state = sw_almost_done; break; case LF: - r->header_start = r->header_end = p - 1; - state = sw_done; - break; + r->header_start = r->header_end = p; + goto done; default: - r->header_start = p - 1; + r->header_start = p; state = sw_value; break; } @@ -572,17 +557,16 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_value: switch (ch) { case ' ': - r->header_end = p - 1; + r->header_end = p; state = sw_space_after_value; break; case CR: - r->header_end = p - 1; + r->header_end = p; state = sw_almost_done; break; case LF: - r->header_end = p - 1; - state = sw_done; - break; + r->header_end = p; + goto done; } break; @@ -595,8 +579,7 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) state = sw_almost_done; break; case LF: - state = sw_done; - break; + goto done; default: state = sw_value; break; @@ -618,8 +601,7 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_almost_done: switch (ch) { case LF: - state = sw_done; - break; + goto done; default: return NGX_HTTP_PARSE_INVALID_HEADER; } @@ -629,34 +611,32 @@ ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b) case sw_header_almost_done: switch (ch) { case LF: - state = sw_header_done; - break; + goto header_done; default: return NGX_HTTP_PARSE_INVALID_HEADER; } break; - - /* suppress warning */ - case sw_done: - case sw_header_done: - break; } } b->pos = p; + r->state = state; - if (state == sw_done) { - r->state = sw_start; - return NGX_OK; + return NGX_AGAIN; - } else if (state == sw_header_done) { - r->state = sw_start; - return NGX_HTTP_PARSE_HEADER_DONE; +done: - } else { - r->state = state; - return NGX_AGAIN; - } + b->pos = p + 1; + r->state = sw_start; + + return NGX_OK; + +header_done: + + b->pos = p + 1; + r->state = sw_start; + + return NGX_HTTP_PARSE_HEADER_DONE; } @@ -677,8 +657,10 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) sw_quoted_second } state, quoted_state; +#if (NGX_SUPPRESS_WARN) decoded = '\0'; quoted_state = sw_usual; +#endif state = sw_usual; p = r->uri_start; @@ -688,10 +670,10 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) ch = *p++; - while (p <= r->uri_end && r->args_start == NULL) { + while (p <= r->uri_end) { /* - * we use "ch = *p++" inside the cycle but this operation is safe + * we use "ch = *p++" inside the cycle, but this operation is safe, * because after the URI there is always at least one charcter: * the line feed */ @@ -731,7 +713,7 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) break; case '?': r->args_start = p; - break; + goto done; case ':': state = sw_colon; *u++ = ch; @@ -766,6 +748,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; default: state = sw_usual; *u++ = ch; @@ -794,6 +779,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; default: state = sw_usual; *u++ = ch; @@ -818,6 +806,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; default: state = sw_usual; *u++ = ch; @@ -844,6 +835,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; default: state = sw_usual; *u++ = ch; @@ -872,6 +866,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) quoted_state = state; state = sw_quoted; break; + case '?': + r->args_start = p; + goto done; #if (NGX_WIN32) case '.': state = sw_dot_dot_dot; @@ -953,11 +950,9 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'f') { ch = (u_char) ((decoded << 4) + c - 'a' + 10); - if (ch == '%') { - state = sw_usual; + if (ch == '?') { *u++ = ch; ch = *p++; - break; } state = quoted_state; break; @@ -967,6 +962,8 @@ ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r) } } +done: + r->uri.len = u - r->uri.data; r->uri.data[r->uri.len] = '\0'; diff --git a/src/http/ngx_http_parse_time.c b/src/http/ngx_http_parse_time.c index 38bbe2e85..da9797177 100644 --- a/src/http/ngx_http_parse_time.c +++ b/src/http/ngx_http_parse_time.c @@ -216,10 +216,6 @@ time_t ngx_http_parse_time(u_char *value, size_t len) + (*(p + 2) - '0') * 10 + *(p + 3) - '0'; } -#if 0 - printf("%d.%d.%d %d:%d:%d\n", day, month + 1, year, hour, min, sec); -#endif - if (hour > 23 || min > 59 || sec > 59) { return NGX_ERROR; } @@ -239,7 +235,7 @@ time_t ngx_http_parse_time(u_char *value, size_t len) /* * shift new year to March 1 and start months from 1 (not 0), - * it's needed for Gauss's formula + * it is needed for Gauss's formula */ if (--month <= 0) { @@ -247,41 +243,16 @@ time_t ngx_http_parse_time(u_char *value, size_t len) year -= 1; } - /* Gauss's formula for Grigorian days from 1 March 1 BC */ + /* Gauss's formula for Grigorian days from 1 March 1 BC */ return (365 * year + year / 4 - year / 100 + year / 400 + 367 * month / 12 - 31 + day - /* - * 719527 days were between March 1, 1 BC and March 1, 1970, - * 31 and 28 days in January and February 1970 - */ + /* + * 719527 days were between March 1, 1 BC and March 1, 1970, + * 31 and 28 days in January and February 1970 + */ - 719527 + 31 + 28) * 86400 + hour * 3600 + min * 60 + sec; } - -#if 0 -char zero[] = "Sun, 01 Jan 1970 08:49:30"; -char one[] = "Sunday, 11-Dec-02 08:49:30"; -char two[] = "Sun Mar 1 08:49:37 2000"; -char thr[] = "Sun Dec 11 08:49:37 2002"; - -main() -{ - int rc; - - rc = ngx_http_parse_time(zero, sizeof(zero) - 1); - printf("rc: %d\n", rc); - - rc = ngx_http_parse_time(one, sizeof(one) - 1); - printf("rc: %d\n", rc); - - rc = ngx_http_parse_time(two, sizeof(two) - 1); - printf("rc: %d\n", rc); - - rc = ngx_http_parse_time(thr, sizeof(thr) - 1); - printf("rc: %d\n", rc); -} - -#endif diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index b1b84fe6f..811031296 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -63,6 +63,8 @@ ngx_http_header_t ngx_http_headers_in[] = { { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer) }, { ngx_string("Content-Length"), offsetof(ngx_http_headers_in_t, content_length) }, + { ngx_string("Content-Type"), + offsetof(ngx_http_headers_in_t, content_type) }, { ngx_string("Range"), offsetof(ngx_http_headers_in_t, range) }, #if 0 @@ -86,7 +88,7 @@ ngx_http_header_t ngx_http_headers_in[] = { { ngx_string("X-Real-IP"), offsetof(ngx_http_headers_in_t, x_real_ip) }, { ngx_string("X-URL"), offsetof(ngx_http_headers_in_t, x_url) }, #endif - + { ngx_null_string, 0 } }; @@ -175,7 +177,7 @@ static void ngx_http_init_request(ngx_event_t *rev) { ngx_uint_t i; socklen_t len; - struct sockaddr_in addr_in; + struct sockaddr_in sin; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_in_port_t *in_port; @@ -283,21 +285,19 @@ static void ngx_http_init_request(ngx_event_t *rev) r->in_addr = ((struct sockaddr_in *) c->local_sockaddr)->sin_addr.s_addr; - } else { + } else #endif + { len = sizeof(struct sockaddr_in); - if (getsockname(c->fd, (struct sockaddr *) &addr_in, &len) == -1) { + if (getsockname(c->fd, (struct sockaddr *) &sin, &len) == -1) { ngx_connection_error(c, ngx_socket_errno, "getsockname() failed"); ngx_http_close_connection(c); return; } - r->in_addr = addr_in.sin_addr.s_addr; - -#if (NGX_WIN32) + r->in_addr = sin.sin_addr.s_addr; } -#endif /* the last in_port->addrs address is "*" */ @@ -573,6 +573,11 @@ static void ngx_http_process_request_line(ngx_event_t *rev) } + if (r->http_protocol.data) { + r->http_protocol.len = r->request_end - r->http_protocol.data; + } + + if (r->uri_ext) { if (r->args_start) { r->exten.len = r->args_start - 1 - r->uri_ext; @@ -2173,6 +2178,8 @@ void ngx_ssl_close_handler(ngx_event_t *ev) void ngx_http_close_connection(ngx_connection_t *c) { + ngx_pool_t *pool; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "close http connection: %d", c->fd); @@ -2192,7 +2199,11 @@ void ngx_http_close_connection(ngx_connection_t *c) (*ngx_stat_active)--; #endif + pool = c->pool; + ngx_close_connection(c); + + ngx_destroy_pool(c->pool); } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index eef929271..14121d1ff 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -133,6 +133,7 @@ typedef struct { ngx_table_elt_t *user_agent; ngx_table_elt_t *referer; ngx_table_elt_t *content_length; + ngx_table_elt_t *content_type; ngx_table_elt_t *range; @@ -201,13 +202,14 @@ typedef struct { } ngx_http_headers_out_t; +typedef void (*ngx_http_client_body_handler_pt)(ngx_http_request_t *r); + typedef struct { - ngx_temp_file_t *temp_file; - ngx_chain_t *bufs; - ngx_buf_t *buf; - size_t rest; - void (*handler) (void *data); - void *data; + ngx_temp_file_t *temp_file; + ngx_chain_t *bufs; + ngx_buf_t *buf; + size_t rest; + ngx_http_client_body_handler_pt post_handler; } ngx_http_request_body_t; @@ -256,6 +258,8 @@ struct ngx_http_request_s { ngx_http_cache_t *cache; + ngx_http_upstream_t *upstream; + ngx_file_t file; ngx_pool_t *pool; @@ -280,6 +284,7 @@ struct ngx_http_request_s { ngx_str_t unparsed_uri; ngx_str_t method_name; + ngx_str_t http_protocol; ngx_http_request_t *main; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c index eb6aebfc6..59f72208d 100644 --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -11,31 +11,67 @@ static void ngx_http_read_client_request_body_handler(ngx_event_t *rev); -static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); +static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r, + ngx_connection_t *c); +/* + * on completion ngx_http_read_client_request_body() adds to + * r->request_body->bufs one or two bufs: + * *) one memory buf that was preread in r->header_in; + * *) one memory or file buf that contains the rest of the body + */ + +ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r, + ngx_http_client_body_handler_pt post_handler) -ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r) { ssize_t size; ngx_buf_t *b; ngx_chain_t *cl; + ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; + if (!(rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + r->request_body = rb; + + if (r->headers_in.content_length_n <= 0) { + post_handler(r); + return NGX_OK; + } + + rb->post_handler = post_handler; + + /* + * set by ngx_pcalloc(): + * + * rb->bufs = NULL; + * rb->buf = NULL; + * rb->rest = 0; + */ + size = r->header_in->last - r->header_in->pos; if (size) { /* there is the pre-read part of the request body */ - ngx_test_null(b, ngx_calloc_buf(r->pool), - NGX_HTTP_INTERNAL_SERVER_ERROR); + if (!(b = ngx_calloc_buf(r->pool))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } b->temporary = 1; b->start = b->pos = r->header_in->pos; b->end = b->last = r->header_in->last; - ngx_alloc_link_and_set_buf(r->request_body->bufs, b, r->pool, - NGX_HTTP_INTERNAL_SERVER_ERROR); + if (!(rb->bufs = ngx_alloc_chain_link(r->pool))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rb->bufs->buf = b; + rb->bufs->next = NULL; if (size >= r->headers_in.content_length_n) { @@ -44,7 +80,7 @@ ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r) r->header_in->pos += r->headers_in.content_length_n; r->request_length += r->headers_in.content_length_n; - r->request_body->handler(r->request_body->data); + post_handler(r); return NGX_OK; } @@ -56,35 +92,39 @@ ngx_int_t ngx_http_read_client_request_body(ngx_http_request_t *r) clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - r->request_body->rest = r->headers_in.content_length_n - size; + rb->rest = r->headers_in.content_length_n - size; - if (r->request_body->rest - < clcf->client_body_buffer_size + if (rb->rest < clcf->client_body_buffer_size + (clcf->client_body_buffer_size >> 2)) { - size = r->request_body->rest; + size = rb->rest; } else { size = clcf->client_body_buffer_size; } - ngx_test_null(r->request_body->buf, ngx_create_temp_buf(r->pool, size), - NGX_HTTP_INTERNAL_SERVER_ERROR); + if (!(rb->buf = ngx_create_temp_buf(r->pool, size))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - ngx_alloc_link_and_set_buf(cl, r->request_body->buf, r->pool, - NGX_HTTP_INTERNAL_SERVER_ERROR); + if (!(cl = ngx_alloc_chain_link(r->pool))) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - if (r->request_body->bufs) { - r->request_body->bufs->next = cl; + cl->buf = rb->buf; + cl->next = NULL; + + if (rb->bufs) { + rb->bufs->next = cl; } else { - r->request_body->bufs = cl; + rb->bufs = cl; } r->connection->read->event_handler = ngx_http_read_client_request_body_handler; - return ngx_http_do_read_client_request_body(r); + return ngx_http_do_read_client_request_body(r, r->connection); } @@ -102,7 +142,7 @@ static void ngx_http_read_client_request_body_handler(ngx_event_t *rev) return; } - rc = ngx_http_do_read_client_request_body(r); + rc = ngx_http_do_read_client_request_body(r, c); if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { ngx_http_finalize_request(r, rc); @@ -110,24 +150,45 @@ static void ngx_http_read_client_request_body_handler(ngx_event_t *rev) } -static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r) +static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r, + ngx_connection_t *c) { size_t size; ssize_t n; ngx_buf_t *b; - ngx_connection_t *c; + ngx_temp_file_t *tf; + ngx_http_request_body_t *rb; ngx_http_core_loc_conf_t *clcf; - c = r->connection; + rb = r->request_body; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read client request body"); for ( ;; ) { - if (r->request_body->buf->last == r->request_body->buf->end) { - n = ngx_write_chain_to_temp_file(r->request_body->temp_file, - r->request_body->bufs->next ? r->request_body->bufs->next: - r->request_body->bufs); + if (rb->buf->last == rb->buf->end) { + + if (rb->temp_file == NULL) { + if (!(tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) { + return NGX_ERROR; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + tf->file.fd = NGX_INVALID_FILE; + tf->file.log = r->connection->log; + tf->path = clcf->client_body_temp_path; + tf->pool = r->pool; + tf->warn = "a client request body is buffered " + "to a temporary file"; + + rb->temp_file = tf; + + } + + n = ngx_write_chain_to_temp_file(rb->temp_file, + rb->bufs->next ? rb->bufs->next: + rb->bufs); /* TODO: n == 0 or not complete and level event */ @@ -135,19 +196,19 @@ static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - r->request_body->temp_file->offset += n; + rb->temp_file->offset += n; - r->request_body->buf->pos = r->request_body->buf->start; - r->request_body->buf->last = r->request_body->buf->start; + rb->buf->pos = rb->buf->start; + rb->buf->last = rb->buf->start; } - size = r->request_body->buf->end - r->request_body->buf->last; + size = rb->buf->end - rb->buf->last; - if (size > r->request_body->rest) { - size = r->request_body->rest; + if (size > rb->rest) { + size = rb->rest; } - n = c->recv(c, r->request_body->buf->last, size); + n = c->recv(c, rb->buf->last, size); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http client request body recv %z", n); @@ -173,33 +234,33 @@ static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r) return NGX_HTTP_BAD_REQUEST; } - r->request_body->buf->last += n; - r->request_body->rest -= n; + rb->buf->last += n; + rb->rest -= n; r->request_length += n; - if (r->request_body->rest == 0) { + if (rb->rest == 0) { break; } - if (r->request_body->buf->last < r->request_body->buf->end) { + if (rb->buf->last < rb->buf->end) { break; } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http client request body rest %uz", - r->request_body->rest); + "http client request body rest %uz", rb->rest); - if (r->request_body->rest) { + if (rb->rest) { return NGX_AGAIN; } - if (r->request_body->temp_file->file.fd != NGX_INVALID_FILE) { + if (rb->temp_file) { /* save the last part */ - n = ngx_write_chain_to_temp_file(r->request_body->temp_file, - r->request_body->bufs->next ? r->request_body->bufs->next: - r->request_body->bufs); + + n = ngx_write_chain_to_temp_file(rb->temp_file, + rb->bufs->next ? rb->bufs->next: + rb->bufs); /* TODO: n == 0 or not complete and level event */ @@ -213,18 +274,18 @@ static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r) b->in_file = 1; b->file_pos = 0; - b->file_last = r->request_body->temp_file->file.offset; - b->file = &r->request_body->temp_file->file; + b->file_last = rb->temp_file->file.offset; + b->file = &rb->temp_file->file; - if (r->request_body->bufs->next) { - r->request_body->bufs->next->buf = b; + if (rb->bufs->next) { + rb->bufs->next->buf = b; } else { - r->request_body->bufs->buf = b; + rb->bufs->buf = b; } } - r->request_body->handler(r->request_body->data); + rb->post_handler(r); return NGX_OK; } diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c index 51a1b47e2..e80824b30 100644 --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -9,42 +9,46 @@ #include <ngx_http.h> -char *ngx_http_script_copy(ngx_http_request_t *r, - ngx_http_script_code_t *code, - char *p, size_t len) +u_char *ngx_http_script_copy(ngx_http_request_t *r, u_char *buf, void *data) { - return ngx_cpymem(p, code->offset, code->len < len ? code->len : len); + u_char **p = data; + + ngx_http_script_code_t *code; + + code = (ngx_http_script_code_t *) + ((char *) data - sizeof(ngx_http_script_code_t)); + + return ngx_cpymem(buf, *p, code->data_len); } -char *ngx_http_script_header_in(ngx_http_request_t *r, - ngx_http_script_code_t *code, - char *p, size_t len) +u_char *ngx_http_script_header_in(ngx_http_request_t *r, + u_char *buf, void *data) { - ngx_str_t *s; + size_t *offset = data; - s = (ngx_str_t *) (((char *) r->headers_in) + code->offset); + ngx_table_elt_t *h; - return ngx_cpymem(p, s->data, s->len < len ? s->len : len); -} + h = *(ngx_table_elt_t **) (((char *) r->headers_in) + *offset); + return ngx_cpymem(p, h->value.data, h->value.len); +} -/* the log script codes */ -char *ngx_http_script_request_line(ngx_http_request_t *r, char *p, size_t len) +u_char *ngx_http_script_request_line(ngx_http_request_t *r, + u_char *buf, void *data) { - return ngx_cpymem(p, r->request_line.data, - r->request_line.len < len ? r->request_line.len : len); + return ngx_cpymem(p, r->request_line.data, r->request_line.len); } -char *ngx_http_script_status(ngx_http_request_t *r, char *p, size_t len) +u_char *ngx_http_script_status(ngx_http_request_t *r, u_char *buf, void *data) { - return ngx_snprintf(p, len, "%d", r->headers_out.status); + return ngx_sprintf(buf, "%ui", r->headers_out.status); } -char *ngx_http_script_sent(ngx_http_request_t *r, char *p, size_t len) +u_char *ngx_http_script_sent(ngx_http_request_t *r, u_char *buf, void *data) { - return ngx_sprintf(p, "%O", r->connection->sent); + return ngx_sprintf(buf, "%O", r->connection->sent); } diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h index 4a745128b..658faaa9b 100644 --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -8,10 +8,18 @@ #define _NGX_HTTP_SCRIPT_H_INCLUDED_ -typedef struct { - handler; - offset / data; - size; +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> + + +typedef u_char *(*ngx_http_script_code_pt) (ngx_http_request_t *r, + u_char *buf, void *data); + +typedef struct ngx_http_script_code_s { + size_t data_len; + size_t code_len; + ngx_http_script_code_pt code; } ngx_http_script_code_t; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c new file mode 100644 index 000000000..9aaf9bf8b --- /dev/null +++ b/src/http/ngx_http_upstream.c @@ -0,0 +1,1204 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> +#include <ngx_event_connect.h> + + +static void ngx_http_upstream_check_broken_connection(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, + ngx_http_upstream_t *u); +static void ngx_http_upstream_send_request(ngx_http_request_t *r, + ngx_http_upstream_t *u); +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_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, + ngx_http_upstream_t *u, + ngx_uint_t ft_type); +static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, + ngx_http_upstream_t *u, + ngx_int_t rc); + +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 ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf); + + +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 */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_upstream_module = { + NGX_MODULE, + &ngx_http_upstream_module_ctx, /* module context */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_log_op_name_t ngx_http_upstream_log_fmt_ops[] = { + { ngx_string("upstream_status"), 0, NULL, + ngx_http_upstream_log_status_getlen, + ngx_http_upstream_log_status }, + { ngx_null_string, 0, NULL, NULL, NULL } +}; + + +char *ngx_http_upstream_header_errors[] = { + "upstream sent invalid header", + "upstream sent too long header line" +}; + + +void ngx_http_upstream_init(ngx_http_request_t *r) +{ + ngx_connection_t *c; + ngx_http_upstream_t *u; + + c = r->connection; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http init upstream, client timer: %d", c->read->timer_set); + + if (c->read->timer_set) { + ngx_del_timer(c->read); + } + + c->read->event_handler = ngx_http_upstream_check_broken_connection; + + if (ngx_event_flags & NGX_USE_CLEAR_EVENT) { + + c->write->event_handler = ngx_http_upstream_check_broken_connection; + + if (!c->write->active) { + if (ngx_add_event(c->write, NGX_WRITE_EVENT, + NGX_CLEAR_EVENT) == NGX_ERROR) + { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + } + + u = r->upstream; + + u->method = r->method; + + if (u->create_request(r) == NGX_ERROR) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->peer.log = r->connection->log; + u->saved_ctx = r->connection->log->data; + u->saved_handler = r->connection->log->handler; + r->connection->log->data = u->log_ctx; + r->connection->log->handler = u->log_handler; + + u->output.sendfile = r->connection->sendfile; + u->output.pool = r->pool; + u->output.bufs.num = 1; + u->output.output_filter = ngx_chain_writer; + u->output.filter_ctx = &u->writer; + + u->writer.pool = r->pool; + + if (ngx_array_init(&u->states, r->pool, u->peer.peers->number, + sizeof(ngx_http_upstream_state_t)) == NGX_ERROR) + { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + if (!(u->state = ngx_push_array(&u->states))) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); + + ngx_http_upstream_connect(r, u); +} + + +static void ngx_http_upstream_check_broken_connection(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); + +#if (NGX_HAVE_KQUEUE) + + if (ngx_event_flags & NGX_USE_KQUEUE_EVENT) { + + if (!ev->pending_eof) { + return; + } + + ev->eof = 1; + + if (ev->kq_errno) { + ev->error = 1; + } + + c = ev->data; + r = c->data; + u = r->upstream; + + if (!u->cachable && u->peer.connection) { + ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno, + "kevent() reported that client closed " + "prematurely connection, " + "so upstream connection is closed too"); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + + ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno, + "kevent() reported that client closed " + "prematurely connection"); + + if (u->peer.connection == NULL) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + + return; + } + +#endif + + c = ev->data; + + n = recv(c->fd, buf, 1, MSG_PEEK); + + err = ngx_socket_errno; + + /* + * we do not need to disable the write event because + * that event has NGX_USE_CLEAR_EVENT type + */ + + if (ev->write && (n >= 0 || err == NGX_EAGAIN)) { + return; + } + + r = c->data; + u = r->upstream; + + if ((ngx_event_flags & NGX_USE_LEVEL_EVENT) && ev->active) { + if (ngx_del_event(ev, NGX_READ_EVENT, 0) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + } + + if (n > 0) { + return; + } + + ev->eof = 1; + + if (n == -1) { + if (err == NGX_EAGAIN) { + return; + } + + ev->error = 1; + + } else { + /* n == 0 */ + err = 0; + } + + if (!u->cachable && u->peer.connection) { + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "client closed prematurely connection, " + "so upstream connection is closed too"); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + + ngx_log_error(NGX_LOG_INFO, ev->log, err, + "client closed prematurely connection"); + + if (u->peer.connection == NULL) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } +} + + +static void ngx_http_upstream_connect(ngx_http_request_t *r, + ngx_http_upstream_t *u) +{ + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_log_ctx_t *ctx; + + ctx = r->connection->log->data; + ctx->action = "connecting to upstream"; + + r->connection->single_connection = 0; + + rc = ngx_event_connect_peer(&u->peer); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream connect: %i", rc); + + if (rc == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->state->peer = &u->peer.peers->peer[u->peer.cur_peer].name; + + if (rc == NGX_CONNECT_ERROR) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + return; + } + + 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->sendfile = r->connection->sendfile; + + c->pool = r->pool; + c->read->log = c->write->log = c->log = r->connection->log; + + /* init or reinit the ngx_output_chain() and ngx_chain_writer() contexts */ + + u->writer.out = NULL; + u->writer.last = &u->writer.out; + u->writer.connection = c; + u->writer.limit = 0; + + if (u->request_sent) { + ngx_http_upstream_reinit(r, u); + } + + if (r->request_body->buf) { + if (r->request_body->temp_file) { + + if (!(u->output.free = ngx_alloc_chain_link(r->pool))) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->output.free->buf = r->request_body->buf; + u->output.free->next = NULL; + u->output.allocated = 1; + + 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; + } + } + + u->request_sent = 0; + + if (rc == NGX_AGAIN) { + ngx_add_timer(c->write, u->conf->connect_timeout); + return; + } + + /* rc == NGX_OK */ + + ngx_http_upstream_send_request(r, u); +} + + +static void 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; + } + + /* reinit the request chain */ + + for (cl = r->request_body->bufs; cl; cl = cl->next) { + cl->buf->pos = cl->buf->start; + cl->buf->file_pos = 0; + } + + /* reinit the ngx_output_chain() context */ + + u->output.buf = NULL; + u->output.in = NULL; + u->output.free = NULL; + u->output.busy = NULL; + + /* reinit u->header_in buffer */ + +#if 0 + if (u->cache) { + u->header_in.pos = u->header_in.start + u->cache->ctx.header_size; + u->header_in.last = u->header_in.pos; + + } else { + u->header_in.pos = u->header_in.start; + 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 */ + + if (!(u->state = ngx_push_array(&u->states))) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); + + u->status = 0; + u->status_count = 0; +} + + +static void ngx_http_upstream_send_request(ngx_http_request_t *r, + ngx_http_upstream_t *u) +{ + int rc; + ngx_connection_t *c; + ngx_http_log_ctx_t *ctx; + + c = u->peer.connection; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream send request"); + +#if (NGX_HAVE_KQUEUE) + + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) + && !u->request_sent + && c->write->pending_eof) + { + ngx_log_error(NGX_LOG_ERR, c->log, c->write->kq_errno, + "connect() failed"); + + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + return; + } + +#endif + + ctx = c->log->data; + ctx->action = "sending request to upstream"; + + rc = ngx_output_chain(&u->output, + u->request_sent ? NULL : r->request_body->bufs); + + u->request_sent = 1; + + if (rc == NGX_ERROR) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + return; + } + + if (c->write->timer_set) { + ngx_del_timer(c->write); + } + + if (rc == NGX_AGAIN) { + ngx_add_timer(c->write, u->conf->send_timeout); + + if (ngx_handle_write_event(c->write, u->conf->send_lowat) == NGX_ERROR) + { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + return; + } + + /* rc == NGX_OK */ + + if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) { + if (ngx_tcp_push(c->fd) == NGX_ERROR) { + ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno, + ngx_tcp_push_n " failed"); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + c->tcp_nopush = NGX_TCP_NOPUSH_UNSET; + return; + } + + ngx_add_timer(c->read, u->conf->read_timeout); + +#if 1 + if (c->read->ready) { + + /* post aio operation */ + + /* + * TODO comment + * although we can post aio operation just in the end + * of ngx_http_upstream_connect() CHECK IT !!! + * it's better to do here because we postpone header buffer allocation + */ + + ngx_http_upstream_process_header(c->read); + return; + } +#endif + + c->write->event_handler = ngx_http_upstream_dummy_handler; + + if (ngx_handle_level_write_event(c->write) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } +} + + +static void ngx_http_upstream_send_request_handler(ngx_event_t *wev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_log_ctx_t *ctx; + ngx_http_upstream_t *u; + + c = wev->data; + r = c->data; + u = r->upstream; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, + "http upstream send request handler"); + + if (wev->timedout) { + ctx = c->log->data; + ctx->action = "sending request to upstream"; + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT); + return; + } + + if (r->connection->write->eof && (!u->cachable || !u->request_sent)) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_http_upstream_send_request(r, u); +} + + +static void ngx_http_upstream_process_header(ngx_event_t *rev) +{ + ssize_t n; + ngx_int_t rc; + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_log_ctx_t *ctx; + ngx_http_upstream_t *u; + + c = rev->data; + r = c->data; + u = r->upstream; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, + "http upstream process handler"); + + ctx = c->log->data; + ctx->action = "reading response header from upstream"; + + if (rev->timedout) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT); + return; + } + + if (u->header_in.start == NULL) { + u->header_in.start = ngx_palloc(r->pool, u->conf->header_buffer_size); + if (u->header_in.start == NULL) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->header_in.pos = u->header_in.start; + u->header_in.last = u->header_in.start; + u->header_in.end = u->header_in.last + u->conf->header_buffer_size; + u->header_in.temporary = 1; + + u->header_in.tag = u->output.tag; + +#if 0 + if (u->cache) { + u->header_in.pos += u->cache->ctx.header_size; + u->header_in.last = u->header_in.pos; + } +#endif + } + + n = ngx_recv(u->peer.connection, u->header_in.last, + u->header_in.end - u->header_in.last); + + if (n == NGX_AGAIN) { +#if 0 + ngx_add_timer(rev, u->read_timeout); +#endif + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + return; + } + + if (n == 0) { + ngx_log_error(NGX_LOG_ERR, rev->log, 0, + "upstream prematurely closed connection"); + } + + if (n == NGX_ERROR || n == 0) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); + return; + } + + if (n == NGX_HTTP_INTERNAL_SERVER_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->header_in.last += n; + +#if 0 + u->valid_header_in = 0; + + u->peer.cached = 0; +#endif + + rc = u->process_header(r); + + if (rc == NGX_AGAIN) { +#if 0 + ngx_add_timer(rev, u->read_timeout); +#endif + + if (u->header_in.last == u->header_in.end) { + ngx_log_error(NGX_LOG_ERR, rev->log, 0, + "upstream sent too big header"); + + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER); + return; + } + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + return; + } + + if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) { + ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER); + return; + } + + if (rc == NGX_ERROR || rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + /* rc == NGX_OK */ + + ngx_http_upstream_send_response(r, u); +} + + +static void ngx_http_upstream_send_response(ngx_http_request_t *r, + ngx_http_upstream_t *u) +{ + ngx_event_pipe_t *p; + ngx_http_core_loc_conf_t *clcf; + + + if (u->send_header(r) == NGX_HTTP_INTERNAL_SERVER_ERROR) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + u->header_sent = 1; + + /* TODO: preallocate event_pipe bufs, look "Content-Length" */ + +#if 0 + + if (u->cache && u->cache->ctx.file.fd != NGX_INVALID_FILE) { + if (ngx_close_file(u->cache->ctx.file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + u->cache->ctx.file.name.data); + } + } + + if (u->cachable) { + header = (ngx_http_cache_header_t *) u->header_in->start; + + header->expires = u->cache->ctx.expires; + header->last_modified = u->cache->ctx.last_modified; + header->date = u->cache->ctx.date; + header->length = r->headers_out.content_length_n; + u->cache->ctx.length = r->headers_out.content_length_n; + + header->key_len = u->cache->ctx.key0.len; + ngx_memcpy(&header->key, u->cache->ctx.key0.data, header->key_len); + header->key[header->key_len] = LF; + } + +#endif + + p = &u->pipe; + + p->output_filter = (ngx_event_pipe_output_filter_pt) ngx_http_output_filter; + p->output_ctx = r; + p->tag = u->output.tag; + p->bufs = u->conf->bufs; + p->busy_size = u->conf->busy_buffers_size; + p->upstream = u->peer.connection; + p->downstream = r->connection; + p->pool = r->pool; + p->log = r->connection->log; + + p->cachable = u->cachable; + + if (!(p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t)))) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + p->temp_file->file.fd = NGX_INVALID_FILE; + p->temp_file->file.log = r->connection->log; + p->temp_file->path = u->conf->temp_path; + p->temp_file->pool = r->pool; + + if (u->cachable) { + p->temp_file->persistent = 1; + } else { + p->temp_file->warn = "an upstream response is buffered " + "to a temporary file"; + } + + p->max_temp_file_size = u->conf->max_temp_file_size; + p->temp_file_write_size = u->conf->temp_file_write_size; + + if (!(p->preread_bufs = ngx_alloc_chain_link(r->pool))) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + p->preread_bufs->buf = &u->header_in; + p->preread_bufs->next = NULL; + u->header_in.recycled = 1; + + p->preread_size = u->header_in.last - u->header_in.pos; + + if (u->cachable) { + p->buf_to_file = ngx_calloc_buf(r->pool); + if (p->buf_to_file == NULL) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + p->buf_to_file->pos = u->header_in.start; + p->buf_to_file->last = u->header_in.pos; + p->buf_to_file->temporary = 1; + } + + if (ngx_event_flags & NGX_USE_AIO_EVENT) { + /* the posted aio operation may currupt a shadow buffer */ + p->single_buf = 1; + } + + /* TODO: p->free_bufs = 0 if use ngx_create_chain_of_bufs() */ + p->free_bufs = 1; + + /* + * event_pipe would do u->header_in.last += p->preread_size + * as though these bytes were read + */ + u->header_in.last = u->header_in.pos; + + if (u->conf->cyclic_temp_file) { + + /* + * we need to disable the use of sendfile() if we use cyclic temp file + * because the writing a new data may interfere with sendfile() + * that uses the same kernel file pages (at least on FreeBSD) + */ + + p->cyclic_temp_file = 1; + r->connection->sendfile = 0; + + } else { + p->cyclic_temp_file = 0; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + p->read_timeout = u->conf->read_timeout; + 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; + + ngx_http_upstream_process_body(u->peer.connection->read); +} + + +static void ngx_http_upstream_process_body(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + ngx_http_log_ctx_t *ctx; + ngx_http_upstream_t *u; + ngx_event_pipe_t *p; + + c = ev->data; + r = c->data; + u = r->upstream; + + ctx = ev->log->data; + + if (ev->write) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http proxy process downstream"); + ctx->action = "sending to client"; + + } else { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http proxy process upstream"); + ctx->action = "reading upstream body"; + } + + p = &u->pipe; + + if (ev->timedout) { + if (ev->write) { + p->downstream_error = 1; + ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, + "client timed out"); + + } else { + p->upstream_error = 1; + ngx_log_error(NGX_LOG_ERR, c->log, NGX_ETIMEDOUT, + "upstream timed out"); + } + + } else { + if (ngx_event_pipe(p, ev->write) == NGX_ABORT) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + } + + if (u->peer.connection) { + +#if (NGX_HTTP_FILE_CACHE) + + if (p->upstream_done && u->cachable) { + if (ngx_http_cache_update(r) == NGX_ERROR) { + ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + } else if (p->upstream_eof && u->cachable) { + + /* TODO: check length & update cache */ + + if (ngx_http_cache_update(r) == NGX_ERROR) { + ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + } + +#endif + + if (p->upstream_done || p->upstream_eof || p->upstream_error) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http proxy upstream exit: %p", p->out); +#if 0 + ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); +#endif + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + } + + if (p->downstream_error) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "http proxy downstream error"); + + if (!u->cachable && u->peer.connection) { + ngx_http_upstream_finalize_request(r, u, 0); + } + } +} + + +static void ngx_http_upstream_dummy_handler(ngx_event_t *wev) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0, + "http upstream dummy handler"); +} + + +static void ngx_http_upstream_next(ngx_http_request_t *r, + ngx_http_upstream_t *u, + ngx_uint_t ft_type) +{ + ngx_uint_t status; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http next upstream, %xD", ft_type); + +#if 0 + ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); +#endif + + if (ft_type != NGX_HTTP_UPSTREAM_FT_HTTP_404) { + ngx_event_connect_peer_failed(&u->peer); + } + + if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT, + "upstream timed out"); + } + + if (u->peer.cached && ft_type == NGX_HTTP_UPSTREAM_FT_ERROR) { + status = 0; + + } else { + switch(ft_type) { + + case NGX_HTTP_UPSTREAM_FT_TIMEOUT: + status = NGX_HTTP_GATEWAY_TIME_OUT; + break; + + case NGX_HTTP_UPSTREAM_FT_HTTP_500: + status = NGX_HTTP_INTERNAL_SERVER_ERROR; + break; + + case NGX_HTTP_UPSTREAM_FT_HTTP_404: + status = NGX_HTTP_NOT_FOUND; + break; + + /* + * NGX_HTTP_UPSTREAM_FT_BUSY_LOCK and NGX_HTTP_UPSTREAM_FT_MAX_WAITING + * never reach here + */ + + default: + status = NGX_HTTP_BAD_GATEWAY; + } + } + + if (r->connection->write->eof) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_CLIENT_CLOSED_REQUEST); + return; + } + + if (status) { + u->state->status = status; + + if (u->peer.tries == 0 || !(u->conf->next_upstream & ft_type)) + { + +#if (NGX_HTTP_CACHE) + + if (u->stale && (u->conf->use_stale & ft_type)) { + ngx_http_upstream_finalize_request(r, u, + ngx_http_proxy_send_cached_response(r)); + return; + } + +#endif + + ngx_http_upstream_finalize_request(r, u, status); + return; + } + } + + if (u->peer.connection) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "close http upstream connection: %d", + u->peer.connection->fd); + + ngx_close_connection(u->peer.connection); + } + +#if 0 + if (u->conf->busy_lock && !u->busy_locked) { + ngx_http_upstream_busy_lock(p); + return; + } +#endif + + ngx_http_upstream_connect(r, u); +} + + +static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, + ngx_http_upstream_t *u, + ngx_int_t rc) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "finalize http upstream request"); + + u->finalize_request(r, rc); + + if (u->peer.connection) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "close http upstream connection: %d", + u->peer.connection->fd); + + ngx_close_connection(u->peer.connection); + } + + if (u->header_sent + && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE)) + { + rc = 0; + } + + if (u->saved_ctx) { + r->connection->log->data = u->saved_ctx; + r->connection->log->handler = u->saved_handler; + } + + if (u->pipe.temp_file->file.fd) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http upstream temp fd: %d", + u->pipe.temp_file->file.fd); + } + +#if 0 + if (u->cache) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy cache fd: %d", + u->cache->ctx.file.fd); + } +#endif + + if (u->pipe.temp_file->file.fd) { + r->file.fd = u->pipe.temp_file->file.fd; + +#if 0 + } else if (u->cache) { + r->file.fd = u->cache->ctx.file.fd; +#endif + } + + if (rc == 0 && r->main == NULL) { + rc = ngx_http_send_last(r); + } + + ngx_http_finalize_request(r, rc); +} + + +static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r, + uintptr_t data) +{ + if (r->upstream) { + return r->upstream->states.nelts * (3 + 2); + } + + return 1; +} + + +static u_char *ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op) +{ + ngx_uint_t i; + ngx_http_upstream_t *u; + ngx_http_upstream_state_t *state; + + u = r->upstream; + + if (u == NULL) { + *buf = '-'; + return buf + 1; + } + + i = 0; + state = u->states.elts; + + for ( ;; ) { + if (state[i].status == 0) { + *buf++ = '-'; + + } else { + buf = ngx_sprintf(buf, "%ui", state[i].status); + } + + if (++i == u->states.nelts) { + return buf; + } + + *buf++ = ','; + *buf++ = ' '; + } +} + + +u_char *ngx_http_upstream_log_error(void *data, u_char *buf, size_t len) +{ + ngx_http_log_ctx_t *ctx = data; + + u_char *p; + ngx_int_t escape; + ngx_str_t uri; + ngx_http_request_t *r; + ngx_http_upstream_t *u; + ngx_peer_connection_t *peer; + + r = ctx->request; + u = r->upstream; + peer = &u->peer; + + p = ngx_snprintf(buf, len, + " while %s, client: %V, URL: %V, upstream: %V%V%s%V", + ctx->action, + &r->connection->addr_text, + &r->unparsed_uri, + &u->schema, + &peer->peers->peer[peer->cur_peer].name, + peer->peers->peer[peer->cur_peer].uri_separator, + &u->uri); + len -= p - buf; + buf = p; + + if (r->quoted_uri) { + escape = 2 * ngx_escape_uri(NULL, r->uri.data + u->location->len, + r->uri.len - u->location->len, + NGX_ESCAPE_URI); + } else { + escape = 0; + } + + if (escape) { + if (len >= r->uri.len - u->location->len + escape) { + + ngx_escape_uri(buf, r->uri.data + u->location->len, + r->uri.len - u->location->len, NGX_ESCAPE_URI); + + buf += r->uri.len - u->location->len + escape; + + if (r->args.len == 0) { + return buf; + } + + len -= r->uri.len - u->location->len + escape; + + return ngx_snprintf(buf, len, "?%V", &r->args); + } + + p = ngx_palloc(r->pool, r->uri.len - u->location->len + escape); + if (p == NULL) { + return buf; + } + + ngx_escape_uri(p, r->uri.data + u->location->len, + r->uri.len - u->location->len, NGX_ESCAPE_URI); + + uri.len = r->uri.len - u->location->len + escape; + uri.data = p; + + } else { + uri.len = r->uri.len - u->location->len; + uri.data = r->uri.data + u->location->len; + + } + + return ngx_snprintf(buf, len, "%V%s%V", + &uri, r->args.len ? "?" : "", &r->args); +} + + +static ngx_int_t ngx_http_upstream_add_log_formats(ngx_conf_t *cf) +{ + ngx_http_log_op_name_t *op; + + for (op = ngx_http_upstream_log_fmt_ops; op->name.len; op++) { /* void */ } + op->run = NULL; + + for (op = ngx_http_log_fmt_ops; op->run; op++) { + if (op->name.len == 0) { + op = (ngx_http_log_op_name_t *) op->run; + } + } + + op->run = (ngx_http_log_op_run_pt) ngx_http_upstream_log_fmt_ops; + + return NGX_OK; +} diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h new file mode 100644 index 000000000..6614211a6 --- /dev/null +++ b/src/http/ngx_http_upstream.h @@ -0,0 +1,122 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_HTTP_UPSTREAM_H_INCLUDED_ +#define _NGX_HTTP_UPSTREAM_H_INCLUDED_ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_event.h> +#include <ngx_event_connect.h> +#include <ngx_event_pipe.h> +#include <ngx_http.h> + + +#define NGX_HTTP_UPSTREAM_FT_ERROR 0x02 +#define NGX_HTTP_UPSTREAM_FT_TIMEOUT 0x04 +#define NGX_HTTP_UPSTREAM_FT_INVALID_HEADER 0x08 +#define NGX_HTTP_UPSTREAM_FT_HTTP_500 0x10 +#define NGX_HTTP_UPSTREAM_FT_HTTP_404 0x20 +#define NGX_HTTP_UPSTREAM_FT_BUSY_LOCK 0x40 +#define NGX_HTTP_UPSTREAM_FT_MAX_WAITING 0x80 + + +#define NGX_HTTP_UPSTREAM_INVALID_HEADER 40 + + +typedef struct { + time_t bl_time; + ngx_uint_t bl_state; + + ngx_uint_t status; + time_t time; + + ngx_str_t *peer; +} ngx_http_upstream_state_t; + + +typedef struct { + ngx_msec_t connect_timeout; + ngx_msec_t send_timeout; + ngx_msec_t read_timeout; + + size_t send_lowat; + size_t header_buffer_size; + size_t busy_buffers_size; + size_t max_temp_file_size; + size_t temp_file_write_size; + + ngx_uint_t next_upstream; + + ngx_bufs_t bufs; + + ngx_flag_t x_powered_by; + ngx_flag_t cyclic_temp_file; + + ngx_path_t *temp_path; +} ngx_http_upstream_conf_t; + + +typedef struct ngx_http_upstream_s ngx_http_upstream_t; + +struct ngx_http_upstream_s { + ngx_http_request_t *request; + + ngx_peer_connection_t peer; + + ngx_event_pipe_t pipe; + + ngx_output_chain_ctx_t output; + ngx_chain_writer_ctx_t writer; + + ngx_http_upstream_conf_t *conf; + + ngx_buf_t header_in; + + ngx_int_t (*create_request)(ngx_http_request_t *r); + ngx_int_t (*reinit_request)(ngx_http_request_t *r); + ngx_int_t (*process_header)(ngx_http_request_t *r); + ngx_int_t (*send_header)(ngx_http_request_t *r); + void (*abort_request)(ngx_http_request_t *r); + void (*finalize_request)(ngx_http_request_t *r, + ngx_int_t rc); + ngx_uint_t method; + + ngx_str_t schema; + ngx_str_t uri; + ngx_str_t *location; + + ngx_http_log_ctx_t *log_ctx; + ngx_log_handler_pt log_handler; + ngx_http_log_ctx_t *saved_ctx; + ngx_log_handler_pt saved_handler; + + /* used to parse an upstream HTTP header */ + ngx_uint_t status; + u_char *status_start; + u_char *status_end; + ngx_uint_t status_count; + ngx_uint_t parse_state; + + ngx_http_upstream_state_t *state; + ngx_array_t states; /* of ngx_http_upstream_state_t */ + + unsigned cachable:1; + + unsigned request_sent:1; + unsigned header_sent:1; +}; + + +void ngx_http_upstream_init(ngx_http_request_t *r); +u_char *ngx_http_upstream_log_error(void *data, u_char *buf, size_t len); + + +extern char *ngx_http_upstream_header_errors[]; + + +#endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */ diff --git a/src/http/ngx_http_write_filter.c b/src/http/ngx_http_write_filter.c index 50e8bc249..632c6bf93 100644 --- a/src/http/ngx_http_write_filter.c +++ b/src/http/ngx_http_write_filter.c @@ -69,8 +69,19 @@ ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) for (cl = ctx->out; cl; cl = cl->next) { ll = &cl->next; + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, + "write old buf t:%d f:%d %p, pos %p, size: %z " + "file: %O, size: %z", + cl->buf->temporary, cl->buf->in_file, + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + #if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "zero size buf in writer"); ngx_debug_point(); } #endif @@ -97,8 +108,19 @@ ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) *ll = cl; ll = &cl->next; + ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, + "write new buf t:%d f:%d %p, pos %p, size: %z " + "file: %O, size: %z", + cl->buf->temporary, cl->buf->in_file, + cl->buf->start, cl->buf->pos, + cl->buf->last - cl->buf->pos, + cl->buf->file_pos, + cl->buf->file_last - cl->buf->file_pos); + #if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "zero size buf in writer"); ngx_debug_point(); } #endif |
