Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nginx/nginx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2003-11-09 23:03:38 +0300
committerIgor Sysoev <igor@sysoev.ru>2003-11-09 23:03:38 +0300
commit74e95c224ad84c6b84b5a834f49c014a441916b5 (patch)
treefea6b4e7b2706f089e462d201e90ec95f5a98fa2 /src
parente8732b06b94ea5f8a25fa3e71cece7d93f5ac0b8 (diff)
nginx-0.0.1-2003-11-09-23:03:38 import; separate building
Diffstat (limited to 'src')
-rw-r--r--src/core/ngx_conf_file.c10
-rw-r--r--src/core/ngx_conf_file.h13
-rw-r--r--src/core/ngx_modules.c6
-rw-r--r--src/core/ngx_string.c14
-rw-r--r--src/event/ngx_event_pipe.c1
-rw-r--r--src/http/modules/ngx_http_log_handler.c202
-rw-r--r--src/http/modules/ngx_http_log_handler.h41
-rw-r--r--src/http/modules/ngx_http_static_handler.c32
-rw-r--r--src/http/modules/proxy/ngx_http_proxy_cache.c186
-rw-r--r--src/http/modules/proxy/ngx_http_proxy_handler.c131
-rw-r--r--src/http/modules/proxy/ngx_http_proxy_handler.h26
-rw-r--r--src/http/modules/proxy/ngx_http_proxy_upstream.c118
-rw-r--r--src/http/ngx_http.c14
-rw-r--r--src/http/ngx_http.h1
-rw-r--r--src/http/ngx_http_busy_lock.c223
-rw-r--r--src/http/ngx_http_busy_lock.h31
-rw-r--r--src/http/ngx_http_cache.c37
-rw-r--r--src/http/ngx_http_cache.h9
-rw-r--r--src/http/ngx_http_config.h2
-rw-r--r--src/http/ngx_http_core_module.c72
-rw-r--r--src/http/ngx_http_core_module.h7
-rw-r--r--src/http/ngx_http_header_filter.c88
-rw-r--r--src/http/ngx_http_headers.c1
-rw-r--r--src/http/ngx_http_log_handler.c773
-rw-r--r--src/http/ngx_http_log_handler.h59
-rw-r--r--src/http/ngx_http_request.c5
-rw-r--r--src/http/ngx_http_request.h3
-rw-r--r--src/http/ngx_http_special_response.c43
-rw-r--r--src/os/unix/ngx_files.h1
-rw-r--r--src/os/unix/ngx_types.h2
-rw-r--r--src/os/win32/ngx_files.h3
-rw-r--r--src/os/win32/ngx_stat.c2
-rw-r--r--src/os/win32/ngx_stat.h30
-rw-r--r--src/os/win32/ngx_types.h14
-rw-r--r--src/os/win32/ngx_win32_config.h24
35 files changed, 1657 insertions, 567 deletions
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index d2484bb39..24aa096fd 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -168,7 +168,15 @@ ngx_log_debug(cf->log, "command '%s'" _ cmd->name.data);
} else if (cmd->type & NGX_CONF_1MORE) {
- if (cf->args->nelts != 1) {
+ if (cf->args->nelts > 1) {
+ valid = 1;
+ } else {
+ valid = 0;
+ }
+
+ } else if (cmd->type & NGX_CONF_2MORE) {
+
+ if (cf->args->nelts > 2) {
valid = 1;
} else {
valid = 0;
diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h
index b2dce803d..d460fbe45 100644
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -23,14 +23,19 @@
#define NGX_CONF_TAKE8 0x00000100
#define NGX_CONF_TAKE9 0x00000200
+#define NGX_CONF_TAKE12 (NGX_CONF_TAKE1|NGX_CONF_TAKE2)
+
+#define NGX_CONF_TAKE13 (NGX_CONF_TAKE1|NGX_CONF_TAKE3)
+
#define NGX_CONF_TAKE1234 (NGX_CONF_TAKE1|NGX_CONF_TAKE2|NGX_CONF_TAKE3 \
|NGX_CONF_TAKE4)
#define NGX_CONF_ARGS_NUMBER 0x0000ffff
-#define NGX_CONF_ANY 0x00010000
-#define NGX_CONF_1MORE 0x00020000
-#define NGX_CONF_BLOCK 0x00040000
-#define NGX_CONF_FLAG 0x00080000
+#define NGX_CONF_BLOCK 0x00010000
+#define NGX_CONF_FLAG 0x00020000
+#define NGX_CONF_ANY 0x00040000
+#define NGX_CONF_1MORE 0x00080000
+#define NGX_CONF_2MORE 0x00100000
#define NGX_MAIN_CONF 0x01000000
diff --git a/src/core/ngx_modules.c b/src/core/ngx_modules.c
index dfe0243ad..c3159ad84 100644
--- a/src/core/ngx_modules.c
+++ b/src/core/ngx_modules.c
@@ -27,6 +27,7 @@ extern ngx_module_t ngx_aio_module;
extern ngx_module_t ngx_http_module;
extern ngx_module_t ngx_http_core_module;
+extern ngx_module_t ngx_http_log_module;
extern ngx_module_t ngx_http_write_filter_module;
extern ngx_module_t ngx_http_output_filter_module;
@@ -42,8 +43,6 @@ extern ngx_module_t ngx_http_static_module;
extern ngx_module_t ngx_http_index_module;
extern ngx_module_t ngx_http_proxy_module;
-extern ngx_module_t ngx_http_log_module;
-
ngx_module_t *ngx_modules[] = {
@@ -78,6 +77,7 @@ ngx_module_t *ngx_modules[] = {
&ngx_http_module,
&ngx_http_core_module,
+ &ngx_http_log_module,
&ngx_http_write_filter_module,
&ngx_http_output_filter_module,
&ngx_http_header_filter_module,
@@ -93,7 +93,5 @@ ngx_module_t *ngx_modules[] = {
&ngx_http_index_module,
&ngx_http_proxy_module,
- &ngx_http_log_module,
-
NULL
};
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index 962674e2f..87b6a0957 100644
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -71,13 +71,15 @@ int ngx_atoi(char *line, size_t n)
void ngx_md5_text(char *text, u_char *md5)
{
- /* STUB */
+ int i;
+ static char hex[] = "0123456789abcdef";
- ngx_snprintf(text, 33,
- "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
- md5[0], md5[1], md5[2], md5[3], md5[4], md5[5],
- md5[6], md5[7], md5[8], md5[9], md5[10], md5[11],
- md5[12], md5[13], md5[14], md5[15]);
+ for (i = 0; i < 16; i++) {
+ *text++ = hex[md5[i] >> 4];
+ *text++ = hex[md5[i] & 0xf];
+ }
+
+ *text = '\0';
}
diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c
index 8e08964f7..af68d4528 100644
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -417,6 +417,7 @@ int ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
}
/* TODO: free hunk if p->free_bufs && upstream done */
+
/* add the free shadow raw hunk to p->free_raw_hunks */
if (cl->hunk->type & NGX_HUNK_LAST_SHADOW) {
diff --git a/src/http/modules/ngx_http_log_handler.c b/src/http/modules/ngx_http_log_handler.c
deleted file mode 100644
index 759ac763e..000000000
--- a/src/http/modules/ngx_http_log_handler.c
+++ /dev/null
@@ -1,202 +0,0 @@
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-
-
-typedef struct {
- ngx_open_file_t *file;
-} ngx_http_log_conf_t;
-
-
-static void *ngx_http_log_create_conf(ngx_conf_t *cf);
-static char *ngx_http_log_merge_conf(ngx_conf_t *cf, void *parent, void *child);
-static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
- void *conf);
-
-static ngx_command_t ngx_http_log_commands[] = {
-
- {ngx_string("access_log"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_http_log_set_log,
- NGX_HTTP_LOC_CONF_OFFSET,
- 0,
- NULL},
-
- ngx_null_command
-};
-
-
-ngx_http_module_t ngx_http_log_module_ctx = {
- NULL, /* create main configuration */
- NULL, /* init main configuration */
-
- NULL, /* create server configuration */
- NULL, /* merge server configuration */
-
- ngx_http_log_create_conf, /* create location configration */
- ngx_http_log_merge_conf /* merge location configration */
-};
-
-
-ngx_module_t ngx_http_log_module = {
- NGX_MODULE,
- &ngx_http_log_module_ctx, /* module context */
- ngx_http_log_commands, /* module directives */
- NGX_HTTP_MODULE, /* module type */
- NULL, /* init module */
- NULL /* init child */
-};
-
-
-static ngx_str_t http_access_log = ngx_string("access.log");
-
-
-static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-
-
-int ngx_http_log_handler(ngx_http_request_t *r)
-{
- char *line, *p;
- size_t len;
- ngx_tm_t tm;
- ngx_http_log_conf_t *lcf;
-#if (WIN32)
- int written;
-#endif
-
- ngx_log_debug(r->connection->log, "log handler");
-
- lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
-
- /* 10:%con, 1:%pipe, 22:%date, 2:"%r", 3:%status, 20:%bytes, 2:%user-agent,
- 7*" ", 2/1: "\r\n" */
-#if (WIN32)
- len = 10 + 1 + 22 + 2 + 3 + 20 + 2 + 7 + 2;
-#else
- len = 10 + 1 + 22 + 2 + 3 + 20 + 2 + 7 + 1;
-#endif
-
- len += r->connection->addr_text.len;
- len += r->request_line.len;
- if (r->headers_in.user_agent) {
- len += r->headers_in.user_agent->value.len;
- }
-
- ngx_test_null(line, ngx_palloc(r->pool, len), NGX_ERROR);
- p = line;
-
- ngx_memcpy(p, r->connection->addr_text.data, r->connection->addr_text.len);
- p += r->connection->addr_text.len;
-
- *p++ = ' ';
-
- p += ngx_snprintf(p, 21, "%u", r->connection->number);
-
- *p++ = ' ';
-
- if (r->pipeline) {
- *p++ = 'p';
- } else {
- *p++ = '.';
- }
-
- *p++ = ' ';
-
- ngx_localtime(&tm);
-
- *p++ = '[';
- p += ngx_snprintf(p, 21, "%02d/%s/%d:%02d:%02d:%02d",
- tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
- tm.ngx_tm_year,
- tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
-
- *p++ = ']';
-
- *p++ = ' ';
-
- *p++ = '"';
- ngx_memcpy(p, r->request_line.data, r->request_line.len);
- p += r->request_line.len;
- *p++ = '"';
-
- *p++ = ' ';
-
- p += ngx_snprintf(p, 4, "%d", r->headers_out.status);
-
- *p++ = ' ';
-
- p += ngx_snprintf(p, 21, OFF_FMT, r->connection->sent);
-
- *p++ = ' ';
-
- *p++ = '"';
- if (r->headers_in.user_agent) {
- ngx_memcpy(p, r->headers_in.user_agent->value.data,
- r->headers_in.user_agent->value.len);
- p += r->headers_in.user_agent->value.len;
- }
- *p++ = '"';
-
-#if (WIN32)
-
- *p++ = CR; *p++ = LF;
- WriteFile(lcf->file->fd, line, p - line, &written, NULL);
-
-#else
-
- *p++ = LF;
- write(lcf->file->fd, line, p - line);
-
-#endif
-
-
- return NGX_OK;
-}
-
-
-static void *ngx_http_log_create_conf(ngx_conf_t *cf)
-{
- ngx_http_log_conf_t *conf;
-
- ngx_test_null(conf, ngx_pcalloc(cf->pool, sizeof(ngx_http_log_conf_t)),
- NGX_CONF_ERROR);
-
- return conf;
-}
-
-
-static char *ngx_http_log_merge_conf(ngx_conf_t *cf, void *parent, void *child)
-{
- ngx_http_log_conf_t *prev = parent;
- ngx_http_log_conf_t *conf = child;
-
- if (conf->file == NULL) {
- if (prev->file) {
- conf->file = prev->file;
- } else {
- ngx_test_null(conf->file,
- ngx_conf_open_file(cf->cycle, &http_access_log),
- NGX_CONF_ERROR);
- }
- }
-
- return NGX_CONF_OK;
-}
-
-
-static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
- void *conf)
-{
- ngx_http_log_conf_t *lcf = conf;
-
- ngx_str_t *value;
-
- value = cf->args->elts;
-
- ngx_test_null(lcf->file, ngx_conf_open_file(cf->cycle, &value[1]),
- NGX_CONF_ERROR);
-
- return NGX_CONF_OK;
-}
diff --git a/src/http/modules/ngx_http_log_handler.h b/src/http/modules/ngx_http_log_handler.h
deleted file mode 100644
index 2bda1f0d9..000000000
--- a/src/http/modules/ngx_http_log_handler.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef _NGX_HTTP_LOG_HANDLER_H_INCLUDED_
-#define _NGX_HTTP_LOG_HANDLER_H_INCLUDED_
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-
-
-typedef struct {
- int dummy;
-} ngx_http_log_conf_t;
-
-
-typedef enum {
-
- NGX_HTTP_LOG_HANDLER = 0,
-
-#if 0
- /* the ngx_str_t field of the request */
- NGX_HTTP_LOG_REQUEST_STR_FIELD,
-
- /* the ngx_str_t field of the r->headers_in */
- NGX_HTTP_LOG_REQUEST_HEADER_IN_FIELD,
-
- /* the ngx_str_t field of the r->headers_out */
- NGX_HTTP_LOG_REQUEST_HEADER_OUT_FIELD,
-#endif
-
-} ngx_http_log_code_e;
-
-
-typedef struct {
- int type;
- int size;
- char *(*handler) (ngx_http_request_t *r, char *p);
- int offset;
-} ngx_http_log_code_t;
-
-
-#endif /* _NGX_HTTP_LOG_HANDLER_H_INCLUDED_ */
diff --git a/src/http/modules/ngx_http_static_handler.c b/src/http/modules/ngx_http_static_handler.c
index ad2669be6..9849dbf34 100644
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -158,22 +158,6 @@ ngx_log_debug(r->connection->log, "FILE: %d" _ r->file.fd);
r->file.info_valid = 1;
}
-#if !(WIN32) /* the not regular files are probably Unix specific */
-
- if (!ngx_is_file(r->file.info)) {
- ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
- "%s is not a regular file", r->file.name.data);
-
- if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
- ngx_close_file_n " %s failed", r->file.name.data);
-
- return NGX_HTTP_NOT_FOUND;
- }
-
-#endif
-#endif
-
if (ngx_is_dir(r->file.info)) {
ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->file.name.data);
@@ -203,6 +187,22 @@ ngx_log_debug(r->connection->log, "HTTP DIR: '%s'" _ r->file.name.data);
return NGX_HTTP_MOVED_PERMANENTLY;
}
+#if !(WIN32) /* the not regular files are probably Unix specific */
+
+ if (!ngx_is_file(r->file.info)) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ "%s is not a regular file", r->file.name.data);
+
+ if (ngx_close_file(r->file.fd) == NGX_FILE_ERROR)
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+ ngx_close_file_n " %s failed", r->file.name.data);
+
+ return NGX_HTTP_NOT_FOUND;
+ }
+
+#endif
+#endif
+
r->content_handler = ngx_http_static_handler;
return NGX_OK;
diff --git a/src/http/modules/proxy/ngx_http_proxy_cache.c b/src/http/modules/proxy/ngx_http_proxy_cache.c
index 0bc7c6159..0f56686b8 100644
--- a/src/http/modules/proxy/ngx_http_proxy_cache.c
+++ b/src/http/modules/proxy/ngx_http_proxy_cache.c
@@ -5,12 +5,14 @@
#include <ngx_http_proxy_handler.h>
+static int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p,
+ int rc);
static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p);
+static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p);
int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p)
{
- int rc;
char *last;
ngx_http_request_t *r;
ngx_http_proxy_cache_t *c;
@@ -54,44 +56,69 @@ int ngx_http_proxy_get_cached_response(ngx_http_proxy_ctx_t *p)
c->ctx.buf = p->header_in;
- rc = ngx_http_cache_get_file(r, &c->ctx);
+ return ngx_http_proxy_process_cached_response(p,
+ ngx_http_cache_get_file(r, &c->ctx));
+}
- switch (rc) {
- case NGX_HTTP_CACHE_STALE:
- p->stale = 1;
- p->state->cache = NGX_HTTP_PROXY_CACHE_EXPR;
- break;
- case NGX_HTTP_CACHE_AGED:
- p->stale = 1;
- p->state->cache = NGX_HTTP_PROXY_CACHE_AGED;
- break;
+static int ngx_http_proxy_process_cached_response(ngx_http_proxy_ctx_t *p,
+ int rc)
+{
+ if (rc == NGX_OK) {
+ p->state->cache_state = NGX_HTTP_PROXY_CACHE_HIT;
+ p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
- case NGX_OK:
- p->state->cache = NGX_HTTP_PROXY_CACHE_HIT;
- break;
+ if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
- default:
- p->state->cache = NGX_HTTP_PROXY_CACHE_MISS;
+ p->valid_header_in = 1;
+
+ return ngx_http_proxy_send_cached_response(p);
}
- if (rc == NGX_OK
- || rc == NGX_HTTP_CACHE_STALE
- || rc == NGX_HTTP_CACHE_AGED)
- {
- p->header_in->pos = p->header_in->start + c->ctx.header_size;
+ if (rc == NGX_HTTP_CACHE_STALE) {
+ p->state->cache_state = NGX_HTTP_PROXY_CACHE_EXPR;
+
+ } else if (rc == NGX_HTTP_CACHE_AGED) {
+ p->state->cache_state = NGX_HTTP_PROXY_CACHE_AGED;
+ }
+
+ if (rc == NGX_HTTP_CACHE_STALE || rc == NGX_HTTP_CACHE_AGED) {
+ p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
+
if (ngx_http_proxy_process_cached_header(p) == NGX_ERROR) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- p->header_in->pos = p->header_in->start + c->ctx.header_size;
+
+ p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
p->header_in->last = p->header_in->pos;
+ p->stale = 1;
+ p->valid_header_in = 1;
+
} else if (rc == NGX_DECLINED) {
- p->header_in->pos = p->header_in->start + c->ctx.header_size;
+ p->state->cache_state = NGX_HTTP_PROXY_CACHE_MISS;
+ p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
p->header_in->last = p->header_in->pos;
}
- return rc;
+ if (p->lcf->busy_lock) {
+ p->try_busy_lock = 1;
+
+ p->header_in->pos = p->header_in->start;
+ p->header_in->last = p->header_in->start;
+
+ p->busy_lock.time = 0;
+ p->busy_lock.event = p->request->connection->read;
+ p->busy_lock.event_handler = ngx_http_proxy_busy_lock_handler;
+ p->busy_lock.md5 = p->cache->ctx.md5;
+
+ ngx_http_proxy_cache_busy_lock(p);
+ return NGX_DONE;
+ }
+
+ return ngx_http_proxy_request_upstream(p);
}
@@ -141,6 +168,7 @@ static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p)
ngx_log_debug(r->connection->log, "http cache status %d '%s'" _
c->status _ c->status_line.data);
+ /* TODO: ngx_init_table */
c->headers_in.headers = ngx_create_table(r->pool, 20);
for ( ;; ) {
@@ -216,28 +244,109 @@ static int ngx_http_proxy_process_cached_header(ngx_http_proxy_ctx_t *p)
}
-#if 0
-
-static void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p)
+void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p)
{
- rc = ngx_http_busy_lock(p->lcf->busy_lock, p->cache->ctx.md5);
+ int rc, ft_type;
+
+ rc = ngx_http_busy_lock_cachable(p->lcf->busy_lock, &p->busy_lock,
+ p->try_busy_lock);
if (rc == NGX_OK) {
- ngx_http_proxy_request_upstream(p);
+ if (p->try_busy_lock) {
+ p->busy_locked = 1;
+ p->header_in->pos = p->header_in->start + p->cache->ctx.header_size;
+ p->header_in->last = p->header_in->pos;
+
+ ngx_http_proxy_request_upstream(p);
+ return;
+ }
+
+ ngx_http_proxy_cache_look_complete_request(p);
+ return;
}
- if (rc == NGX_AGAIN) {
- if (p->busy_lock_time) {
- ngx_add_timer(p->request->connection->read, 1000);
+ p->try_busy_lock = 0;
+
+ if (p->cache->ctx.file.fd != NGX_INVALID_FILE
+ && !p->cache->ctx.file.info_valid)
+ {
+ if (ngx_stat_fd(p->cache->ctx.file.fd, &p->cache->ctx.file.info)
+ == NGX_FILE_ERROR)
+ {
+ ngx_log_error(NGX_LOG_CRIT, p->request->connection->log, ngx_errno,
+ ngx_stat_fd_n " \"%s\" failed",
+ p->cache->ctx.file.name.data);
+ ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
+
+ p->cache->ctx.file.info_valid = 1;
}
- rc == NGX_ERROR
- check waitn
+
+ if (rc == NGX_AGAIN) {
+ return;
+ }
+
+ if (rc == NGX_DONE) {
+ ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK;
+
+ } else {
+ /* rc == NGX_ERROR */
+ ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING;
+ }
+
+ if (p->stale && (p->lcf->use_stale & ft_type)) {
+ ngx_http_proxy_finalize_request(p,
+ ngx_http_proxy_send_cached_response(p));
+ return;
+ }
+
+ ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE);
}
-#endif
+
+static void ngx_http_proxy_cache_look_complete_request(ngx_http_proxy_ctx_t *p)
+{
+ int rc;
+ ngx_http_cache_ctx_t *ctx;
+
+ if (!(ctx = ngx_pcalloc(p->request->pool, sizeof(ngx_http_cache_ctx_t)))) {
+ ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ *ctx = p->cache->ctx;
+
+ rc = ngx_http_cache_open_file(p->request, ctx,
+ ngx_file_uniq(p->cache->ctx.file.info));
+
+ if (rc == NGX_HTTP_CACHE_THE_SAME) {
+ p->try_busy_lock = 1;
+ p->busy_lock.time = 0;
+ ngx_http_proxy_cache_busy_lock(p);
+ return;
+ }
+
+ngx_log_debug(p->request->connection->log, "OLD: %d, NEW: %d" _
+ p->cache->ctx.file.fd _ ctx->file.fd);
+
+ if (p->cache->ctx.file.fd != NGX_INVALID_FILE) {
+ if (ngx_close_file(p->cache->ctx.file.fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, p->request->connection->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed",
+ p->cache->ctx.file.name.data);
+ }
+ }
+
+ p->cache->ctx = *ctx;
+
+ p->status = 0;
+ p->status_count = 0;
+
+ ngx_http_proxy_finalize_request(p,
+ ngx_http_proxy_process_cached_response(p, rc));
+}
int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p)
@@ -435,8 +544,8 @@ int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p)
/* FIXME: time_t == int_64_t, we can use fpu */
p->state->reason = NGX_HTTP_PROXY_CACHE_LMF;
- p->cache->ctx.expires = ngx_time()
- + (((int64_t) (date - last_modified)) * p->lcf->lm_factor) / 100;
+ p->cache->ctx.expires = (time_t) (ngx_time()
+ + (((int64_t) (date - last_modified)) * p->lcf->lm_factor) / 100);
return 1;
}
@@ -460,6 +569,9 @@ int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p)
ep = p->upstream->event_pipe;
+ngx_log_debug(p->request->connection->log, "LEN: " OFF_FMT ", " OFF_FMT _
+ p->cache->ctx.length _ ep->read_length);
+
if (p->cache->ctx.length == -1) {
/* TODO: test rc */
ngx_write_file(&ep->temp_file->file,
diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.c b/src/http/modules/proxy/ngx_http_proxy_handler.c
index a28495668..4a48250e3 100644
--- a/src/http/modules/proxy/ngx_http_proxy_handler.c
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.c
@@ -132,7 +132,7 @@ static ngx_command_t ngx_http_proxy_commands[] = {
{ ngx_string("proxy_busy_lock"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3,
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13,
ngx_http_set_busy_lock_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, busy_lock),
@@ -240,9 +240,31 @@ ngx_http_header_t ngx_http_proxy_headers_in[] = {
};
+static ngx_str_t cache_states[] = {
+ ngx_string("PASS"),
+ ngx_string("BYPASS"),
+ ngx_string("AUTH"),
+ ngx_string("PGNC"),
+ ngx_string("MISS"),
+ ngx_string("EXPR"),
+ ngx_string("AGED"),
+ ngx_string("HIT")
+};
+
+
+static ngx_str_t cache_reason[] = {
+ ngx_string("BPS"),
+ ngx_string("XAE"),
+ ngx_string("CTL"),
+ ngx_string("EXP"),
+ ngx_string("MVD"),
+ ngx_string("LMF"),
+ ngx_string("PDE")
+};
+
+
static int ngx_http_proxy_handler(ngx_http_request_t *r)
{
- int rc;
ngx_http_proxy_ctx_t *p;
ngx_http_create_ctx(r, p, ngx_http_proxy_module,
@@ -269,16 +291,16 @@ static int ngx_http_proxy_handler(ngx_http_request_t *r)
if (!p->lcf->cache
|| (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD))
{
- p->state->cache = NGX_HTTP_PROXY_CACHE_PASS;
+ p->state->cache_state = NGX_HTTP_PROXY_CACHE_PASS;
} else if (r->bypass_cache) {
- p->state->cache = NGX_HTTP_PROXY_CACHE_BYPASS;
+ p->state->cache_state = NGX_HTTP_PROXY_CACHE_BYPASS;
} else if (r->headers_in.authorization) {
- p->state->cache = NGX_HTTP_PROXY_CACHE_AUTH;
+ p->state->cache_state = NGX_HTTP_PROXY_CACHE_AUTH;
} else if (r->no_cache) {
- p->state->cache = NGX_HTTP_PROXY_CACHE_PGNC;
+ p->state->cache_state = NGX_HTTP_PROXY_CACHE_PGNC;
p->cachable = 1;
} else {
@@ -286,25 +308,72 @@ static int ngx_http_proxy_handler(ngx_http_request_t *r)
}
- if (p->state->cache) {
+ if (p->state->cache_state != 0) {
return ngx_http_proxy_request_upstream(p);
}
- rc = ngx_http_proxy_get_cached_response(p);
+ return ngx_http_proxy_get_cached_response(p);
+}
+
- if (rc == NGX_DONE || rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
- return rc;
+void ngx_http_proxy_busy_lock_handler(ngx_event_t *rev)
+{
+ ngx_connection_t *c;
+ ngx_http_request_t *r;
+ ngx_http_proxy_ctx_t *p;
+
+ ngx_log_debug(rev->log, "busy lock");
+
+ c = rev->data;
+ r = c->data;
+ p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+ p->action = "waiting upstream in busy lock";
+
+ if (rev->timedout) {
+ rev->timedout = 0;
+ p->busy_lock.time++;
+ p->state->bl_time = p->busy_lock.time;
+ if (p->state->cache_state < NGX_HTTP_PROXY_CACHE_MISS) {
+ ngx_http_proxy_upstream_busy_lock(p);
+
+ } else {
+ ngx_http_proxy_cache_busy_lock(p);
+ }
+
+ return;
}
- p->valid_header_in = 1;
+ ngx_log_debug(rev->log, "client sent while busy lock");
+
+ /*
+ * TODO: kevent() notify about error, otherwise we need to
+ * call ngx_peek(): recv(MGS_PEEK) to get errno. THINK about aio
+ * if there's no error we need to disable event.
+ */
- if (rc == NGX_OK) {
- return ngx_http_proxy_send_cached_response(p);
+#if (HAVE_KQUEUE)
+
+ if ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) && rev->kq_eof) {
+ p->lcf->busy_lock->waiting--;
+
+ ngx_del_timer(rev);
+
+ ngx_log_error(NGX_LOG_ERR, c->log, rev->kq_errno,
+ "client() closed connection");
+
+ if (ngx_del_event(rev, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) {
+ ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ /* we have not HTTP code for the case when a client cancels a request */
+
+ ngx_http_proxy_finalize_request(p, 0);
+ return;
}
- /* rc == NGX_DECLINED || NGX_HTTP_CACHE_STALE || NGX_HTTP_CACHE_AGED */
+#endif
- return ngx_http_proxy_request_upstream(p);
}
@@ -313,7 +382,7 @@ void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc)
ngx_log_debug(p->request->connection->log,
"finalize http proxy request");
- if (p->upstream->peer.connection) {
+ if (p->upstream && p->upstream->peer.connection) {
ngx_http_proxy_close_connection(p);
}
@@ -323,8 +392,10 @@ void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc)
rc = 0;
}
- p->request->connection->log->data = p->saved_ctx;
- p->request->connection->log->handler = p->saved_handler;
+ if (p->saved_ctx) {
+ p->request->connection->log->data = p->saved_ctx;
+ p->request->connection->log->handler = p->saved_handler;
+ }
ngx_http_finalize_request(p->request, rc);
}
@@ -338,7 +409,7 @@ void ngx_http_proxy_close_connection(ngx_http_proxy_ctx_t *p)
p->upstream->peer.connection = NULL;
if (p->lcf->busy_lock) {
- p->lcf->busy_lock->conn_n--;
+ p->lcf->busy_lock->busy--;
}
ngx_log_debug(c->log, "proxy close connection: %d" _ c->fd);
@@ -382,6 +453,12 @@ void ngx_http_proxy_close_connection(ngx_http_proxy_ctx_t *p)
}
+size_t ngx_http_proxy_log_state(void *data, char *buf, size_t len)
+{
+ return 0;
+}
+
+
size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len)
{
ngx_http_proxy_ctx_t *p = data;
@@ -513,21 +590,21 @@ static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
conf->busy_lock = prev->busy_lock;
}
- if (conf->busy_lock && conf->cache && conf->busy_lock->busy == NULL) {
+ if (conf->busy_lock && conf->cache && conf->busy_lock->md5 == NULL) {
- /* ngx_alloc_shared() */
- conf->busy_lock->busy_mask =
- ngx_palloc(cf->pool, (conf->busy_lock->max_conn + 7) / 8);
- if (conf->busy_lock->busy_mask == NULL) {
+ /* ngx_calloc_shared() */
+ conf->busy_lock->md5_mask =
+ ngx_pcalloc(cf->pool, (conf->busy_lock->max_busy + 7) / 8);
+ if (conf->busy_lock->md5_mask == NULL) {
return NGX_CONF_ERROR;
}
/* 16 bytes are 128 bits of the md5 */
/* ngx_alloc_shared() */
- conf->busy_lock->busy = ngx_palloc(cf->pool,
- 16 * conf->busy_lock->max_conn);
- if (conf->busy_lock->busy == NULL) {
+ conf->busy_lock->md5 = ngx_palloc(cf->pool,
+ 16 * conf->busy_lock->max_busy);
+ if (conf->busy_lock->md5 == NULL) {
return NGX_CONF_ERROR;
}
}
diff --git a/src/http/modules/proxy/ngx_http_proxy_handler.h b/src/http/modules/proxy/ngx_http_proxy_handler.h
index 919a0afc3..138a778f0 100644
--- a/src/http/modules/proxy/ngx_http_proxy_handler.h
+++ b/src/http/modules/proxy/ngx_http_proxy_handler.h
@@ -80,10 +80,24 @@ typedef struct {
} ngx_http_proxy_loc_conf_t;
+/*
+ * "EXPR/10/5/- 200/EXP/60 4"
+ * "MISS/-/-/B 503/-/- -"
+ * "EXPR/10/20/SB HIT/-/- -"
+ * "EXPR/10/15/NB HIT/-/- -"
+ */
+
typedef struct {
- ngx_http_proxy_state_e cache;
- ngx_http_proxy_reason_e reason;
+ ngx_http_proxy_state_e cache_state;
+ time_t expired;
+ time_t bl_time;
+ int bl_state;
+
int status;
+ ngx_http_proxy_reason_e reason;
+ time_t time;
+ time_t expires;
+
ngx_str_t *peer;
} ngx_http_proxy_state_t;
@@ -140,12 +154,14 @@ struct ngx_http_proxy_ctx_s {
ngx_hunk_t *header_in;
- time_t busy_lock_time;
+ ngx_http_busy_lock_ctx_t busy_lock;
unsigned accel:1;
unsigned cachable:1;
unsigned stale:1;
+ unsigned try_busy_lock:1;
+ unsigned busy_locked:1;
unsigned valid_header_in:1;
unsigned request_sent:1;
@@ -187,6 +203,10 @@ int ngx_http_proxy_send_cached_response(ngx_http_proxy_ctx_t *p);
int ngx_http_proxy_is_cachable(ngx_http_proxy_ctx_t *p);
int ngx_http_proxy_update_cache(ngx_http_proxy_ctx_t *p);
+void ngx_http_proxy_busy_lock_handler(ngx_event_t *rev);
+void ngx_http_proxy_cache_busy_lock(ngx_http_proxy_ctx_t *p);
+void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p);
+
size_t ngx_http_proxy_log_error(void *data, char *buf, size_t len);
void ngx_http_proxy_finalize_request(ngx_http_proxy_ctx_t *p, int rc);
void ngx_http_proxy_close_connection(ngx_http_proxy_ctx_t *p);
diff --git a/src/http/modules/proxy/ngx_http_proxy_upstream.c b/src/http/modules/proxy/ngx_http_proxy_upstream.c
index c66c16418..0ec2fee48 100644
--- a/src/http/modules/proxy/ngx_http_proxy_upstream.c
+++ b/src/http/modules/proxy/ngx_http_proxy_upstream.c
@@ -11,8 +11,6 @@
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_reinit_upstream(ngx_http_proxy_ctx_t *p);
-static void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p);
-static void ngx_http_proxy_upstream_busy_lock_handler(ngx_event_t *rev);
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);
static void ngx_http_proxy_send_request_handler(ngx_event_t *wev);
@@ -266,7 +264,7 @@ ngx_log_debug(r->connection->log, "timer_set: %d" _
wctx->pool = r->pool;
- if (p->lcf->busy_lock) {
+ if (p->lcf->busy_lock && !p->busy_locked) {
ngx_http_proxy_upstream_busy_lock(p);
} else {
ngx_http_proxy_connect(p);
@@ -312,41 +310,31 @@ static void ngx_http_proxy_reinit_upstream(ngx_http_proxy_ctx_t *p)
}
-static void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p)
+void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p)
{
- int ft_type;
+ int rc, ft_type;
- if (p->lcf->busy_lock->conn_n < p->lcf->busy_lock->max_conn) {
- p->lcf->busy_lock->conn_n++;
+ if (p->busy_lock.time == 0) {
+ p->busy_lock.event = p->request->connection->read;
+ p->busy_lock.event_handler = ngx_http_proxy_busy_lock_handler;
+ }
- if (p->busy_lock_time) {
- p->busy_lock_time = 0;
- p->lcf->busy_lock->waiting_n--;
- }
+ rc = ngx_http_busy_lock(p->lcf->busy_lock, &p->busy_lock);
- ngx_http_proxy_connect(p);
+ if (rc == NGX_AGAIN) {
return;
}
- if (p->busy_lock_time) {
- if (p->busy_lock_time < p->lcf->busy_lock->timeout) {
- ngx_add_timer(p->request->connection->read, 1000);
- return;
- }
+ if (rc == NGX_OK) {
+ ngx_http_proxy_connect(p);
+ return;
+ }
- p->lcf->busy_lock->waiting_n--;
+ if (rc == NGX_DONE) {
ft_type = NGX_HTTP_PROXY_FT_BUSY_LOCK;
} else {
- if (p->lcf->busy_lock->waiting_n < p->lcf->busy_lock->max_waiting) {
- p->lcf->busy_lock->waiting_n++;
- ngx_add_timer(p->request->connection->read, 1000);
- p->request->connection->read->event_handler =
- ngx_http_proxy_upstream_busy_lock_handler;
- /* TODO: ngx_handle_level_read_event() */
- return;
- }
-
+ /* rc == NGX_ERROR */
ft_type = NGX_HTTP_PROXY_FT_MAX_WAITING;
}
@@ -357,61 +345,6 @@ static void ngx_http_proxy_upstream_busy_lock(ngx_http_proxy_ctx_t *p)
}
ngx_http_proxy_finalize_request(p, NGX_HTTP_SERVICE_UNAVAILABLE);
- return;
-}
-
-
-static void ngx_http_proxy_upstream_busy_lock_handler(ngx_event_t *rev)
-{
- ngx_connection_t *c;
- ngx_http_request_t *r;
- ngx_http_proxy_ctx_t *p;
-
- ngx_log_debug(rev->log, "busy lock");
-
- c = rev->data;
- r = c->data;
- p = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
- p->action = "waiting upstream in busy lock";
-
- if (rev->timedout) {
- rev->timedout = 0;
- p->busy_lock_time++;
- ngx_http_proxy_upstream_busy_lock(p);
- return;
- }
-
- ngx_log_debug(rev->log, "client sent while busy lock");
-
- /*
- * TODO: kevent() notify about error, otherwise we need to
- * call ngx_peek(): recv(MGS_PEEK) to get errno. THINK about aio
- * if there's no error we need to disable event.
- */
-
-#if (HAVE_KQUEUE)
-
- if ((ngx_event_flags & NGX_HAVE_KQUEUE_EVENT) && rev->kq_eof) {
- p->lcf->busy_lock->waiting_n--;
-
- ngx_del_timer(rev);
-
- ngx_log_error(NGX_LOG_ERR, c->log, rev->kq_errno,
- "client() closed connection");
-
- if (ngx_del_event(rev, NGX_READ_EVENT, NGX_CLOSE_EVENT) == NGX_ERROR) {
- ngx_http_proxy_finalize_request(p, NGX_HTTP_INTERNAL_SERVER_ERROR);
- return;
- }
-
- /* we have not HTTP code for the case when a client cancels a request */
-
- ngx_http_proxy_finalize_request(p, 0);
- return;
- }
-
-#endif
-
}
@@ -724,6 +657,16 @@ static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
}
}
+ if (p->status == NGX_HTTP_NOT_FOUND
+ && p->upstream->peer.tries > 1
+ && p->lcf->next_upstream & NGX_HTTP_PROXY_FT_HTTP_404)
+ {
+ ngx_http_proxy_next_upstream(p, NGX_HTTP_PROXY_FT_HTTP_404);
+ return;
+ }
+
+ /* TODO: "proxy_error_page" */
+
p->upstream->status_line.len = p->status_end - p->status_start;
p->upstream->status_line.data = ngx_palloc(p->request->pool,
p->upstream->status_line.len + 1);
@@ -740,6 +683,7 @@ static void ngx_http_proxy_process_upstream_status_line(ngx_event_t *rev)
if (p->upstream->headers_in.headers) {
p->upstream->headers_in.headers->nelts = 0;
} else {
+ /* TODO: ngx_init_table */
p->upstream->headers_in.headers = ngx_create_table(p->request->pool,
20);
}
@@ -956,8 +900,8 @@ static void ngx_http_proxy_send_response(ngx_http_proxy_ctx_t *p)
header->expires = p->cache->ctx.expires;
header->last_modified = p->cache->ctx.last_modified;
header->date = p->cache->ctx.date;
- /* TODO: r->headers_out.content_length_n == -1 */
header->length = r->headers_out.content_length_n;
+ p->cache->ctx.length = r->headers_out.content_length_n;
header->key_len = p->cache->ctx.key.len;
ngx_memcpy(&header->key, p->cache->ctx.key.data, header->key_len);
@@ -1105,18 +1049,24 @@ static void ngx_http_proxy_process_body(ngx_event_t *ev)
if (p->upstream->peer.connection) {
if (ep->upstream_done && p->cachable) {
if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
+ ngx_http_busy_unlock_cachable(p->lcf->busy_lock, &p->busy_lock);
ngx_http_proxy_finalize_request(p, 0);
return;
}
+ ngx_http_busy_unlock_cachable(p->lcf->busy_lock, &p->busy_lock);
+
} else if (ep->upstream_eof && p->cachable) {
/* TODO: check length & update cache */
if (ngx_http_proxy_update_cache(p) == NGX_ERROR) {
+ ngx_http_busy_unlock_cachable(p->lcf->busy_lock, &p->busy_lock);
ngx_http_proxy_finalize_request(p, 0);
return;
}
+
+ ngx_http_busy_unlock_cachable(p->lcf->busy_lock, &p->busy_lock);
}
if (ep->upstream_done || ep->upstream_eof || ep->upstream_error) {
@@ -1206,7 +1156,7 @@ ngx_log_debug(p->request->connection->log, "next upstream: %d" _ ft_type);
}
}
- if (p->lcf->busy_lock) {
+ if (p->lcf->busy_lock && !p->busy_locked) {
ngx_http_proxy_upstream_busy_lock(p);
} else {
ngx_http_proxy_connect(p);
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index c2e917815..5f561f713 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -123,7 +123,6 @@ static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
}
-
/* parse inside the http{} block */
pcf = *cf;
@@ -131,14 +130,16 @@ static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
cf->module_type = NGX_HTTP_MODULE;
cf->cmd_type = NGX_HTTP_MAIN_CONF;
rv = ngx_conf_parse(cf, NULL);
- *cf = pcf;
- if (rv != NGX_CONF_OK)
+ if (rv != NGX_CONF_OK) {
+ *cf = pcf;
return rv;
+ }
-
- /* init http{} main_conf's, merge the server{}s' srv_conf's
- and its location{}s' loc_conf's */
+ /*
+ * init http{} main_conf's, merge the server{}s' srv_conf's
+ * and its location{}s' loc_conf's
+ */
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
cscfp = cmcf->servers.elts;
@@ -556,5 +557,6 @@ ngx_log_debug(cf->log, "%s %08x" _ s_name[n].name.data _
}
/**/
+ *cf = pcf;
return NGX_CONF_OK;
}
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index 3df2188cf..26dde7fca 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -9,6 +9,7 @@
#include <ngx_http_cache.h>
#include <ngx_http_busy_lock.h>
#include <ngx_http_filter.h>
+#include <ngx_http_log_handler.h>
#include <ngx_http_core_module.h>
diff --git a/src/http/ngx_http_busy_lock.c b/src/http/ngx_http_busy_lock.c
index 9431a3876..2ed66dc0b 100644
--- a/src/http/ngx_http_busy_lock.c
+++ b/src/http/ngx_http_busy_lock.c
@@ -4,42 +4,151 @@
#include <ngx_http.h>
-int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, u_char *md5)
+
+static int ngx_http_busy_lock_look_cachable(ngx_http_busy_lock_t *bl,
+ ngx_http_busy_lock_ctx_t *bc,
+ int lock);
+
+
+int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc)
{
- int i, b, busy, free;
+ if (bl->busy < bl->max_busy) {
+ bl->busy++;
+
+ if (bc->time) {
+ bc->time = 0;
+ bl->waiting--;
+ }
+
+ return NGX_OK;
+ }
+
+ if (bc->time) {
+ if (bc->time < bl->timeout) {
+ ngx_add_timer(bc->event, 1000);
+ return NGX_AGAIN;
+ }
+
+ bl->waiting--;
+ return NGX_DONE;
+
+ }
+
+ if (bl->timeout == 0) {
+ return NGX_DONE;
+ }
+
+ if (bl->waiting < bl->max_waiting) {
+ bl->waiting++;
+ ngx_add_timer(bc->event, 1000);
+ bc->event->event_handler = bc->event_handler;
+
+ /* TODO: ngx_handle_level_read_event() */
+
+ return NGX_AGAIN;
+ }
+
+ return NGX_ERROR;
+}
+
+
+int ngx_http_busy_lock_cachable(ngx_http_busy_lock_t *bl,
+ ngx_http_busy_lock_ctx_t *bc, int lock)
+{
+ int rc;
+
+ rc = ngx_http_busy_lock_look_cachable(bl, bc, lock);
+
+ngx_log_debug(bc->event->log, "BUSYLOCK: %d" _ rc);
+
+ if (rc == NGX_OK) { /* no the same request, there's free slot */
+ return NGX_OK;
+ }
+
+ if (rc == NGX_ERROR && !lock) { /* no the same request, no free slot */
+ return NGX_OK;
+ }
+
+ /* rc == NGX_AGAIN: the same request */
+
+ if (bc->time) {
+ if (bc->time < bl->timeout) {
+ ngx_add_timer(bc->event, 1000);
+ return NGX_AGAIN;
+ }
+
+ bl->waiting--;
+ return NGX_DONE;
+
+ }
+
+ if (bl->timeout == 0) {
+ return NGX_DONE;
+ }
+
+ if (bl->waiting < bl->max_waiting) {
+ bl->waiting++;
+ ngx_add_timer(bc->event, 1000);
+ bc->event->event_handler = bc->event_handler;
+
+ /* TODO: ngx_handle_level_read_event() */
+
+ return NGX_AGAIN;
+ }
+
+ return NGX_ERROR;
+}
+
+
+void ngx_http_busy_unlock_cachable(ngx_http_busy_lock_t *bl,
+ ngx_http_busy_lock_ctx_t *bc)
+{
+ bl->md5_mask[bc->slot / 8] &= ~(1 << (bc->slot & 7));
+ bl->cachable--;
+ bl->busy--;
+}
+
+
+static int ngx_http_busy_lock_look_cachable(ngx_http_busy_lock_t *bl,
+ ngx_http_busy_lock_ctx_t *bc,
+ int lock)
+{
+ int i, b, cachable, free;
u_int mask;
b = 0;
- busy = 0;
+ cachable = 0;
free = -1;
#if (NGX_SUPPRESS_WARN)
mask = 0;
#endif
- for (i = 0; i < bl->max_conn; i++) {
+ for (i = 0; i < bl->max_busy; i++) {
if ((b & 7) == 0) {
- mask = bl->busy_mask[i / 8];
+ mask = bl->md5_mask[i / 8];
}
if (mask & 1) {
- if (ngx_memcmp(&bl->busy[i * 16], md5, 16) == 0) {
+ if (ngx_memcmp(&bl->md5[i * 16], bc->md5, 16) == 0) {
return NGX_AGAIN;
}
- busy++;
+ cachable++;
} else if (free == -1) {
free = i;
}
- if (busy == bl->busy_n) {
- if (busy < bl->max_conn) {
+#if 1
+ if (cachable == bl->cachable) {
+ if (free == -1 && cachable < bl->max_busy) {
free = i + 1;
}
break;
}
+#endif
mask >>= 1;
b++;
@@ -49,11 +158,18 @@ int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, u_char *md5)
return NGX_ERROR;
}
- ngx_memcpy(&bl->busy[free * 16], md5, 16);
- bl->busy_mask[free / 8] |= free % 8;
+ if (lock) {
+ if (bl->busy == bl->max_busy) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(&bl->md5[free * 16], bc->md5, 16);
+ bl->md5_mask[free / 8] |= 1 << (free & 7);
+ bc->slot = free;
- bl->busy_n++;
- bl->conn_n++;
+ bl->cachable++;
+ bl->busy++;
+ }
return NGX_OK;
}
@@ -64,8 +180,8 @@ char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
{
char *p = conf;
- int i;
- ngx_str_t *value;
+ int i, dup, invalid;
+ ngx_str_t *value, line;
ngx_http_busy_lock_t *bl, **blp;
blp = (ngx_http_busy_lock_t **) (p + cmd->offset);
@@ -79,57 +195,86 @@ char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
}
*blp = bl;
+ dup = 0;
+ invalid = 0;
value = (ngx_str_t *) cf->args->elts;
- for (i = 1; i < 4; i++) {
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ if (value[i].data[1] != '=') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid value \"%s\"", value[i].data);
+ return NGX_CONF_ERROR;
+ }
- if (value[i].len > 2 && ngx_strncasecmp(value[i].data, "c:", 2) == 0) {
- if (bl->max_conn) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "duplicate \"%s\"", value[i].data);
- return NGX_CONF_ERROR;
+ switch (value[i].data[0]) {
+
+ case 'b':
+ if (bl->max_busy) {
+ dup = 1;
+ break;
}
- bl->max_conn = ngx_atoi(value[i].data + 2, value[i].len - 2);
- if (bl->max_conn == NGX_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid value \"%s\"", value[i].data);
- return NGX_CONF_ERROR;
+ bl->max_busy = ngx_atoi(value[i].data + 2, value[i].len - 2);
+ if (bl->max_busy == NGX_ERROR) {
+ invalid = 1;
+ break;
}
continue;
- }
- if (value[i].len > 2 && ngx_strncasecmp(value[i].data, "w:", 2) == 0) {
+ case 'w':
if (bl->max_waiting) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "duplicate \"%s\"", value[i].data);
- return NGX_CONF_ERROR;
+ dup = 1;
+ break;
}
bl->max_waiting = ngx_atoi(value[i].data + 2, value[i].len - 2);
if (bl->max_waiting == NGX_ERROR) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid value \"%s\"", value[i].data);
- return NGX_CONF_ERROR;
+ invalid = 1;
+ break;
+ }
+
+ continue;
+
+ case 't':
+ if (bl->timeout) {
+ dup = 1;
+ break;
+ }
+
+ line.len = value[i].len - 2;
+ line.data = value[i].data + 2;
+
+ bl->timeout = ngx_parse_time(&line, 1);
+ if (bl->timeout == NGX_ERROR) {
+ invalid = 1;
+ break;
}
continue;
+
+ default:
+ invalid = 1;
}
- if (bl->timeout) {
+ if (dup) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "duplicate timeout \"%s\"", value[i].data);
+ "duplicate value \"%s\"", value[i].data);
return NGX_CONF_ERROR;
}
- bl->timeout = ngx_parse_time(&value[1], 1);
- if (bl->timeout == NGX_ERROR) {
+ if (invalid) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid timeout \"%s\"", value[i].data);
+ "invalid value \"%s\"", value[i].data);
return NGX_CONF_ERROR;
}
}
+ if (bl->timeout == 0 && bl->max_waiting) {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "busy lock waiting is useless with zero timeout");
+ }
+
return NGX_CONF_OK;
}
diff --git a/src/http/ngx_http_busy_lock.h b/src/http/ngx_http_busy_lock.h
index 1ee95c93d..d36b9b741 100644
--- a/src/http/ngx_http_busy_lock.h
+++ b/src/http/ngx_http_busy_lock.h
@@ -4,19 +4,20 @@
#include <ngx_config.h>
#include <ngx_core.h>
+#include <ngx_event.h>
#include <ngx_http.h>
typedef struct {
- u_char *busy_mask;
- char *busy;
- int busy_n;
+ u_char *md5_mask;
+ char *md5;
+ int cachable;
- int waiting_n;
- int max_waiting;
+ int busy;
+ int max_busy;
- int conn_n;
- int max_conn;
+ int waiting;
+ int max_waiting;
time_t timeout;
@@ -25,7 +26,21 @@ typedef struct {
} ngx_http_busy_lock_t;
-int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, u_char *md5);
+typedef struct {
+ time_t time;
+ ngx_event_t *event;
+ void (*event_handler)(ngx_event_t *ev);
+ u_char *md5;
+ int slot;
+} ngx_http_busy_lock_ctx_t;
+
+
+int ngx_http_busy_lock(ngx_http_busy_lock_t *bl, ngx_http_busy_lock_ctx_t *bc);
+int ngx_http_busy_lock_cachable(ngx_http_busy_lock_t *bl,
+ ngx_http_busy_lock_ctx_t *bc, int lock);
+void ngx_http_busy_unlock_cachable(ngx_http_busy_lock_t *bl,
+ ngx_http_busy_lock_ctx_t *bc);
+
char *ngx_http_set_busy_lock_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
diff --git a/src/http/ngx_http_cache.c b/src/http/ngx_http_cache.c
index 6ae779ad0..580840623 100644
--- a/src/http/ngx_http_cache.c
+++ b/src/http/ngx_http_cache.c
@@ -8,10 +8,7 @@
int ngx_http_cache_get_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx)
{
- ssize_t n;
- MD5_CTX md5;
- ngx_err_t err;
- ngx_http_cache_header_t *h;
+ MD5_CTX md5;
ctx->header_size = sizeof(ngx_http_cache_header_t) + ctx->key.len + 1;
@@ -38,6 +35,19 @@ ngx_log_debug(r->connection->log, "FILE: %s" _ ctx->file.name.data);
/* TODO: look open files cache */
+ return ngx_http_cache_open_file(r, ctx, 0);
+}
+
+
+/* TODO: Win32 inode analogy */
+
+int ngx_http_cache_open_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx,
+ ngx_file_uniq_t uniq)
+{
+ ssize_t n;
+ ngx_err_t err;
+ ngx_http_cache_header_t *h;
+
ctx->file.fd = ngx_open_file(ctx->file.name.data,
NGX_FILE_RDONLY, NGX_FILE_OPEN);
@@ -53,6 +63,25 @@ ngx_log_debug(r->connection->log, "FILE: %s" _ ctx->file.name.data);
return NGX_ERROR;
}
+ if (uniq) {
+ if (ngx_stat_fd(ctx->file.fd, &ctx->file.info) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_stat_fd_n " \"%s\" failed", ctx->file.name.data);
+
+ return NGX_ERROR;
+ }
+
+ if (ngx_file_uniq(ctx->file.info) == uniq) {
+ if (ngx_close_file(ctx->file.fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed",
+ ctx->file.name.data);
+ }
+
+ return NGX_HTTP_CACHE_THE_SAME;
+ }
+ }
+
n = ngx_read_file(&ctx->file, ctx->buf->pos,
ctx->buf->end - ctx->buf->last, 0);
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
index 9efbade4e..67ca22398 100644
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -13,7 +13,7 @@ typedef struct {
time_t date;
off_t length;
size_t key_len;
- char key[0];
+ char key[1];
} ngx_http_cache_header_t;
@@ -46,11 +46,14 @@ typedef struct {
} ngx_http_cache_ctx_t;
-#define NGX_HTTP_CACHE_STALE 1
-#define NGX_HTTP_CACHE_AGED 2
+#define NGX_HTTP_CACHE_STALE 1
+#define NGX_HTTP_CACHE_AGED 2
+#define NGX_HTTP_CACHE_THE_SAME 3
int ngx_http_cache_get_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx);
+int ngx_http_cache_open_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx,
+ ngx_file_uniq_t uniq);
int ngx_http_cache_update_file(ngx_http_request_t *r,ngx_http_cache_ctx_t *ctx,
ngx_str_t *temp_file);
diff --git a/src/http/ngx_http_config.h b/src/http/ngx_http_config.h
index 9d200c448..d12dfca94 100644
--- a/src/http/ngx_http_config.h
+++ b/src/http/ngx_http_config.h
@@ -47,6 +47,8 @@ typedef struct {
#define ngx_http_get_module_srv_conf(r, module) r->srv_conf[module.ctx_index]
#define ngx_http_get_module_loc_conf(r, module) r->loc_conf[module.ctx_index]
+#define ngx_http_conf_module_main_conf(cf, module) \
+ ((ngx_http_conf_ctx_t *) cf->ctx)->main_conf[module.ctx_index]
extern int (*ngx_http_top_header_filter) (ngx_http_request_t *r);
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 6c50b6b32..d7b4fac2b 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -31,6 +31,7 @@ static char *ngx_set_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf);
static char *ngx_set_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_set_server_name(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_set_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static char *ngx_http_lowat_check(ngx_conf_t *cf, void *post, void *data);
@@ -192,6 +193,13 @@ static ngx_command_t ngx_http_core_commands[] = {
offsetof(ngx_http_core_loc_conf_t, msie_padding),
NULL},
+ {ngx_string("error_page"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
+ ngx_set_error_page,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL},
+
{ngx_string("error_log"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_set_error_log,
@@ -631,8 +639,8 @@ static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
char *rv;
ngx_str_t *location;
ngx_http_module_t *module;
- ngx_conf_t pcf;
- ngx_http_conf_ctx_t *ctx, *pctx;
+ ngx_conf_t pvcf;
+ ngx_http_conf_ctx_t *ctx, *pvctx;
ngx_http_core_srv_conf_t *cscf;
ngx_http_core_loc_conf_t *clcf, **clcfp;
@@ -640,9 +648,9 @@ static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)),
NGX_CONF_ERROR);
- pctx = (ngx_http_conf_ctx_t *) cf->ctx;
- ctx->main_conf = pctx->main_conf;
- ctx->srv_conf = pctx->srv_conf;
+ pvctx = (ngx_http_conf_ctx_t *) cf->ctx;
+ ctx->main_conf = pvctx->main_conf;
+ ctx->srv_conf = pvctx->srv_conf;
ngx_test_null(ctx->loc_conf,
ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module),
@@ -672,11 +680,11 @@ static char *ngx_location_block(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
ngx_test_null(clcfp, ngx_push_array(&cscf->locations), NGX_CONF_ERROR);
*clcfp = clcf;
- pcf = *cf;
+ pvcf = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_LOC_CONF;
rv = ngx_conf_parse(cf, NULL);
- *cf = pcf;
+ *cf = pvcf;
return rv;
}
@@ -856,6 +864,7 @@ static void *ngx_http_core_create_loc_conf(ngx_conf_t *cf)
lcf->default_type.len = 0;
lcf->default_type.data = NULL;
lcf->err_log = NULL;
+ lcf->error_pages = NULL;
*/
@@ -929,6 +938,10 @@ static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf,
}
}
+ if (conf->error_pages == NULL && prev->error_pages) {
+ conf->error_pages = prev->error_pages;
+ }
+
ngx_conf_merge_str_value(conf->default_type,
prev->default_type, "text/plain");
@@ -1061,6 +1074,47 @@ static char *ngx_set_server_name(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
+static char *ngx_set_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_core_loc_conf_t *lcf = conf;
+
+ int i;
+ ngx_str_t *value;
+ ngx_http_err_page_t *err;
+
+ if (lcf->error_pages == NULL) {
+ lcf->error_pages = ngx_create_array(cf->pool, 5,
+ sizeof(ngx_http_err_page_t));
+ if (lcf->error_pages == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ value = cf->args->elts;
+
+ for (i = 1; i < cf->args->nelts - 1; i++) {
+ ngx_test_null(err, ngx_push_array(lcf->error_pages), NGX_CONF_ERROR);
+ err->code = ngx_atoi(value[i].data, value[i].len);
+ if (err->code == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid value \"%s\"", value[i].data);
+ return NGX_CONF_ERROR;
+ }
+
+ if (err->code < 400 || err->code > 599) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "value \"%s\" must be between 400 and 599",
+ value[i].data);
+ return NGX_CONF_ERROR;
+ }
+
+ err->uri = value[cf->args->nelts - 1];
+ }
+
+ return NGX_CONF_OK;
+}
+
+
static char *ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
@@ -1079,10 +1133,10 @@ static char *ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
static char *ngx_http_lowat_check(ngx_conf_t *cf, void *post, void *data)
{
- int *np = data;
-
#if (HAVE_LOWAT_EVENT)
+ int *np = data;
+
if (*np >= ngx_freebsd_net_inet_tcp_sendspace) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"send_lowat\" must be less than %d "
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index 9fc16f86a..7bd7eeaa1 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -100,6 +100,12 @@ typedef struct {
typedef struct {
+ int code;
+ ngx_str_t uri;
+} ngx_http_err_page_t;
+
+
+typedef struct {
ngx_str_t name; /* location name */
void **loc_conf ; /* pointer to the modules' loc_conf */
@@ -120,6 +126,7 @@ typedef struct {
ngx_msec_t lingering_timeout; /* lingering_timeout */
int msie_padding; /* msie_padding */
+ ngx_array_t *error_pages; /* error_page */
ngx_log_t *err_log;
} ngx_http_core_loc_conf_t;
diff --git a/src/http/ngx_http_header_filter.c b/src/http/ngx_http_header_filter.c
index f85bd4575..3f56563d0 100644
--- a/src/http/ngx_http_header_filter.c
+++ b/src/http/ngx_http_header_filter.c
@@ -90,8 +90,9 @@ static ngx_str_t http_codes[] = {
static int ngx_http_header_filter(ngx_http_request_t *r)
{
int len, status, i;
+ char *p;
ngx_hunk_t *h;
- ngx_chain_t *ch;
+ ngx_chain_t *ln;
ngx_table_elt_t *header;
if (r->http_version < NGX_HTTP_VERSION_10) {
@@ -149,7 +150,7 @@ static int ngx_http_header_filter(ngx_http_request_t *r)
len += r->headers_out.date->key.len
+ r->headers_out.date->value.len + 2;
} else {
- len += sizeof("Date: Mon, 28 Sep 1970 00:00:00 GMT" CRLF) - 1;
+ len += sizeof("Date: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
}
if (r->headers_out.content_length == NULL) {
@@ -174,7 +175,7 @@ static int ngx_http_header_filter(ngx_http_request_t *r)
&& r->headers_out.location->value.data[0] == '/')
{
r->headers_out.location->key.len = 0;
- len += sizeof("Location: http://") - 1,
+ len += sizeof("Location: http://") - 1
+ r->server_name->len + r->headers_out.location->value.len + 2;
if (r->port != 80) {
@@ -187,7 +188,7 @@ static int ngx_http_header_filter(ngx_http_request_t *r)
+ r->headers_out.last_modified->value.len + 2;
} else if (r->headers_out.last_modified_time != -1) {
- len += sizeof("Last-Modified: Mon, 28 Sep 1970 00:00:00 GMT" CRLF) - 1;
+ len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
}
if (r->chunked) {
@@ -210,7 +211,9 @@ static int ngx_http_header_filter(ngx_http_request_t *r)
len += header[i].key.len + 2 + header[i].value.len + 2;
}
- ngx_test_null(h, ngx_create_temp_hunk(r->pool, len), NGX_ERROR);
+ if (!(h = ngx_create_temp_hunk(r->pool, len))) {
+ return NGX_ERROR;
+ }
/* "HTTP/1.x " */
h->last = ngx_cpymem(h->last, "HTTP/1.1 ", sizeof("HTTP/1.x ") - 1);
@@ -232,30 +235,70 @@ static int ngx_http_header_filter(ngx_http_request_t *r)
if (!(r->headers_out.date && r->headers_out.date->key.len)) {
h->last = ngx_cpymem(h->last, "Date: ", sizeof("Date: ") - 1);
- h->last += ngx_http_get_time(h->last, time(NULL));
+#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
+ p = h->last;
+#endif
+ h->last += ngx_http_get_time(h->last, ngx_time());
+
+#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
+ r->headers_out.date = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
+ if (r->headers_out.date == NULL) {
+ return NGX_ERROR;
+ }
+
+ r->headers_out.date->key.len = 0;
+ r->headers_out.date->key.data = NULL;
+ r->headers_out.date->value.len = h->last - p;
+ r->headers_out.date->value.data = p;
+#endif
+
*(h->last++) = CR; *(h->last++) = LF;
}
if (r->headers_out.content_length == NULL) {
if (r->headers_out.content_length_n >= 0) {
+#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
+ p = h->last + sizeof("Content-Length: ") - 1;
+#endif
h->last += ngx_snprintf(h->last, /* 2^64 */
sizeof("Content-Length: 18446744073709551616" CRLF),
"Content-Length: " OFF_FMT CRLF,
r->headers_out.content_length_n);
+
+#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
+ r->headers_out.content_length = ngx_palloc(r->pool,
+ sizeof(ngx_table_elt_t));
+ if (r->headers_out.content_length == NULL) {
+ return NGX_ERROR;
+ }
+
+ r->headers_out.content_length->key.len = 0;
+ r->headers_out.content_length->key.data = NULL;
+ r->headers_out.content_length->value.len = h->last - p - 2;
+ r->headers_out.content_length->value.data = p;
+#endif
}
}
if (r->headers_out.content_type && r->headers_out.content_type->value.len) {
h->last = ngx_cpymem(h->last, "Content-Type: ",
sizeof("Content-Type: ") - 1);
+#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
+ p = h->last;
+#endif
h->last = ngx_cpymem(h->last, r->headers_out.content_type->value.data,
r->headers_out.content_type->value.len);
+#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
if (r->headers_out.charset.len) {
h->last = ngx_cpymem(h->last, "; charset=",
sizeof("; charset=") - 1);
h->last = ngx_cpymem(h->last, r->headers_out.charset.data,
r->headers_out.charset.len);
+
+ r->headers_out.content_type->value.len = h->last - p;
+ r->headers_out.content_type->value.data = p;
+#endif
}
*(h->last++) = CR; *(h->last++) = LF;
@@ -265,6 +308,7 @@ static int ngx_http_header_filter(ngx_http_request_t *r)
&& r->headers_out.location->value.len
&& r->headers_out.location->value.data[0] == '/')
{
+ p = h->last + sizeof("Location: ") - 1;
h->last = ngx_cpymem(h->last, "Location: http://",
sizeof("Location: http://") - 1);
h->last = ngx_cpymem(h->last, r->server_name->data,
@@ -277,6 +321,9 @@ static int ngx_http_header_filter(ngx_http_request_t *r)
h->last = ngx_cpymem(h->last, r->headers_out.location->value.data,
r->headers_out.location->value.len);
+ r->headers_out.location->value.len = h->last - p;
+ r->headers_out.location->value.data = p;
+
*(h->last++) = CR; *(h->last++) = LF;
}
@@ -285,8 +332,25 @@ static int ngx_http_header_filter(ngx_http_request_t *r)
{
h->last = ngx_cpymem(h->last, "Last-Modified: ",
sizeof("Last-Modified: ") - 1);
+#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
+ p = h->last;
+#endif
h->last += ngx_http_get_time(h->last,
- r->headers_out.last_modified_time);
+ r->headers_out.last_modified_time);
+
+#if (NGX_HTTP_LOG_ALL_HEADERS_OUT)
+ r->headers_out.last_modified = ngx_palloc(r->pool,
+ sizeof(ngx_table_elt_t));
+ if (r->headers_out.last_modified == NULL) {
+ return NGX_ERROR;
+ }
+
+ r->headers_out.last_modified->key.len = 0;
+ r->headers_out.last_modified->key.data = NULL;
+ r->headers_out.last_modified->value.len = h->last - p;
+ r->headers_out.last_modified->value.data = p;
+#endif
+
*(h->last++) = CR; *(h->last++) = LF;
}
@@ -329,12 +393,14 @@ static int ngx_http_header_filter(ngx_http_request_t *r)
h->type |= NGX_HUNK_LAST;
}
- ngx_test_null(ch, ngx_palloc(r->pool, sizeof(ngx_chain_t)), NGX_ERROR);
+ if (!(ln = ngx_alloc_chain_link(r->pool))) {
+ return NGX_ERROR;
+ }
- ch->hunk = h;
- ch->next = NULL;
+ ln->hunk = h;
+ ln->next = NULL;
- return ngx_http_write_filter(r, ch);
+ return ngx_http_write_filter(r, ln);
}
diff --git a/src/http/ngx_http_headers.c b/src/http/ngx_http_headers.c
index a77483ac0..150ad1eeb 100644
--- a/src/http/ngx_http_headers.c
+++ b/src/http/ngx_http_headers.c
@@ -10,6 +10,7 @@ ngx_http_header_t ngx_http_headers_in[] = {
{ ngx_string("If-Modified-Since"),
offsetof(ngx_http_headers_in_t, if_modified_since) },
{ ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent) },
+ { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer) },
{ ngx_string("Content-Length"),
offsetof(ngx_http_headers_in_t, content_length) },
diff --git a/src/http/ngx_http_log_handler.c b/src/http/ngx_http_log_handler.c
new file mode 100644
index 000000000..b4811c8e9
--- /dev/null
+++ b/src/http/ngx_http_log_handler.c
@@ -0,0 +1,773 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+#include <nginx.h>
+
+
+static char *ngx_http_log_addr(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+static char *ngx_http_log_connection(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+static char *ngx_http_log_pipe(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+static char *ngx_http_log_time(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+static char *ngx_http_log_request(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+static char *ngx_http_log_status(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+static char *ngx_http_log_length(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+static char *ngx_http_log_header_in(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+static char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+static char *ngx_http_log_header_out(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+static char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+
+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,
+ void *child);
+static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static int ngx_http_log_parse_format(ngx_conf_t *cf, ngx_array_t *ops,
+ ngx_str_t *line);
+
+
+static ngx_command_t ngx_http_log_commands[] = {
+
+ {ngx_string("log_format"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
+ ngx_http_log_set_format,
+ NGX_HTTP_MAIN_CONF_OFFSET,
+ 0,
+ NULL},
+
+ {ngx_string("access_log"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+ ngx_http_log_set_log,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL},
+
+ ngx_null_command
+};
+
+
+ngx_http_module_t ngx_http_log_module_ctx = {
+ ngx_http_log_create_main_conf, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ ngx_http_log_create_loc_conf, /* create location configration */
+ ngx_http_log_merge_loc_conf /* merge location configration */
+};
+
+
+ngx_module_t ngx_http_log_module = {
+ NGX_MODULE,
+ &ngx_http_log_module_ctx, /* module context */
+ ngx_http_log_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ NULL, /* init module */
+ NULL /* init child */
+};
+
+
+static ngx_str_t http_access_log = ngx_string("access.log");
+
+
+static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+static ngx_str_t ngx_http_combined_fmt =
+ ngx_string("%addr - - [%time] \"%request\" %status %length "
+ "\"%{Referer}i\" %{User-Agent}i\"");
+
+
+static 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("time"), sizeof("28/Sep/1970:12:00:00") - 1,
+ ngx_http_log_time },
+ { ngx_string("request"), 0, ngx_http_log_request },
+ { ngx_string("status"), 3, ngx_http_log_status },
+ { ngx_string("length"), NGX_OFF_LEN, ngx_http_log_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 }
+};
+
+
+int ngx_http_log_handler(ngx_http_request_t *r)
+{
+ int i, l;
+ u_int data;
+ char *line, *p;
+ size_t len;
+ ngx_http_log_t *log;
+ ngx_http_log_op_t *op;
+ ngx_http_log_loc_conf_t *lcf;
+#if (WIN32)
+ u_int written;
+#endif
+
+ ngx_log_debug(r->connection->log, "log handler");
+
+ lcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module);
+
+ log = lcf->logs->elts;
+ for (l = 0; l < lcf->logs->nelts; l++) {
+
+ len = 0;
+ 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);
+
+ } else {
+ len += op[i].len;
+ }
+ }
+
+#if (WIN32)
+ len += 2;
+#else
+ len++;
+#endif
+
+ ngx_test_null(line, ngx_palloc(r->pool, len), NGX_ERROR);
+ 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++ = 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);
+ }
+ }
+
+#if (WIN32)
+ *p++ = CR; *p++ = LF;
+ WriteFile(log[l].file->fd, line, p - line, &written, NULL);
+#else
+ *p++ = LF;
+ write(log[l].file->fd, line, p - line);
+#endif
+ }
+
+ return NGX_OK;
+}
+
+
+static char *ngx_http_log_addr(ngx_http_request_t *r, char *buf, uintptr_t data)
+{
+ return ngx_cpymem(buf, r->connection->addr_text.data,
+ r->connection->addr_text.len);
+}
+
+
+static char *ngx_http_log_connection(ngx_http_request_t *r, char *buf,
+ uintptr_t data)
+{
+ return buf + ngx_snprintf(buf, NGX_INT32_LEN + 1, "%u",
+ r->connection->number);
+}
+
+
+static char *ngx_http_log_pipe(ngx_http_request_t *r, char *buf, uintptr_t data)
+{
+ if (r->pipeline) {
+ *buf = 'p';
+ } else {
+ *buf = '.';
+ }
+
+ return buf + 1;
+}
+
+
+static char *ngx_http_log_time(ngx_http_request_t *r, char *buf, uintptr_t data)
+{
+ ngx_tm_t tm;
+
+ ngx_localtime(&tm);
+
+ return buf + ngx_snprintf(buf, sizeof("28/Sep/1970:12:00:00"),
+ "%02d/%s/%d:%02d:%02d:%02d",
+ tm.ngx_tm_mday, months[tm.ngx_tm_mon - 1],
+ tm.ngx_tm_year,
+ tm.ngx_tm_hour, tm.ngx_tm_min, tm.ngx_tm_sec);
+}
+
+
+static char *ngx_http_log_request(ngx_http_request_t *r, char *buf,
+ uintptr_t data)
+{
+ if (buf == NULL) {
+ /* find the request line length */
+ return (char *) r->request_line.len;
+ }
+
+ return ngx_cpymem(buf, r->request_line.data, r->request_line.len);
+}
+
+
+static char *ngx_http_log_status(ngx_http_request_t *r, char *buf,
+ uintptr_t data)
+{
+ return buf + ngx_snprintf(buf, 4, "%d", r->headers_out.status);
+}
+
+
+static char *ngx_http_log_length(ngx_http_request_t *r, char *buf,
+ uintptr_t data)
+{
+ return buf + ngx_snprintf(buf, NGX_OFF_LEN + 1, OFF_FMT,
+ r->connection->sent);
+}
+
+
+static char *ngx_http_log_header_in(ngx_http_request_t *r, char *buf,
+ uintptr_t data)
+{
+ int 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);
+
+ if (h == NULL) {
+
+ /* no header */
+
+ if (buf) {
+ *buf = '-';
+ }
+
+ return buf + 1;
+ }
+
+ if (buf == NULL) {
+ /* find the header length */
+ return (char *) h->value.len;
+ }
+
+ return ngx_cpymem(buf, h->value.data, h->value.len);
+ }
+
+ /* find an offset while a format string compilation */
+
+ op = (ngx_http_log_op_t *) buf;
+ s = (ngx_str_t *) data;
+
+ 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;
+ }
+
+ 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;
+ }
+ }
+
+ op->op = ngx_http_log_unknown_header_in;
+ op->data = (uintptr_t) s;
+
+ return NULL;
+}
+
+
+static char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, char *buf,
+ uintptr_t data)
+{
+ int i;
+ ngx_str_t *s;
+ ngx_table_elt_t *h;
+
+ s = (ngx_str_t *) data;
+
+ h = r->headers_in.headers->elts;
+ for (i = 0; i < r->headers_in.headers->nelts; i++) {
+ if (h[i].key.len != s->len) {
+ continue;
+ }
+
+ if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) {
+ if (buf == NULL) {
+ /* find the header length */
+ return (char *) h[i].value.len;
+ }
+
+ return ngx_cpymem(buf, h[i].value.data, h[i].value.len);
+ }
+ }
+
+ /* no header */
+
+ if (buf) {
+ *buf = '-';
+ }
+
+ return buf + 1;
+}
+
+
+static char *ngx_http_log_header_out(ngx_http_request_t *r, char *buf,
+ uintptr_t data)
+{
+ int 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_out + data);
+
+ if (h == NULL) {
+
+ /* no header */
+
+ if (data == offsetof(ngx_http_headers_out_t, server)) {
+ if (buf == NULL) {
+ return (char *) (sizeof(NGINX_VER) - 1);
+ }
+ return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1);
+ }
+
+ if (buf) {
+ *buf = '-';
+ }
+
+ return buf + 1;
+ }
+
+ if (buf == NULL) {
+ /* find the header length */
+ return (char *) h->value.len;
+ }
+
+ return ngx_cpymem(buf, h->value.data, h->value.len);
+ }
+
+ /* find an offset while a format string compilation */
+
+ op = (ngx_http_log_op_t *) buf;
+ s = (ngx_str_t *) data;
+
+ op->len = 0;
+
+ for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) {
+ if (ngx_http_headers_out[i].name.len != s->len) {
+ continue;
+ }
+
+ 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;
+ }
+ }
+
+ op->op = ngx_http_log_unknown_header_out;
+ op->data = (uintptr_t) s;
+
+ return NULL;
+}
+
+
+static char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, char *buf,
+ uintptr_t data)
+{
+ int i;
+ ngx_str_t *s;
+ ngx_table_elt_t *h;
+
+ s = (ngx_str_t *) data;
+
+ h = r->headers_out.headers->elts;
+ for (i = 0; i < r->headers_out.headers->nelts; i++) {
+ if (h[i].key.len != s->len) {
+ continue;
+ }
+
+ if (ngx_strncasecmp(h[i].key.data, s->data, s->len) == 0) {
+ if (buf == NULL) {
+ /* find the header length */
+ return (char *) h[i].value.len;
+ }
+
+ return ngx_cpymem(buf, h[i].value.data, h[i].value.len);
+ }
+ }
+
+ /* no header */
+
+ if (buf) {
+ *buf = '-';
+ }
+
+ return buf + 1;
+}
+
+
+static void *ngx_http_log_create_main_conf(ngx_conf_t *cf)
+{
+ ngx_http_log_main_conf_t *conf;
+
+ char *rc;
+ ngx_str_t *value;
+
+ if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_main_conf_t)))) {
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_init_array(conf->formats, cf->pool, 5, sizeof(ngx_http_log_fmt_t),
+ NGX_CONF_ERROR);
+
+ cf->args->nelts = 0;
+
+ if (!(value = ngx_push_array(cf->args))) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (!(value = ngx_push_array(cf->args))) {
+ return NGX_CONF_ERROR;
+ }
+
+ value->len = sizeof("combined") - 1;
+ value->data = "combined";
+
+ if (!(value = ngx_push_array(cf->args))) {
+ return NGX_CONF_ERROR;
+ }
+
+ *value = ngx_http_combined_fmt;
+
+ rc = ngx_http_log_set_format(cf, NULL, conf);
+ if (rc != NGX_CONF_OK) {
+ return rc;
+ }
+
+ return conf;
+}
+
+
+static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf)
+{
+ ngx_http_log_loc_conf_t *conf;
+
+ ngx_test_null(conf, ngx_pcalloc(cf->pool, sizeof(ngx_http_log_loc_conf_t)),
+ NGX_CONF_ERROR);
+
+ return conf;
+}
+
+
+static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent,
+ void *child)
+{
+ ngx_http_log_loc_conf_t *prev = parent;
+ ngx_http_log_loc_conf_t *conf = child;
+
+ ngx_http_log_t *log;
+ ngx_http_log_fmt_t *fmt;
+ ngx_http_log_main_conf_t *lmcf;
+
+ if (conf->logs == NULL) {
+ if (prev->logs) {
+ conf->logs = prev->logs;
+
+ } else {
+
+ conf->logs = ngx_create_array(cf->pool, 2, sizeof(ngx_http_log_t));
+ if (conf->logs == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (!(log = ngx_push_array(conf->logs))) {
+ return NGX_CONF_ERROR;
+ }
+
+ log->file = ngx_conf_open_file(cf->cycle, &http_access_log);
+ if (log->file == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ lmcf = ngx_http_conf_module_main_conf(cf, ngx_http_log_module);
+ fmt = lmcf->formats.elts;
+ /* the default "combined" format */
+ log->ops = fmt[0].ops;
+ }
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *ngx_http_log_set_log(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf)
+{
+ ngx_http_log_loc_conf_t *llcf = conf;
+
+ int i;
+ ngx_str_t *value, name;
+ ngx_http_log_t *log;
+ ngx_http_log_fmt_t *fmt;
+ ngx_http_log_main_conf_t *lmcf;
+
+ if (llcf->logs == NULL) {
+ if (!(llcf->logs = ngx_create_array(cf->pool, 2,
+ sizeof(ngx_http_log_t)))) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ value = cf->args->elts;
+ lmcf = ngx_http_conf_module_main_conf(cf, ngx_http_log_module);
+
+ if (!(log = ngx_push_array(llcf->logs))) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (!(log->file = ngx_conf_open_file(cf->cycle, &value[1]))) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (cf->args->nelts == 3) {
+ name = value[2];
+ } else {
+ name.len = sizeof("combined") - 1;
+ name.data = "combined";
+ }
+
+ fmt = lmcf->formats.elts;
+ for (i = 0; i < lmcf->formats.nelts; i++) {
+ if (fmt[i].name.len == name.len
+ && ngx_strcasecmp(fmt[i].name.data, name.data) == 0)
+ {
+ log->ops = fmt[i].ops;
+ return NGX_CONF_OK;
+ }
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *ngx_http_log_set_format(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf)
+{
+ ngx_http_log_main_conf_t *lmcf = conf;
+
+ int s, f, invalid;
+ char *data, *p, *fname;
+ size_t i, len, fname_len;
+ ngx_str_t *value, arg, *a;
+ ngx_http_log_op_t *op;
+ ngx_http_log_fmt_t *fmt;
+ ngx_http_log_op_name_t *name;
+
+ value = cf->args->elts;
+#if 0
+ lmcf = ngx_http_conf_module_main_conf(cf, ngx_http_log_module);
+#endif
+
+ fmt = lmcf->formats.elts;
+ for (f = 0; f < lmcf->formats.nelts; f++) {
+ if (fmt[f].name.len == value[1].len
+ && ngx_strcmp(fmt->name.data, value[1].data) == 0)
+ {
+ return "duplicate \"log_format\" name";
+ }
+ }
+
+ if (!(fmt = ngx_push_array(&lmcf->formats))) {
+ return NGX_CONF_ERROR;
+ }
+
+ fmt->name = value[1];
+
+ if (!(fmt->ops = ngx_create_array(cf->pool, 20,
+ sizeof(ngx_http_log_op_t)))) {
+ return NGX_CONF_ERROR;
+ }
+
+ invalid = 0;
+ data = NULL;
+
+ for (s = 2; s < cf->args->nelts && !invalid; s++) {
+
+ i = 0;
+
+ while (i < value[s].len) {
+
+ if (!(op = ngx_push_array(fmt->ops))) {
+ return NGX_CONF_ERROR;
+ }
+
+ data = &value[s].data[i];
+
+ if (value[s].data[i] == '%') {
+ i++;
+
+ if (i == value[s].len) {
+ invalid = 1;
+ break;
+ }
+
+ if (value[s].data[i] == '{') {
+ i++;
+
+ arg.data = &value[s].data[i];
+
+ while (i < value[s].len && value[s].data[i] != '}') {
+ i++;
+ }
+
+ arg.len = &value[s].data[i] - arg.data;
+
+ if (i == value[s].len || arg.len == 0) {
+ invalid = 1;
+ break;
+ }
+
+ i++;
+
+ } else {
+ arg.len = 0;
+ }
+
+ fname = &value[s].data[i];
+
+ while (i < value[s].len
+ && value[s].data[i] >= 'a'
+ && value[s].data[i] <= 'z')
+ {
+ i++;
+ }
+
+ fname_len = &value[s].data[i] - fname;
+
+ if (fname_len == 0) {
+ invalid = 1;
+ break;
+ }
+
+ for (name = ngx_http_log_fmt_ops; name->name.len; name++) {
+ if (name->name.len == fname_len
+ && ngx_strncmp(name->name.data, fname, fname_len) == 0)
+ {
+ if (name->len != NGX_HTTP_LOG_ARG) {
+ if (arg.len) {
+ fname[fname_len] = '\0';
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%s\" must not have argument",
+ data);
+ return NGX_CONF_ERROR;
+ }
+
+ op->len = name->len;
+ op->op = name->op;
+ op->data = 0;
+
+ break;
+ }
+
+ if (arg.len == 0) {
+ fname[fname_len] = '\0';
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%s\" requires argument",
+ data);
+ return NGX_CONF_ERROR;
+ }
+
+ if (!(a = ngx_palloc(cf->pool, sizeof(ngx_str_t)))) {
+ return NGX_CONF_ERROR;
+ }
+
+ *a = arg;
+ name->op(NULL, (char *) op, (uintptr_t) a);
+
+ break;
+ }
+ }
+
+ if (name->name.len == 0) {
+ invalid = 1;
+ break;
+ }
+
+ } else {
+ i++;
+
+ while (i < value[s].len && value[s].data[i] != '%') {
+ i++;
+ }
+
+ len = &value[s].data[i] - data;
+
+ if (len) {
+
+ op->len = len;
+
+ if (len <= sizeof(uintptr_t)) {
+ op->op = NGX_HTTP_LOG_COPY_SHORT;
+ op->data = 0;
+
+ while (len--) {
+ op->data <<= 8;
+ op->data |= data[len];
+ }
+
+ } else {
+ op->op = NGX_HTTP_LOG_COPY_LONG;
+
+ if (!(p = ngx_palloc(cf->pool, len))) {
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memcpy(p, data, len);
+ op->data = (uintptr_t) p;
+ }
+ }
+ }
+ }
+ }
+
+ if (invalid) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%s\"", data);
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
diff --git a/src/http/ngx_http_log_handler.h b/src/http/ngx_http_log_handler.h
new file mode 100644
index 000000000..ba301aebf
--- /dev/null
+++ b/src/http/ngx_http_log_handler.h
@@ -0,0 +1,59 @@
+#ifndef _NGX_HTTP_LOG_HANDLER_H_INCLUDED_
+#define _NGX_HTTP_LOG_HANDLER_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef char *(*ngx_http_log_op_pt) (ngx_http_request_t *r, char *buf,
+ uintptr_t data);
+
+#define NGX_HTTP_LOG_COPY_SHORT (ngx_http_log_op_pt) 0
+#define NGX_HTTP_LOG_COPY_LONG (ngx_http_log_op_pt) -1
+
+#define NGX_HTTP_LOG_ARG (u_int) -1
+
+/* STUB */
+#define NGX_INT32_LEN sizeof("4294967296") - 1
+#define NGX_OFF_LEN sizeof("18446744073709551616") - 1
+
+
+typedef struct {
+ size_t len;
+ ngx_http_log_op_pt op;
+ uintptr_t data;
+} ngx_http_log_op_t;
+
+
+typedef struct {
+ 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_http_log_op_name_t;
+
+
+typedef struct {
+ 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_http_log_t;
+
+
+typedef struct {
+ ngx_array_t *logs; /* array of ngx_http_log_t */
+} ngx_http_log_loc_conf_t;
+
+
+#endif /* _NGX_HTTP_LOG_HANDLER_H_INCLUDED_ */
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index dcf8dac66..9dd040e43 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -225,6 +225,7 @@ ngx_log_debug(rev->log, "IN: %08x" _ in_port);
return;
}
+ /* TODO: ngx_init_table */
if (!(r->headers_out.headers = ngx_create_table(r->pool, 20))) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
ngx_http_close_connection(c);
@@ -416,6 +417,7 @@ static void ngx_http_process_request_line(ngx_event_t *rev)
lctx = c->log->data;
lctx->action = "reading client request headers";
lctx->url = r->unparsed_uri.data;
+ /* TODO: ngx_init_table */
r->headers_in.headers = ngx_create_table(r->pool, 20);
if (cscf->large_client_header
@@ -1068,7 +1070,8 @@ static void ngx_http_set_keepalive(ngx_http_request_t *r)
if (h->pos < h->last) {
- /* Pipelined request.
+ /*
+ * Pipelined request.
*
* We do not know here whether a pipelined request is complete
* so if the large client headers are not enabled
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 8e50d59f9..526e13d11 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -74,6 +74,7 @@ typedef struct {
ngx_table_elt_t *connection;
ngx_table_elt_t *if_modified_since;
ngx_table_elt_t *user_agent;
+ ngx_table_elt_t *referer;
ngx_table_elt_t *content_length;
ngx_table_elt_t *accept_encoding;
@@ -202,6 +203,8 @@ struct ngx_http_request_s {
unsigned bypass_cache:1;
unsigned no_cache:1;
+ unsigned error_page:1;
+
#if 0
unsigned cachable:1;
#endif
diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c
index 017376a5b..c1cb23aa4 100644
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -168,9 +168,10 @@ static ngx_str_t error_pages[] = {
int ngx_http_special_response_handler(ngx_http_request_t *r, int error)
{
- int err, rc;
+ int err, rc, i;
ngx_hunk_t *h;
ngx_chain_t *out, **ll, *cl;
+ ngx_http_err_page_t *err_page;
ngx_http_core_loc_conf_t *clcf;
rc = ngx_http_discard_body(r);
@@ -181,19 +182,6 @@ int ngx_http_special_response_handler(ngx_http_request_t *r, int error)
r->headers_out.status = error;
- if (error < NGX_HTTP_BAD_REQUEST) {
- /* 3XX */
- err = error - NGX_HTTP_MOVED_PERMANENTLY;
-
- } else if (error < NGX_HTTP_INTERNAL_SERVER_ERROR) {
- /* 4XX */
- err = error - NGX_HTTP_BAD_REQUEST + 3;
-
- } else {
- /* 5XX */
- err = error - NGX_HTTP_INTERNAL_SERVER_ERROR + 3 + 17;
- }
-
if (r->keepalive != 0) {
switch (error) {
case NGX_HTTP_BAD_REQUEST:
@@ -213,6 +201,31 @@ int ngx_http_special_response_handler(ngx_http_request_t *r, int error)
}
}
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ if (!r->error_page && clcf->error_pages) {
+ err_page = clcf->error_pages->elts;
+ for (i = 0; i < clcf->error_pages->nelts; i++) {
+ if (err_page[i].code == error) {
+ r->error_page = 1;
+ return ngx_http_internal_redirect(r, &err_page[i].uri, NULL);
+ }
+ }
+ }
+
+ if (error < NGX_HTTP_BAD_REQUEST) {
+ /* 3XX */
+ err = error - NGX_HTTP_MOVED_PERMANENTLY;
+
+ } else if (error < NGX_HTTP_INTERNAL_SERVER_ERROR) {
+ /* 4XX */
+ err = error - NGX_HTTP_BAD_REQUEST + 3;
+
+ } else {
+ /* 5XX */
+ err = error - NGX_HTTP_INTERNAL_SERVER_ERROR + 3 + 17;
+ }
+
if (error_pages[err].len) {
r->headers_out.content_length_n = error_pages[err].len
+ sizeof(error_tail) - 1
@@ -272,8 +285,6 @@ int ngx_http_special_response_handler(ngx_http_request_t *r, int error)
ngx_alloc_link_and_set_hunk(cl, h, r->pool, NGX_ERROR);
ngx_chain_add_link(out, ll, cl);
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
if (clcf->msie_padding
&& r->http_version >= NGX_HTTP_VERSION_10
&& error >= NGX_HTTP_BAD_REQUEST
diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h
index 494ec55b1..9990ae8c3 100644
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -63,6 +63,7 @@ ssize_t ngx_write_chain_to_file(ngx_file_t *file, ngx_chain_t *ce,
#define ngx_is_file(sb) (S_ISREG(sb.st_mode))
#define ngx_file_size(sb) sb.st_size
#define ngx_file_mtime(sb) sb.st_mtime
+#define ngx_file_uniq(sb) sb.st_ino
#endif /* _NGX_FILES_H_INCLUDED_ */
diff --git a/src/os/unix/ngx_types.h b/src/os/unix/ngx_types.h
index 8d6065027..3bc065306 100644
--- a/src/os/unix/ngx_types.h
+++ b/src/os/unix/ngx_types.h
@@ -10,6 +10,8 @@
typedef int ngx_fd_t;
typedef struct stat ngx_file_info_t;
+typedef ino_t ngx_file_uniq_t;
+
#endif /* _NGX_TYPES_H_INCLUDED_ */
diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h
index a23c0e2a0..a29e333cc 100644
--- a/src/os/win32/ngx_files.h
+++ b/src/os/win32/ngx_files.h
@@ -6,7 +6,7 @@
#include <ngx_core.h>
-/* INVALID_FILE_ATTRIBUTES specified but never defined at least in VC6SP2 */
+/* INVALID_FILE_ATTRIBUTES specified but not defined at least in MSVC6SP2 */
#ifndef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
#endif
@@ -67,6 +67,7 @@ int ngx_file_type(char *filename, ngx_file_info_t *fi);
#define ngx_file_size(fi) \
(((off_t) fi.nFileSizeHigh << 32) | fi.nFileSizeLow)
+#define ngx_file_uniq(fi) (*(ngx_file_uniq_t *) &fi.nFileIndexHigh)
/* There are 134774 days between 1 Jan 1970 and 1 Jan 1601,
11644473600 seconds or 11644473600,000,000,0 100-nanosecond intervals */
diff --git a/src/os/win32/ngx_stat.c b/src/os/win32/ngx_stat.c
index 81559bc31..786bc7f38 100644
--- a/src/os/win32/ngx_stat.c
+++ b/src/os/win32/ngx_stat.c
@@ -1,7 +1,7 @@
#include <ngx_config.h>
+#include <ngx_core.h>
-#include <ngx_stat.h>
int ngx_file_type(char *file, ngx_file_info_t *sb)
{
diff --git a/src/os/win32/ngx_stat.h b/src/os/win32/ngx_stat.h
deleted file mode 100644
index bd0423b29..000000000
--- a/src/os/win32/ngx_stat.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef _NGX_STAT_H_INCLUDED_
-#define _NGX_STAT_H_INCLUDED_
-
-
-#include <windows.h>
-
-/* INVALID_FILE_ATTRIBUTES specified but never defined at least in VC6SP2 */
-#ifndef INVALID_FILE_ATTRIBUTES
-#define INVALID_FILE_ATTRIBUTES 0xFFFFFFFF
-#endif
-
-typedef BY_HANDLE_FILE_INFORMATION ngx_file_info_t;
-
-
-#define ngx_file_type_n "GetFileAttributes"
-
-#define ngx_is_dir(fi) (fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
-
-#define ngx_stat_n "GetFileAttributes"
-
-#define ngx_fstat(file, fd, sb) ngx_stat(file, sb)
-#define ngx_fstat_n "GetFileAttributes"
-
-
-/*
-int ngx_stat(char *file, ngx_stat_t *sb);
-*/
-
-
-#endif /* _NGX_STAT_H_INCLUDED_ */
diff --git a/src/os/win32/ngx_types.h b/src/os/win32/ngx_types.h
index 59ee72173..043265536 100644
--- a/src/os/win32/ngx_types.h
+++ b/src/os/win32/ngx_types.h
@@ -6,21 +6,9 @@
#include <ngx_core.h>
-typedef unsigned __int32 u_int32_t;
-typedef __int64 int64_t;
-
-typedef int ssize_t;
-typedef long time_t;
-
typedef HANDLE ngx_fd_t;
-typedef unsigned __int64 off_t;
typedef BY_HANDLE_FILE_INFORMATION ngx_file_info_t;
-
-
-#define OFF_FMT "%I64d"
-#define SIZE_FMT "%d"
-#define SIZEX_FMT "%x"
-#define PID_FMT "%d"
+typedef uint64_t ngx_file_uniq_t;
#endif /* _NGX_TYPES_H_INCLUDED_ */
diff --git a/src/os/win32/ngx_win32_config.h b/src/os/win32/ngx_win32_config.h
index 7d123d71c..74769befd 100644
--- a/src/os/win32/ngx_win32_config.h
+++ b/src/os/win32/ngx_win32_config.h
@@ -18,6 +18,30 @@
#define ngx_inline __inline
+#if 0
+typedef unsigned __int32 uint32_t;
+#else
+typedef unsigned int uint32_t;
+#endif
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+typedef u_int uintptr_t;
+
+typedef int ssize_t;
+typedef long time_t;
+typedef unsigned __int64 off_t;
+
+
+#define OFF_FMT "%I64d"
+#define SIZE_FMT "%d"
+#define SIZEX_FMT "%x"
+#define PID_FMT "%d"
+
+
+/* STUB */
+typedef uint32_t u_int32_t;
+
+
#ifndef HAVE_INHERITED_NONBLOCK
#define HAVE_INHERITED_NONBLOCK 1
#endif