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
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2003-06-02 19:24:30 +0400
committerIgor Sysoev <igor@sysoev.ru>2003-06-02 19:24:30 +0400
commit7578ec9df43bbb31db5291f1b76359d10900a679 (patch)
tree87d7b3cb729c0e07b21d52737fd76e12a0c17d72 /src/http/modules
parentaa3436c04c222d57498bfa34c9fdec50f07fd08d (diff)
nginx-0.0.1-2003-06-02-19:24:30 import
Diffstat (limited to 'src/http/modules')
-rw-r--r--src/http/modules/ngx_http_charset_filter.c124
-rw-r--r--src/http/modules/ngx_http_chunked_filter.c129
-rw-r--r--src/http/modules/ngx_http_index_handler.c28
-rw-r--r--src/http/modules/ngx_http_index_handler.h22
-rw-r--r--src/http/modules/ngx_http_log_handler.c139
-rw-r--r--src/http/modules/ngx_http_log_handler.h41
-rw-r--r--src/http/modules/ngx_http_range_filter.c362
-rw-r--r--src/http/modules/ngx_http_static_handler.c11
8 files changed, 807 insertions, 49 deletions
diff --git a/src/http/modules/ngx_http_charset_filter.c b/src/http/modules/ngx_http_charset_filter.c
new file mode 100644
index 000000000..baf6d9aba
--- /dev/null
+++ b/src/http/modules/ngx_http_charset_filter.c
@@ -0,0 +1,124 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+ ngx_str_t default_charset;
+} ngx_http_charset_loc_conf_t;
+
+
+static void *ngx_http_charset_create_loc_conf(ngx_pool_t *pool);
+static char *ngx_http_charset_merge_loc_conf(ngx_pool_t *pool,
+ void *parent, void *child);
+static int ngx_http_charset_filter_init(ngx_pool_t *pool);
+
+
+static ngx_command_t ngx_http_charset_filter_commands[] = {
+
+ {ngx_string("default_charset"),
+ 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_charset_loc_conf_t, default_charset),
+ NULL},
+
+ ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_charset_filter_module_ctx = {
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ ngx_http_charset_create_loc_conf, /* create location configuration */
+ ngx_http_charset_merge_loc_conf /* merge location configuration */
+};
+
+
+ngx_module_t ngx_http_charset_filter_module = {
+ NGX_MODULE,
+ &ngx_http_charset_filter_module_ctx, /* module context */
+ ngx_http_charset_filter_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ ngx_http_charset_filter_init /* init module */
+};
+
+
+static int (*next_header_filter) (ngx_http_request_t *r);
+#if 0
+static int (*next_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
+#endif
+
+
+static int ngx_http_charset_header_filter(ngx_http_request_t *r)
+{
+ ngx_http_charset_loc_conf_t *lcf;
+
+ lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module);
+
+ if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY
+ && r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY)
+ {
+ /* do not set charset for the redirect because NN 4.x uses this
+ charset instead of the next page charset */
+ r->headers_out.charset.len = 0;
+
+ } else if (r->headers_out.charset.len == 0) {
+ r->headers_out.charset = lcf->default_charset;
+ }
+
+ return next_header_filter(r);
+}
+
+
+#if 0
+static int ngx_http_charset_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
+{
+ ngx_log_debug(r->connection->log, "CHARSET BODY");
+ return next_body_filter(r, in);
+}
+#endif
+
+
+static int ngx_http_charset_filter_init(ngx_pool_t *pool)
+{
+ next_header_filter = ngx_http_top_header_filter;
+ ngx_http_top_header_filter = ngx_http_charset_header_filter;
+
+#if 0
+ next_body_filter = ngx_http_top_body_filter;
+ ngx_http_top_body_filter = ngx_http_charset_body_filter;
+#endif
+
+ return NGX_OK;
+}
+
+
+static void *ngx_http_charset_create_loc_conf(ngx_pool_t *pool)
+{
+ ngx_http_charset_loc_conf_t *lcf;
+
+ ngx_test_null(lcf,
+ ngx_pcalloc(pool, sizeof(ngx_http_charset_loc_conf_t)),
+ NGX_CONF_ERROR);
+
+ return lcf;
+}
+
+
+static char *ngx_http_charset_merge_loc_conf(ngx_pool_t *pool,
+ void *parent, void *child)
+{
+ ngx_http_charset_loc_conf_t *prev = parent;
+ ngx_http_charset_loc_conf_t *conf = child;
+
+ ngx_conf_merge_str_value(conf->default_charset,
+ prev->default_charset, "koi8-r");
+
+ return NGX_CONF_OK;
+}
diff --git a/src/http/modules/ngx_http_chunked_filter.c b/src/http/modules/ngx_http_chunked_filter.c
new file mode 100644
index 000000000..75a0cdfd6
--- /dev/null
+++ b/src/http/modules/ngx_http_chunked_filter.c
@@ -0,0 +1,129 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+static int ngx_http_chunked_filter_init(ngx_pool_t *pool);
+
+
+static ngx_http_module_t ngx_http_chunked_filter_module_ctx = {
+ 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_chunked_filter_module = {
+ NGX_MODULE,
+ &ngx_http_chunked_filter_module_ctx, /* module context */
+ NULL, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ ngx_http_chunked_filter_init /* init module */
+};
+
+
+static int (*next_header_filter) (ngx_http_request_t *r);
+static int (*next_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
+
+
+static int ngx_http_chunked_header_filter(ngx_http_request_t *r)
+{
+ if (r->headers_out.content_length == -1) {
+ if (r->http_version < NGX_HTTP_VERSION_11) {
+ r->keepalive = 0;
+
+ } else {
+ r->chunked = 1;
+ }
+ }
+
+ return next_header_filter(r);
+}
+
+
+static int ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
+{
+ char *chunk;
+ size_t size, len;
+ ngx_hunk_t *h;
+ ngx_chain_t *out, *ce, *te, **le;
+
+ if (in == NULL || !r->chunked) {
+ return next_body_filter(r, in);
+ }
+
+ ngx_test_null(out, ngx_alloc_chain_entry(r->pool), NGX_ERROR);
+ le = &out->next;
+
+ size = 0;
+ ce = in;
+
+ for ( ;; ) {
+
+ if (ce->hunk->type & NGX_HUNK_IN_MEMORY) {
+ size += ce->hunk->last - ce->hunk->pos;
+ } else {
+ size += (size_t) (ce->hunk->file_last - ce->hunk->file_pos);
+ }
+
+ ngx_test_null(te, ngx_alloc_chain_entry(r->pool), NGX_ERROR);
+ te->hunk = ce->hunk;
+ *le = te;
+ le = &te->next;
+
+ if (ce->next == NULL) {
+ break;
+ }
+
+ ce = ce->next;
+ }
+
+ ngx_test_null(chunk, ngx_palloc(r->pool, 11), NGX_ERROR);
+ len = ngx_snprintf(chunk, 11, "%x" CRLF, size);
+
+ ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
+ h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
+ h->pos = chunk;
+ h->last = chunk + len;
+
+ out->hunk = h;
+
+ ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
+
+ if (ce->hunk->type & NGX_HUNK_LAST) {
+ ce->hunk->type &= ~NGX_HUNK_LAST;
+ h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_MEMORY|NGX_HUNK_LAST;
+ h->pos = CRLF "0" CRLF CRLF;
+ h->last = h->pos + 7;
+
+ } else {
+ h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_MEMORY;
+ h->pos = CRLF;
+ h->last = h->pos + 2;
+ }
+
+ ngx_test_null(te, ngx_alloc_chain_entry(r->pool), NGX_ERROR);
+ te->hunk = h;
+ te->next = NULL;
+ *le = te;
+
+ return next_body_filter(r, out);
+}
+
+
+static int ngx_http_chunked_filter_init(ngx_pool_t *pool)
+{
+ next_header_filter = ngx_http_top_header_filter;
+ ngx_http_top_header_filter = ngx_http_chunked_header_filter;
+
+ next_body_filter = ngx_http_top_body_filter;
+ ngx_http_top_body_filter = ngx_http_chunked_body_filter;
+
+ return NGX_OK;
+}
diff --git a/src/http/modules/ngx_http_index_handler.c b/src/http/modules/ngx_http_index_handler.c
index c9ad91112..cc7c92790 100644
--- a/src/http/modules/ngx_http_index_handler.c
+++ b/src/http/modules/ngx_http_index_handler.c
@@ -1,5 +1,16 @@
-#include <ngx_http_index_handler.h>
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+ ngx_array_t indices;
+ size_t max_index_len;
+} ngx_http_index_conf_t;
+
+
+#define NGX_HTTP_DEFAULT_INDEX "index.html"
static int ngx_http_index_test_dir(ngx_http_request_t *r);
@@ -14,7 +25,7 @@ static char *ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd,
static ngx_command_t ngx_http_index_commands[] = {
{ngx_string("index"),
- NGX_HTTP_LOC_CONF|NGX_CONF_ANY1,
+ NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
ngx_http_index_set_index,
NGX_HTTP_LOC_CONF_OFFSET,
0,
@@ -46,8 +57,8 @@ ngx_module_t ngx_http_index_module = {
/*
- Try to open first index file before the test of the directory existence
- because the valid requests should be many more then invalid ones.
+ Try to open the first index file before the directory existence test
+ because the valid requests should be many more than invalid ones.
If open() failed then stat() should be more quickly because some data
is already cached in the kernel.
Besides Win32 has ERROR_PATH_NOT_FOUND (NGX_ENOTDIR).
@@ -57,7 +68,7 @@ ngx_module_t ngx_http_index_module = {
int ngx_http_index_handler(ngx_http_request_t *r)
{
- int i, rc, test_dir;
+ int i, rc, test_dir, path_not_found;
char *name, *file;
ngx_str_t redirect, *index;
ngx_err_t err;
@@ -80,6 +91,7 @@ int ngx_http_index_handler(ngx_http_request_t *r)
r->path.len = file - r->path.data;
test_dir = 1;
+ path_not_found = 1;
index = icf->indices.elts;
for (i = 0; i < icf->indices.nelts; i++) {
@@ -92,7 +104,7 @@ int ngx_http_index_handler(ngx_http_request_t *r)
name = index[i].data;
}
- fd = ngx_open_file(name, NGX_FILE_RDONLY);
+ fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN);
if (fd == NGX_INVALID_FILE) {
err = ngx_errno;
@@ -100,7 +112,7 @@ ngx_log_error(NGX_LOG_DEBUG, r->connection->log, err,
"DEBUG: " ngx_open_file_n " %s failed", name);
if (err == NGX_ENOTDIR) {
- r->path_not_found = 1;
+ path_not_found = 1;
} else if (err == NGX_EACCES) {
r->path_err = err;
@@ -108,7 +120,7 @@ ngx_log_error(NGX_LOG_DEBUG, r->connection->log, err,
}
if (test_dir) {
- if (r->path_not_found) {
+ if (path_not_found) {
r->path_err = err;
return NGX_HTTP_NOT_FOUND;
}
diff --git a/src/http/modules/ngx_http_index_handler.h b/src/http/modules/ngx_http_index_handler.h
deleted file mode 100644
index 3d2f6f00d..000000000
--- a/src/http/modules/ngx_http_index_handler.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _NGX_HTTP_INDEX_HANDLER_H_INCLUDED_
-#define _NGX_HTTP_INDEX_HANDLER_H_INCLUDED_
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-
-
-#define NGX_HTTP_DEFAULT_INDEX "index.html"
-
-
-typedef struct {
- ngx_array_t indices;
- size_t max_index_len;
-} ngx_http_index_conf_t;
-
-
-extern ngx_module_t ngx_http_index_module;
-
-
-#endif /* _NGX_HTTP_INDEX_HANDLER_H_INCLUDED_ */
diff --git a/src/http/modules/ngx_http_log_handler.c b/src/http/modules/ngx_http_log_handler.c
index 44df45302..f61461ce7 100644
--- a/src/http/modules/ngx_http_log_handler.c
+++ b/src/http/modules/ngx_http_log_handler.c
@@ -1,38 +1,82 @@
#include <ngx_config.h>
#include <ngx_core.h>
-#include <ngx_string.h>
-#include <ngx_alloc.h>
-#include <ngx_time.h>
#include <ngx_http.h>
-#include <ngx_http_config.h>
-ngx_http_module_t ngx_http_log_module;
+typedef struct {
+ ngx_file_t file;
+} ngx_http_log_conf_t;
+
+
+static void *ngx_http_log_create_conf(ngx_pool_t *pool);
+static char *ngx_http_log_merge_conf(ngx_pool_t *p, 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 */
+};
+
static char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
int ngx_http_log_handler(ngx_http_request_t *r)
{
- size_t len;
- char *line, *p;
- ngx_tm_t tm;
+ char *line, *p;
+ size_t len;
+ ngx_tm_t tm;
+ ngx_http_log_conf_t *lcf;
ngx_log_debug(r->connection->log, "log handler");
- /* 10:%con, 1:%pipe, 22:%date, 2:"%r", 3:%status, 20:%bytes,
- 6*" ", 2/1: "\r\n" */
+ 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 + 6 + 2;
+ len = 10 + 1 + 22 + 2 + 3 + 20 + 2 + 7 + 2;
#else
- len = 10 + 1 + 22 + 2 + 3 + 20 + 6 + 1;
+ 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;
@@ -79,13 +123,80 @@ int ngx_http_log_handler(ngx_http_request_t *r)
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;
#else
*p++ = LF;
#endif
- write(1, line, p - line);
+ write(lcf->file.fd, line, p - line);
return NGX_OK;
}
+
+
+static void *ngx_http_log_create_conf(ngx_pool_t *pool)
+{
+ ngx_http_log_conf_t *conf;
+
+ ngx_test_null(conf, ngx_pcalloc(pool, sizeof(ngx_http_log_conf_t)),
+ NGX_CONF_ERROR);
+
+ return conf;
+}
+
+
+static char *ngx_http_log_merge_conf(ngx_pool_t *p, void *parent, void *child)
+{
+ ngx_http_log_conf_t *prev = parent;
+ ngx_http_log_conf_t *conf = child;
+
+ /* STUB */
+ *conf = *prev;
+
+ 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;
+
+ int len;
+ ngx_err_t err;
+ ngx_str_t *value;
+
+ value = cf->args->elts;
+
+ lcf->file.name.len = value[1].len;
+ lcf->file.name.data = value[1].data;
+
+ lcf->file.fd = ngx_open_file(lcf->file.name.data,
+ NGX_FILE_RDWR,
+ NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND);
+
+ if (lcf->file.fd == NGX_INVALID_FILE) {
+ err = ngx_errno;
+ len = ngx_snprintf(ngx_conf_errstr, sizeof(ngx_conf_errstr) - 1,
+ ngx_open_file_n " \"%s\" failed (%d: ",
+ lcf->file.name.data, err);
+ len += ngx_strerror_r(err, ngx_conf_errstr + len,
+ sizeof(ngx_conf_errstr) - len - 1);
+ ngx_conf_errstr[len++] = ')';
+ ngx_conf_errstr[len++] = '\0';
+ return ngx_conf_errstr;
+ }
+
+ return NGX_CONF_OK;
+}
diff --git a/src/http/modules/ngx_http_log_handler.h b/src/http/modules/ngx_http_log_handler.h
new file mode 100644
index 000000000..2bda1f0d9
--- /dev/null
+++ b/src/http/modules/ngx_http_log_handler.h
@@ -0,0 +1,41 @@
+#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_range_filter.c b/src/http/modules/ngx_http_range_filter.c
new file mode 100644
index 000000000..d2696fd2d
--- /dev/null
+++ b/src/http/modules/ngx_http_range_filter.c
@@ -0,0 +1,362 @@
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+ ngx_str_t boundary_header;
+} ngx_http_range_filter_ctx_t;
+
+
+static int ngx_http_range_filter_init(ngx_pool_t *pool);
+
+
+static ngx_http_module_t ngx_http_range_filter_module_ctx = {
+ 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_range_filter_module = {
+ NGX_MODULE,
+ &ngx_http_range_filter_module_ctx, /* module context */
+ NULL, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ ngx_http_range_filter_init /* init module */
+};
+
+
+static int (*next_header_filter) (ngx_http_request_t *r);
+static int (*next_body_filter) (ngx_http_request_t *r, ngx_chain_t *ch);
+
+
+static int ngx_http_range_header_filter(ngx_http_request_t *r)
+{
+ int rc, boundary, len, i;
+ char *p;
+ off_t start, end;
+ ngx_http_range_t *range;
+ ngx_http_range_filter_ctx_t *ctx;
+
+ if (r->main
+ || r->http_version < NGX_HTTP_VERSION_10
+ || r->headers_out.status != NGX_HTTP_OK
+ || r->headers_out.content_length == -1
+ /* STUB: we currently support ranges for file hunks only */
+ || r->filter & NGX_HTTP_FILTER_NEED_IN_MEMORY
+ || r->headers_in.range == NULL
+ || r->headers_in.range->value.len < 7
+ || ngx_strncasecmp(r->headers_in.range->value.data, "bytes=", 6) != 0)
+ {
+ return next_header_filter(r);
+ }
+
+ ngx_init_array(r->headers_out.ranges, r->pool, 5, sizeof(ngx_http_range_t),
+ NGX_ERROR);
+
+ rc = 0;
+ p = r->headers_in.range->value.data + 6;
+
+ for ( ;; ) {
+ start = end = 0;
+
+ while (*p == ' ') { p++; }
+
+ if (*p < '0' || *p > '9') {
+ rc = NGX_HTTP_RANGE_NOT_SATISFIABLE;
+ break;
+ }
+
+ while (*p >= '0' && *p <= '9') {
+ start = start * 10 + *p++ - '0';
+ }
+
+ while (*p == ' ') { p++; }
+
+ if (*p++ != '-') {
+ rc = NGX_HTTP_RANGE_NOT_SATISFIABLE;
+ break;
+ }
+
+ if (start >= r->headers_out.content_length) {
+ rc = NGX_HTTP_RANGE_NOT_SATISFIABLE;
+ break;
+ }
+
+ while (*p == ' ') { p++; }
+
+ if (*p == ',' || *p == '\0') {
+ ngx_test_null(range, ngx_push_array(&r->headers_out.ranges),
+ NGX_ERROR);
+ range->start = start;
+ range->end = r->headers_out.content_length;
+
+ if (*p++ == ',') {
+ continue;
+ }
+
+ break;
+ }
+
+ if (*p < '0' || *p > '9') {
+ rc = NGX_HTTP_RANGE_NOT_SATISFIABLE;
+ break;
+ }
+
+ while (*p >= '0' && *p <= '9') {
+ end = end * 10 + *p++ - '0';
+ }
+
+ while (*p == ' ') { p++; }
+
+ if (*p != ',' && *p != '\0') {
+ rc = NGX_HTTP_RANGE_NOT_SATISFIABLE;
+ break;
+ }
+
+ if (end >= r->headers_out.content_length || start >= end) {
+ rc = NGX_HTTP_RANGE_NOT_SATISFIABLE;
+ break;
+ }
+
+ ngx_test_null(range, ngx_push_array(&r->headers_out.ranges), NGX_ERROR);
+ range->start = start;
+ range->end = end + 1;
+
+ if (*p++ == ',') {
+ continue;
+ }
+
+ break;
+ }
+
+ if (rc) {
+ r->headers_out.status = rc;
+ r->headers_out.ranges.nelts = 0;
+
+ ngx_test_null(r->headers_out.content_range,
+ ngx_push_table(r->headers_out.headers),
+ NGX_ERROR);
+
+ ngx_test_null(r->headers_out.content_range->value.data,
+ ngx_palloc(r->pool, 8 + 20 + 1),
+ NGX_ERROR);
+
+ r->headers_out.content_range->value.len =
+ ngx_snprintf(r->headers_out.content_range->value.data,
+ 8 + 20 + 1, "bytes */" OFF_FMT,
+ r->headers_out.content_length);
+
+ r->headers_out.content_length = -1;
+
+ return rc;
+
+ } else {
+ r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
+
+ if (r->headers_out.ranges.nelts == 1) {
+ ngx_test_null(r->headers_out.content_range,
+ ngx_push_table(r->headers_out.headers),
+ NGX_ERROR);
+
+ ngx_test_null(r->headers_out.content_range->value.data,
+ ngx_palloc(r->pool, 6 + 20 + 1 + 20 + 1 + 20 + 1),
+ NGX_ERROR);
+
+ r->headers_out.content_range->value.len =
+ ngx_snprintf(r->headers_out.content_range->value.data,
+ 6 + 20 + 1 + 20 + 1 + 20 + 1,
+ "bytes " OFF_FMT "-" OFF_FMT "/" OFF_FMT,
+ range->start, range->end - 1,
+ r->headers_out.content_length);
+
+ r->headers_out.content_length = range->end - range->start;
+
+ } else {
+
+#if 0
+ /* TODO: what if no content_type ?? */
+ ngx_test_null(r->headers_out.content_type,
+ ngx_push_table(r->headers_out.headers),
+ NGX_ERROR);
+#endif
+
+ ngx_http_create_ctx(r, ctx, ngx_http_range_filter_module,
+ sizeof(ngx_http_range_filter_ctx_t), NGX_ERROR);
+
+ len = 4 + 10 + 2 + 14 + r->headers_out.content_type->value.len
+ + 2 + 21 + 1;
+
+ if (r->headers_out.charset.len) {
+ len += 10 + r->headers_out.charset.len;
+ }
+
+ ngx_test_null(ctx->boundary_header.data, ngx_palloc(r->pool, len),
+ NGX_ERROR);
+
+ boundary = ngx_next_temp_number(0);
+
+ if (r->headers_out.charset.len) {
+ ctx->boundary_header.len =
+ ngx_snprintf(ctx->boundary_header.data, len,
+ CRLF "--%010u" CRLF
+ "Content-Type: %s; charset=%s" CRLF
+ "Content-Range: bytes ",
+ boundary,
+ r->headers_out.content_type->value.data,
+ r->headers_out.charset.data);
+
+ r->headers_out.charset.len = 0;
+
+ } else {
+ ctx->boundary_header.len =
+ ngx_snprintf(ctx->boundary_header.data, len,
+ CRLF "--%010u" CRLF
+ "Content-Type: %s" CRLF
+ "Content-Range: bytes ",
+ boundary,
+ r->headers_out.content_type->value.data);
+ }
+
+ ngx_test_null(r->headers_out.content_type->value.data,
+ ngx_palloc(r->pool, 31 + 10 + 1),
+ NGX_ERROR);
+
+ r->headers_out.content_type->value.len =
+ ngx_snprintf(r->headers_out.content_type->value.data,
+ 31 + 10 + 1,
+ "multipart/byteranges; boundary=%010u",
+ boundary);
+
+ /* the last "CRLF--BOUNDARY--CRLF" */
+ len = 4 + 10 + 4;
+
+ range = r->headers_out.ranges.elts;
+ for (i = 0; i < r->headers_out.ranges.nelts; i++) {
+ ngx_test_null(range[i].content_range.data,
+ ngx_palloc(r->pool, 20 + 1 + 20 + 1 + 20 + 5),
+ NGX_ERROR);
+
+ range[i].content_range.len =
+ ngx_snprintf(range[i].content_range.data,
+ 20 + 1 + 20 + 1 + 20 + 5,
+ OFF_FMT "-" OFF_FMT "/" OFF_FMT CRLF CRLF,
+ range[i].start, range[i].end - 1,
+ r->headers_out.content_length);
+
+ len += ctx->boundary_header.len + range[i].content_range.len
+ + range[i].end - range[i].start;
+ }
+
+ r->headers_out.content_length = len;
+ }
+ }
+
+ return next_header_filter(r);
+}
+
+
+static int ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
+{
+ int i;
+ ngx_hunk_t *h;
+ ngx_chain_t *out, *hce, *rce, *dce, **le;
+ ngx_http_range_t *range;
+ ngx_http_range_filter_ctx_t *ctx;
+
+ if (r->headers_out.ranges.nelts == 0) {
+ return next_body_filter(r, in);
+ }
+
+ /* the optimized version for the static files only
+ that are passed in the single file hunk */
+
+ if (in
+ && in->hunk->type & NGX_HUNK_FILE
+ && in->hunk->type & NGX_HUNK_LAST)
+ {
+ if (r->headers_out.ranges.nelts == 1) {
+ range = r->headers_out.ranges.elts;
+ in->hunk->file_pos = range->start;
+ in->hunk->file_last = range->end;
+
+ return next_body_filter(r, in);
+ }
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_range_filter_module);
+ le = &out;
+
+ range = r->headers_out.ranges.elts;
+ for (i = 0; i < r->headers_out.ranges.nelts; i++) {
+
+ ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
+ h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_MEMORY;
+ h->pos = ctx->boundary_header.data;
+ h->last = ctx->boundary_header.data + ctx->boundary_header.len;
+
+ ngx_test_null(hce, ngx_alloc_chain_entry(r->pool), NGX_ERROR);
+ hce->hunk = h;
+
+ ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
+ h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP;
+ h->pos = range[i].content_range.data;
+ h->last = range[i].content_range.data + range[i].content_range.len;
+
+ ngx_test_null(rce, ngx_alloc_chain_entry(r->pool), NGX_ERROR);
+ rce->hunk = h;
+
+ ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
+ h->type = NGX_HUNK_FILE;
+ h->file_pos = range[i].start;
+ h->file_last = range[i].end;
+ h->file = in->hunk->file;
+
+ ngx_test_null(dce, ngx_alloc_chain_entry(r->pool), NGX_ERROR);
+ dce->hunk = h;
+ dce->next = NULL;
+
+ *le = hce;
+ hce->next = rce;
+ rce->next = dce;
+ le = &dce->next;
+ }
+
+ ngx_test_null(h, ngx_calloc_hunk(r->pool), NGX_ERROR);
+ h->type = NGX_HUNK_IN_MEMORY|NGX_HUNK_TEMP|NGX_HUNK_LAST;
+ ngx_test_null(h->pos, ngx_palloc(r->pool, 4 + 10 + 4), NGX_ERROR);
+ h->last = ngx_cpymem(h->pos, ctx->boundary_header.data, 4 + 10);
+ *h->last++ = '-'; *h->last++ = '-';
+ *h->last++ = CR; *h->last++ = LF;
+
+ ngx_test_null(hce, ngx_alloc_chain_entry(r->pool), NGX_ERROR);
+ hce->hunk = h;
+ hce->next = NULL;
+ *le = hce;
+
+ return next_body_filter(r, out);
+ }
+
+ /* TODO: several incoming hunks of proxied responses
+ and memory hunks on platforms that have no sendfile() */
+
+ return next_body_filter(r, in);
+}
+
+
+static int ngx_http_range_filter_init(ngx_pool_t *pool)
+{
+ next_header_filter = ngx_http_top_header_filter;
+ ngx_http_top_header_filter = ngx_http_range_header_filter;
+
+ next_body_filter = ngx_http_top_body_filter;
+ ngx_http_top_body_filter = ngx_http_range_body_filter;
+
+ return NGX_OK;
+}
diff --git a/src/http/modules/ngx_http_static_handler.c b/src/http/modules/ngx_http_static_handler.c
index bc88fc920..8ea6a0a00 100644
--- a/src/http/modules/ngx_http_static_handler.c
+++ b/src/http/modules/ngx_http_static_handler.c
@@ -2,10 +2,6 @@
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
-#include <ngx_http_config.h>
-#include <ngx_http_core_module.h>
-#include <ngx_http_output_filter.h>
-
int ngx_http_static_handler(ngx_http_request_t *r)
@@ -32,7 +28,8 @@ int ngx_http_static_handler(ngx_http_request_t *r)
ctx->action = "sending response";
if (r->file.fd == NGX_INVALID_FILE) {
- r->file.fd = ngx_open_file(r->file.name.data, NGX_FILE_RDONLY);
+ r->file.fd = ngx_open_file(r->file.name.data,
+ NGX_FILE_RDONLY, NGX_FILE_OPEN);
if (r->file.fd == NGX_INVALID_FILE) {
err = ngx_errno;
@@ -129,6 +126,10 @@ int ngx_http_static_handler(ngx_http_request_t *r)
rc = ngx_http_send_header(r);
+ if (rc == NGX_ERROR || rc > NGX_OK) {
+ ngx_http_finalize_request(r, rc);
+ return NGX_OK;
+ }
if (r->header_only) {
if (rc == NGX_AGAIN) {