summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2008-08-04 15:05:24 +0000
committerJonathan Kolb <jon@b0g.us>2008-08-04 15:05:24 +0000
commite2b02861808fe0540d9e824c4a6269e059f9ebcb (patch)
treef4e517379e41252071b525a8f9242f0823b38dda
parent49d825b7bd87fb50315138ac87135c1d85354d5a (diff)
downloadnginx-e2b02861808fe0540d9e824c4a6269e059f9ebcb.tar.gz
CHANGES not updated for this versionv0.7.8
-rw-r--r--auto/feature4
-rw-r--r--auto/lib/conf4
-rw-r--r--auto/lib/libxslt/conf78
-rw-r--r--auto/lib/pcre/conf2
-rw-r--r--auto/modules11
-rw-r--r--auto/options5
-rw-r--r--auto/os/features11
-rw-r--r--auto/sources4
-rw-r--r--src/core/nginx.h2
-rw-r--r--src/core/ngx_hash.c29
-rw-r--r--src/core/ngx_hash.h2
-rw-r--r--src/core/ngx_string.c11
-rw-r--r--src/core/ngx_string.h2
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c11
-rw-r--r--src/http/modules/ngx_http_map_module.c8
-rw-r--r--src/http/modules/ngx_http_proxy_module.c5
-rw-r--r--src/http/modules/ngx_http_ssi_filter_module.c32
-rw-r--r--src/http/modules/ngx_http_sub_filter_module.c7
-rw-r--r--src/http/modules/ngx_http_xslt_filter_module.c1109
-rw-r--r--src/http/modules/perl/nginx.pm2
-rw-r--r--src/http/modules/perl/nginx.xs12
-rw-r--r--src/http/ngx_http.c140
-rw-r--r--src/http/ngx_http.h8
-rw-r--r--src/http/ngx_http_core_module.c61
-rw-r--r--src/http/ngx_http_core_module.h2
-rw-r--r--src/http/ngx_http_request.c21
-rw-r--r--src/http/ngx_http_request.h2
-rw-r--r--src/http/ngx_http_script.c42
-rw-r--r--src/http/ngx_http_upstream.c3
-rw-r--r--src/http/ngx_http_variables.c82
-rw-r--r--src/os/unix/ngx_atomic.h7
-rw-r--r--src/os/unix/ngx_files.h5
32 files changed, 1585 insertions, 139 deletions
diff --git a/auto/feature b/auto/feature
index 2cb405921..cd71e27b1 100644
--- a/auto/feature
+++ b/auto/feature
@@ -19,7 +19,9 @@ if test -n "$ngx_feature_name"; then
fi
if test -n "$ngx_feature_path"; then
- ngx_feature_inc_path="-I $ngx_feature_path"
+ for ngx_temp in $ngx_feature_path; do
+ ngx_feature_inc_path="$ngx_feature_inc_path -I $ngx_temp"
+ done
fi
cat << END > $NGX_AUTOTEST.c
diff --git a/auto/lib/conf b/auto/lib/conf
index fcf2b3f63..0462228ab 100644
--- a/auto/lib/conf
+++ b/auto/lib/conf
@@ -41,6 +41,10 @@ if [ $USE_ZLIB = YES ]; then
. auto/lib/zlib/conf
fi
+if [ $USE_LIBXSLT = YES ]; then
+ . auto/lib/libxslt/conf
+fi
+
if [ $USE_PERL = YES ]; then
. auto/lib/perl/conf
fi
diff --git a/auto/lib/libxslt/conf b/auto/lib/libxslt/conf
new file mode 100644
index 000000000..877c17189
--- /dev/null
+++ b/auto/lib/libxslt/conf
@@ -0,0 +1,78 @@
+
+# Copyright (C) Igor Sysoev
+
+
+ ngx_feature="libxslt"
+ ngx_feature_name=
+ ngx_feature_run=no
+ ngx_feature_incs="#include <libxml/parser.h>
+ #include <libxml/tree.h>
+ #include <libxslt/xslt.h>
+ #include <libxslt/xsltInternals.h>
+ #include <libxslt/transform.h>
+ #include <libxslt/xsltutils.h>"
+ ngx_feature_path="/usr/include/libxml2"
+ ngx_feature_libs="-lxml2 -lxslt"
+ ngx_feature_test="xmlParserCtxtPtr ctxt = NULL;
+ xsltStylesheetPtr sheet = NULL;
+ xmlDocPtr doc;
+ doc = xmlParseChunk(ctxt, NULL, 0, 0);
+ xsltApplyStylesheet(sheet, doc, NULL);"
+ . auto/feature
+
+
+if [ $ngx_found = no ]; then
+
+ # FreeBSD port
+
+ ngx_feature="libxslt in /usr/local/"
+ ngx_feature_path="/usr/local/include/libxml2 /usr/local/include"
+
+ if [ $NGX_RPATH = YES ]; then
+ ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lxml2 -lxslt"
+ else
+ ngx_feature_libs="-L/usr/local/lib -lxml2 -lxslt"
+ fi
+
+ . auto/feature
+fi
+
+
+if [ $ngx_found = no ]; then
+
+ # NetBSD port
+
+ ngx_feature="libxslt in /usr/pkg/"
+ ngx_feature_path="/usr/pkg/include/libxml2 /usr/pkg/include"
+
+ if [ $NGX_RPATH = YES ]; then
+ ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lxml2 -lxslt"
+ else
+ ngx_feature_libs="-L/usr/pkg/lib -lxml2 -lxslt"
+ fi
+
+ . auto/feature
+fi
+
+
+if [ $ngx_found = no ]; then
+
+ # MacPorts
+
+ ngx_feature="libxslt in /opt/local/"
+ ngx_feature_path="/opt/local/include/libxml2 /opt/local/include"
+
+ if [ $NGX_RPATH = YES ]; then
+ ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lxml2 -lxslt"
+ else
+ ngx_feature_libs="-L/opt/local/lib -lxml2 -lxslt"
+ fi
+
+ . auto/feature
+fi
+
+
+if [ $ngx_found = yes ]; then
+ CORE_INCS="$CORE_INCS $ngx_feature_path"
+ CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
+fi
diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf
index 9a9c6ee4f..3a26b858f 100644
--- a/auto/lib/pcre/conf
+++ b/auto/lib/pcre/conf
@@ -114,7 +114,7 @@ else
if [ $ngx_found = no ]; then
- # Linux package
+ # RedHat RPM, Solaris package
ngx_feature="PCRE library in /usr/include/pcre/"
ngx_feature_path="/usr/include/pcre"
diff --git a/auto/modules b/auto/modules
index cba3768d5..0c2a36787 100644
--- a/auto/modules
+++ b/auto/modules
@@ -76,6 +76,9 @@ fi
# the module order is important
+# ngx_http_static_module
+# ngx_http_gzip_static_module
+# ngx_http_dav_module
# ngx_http_autoindex_module
# ngx_http_index_module
#
@@ -92,6 +95,8 @@ fi
# ngx_http_postpone_filter
# ngx_http_charset_filter
# ngx_http_ssi_filter
+# ngx_http_xslt_filter
+# ngx_http_sub_filter
# ngx_http_addition_filter
# ngx_http_userid_filter
# ngx_http_headers_filter
@@ -129,6 +134,12 @@ if [ $HTTP_SSI = YES ]; then
HTTP_SRCS="$HTTP_SRCS $HTTP_SSI_SRCS"
fi
+if [ $HTTP_XSLT = YES ]; then
+ USE_LIBXSLT=YES
+ HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_XSLT_FILTER_MODULE"
+ HTTP_SRCS="$HTTP_SRCS $HTTP_XSLT_SRCS"
+fi
+
if [ $HTTP_SUB = YES ]; then
HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SUB_FILTER_MODULE"
HTTP_SRCS="$HTTP_SRCS $HTTP_SUB_SRCS"
diff --git a/auto/options b/auto/options
index e00bf9764..1498243bb 100644
--- a/auto/options
+++ b/auto/options
@@ -56,6 +56,7 @@ HTTP_SSL=NO
HTTP_SSI=YES
HTTP_POSTPONE=NO
HTTP_REALIP=NO
+HTTP_XSLT=NO
HTTP_SUB=NO
HTTP_ADDITION=NO
HTTP_DAV=NO
@@ -115,6 +116,8 @@ ZLIB_ASM=NO
USE_PERL=NO
NGX_PERL=perl
+USE_LIBXSLT=NO
+
NGX_GOOGLE_PERFTOOLS=NO
NGX_CPU_CACHE_LINE=
@@ -162,6 +165,7 @@ do
--with-http_ssl_module) HTTP_SSL=YES ;;
--with-http_realip_module) HTTP_REALIP=YES ;;
--with-http_addition_module) HTTP_ADDITION=YES ;;
+ --with-http_xslt_module) HTTP_XSLT=YES ;;
--with-http_sub_module) HTTP_SUB=YES ;;
--with-http_dav_module) HTTP_DAV=YES ;;
--with-http_flv_module) HTTP_FLV=YES ;;
@@ -276,6 +280,7 @@ cat << END
--with-http_ssl_module enable ngx_http_ssl_module
--with-http_realip_module enable ngx_http_realip_module
--with-http_addition_module enable ngx_http_addition_module
+ --with-http_xslt_module enable ngx_http_xslt_module
--with-http_sub_module enable ngx_http_sub_module
--with-http_dav_module enable ngx_http_dav_module
--with-http_flv_module enable ngx_http_flv_module
diff --git a/auto/os/features b/auto/os/features
index ffb27a481..8efed75a2 100644
--- a/auto/os/features
+++ b/auto/os/features
@@ -190,3 +190,14 @@ ngx_feature_path=
ngx_feature_libs=
ngx_feature_test="fcntl(0, F_NOCACHE, 1);"
. auto/feature
+
+
+ngx_feature="directio()"
+ngx_feature_name="NGX_HAVE_DIRECTIO"
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/types.h>
+ #include <sys/fcntl.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="directio(0, DIRECTIO_ON);"
+. auto/feature
diff --git a/auto/sources b/auto/sources
index 12ab1b79d..82734ddb9 100644
--- a/auto/sources
+++ b/auto/sources
@@ -332,6 +332,10 @@ HTTP_SSI_DEPS=src/http/modules/ngx_http_ssi_filter_module.h
HTTP_SSI_SRCS=src/http/modules/ngx_http_ssi_filter_module.c
+HTTP_XSLT_FILTER_MODULE=ngx_http_xslt_filter_module
+HTTP_XSLT_SRCS=src/http/modules/ngx_http_xslt_filter_module.c
+
+
HTTP_SUB_FILTER_MODULE=ngx_http_sub_filter_module
HTTP_SUB_SRCS=src/http/modules/ngx_http_sub_filter_module.c
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 44b0099d2..576c7feaa 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
#define _NGINX_H_INCLUDED_
-#define NGINX_VERSION "0.7.7"
+#define NGINX_VERSION "0.7.8"
#define NGINX_VER "nginx/" NGINX_VERSION
#define NGINX_VAR "NGINX"
diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c
index abd2cf173..2954266ae 100644
--- a/src/core/ngx_hash.c
+++ b/src/core/ngx_hash.c
@@ -390,9 +390,7 @@ found:
elt->value = names[n].value;
elt->len = (u_char) names[n].key.len;
- for (i = 0; i < names[n].key.len; i++) {
- elt->name[i] = ngx_tolower(names[n].key.data[i]);
- }
+ ngx_strlow(elt->name, names[n].key.data, names[n].key.len);
test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n]));
}
@@ -622,6 +620,24 @@ ngx_hash_key_lc(u_char *data, size_t len)
}
+ngx_uint_t
+ngx_hash_strlow(u_char *dst, u_char *src, size_t n)
+{
+ ngx_uint_t key;
+
+ key = 0;
+
+ while (n--) {
+ *dst = ngx_tolower(*src);
+ key = ngx_hash(key, *dst);
+ dst++;
+ src++;
+ }
+
+ return key;
+}
+
+
ngx_int_t
ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type)
{
@@ -796,12 +812,7 @@ wildcard:
/* wildcard hash */
- k = 0;
-
- for (i = skip; i < last; i++) {
- key->data[i] = ngx_tolower(key->data[i]);
- k = ngx_hash(k, key->data[i]);
- }
+ k = ngx_hash_strlow(&key->data[skip], &key->data[skip], last - skip);
k %= ha->hsize;
diff --git a/src/core/ngx_hash.h b/src/core/ngx_hash.h
index 95e04046f..76e3c774e 100644
--- a/src/core/ngx_hash.h
+++ b/src/core/ngx_hash.h
@@ -110,6 +110,8 @@ ngx_int_t ngx_hash_wildcard_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
#define ngx_hash(key, c) ((ngx_uint_t) key * 31 + c)
ngx_uint_t ngx_hash_key(u_char *data, size_t len);
ngx_uint_t ngx_hash_key_lc(u_char *data, size_t len);
+ngx_uint_t ngx_hash_strlow(u_char *dst, u_char *src, size_t n);
+
ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type);
ngx_int_t ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key,
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index 2da6c8319..203cd3e37 100644
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -8,6 +8,17 @@
#include <ngx_core.h>
+void
+ngx_strlow(u_char *dst, u_char *src, size_t n)
+{
+ while (n--) {
+ *dst = ngx_tolower(*src);
+ dst++;
+ src++;
+ }
+}
+
+
u_char *
ngx_cpystrn(u_char *dst, u_char *src, size_t n)
{
diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h
index dfb3bc4cc..fff618b19 100644
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -43,6 +43,8 @@ typedef struct {
#define ngx_tolower(c) (u_char) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c)
#define ngx_toupper(c) (u_char) ((c >= 'a' && c <= 'z') ? (c & ~0x20) : c)
+void ngx_strlow(u_char *dst, u_char *src, size_t n);
+
#define ngx_strncmp(s1, s2, n) strncmp((const char *) s1, (const char *) s2, n)
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index b975c0675..8d57a46a2 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -1120,9 +1120,7 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
} else {
- for (i = 0; i < h->key.len; i++) {
- h->lowcase_key[i] = ngx_tolower(h->key.data[i]);
- }
+ ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
}
hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
@@ -1167,6 +1165,13 @@ ngx_http_fastcgi_process_header(ngx_http_request_t *r)
u->headers_in.status_n = status;
u->headers_in.status_line = *status_line;
+ } else if (u->headers_in.location) {
+ u->headers_in.status_n = 302;
+ u->headers_in.status_line.len =
+ sizeof("302 Moved Temporarily") - 1;
+ u->headers_in.status_line.data =
+ (u_char *) "302 Moved Temporarily";
+
} else {
u->headers_in.status_n = 200;
u->headers_in.status_line.len = sizeof("200 OK") - 1;
diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c
index cedc50879..c2459f271 100644
--- a/src/http/modules/ngx_http_map_module.c
+++ b/src/http/modules/ngx_http_map_module.c
@@ -106,7 +106,7 @@ ngx_http_map_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
size_t len;
u_char *name;
- ngx_uint_t key, i;
+ ngx_uint_t key;
ngx_http_variable_value_t *vv, *value;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -135,11 +135,7 @@ ngx_http_map_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
return NGX_ERROR;
}
- key = 0;
- for (i = 0; i < len; i++) {
- name[i] = ngx_tolower(vv->data[i]);
- key = ngx_hash(key, name[i]);
- }
+ key = ngx_hash_strlow(name, vv->data, len);
value = ngx_hash_find_combined(&map->hash, key, name, len);
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 8a7f2ab9e..880d99840 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -1196,7 +1196,6 @@ static ngx_int_t
ngx_http_proxy_process_header(ngx_http_request_t *r)
{
ngx_int_t rc;
- ngx_uint_t i;
ngx_table_elt_t *h;
ngx_http_upstream_header_t *hh;
ngx_http_upstream_main_conf_t *umcf;
@@ -1237,9 +1236,7 @@ ngx_http_proxy_process_header(ngx_http_request_t *r)
ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
} else {
- for (i = 0; i < h->key.len; i++) {
- h->lowcase_key[i] = ngx_tolower(h->key.data[i]);
- }
+ ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
}
hh = ngx_hash_find(&umcf->headers_in_hash, h->hash,
diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c
index d8fc8f3fc..5de41f325 100644
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -1605,7 +1605,7 @@ ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
size_t *size, len, prefix, part_len;
ngx_str_t var, *val;
ngx_int_t key;
- ngx_uint_t i, j, n, bracket, quoted;
+ ngx_uint_t i, n, bracket, quoted;
ngx_array_t lengths, values;
ngx_http_variable_value_t *vv;
@@ -1731,12 +1731,7 @@ ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
goto invalid_variable;
}
- key = 0;
-
- for (j = 0; j < var.len; j++) {
- var.data[j] = ngx_tolower(var.data[j]);
- key = ngx_hash(key, var.data[j]);
- }
+ key = ngx_hash_strlow(var.data, var.data, var.len);
val = ngx_http_ssi_get_variable(r, &var, key);
@@ -2025,12 +2020,7 @@ ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
}
if (set) {
- key = 0;
-
- for (i = 0; i < set->len; i++) {
- set->data[i] = ngx_tolower(set->data[i]);
- key = ngx_hash(key, set->data[i]);
- }
+ key = ngx_hash_strlow(set->data, set->data, set->len);
psr = ngx_palloc(r->pool, sizeof(ngx_http_post_subrequest_t));
if (psr == NULL) {
@@ -2141,7 +2131,6 @@ ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
u_char *p;
uintptr_t len;
ngx_int_t key;
- ngx_uint_t i;
ngx_buf_t *b;
ngx_str_t *var, *value, *enc, text;
ngx_chain_t *cl;
@@ -2152,12 +2141,7 @@ ngx_http_ssi_echo(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"ssi echo \"%V\"", var);
- key = 0;
-
- for (i = 0; i < var->len; i++) {
- var->data[i] = ngx_tolower(var->data[i]);
- key = ngx_hash(key, var->data[i]);
- }
+ key = ngx_hash_strlow(var->data, var->data, var->len);
value = ngx_http_ssi_get_variable(r, var, key);
@@ -2310,7 +2294,6 @@ ngx_http_ssi_set(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
ngx_str_t **params)
{
ngx_int_t key, rc;
- ngx_uint_t i;
ngx_str_t *name, *value, *vv;
ngx_http_ssi_var_t *var;
ngx_http_ssi_ctx_t *mctx;
@@ -2337,12 +2320,7 @@ ngx_http_ssi_set(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
return rc;
}
- key = 0;
-
- for (i = 0; i < name->len; i++) {
- name->data[i] = ngx_tolower(name->data[i]);
- key = ngx_hash(key, name->data[i]);
- }
+ key = ngx_hash_strlow(name->data, name->data, name->len);
vv = ngx_http_ssi_get_variable(r, name, key);
diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c
index e45ca6e49..62a8f0814 100644
--- a/src/http/modules/ngx_http_sub_filter_module.c
+++ b/src/http/modules/ngx_http_sub_filter_module.c
@@ -632,7 +632,6 @@ ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ngx_str_t *value;
ngx_int_t n;
- ngx_uint_t i;
ngx_http_script_compile_t sc;
if (slcf->match.len) {
@@ -641,11 +640,9 @@ ngx_http_sub_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
value = cf->args->elts;
- slcf->match = value[1];
+ ngx_strlow(value[1].data, value[1].data, value[1].len);
- for (i = 0; i < value[1].len; i++) {
- value[1].data[i] = ngx_tolower(value[1].data[i]);
- }
+ slcf->match = value[1];
n = ngx_http_script_variables_count(&value[2]);
diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c
new file mode 100644
index 000000000..364fed642
--- /dev/null
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -0,0 +1,1109 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxslt/xslt.h>
+#include <libxslt/xsltInternals.h>
+#include <libxslt/transform.h>
+#include <libxslt/xsltutils.h>
+
+
+#ifndef NGX_HTTP_XSLT_REUSE_DTD
+#define NGX_HTTP_XSLT_REUSE_DTD 1
+#endif
+
+
+typedef struct {
+ ngx_array_t *lengths;
+ ngx_array_t *values;
+} ngx_http_xslt_param_t;
+
+
+typedef struct {
+ xsltStylesheetPtr stylesheet;
+ ngx_array_t params; /* ngx_http_xslt_param_t */
+} ngx_http_xslt_sheet_t;
+
+
+typedef struct {
+ xmlDtdPtr dtd;
+ ngx_array_t sheets; /* ngx_http_xslt_sheet_t */
+ ngx_hash_t types_hash;
+ ngx_array_t *keys;
+} ngx_http_xslt_filter_conf_t;
+
+
+typedef struct {
+ xmlDocPtr doc;
+ xmlParserCtxtPtr ctxt;
+ xmlSAXHandler *sax;
+ ngx_http_request_t *request;
+ ngx_array_t params;
+ unsigned done:1;
+ unsigned html:1;
+} ngx_http_xslt_filter_ctx_t;
+
+
+static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r,
+ ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
+static ngx_int_t ngx_http_xslt_filter_internal_error(ngx_http_request_t *r);
+static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r,
+ ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b);
+
+
+static void ngx_http_xslt_sax_start_document(void *data);
+static void ngx_http_xslt_sax_end_document(void *data);
+static void ngx_http_xslt_sax_internal_subset(void *data, const xmlChar *name,
+ const xmlChar *externalId, const xmlChar *systemId);
+static void ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name,
+ const xmlChar *externalId, const xmlChar *systemId);
+static void ngx_http_xslt_sax_entity_decl(void *data, const xmlChar *name,
+ int type, const xmlChar *publicId, const xmlChar *systemId,
+ xmlChar *content);
+static void ngx_http_xslt_sax_attribute_decl(void *data, const xmlChar *elem,
+ const xmlChar *fullname, int type, int def, const xmlChar *defaultValue,
+ xmlEnumerationPtr tree);
+static void ngx_http_xslt_sax_element_decl(void *data, const xmlChar * name,
+ int type, xmlElementContentPtr content);
+static void ngx_http_xslt_sax_notation_decl(void *data, const xmlChar *name,
+ const xmlChar *publicId, const xmlChar *systemId);
+static void ngx_http_xslt_sax_unparsed_entity_decl(void *data,
+ const xmlChar *name, const xmlChar *publicId, const xmlChar *systemId,
+ const xmlChar *notationName);
+static void ngx_http_xslt_sax_start_element(void *data,
+ const xmlChar *localname, const xmlChar *prefix, const xmlChar *URI,
+ int nb_namespaces, const xmlChar **namespaces, int nb_attributes,
+ int nb_defaulted, const xmlChar **attributes);
+static void ngx_http_xslt_sax_end_element(void *data,
+ const xmlChar * localname ATTRIBUTE_UNUSED,
+ const xmlChar * prefix ATTRIBUTE_UNUSED,
+ const xmlChar * URI ATTRIBUTE_UNUSED);
+static void ngx_http_xslt_sax_characters(void *data, const xmlChar *p, int len);
+static void ngx_http_xslt_sax_cdata_block(void *data, const xmlChar *p,
+ int len);
+static xmlEntityPtr ngx_http_xslt_sax_get_entity(void *data,
+ const xmlChar *name);
+static xmlEntityPtr ngx_http_xslt_sax_get_parameter_entity(void *data,
+ const xmlChar *name);
+static xmlParserInputPtr ngx_http_xslt_sax_resolve_entity(void *data,
+ const xmlChar *publicId, const xmlChar *systemId);
+static void ngx_http_xslt_sax_reference(void *data, const xmlChar *name);
+static void ngx_http_xslt_sax_comment(void *data, const xmlChar *value);
+static void ngx_http_xslt_sax_processing_instruction(void *data,
+ const xmlChar *target, const xmlChar *pidata);
+static int ngx_http_xslt_sax_is_standalone(void *data);
+static int ngx_http_xslt_sax_has_internal_subset(void *data);
+static int ngx_http_xslt_sax_has_external_subset(void *data);
+static void ngx_cdecl ngx_http_xslt_sax_error(void *data, const char *msg, ...);
+
+
+static ngx_buf_t *ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
+ ngx_http_xslt_filter_ctx_t *ctx);
+static ngx_int_t ngx_http_xslt_params(ngx_http_request_t *r,
+ ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params);
+static void ngx_http_xslt_cleanup(void *data);
+
+static char *ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static void ngx_http_xslt_cleanup_stylesheet(void *data);
+static void *ngx_http_xslt_filter_create_conf(ngx_conf_t *cf);
+static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent,
+ void *child);
+static ngx_int_t ngx_http_xslt_filter_init(ngx_conf_t *cf);
+
+
+ngx_str_t ngx_http_xslt_default_types[] = {
+ ngx_string("text/xml"),
+ ngx_null_string
+};
+
+
+static ngx_command_t ngx_http_xslt_filter_commands[] = {
+
+ { ngx_string("xml_entities"),
+ NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1,
+ ngx_http_xslt_entities,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("xslt_stylesheet"),
+ NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_1MORE,
+ ngx_http_xslt_stylesheet,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ { ngx_string("xslt_types"),
+ NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_1MORE,
+ ngx_http_types_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_xslt_filter_conf_t, keys),
+ &ngx_http_xslt_default_types[0] },
+
+ ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_xslt_filter_module_ctx = {
+ NULL, /* preconfiguration */
+ ngx_http_xslt_filter_init, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ ngx_http_xslt_filter_create_conf, /* create location configuration */
+ ngx_http_xslt_filter_merge_conf /* merge location configuration */
+};
+
+
+ngx_module_t ngx_http_xslt_filter_module = {
+ NGX_MODULE_V1,
+ &ngx_http_xslt_filter_module_ctx, /* module context */
+ ngx_http_xslt_filter_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
+static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
+
+
+static ngx_int_t
+ngx_http_xslt_header_filter(ngx_http_request_t *r)
+{
+ ngx_http_xslt_filter_ctx_t *ctx;
+ ngx_http_xslt_filter_conf_t *conf;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "xslt filter header");
+
+ if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) {
+ return ngx_http_next_header_filter(r);
+ }
+
+ conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
+
+ if (conf->sheets.nelts == 0
+ || ngx_http_test_content_type(r, &conf->types_hash) == NULL)
+ {
+ return ngx_http_next_header_filter(r);
+ }
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module);
+
+ if (ctx) {
+ return ngx_http_next_header_filter(r);
+ }
+
+ ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_xslt_filter_ctx_t));
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_http_set_ctx(r, ctx, ngx_http_xslt_filter_module);
+
+ r->main_filter_need_in_memory = 1;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_xslt_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
+{
+ ngx_chain_t *cl;
+ ngx_http_xslt_filter_ctx_t *ctx;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "xslt filter body");
+
+ if (in == NULL) {
+ return ngx_http_next_body_filter(r, in);
+ }
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_xslt_filter_module);
+
+ if (ctx == NULL || ctx->done) {
+ return ngx_http_next_body_filter(r, in);
+ }
+
+ for (cl = in; cl; cl = cl->next) {
+
+ if (ngx_http_xslt_add_chunk(r, ctx, cl->buf) != NGX_OK) {
+
+ if (ctx->ctxt->myDoc){
+
+#if (NGX_HTTP_XSLT_REUSE_DTD)
+ ctx->ctxt->myDoc->extSubset = NULL;
+#endif
+ xmlFreeDoc(ctx->ctxt->myDoc);
+ }
+
+ xmlFreeParserCtxt(ctx->ctxt);
+
+ return ngx_http_xslt_send(r, ctx, NULL);
+ }
+
+ if (cl->buf->last_buf) {
+
+ ctx->doc = ctx->ctxt->myDoc;
+
+#if (NGX_HTTP_XSLT_REUSE_DTD)
+ ctx->doc->extSubset = NULL;
+#endif
+
+ xmlFreeParserCtxt(ctx->ctxt);
+
+ if (ctx->ctxt->wellFormed) {
+ return ngx_http_xslt_send(r, ctx,
+ ngx_http_xslt_apply_stylesheet(r, ctx));
+ }
+
+ xmlFreeDoc(ctx->doc);
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "not well formed XML document");
+
+ return ngx_http_xslt_send(r, ctx, NULL);
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
+ ngx_buf_t *b)
+{
+ ngx_int_t rc;
+ ngx_chain_t out;
+ ngx_pool_cleanup_t *cln;
+
+ ctx->done = 1;
+
+ if (b == NULL) {
+ return ngx_http_xslt_filter_internal_error(r);
+ }
+
+ cln = ngx_pool_cleanup_add(r->pool, 0);
+
+ if (cln == NULL) {
+ ngx_free(b->pos);
+ return ngx_http_special_response_handler(r,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ }
+
+ if (ctx->html) {
+ r->headers_out.content_type_len = sizeof("text/html") - 1;
+ r->headers_out.content_type.len = sizeof("text/html") - 1;
+ r->headers_out.content_type.data = (u_char *) "text/html";
+ }
+
+ r->headers_out.content_length_n = b->last - b->pos;
+
+ if (r->headers_out.content_length) {
+ r->headers_out.content_length->hash = 0;
+ r->headers_out.content_length = NULL;
+ }
+
+ r->allow_ranges = 1;
+
+ rc = ngx_http_next_header_filter(r);
+
+ if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+ ngx_free(b->pos);
+ return rc;
+ }
+
+ cln->handler = ngx_http_xslt_cleanup;
+ cln->data = b->pos;
+
+ out.buf = b;
+ out.next = NULL;
+
+ return ngx_http_next_body_filter(r, &out);
+}
+
+
+static ngx_int_t
+ngx_http_xslt_filter_internal_error(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+
+ /* clear the modules contexts */
+ ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module);
+
+ rc = ngx_http_special_response_handler(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+
+ /* NGX_ERROR resets any pending data */
+
+ return (rc == NGX_OK) ? NGX_ERROR : rc;
+}
+
+
+static ngx_int_t
+ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
+ ngx_buf_t *b)
+{
+ int err;
+ xmlSAXHandler *sax;
+ xmlParserCtxtPtr ctxt;
+
+ if (ctx->ctxt == NULL) {
+
+ ctxt = xmlCreatePushParserCtxt(NULL, NULL, NULL, 0, NULL);
+ if (ctxt == NULL) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "xmlCreatePushParserCtxt() failed");
+ return NGX_ERROR;
+ }
+
+ ctx->sax = ngx_palloc(r->pool, sizeof(xmlSAXHandler));
+ if (ctx->sax == NULL) {
+ return NGX_ERROR;
+ }
+
+ sax = ctxt->sax;
+
+ ngx_memcpy(ctx->sax, sax, sizeof(xmlSAXHandler));
+
+ sax->startDocument = ngx_http_xslt_sax_start_document;
+ sax->endDocument = ngx_http_xslt_sax_end_document;
+
+ sax->internalSubset = ngx_http_xslt_sax_internal_subset;
+ sax->externalSubset = ngx_http_xslt_sax_external_subset;
+ sax->entityDecl = ngx_http_xslt_sax_entity_decl;
+ sax->attributeDecl = ngx_http_xslt_sax_attribute_decl;
+ sax->elementDecl = ngx_http_xslt_sax_element_decl;
+ sax->notationDecl = ngx_http_xslt_sax_notation_decl;
+ sax->unparsedEntityDecl = ngx_http_xslt_sax_unparsed_entity_decl;
+ sax->setDocumentLocator = NULL;
+
+ sax->startElementNs = ngx_http_xslt_sax_start_element;
+ sax->endElementNs = ngx_http_xslt_sax_end_element;
+
+ sax->characters = ngx_http_xslt_sax_characters;
+ sax->ignorableWhitespace = ngx_http_xslt_sax_characters;
+ sax->cdataBlock = ngx_http_xslt_sax_cdata_block;
+ sax->getEntity = ngx_http_xslt_sax_get_entity;
+ sax->resolveEntity = ngx_http_xslt_sax_resolve_entity;
+ sax->getParameterEntity = ngx_http_xslt_sax_get_parameter_entity;
+ sax->reference = ngx_http_xslt_sax_reference;
+ sax->comment = ngx_http_xslt_sax_comment;
+ sax->processingInstruction = ngx_http_xslt_sax_processing_instruction;
+
+ sax->isStandalone = ngx_http_xslt_sax_is_standalone;
+ sax->hasInternalSubset = ngx_http_xslt_sax_has_internal_subset;
+ sax->hasExternalSubset = ngx_http_xslt_sax_has_external_subset;
+
+ sax->warning = NULL;
+ sax->error = ngx_http_xslt_sax_error;
+ sax->fatalError = ngx_http_xslt_sax_error;
+
+ ctxt->userData = ctx;
+
+ ctxt->replaceEntities = 1;
+ ctxt->loadsubset = 1;
+
+ ctx->ctxt = ctxt;
+ ctx->request = r;
+ }
+
+ err = xmlParseChunk(ctx->ctxt, (char *) b->pos,
+ (int) (b->last - b->pos), b->last_buf);
+
+ if (err == 0) {
+ b->pos = b->last;
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "xmlParseChunk() failed, error:%d", err);
+
+ return NGX_ERROR;
+}
+
+
+static void
+ngx_http_xslt_sax_start_document(void *data)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->startDocument(ctx->ctxt);
+}
+
+
+static void
+ngx_http_xslt_sax_end_document(void *data)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->endDocument(ctx->ctxt);
+}
+
+
+static void
+ngx_http_xslt_sax_internal_subset(void *data, const xmlChar *name,
+ const xmlChar *externalId, const xmlChar *systemId)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->internalSubset(ctx->ctxt, name, externalId, systemId);
+}
+
+
+static void
+ngx_http_xslt_sax_external_subset(void *data, const xmlChar *name,
+ const xmlChar *externalId, const xmlChar *systemId)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ xmlDocPtr doc;
+ xmlDtdPtr dtd;
+ ngx_http_request_t *r;
+ ngx_http_xslt_filter_conf_t *conf;
+
+ r = ctx->request;
+
+ conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
+
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "xslt filter extSubset: \"%s\" \"%s\" \"%s\"",
+ name ? name : (xmlChar *) "",
+ externalId ? externalId : (xmlChar *) "",
+ systemId ? systemId : (xmlChar *) "");
+
+ doc = ctx->ctxt->myDoc;
+
+#if (NGX_HTTP_XSLT_REUSE_DTD)
+
+ dtd = conf->dtd;
+
+#else
+
+ dtd = xmlCopyDtd(conf->dtd);
+ if (dtd == NULL) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "xmlCopyDtd() failed");
+ return;
+ }
+
+ dtd->name = xmlStrdup(name);
+
+ if (doc->children == NULL) {
+ xmlAddChild((xmlNodePtr) doc, (xmlNodePtr) dtd);
+
+ } else {
+ xmlAddPrevSibling(doc->children, (xmlNodePtr) dtd);
+ }
+
+#endif
+
+ doc->extSubset = dtd;
+}
+
+
+static void
+ngx_http_xslt_sax_entity_decl(void *data, const xmlChar *name, int type,
+ const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->entityDecl(ctx->ctxt, name, type, publicId, systemId, content);
+}
+
+
+static void
+ngx_http_xslt_sax_attribute_decl(void *data, const xmlChar *elem,
+ const xmlChar *fullname, int type, int def, const xmlChar *defaultValue,
+ xmlEnumerationPtr tree)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->attributeDecl(ctx->ctxt, elem, fullname, type, def, defaultValue,
+ tree);
+}
+
+
+static void
+ngx_http_xslt_sax_element_decl(void *data, const xmlChar * name, int type,
+ xmlElementContentPtr content)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->elementDecl(ctx->ctxt, name, type, content);
+}
+
+
+static void
+ngx_http_xslt_sax_notation_decl(void *data, const xmlChar *name,
+ const xmlChar *publicId, const xmlChar *systemId)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->notationDecl(ctx->ctxt, name, publicId, systemId);
+}
+
+
+static void
+ngx_http_xslt_sax_unparsed_entity_decl(void *data, const xmlChar *name,
+ const xmlChar *publicId, const xmlChar *systemId,
+ const xmlChar *notationName)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->unparsedEntityDecl(ctx->ctxt, name, publicId, systemId,
+ notationName);
+}
+
+
+static void
+ngx_http_xslt_sax_start_element(void *data, const xmlChar *localname,
+ const xmlChar *prefix, const xmlChar *URI, int nb_namespaces,
+ const xmlChar **namespaces, int nb_attributes, int nb_defaulted,
+ const xmlChar **attributes)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->startElementNs(ctx->ctxt, localname, prefix, URI, nb_namespaces,
+ namespaces, nb_attributes, nb_defaulted, attributes);
+}
+
+
+static void
+ngx_http_xslt_sax_end_element(void *data,
+ const xmlChar * localname ATTRIBUTE_UNUSED,
+ const xmlChar * prefix ATTRIBUTE_UNUSED,
+ const xmlChar * URI ATTRIBUTE_UNUSED)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->endElementNs(ctx->ctxt, localname, prefix, URI);
+}
+
+
+static void
+ngx_http_xslt_sax_characters(void *data, const xmlChar *p, int len)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->characters(ctx->ctxt, p, len);
+}
+
+
+static void
+ngx_http_xslt_sax_cdata_block(void *data, const xmlChar *p, int len)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->cdataBlock(ctx->ctxt, p, len);
+}
+
+
+static xmlEntityPtr
+ngx_http_xslt_sax_get_entity(void *data, const xmlChar *name)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ return ctx->sax->getEntity(ctx->ctxt, name);
+}
+
+
+static xmlEntityPtr
+ngx_http_xslt_sax_get_parameter_entity(void *data, const xmlChar *name)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ return ctx->sax->getParameterEntity(ctx->ctxt, name);
+}
+
+
+static xmlParserInputPtr
+ngx_http_xslt_sax_resolve_entity(void *data, const xmlChar *publicId,
+ const xmlChar *systemId)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ return ctx->sax->resolveEntity(ctx->ctxt, publicId, systemId);
+}
+
+
+static void
+ngx_http_xslt_sax_reference(void *data, const xmlChar *name)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->reference(ctx->ctxt, name);
+}
+
+
+static void
+ngx_http_xslt_sax_comment(void *data, const xmlChar *value)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->comment(ctx->ctxt, value);
+}
+
+
+static void
+ngx_http_xslt_sax_processing_instruction(void *data, const xmlChar *target,
+ const xmlChar *pidata)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ ctx->sax->processingInstruction(ctx->ctxt, target, pidata);
+}
+
+
+static int
+ngx_http_xslt_sax_is_standalone(void *data)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ return ctx->sax->isStandalone(ctx->ctxt);
+}
+
+
+static int
+ngx_http_xslt_sax_has_internal_subset(void *data)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ return ctx->sax->hasInternalSubset(ctx->ctxt);
+}
+
+
+static int
+ngx_http_xslt_sax_has_external_subset(void *data)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ return ctx->sax->hasExternalSubset(ctx->ctxt);
+}
+
+
+static void ngx_cdecl
+ngx_http_xslt_sax_error(void *data, const char *msg, ...)
+{
+ ngx_http_xslt_filter_ctx_t *ctx = data;
+
+ size_t n;
+ va_list args;
+ u_char buf[NGX_MAX_ERROR_STR];
+
+ buf[0] = '\0';
+
+ va_start(args, msg);
+ n = (size_t) vsnprintf((char *) buf, NGX_MAX_ERROR_STR, msg, args);
+ va_end(args);
+
+ while (--n && (buf[n] == CR || buf[n] == LF)) { /* void */ }
+
+ ngx_log_error(NGX_LOG_ERR, ctx->request->connection->log, 0,
+ "libxml2 error: \"%*s\"", n, buf);
+}
+
+
+static ngx_buf_t *
+ngx_http_xslt_apply_stylesheet(ngx_http_request_t *r,
+ ngx_http_xslt_filter_ctx_t *ctx)
+{
+ int len, rc;
+ ngx_buf_t *b;
+ ngx_uint_t i;
+ xmlChar *buf;
+ xmlDocPtr doc, res;
+ ngx_http_xslt_sheet_t *sheet;
+ ngx_http_xslt_filter_conf_t *conf;
+
+ conf = ngx_http_get_module_loc_conf(r, ngx_http_xslt_filter_module);
+ sheet = conf->sheets.elts;
+ doc = ctx->doc;
+
+ /* preallocate array for 4 params */
+
+ if (ngx_array_init(&ctx->params, r->pool, 4 * 2 + 1, sizeof(char *))
+ != NGX_OK)
+ {
+ xmlFreeDoc(doc);
+ return NULL;
+ }
+
+ for (i = 0; i < conf->sheets.nelts; i++) {
+
+ if (ngx_http_xslt_params(r, ctx, &sheet[i].params) != NGX_OK) {
+ xmlFreeDoc(doc);
+ return NULL;
+ }
+
+ res = xsltApplyStylesheet(sheet[i].stylesheet, doc, ctx->params.elts);
+
+ xmlFreeDoc(doc);
+
+ if (res == NULL) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "xsltApplyStylesheet() failed");
+ return NULL;
+ }
+
+ doc = res;
+
+ /* reset array elements */
+ ctx->params.nelts = 0;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "xslt filter doc type: %d", doc->type);
+
+ ctx->html = (doc->type == XML_HTML_DOCUMENT_NODE) ? 1 : 0;
+
+ rc = xsltSaveResultToString(&buf, &len, doc, sheet[i - 1].stylesheet);
+
+ xmlFreeDoc(doc);
+
+ if (rc != 0) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "xsltSaveResultToString() failed");
+ return NULL;
+ }
+
+ if (len == 0) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "xsltSaveResultToString() returned zero-length result");
+ return NULL;
+ }
+
+ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+ if (b == NULL) {
+ ngx_free(buf);
+ return NULL;
+ }
+
+ b->pos = buf;
+ b->last = buf + len;
+ b->memory = 1;
+ b->last_buf = 1;
+
+ return b;
+}
+
+
+static ngx_int_t
+ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx,
+ ngx_array_t *params)
+{
+ u_char *p, *last, *value, *dst, *src, **s;
+ size_t len;
+ ngx_uint_t i;
+ ngx_str_t string;
+ ngx_http_xslt_param_t *param;
+
+ param = params->elts;
+
+ for (i = 0; i < params->nelts; i++) {
+
+ if (ngx_http_script_run(r, &string, param[i].lengths->elts, 1,
+ param[i].values->elts)
+ == NULL)
+ {
+ return NGX_ERROR;
+ }
+
+ last = string.data + string.len - 1;
+ *last = '\0';
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "xslt filter param: \"%s\"", string.data);
+
+ p = string.data;
+
+ while (p && *p) {
+
+ value = p;
+ p = (u_char *) ngx_strchr(p, '=');
+ if (p == NULL) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "invalid libxslt parameter \"%s\"", value);
+ return NGX_ERROR;
+ }
+ *p++ = '\0';
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "xslt filter param name: \"%s\"", value);
+
+ s = ngx_array_push(&ctx->params);
+ if (s == NULL) {
+ return NGX_ERROR;
+ }
+
+ *s = value;
+
+ value = p;
+ p = (u_char *) ngx_strchr(p, ':');
+
+ if (p) {
+ len = p - value;
+ *p++ = '\0';
+
+ } else {
+ len = last - value;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "xslt filter param value: \"%s\"", value);
+
+ dst = value;
+ src = value;
+
+ ngx_unescape_uri(&dst, &src, len, 0);
+
+ *dst = '\0';
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "xslt filter param unescaped: \"%s\"", value);
+
+ s = ngx_array_push(&ctx->params);
+ if (s == NULL) {
+ return NGX_ERROR;
+ }
+
+ *s = value;
+ }
+ }
+
+ s = ngx_array_push(&ctx->params);
+ if (s == NULL) {
+ return NGX_ERROR;
+ }
+
+ *s = NULL;
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_http_xslt_cleanup(void *data)
+{
+ ngx_free(data);
+}
+
+
+static char *
+ngx_http_xslt_entities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_xslt_filter_conf_t *xlcf = conf;
+
+ ngx_str_t *value;
+
+ if (xlcf->dtd) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ xlcf->dtd = xmlParseDTD(NULL, (xmlChar *) value[1].data);
+
+ if (xlcf->dtd == NULL) {
+ ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "xmlParseDTD() failed");
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+
+static char *
+ngx_http_xslt_stylesheet(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_xslt_filter_conf_t *xlcf = conf;
+
+ ngx_str_t *value;
+ ngx_uint_t i, n;
+ ngx_pool_cleanup_t *cln;
+ ngx_http_xslt_sheet_t *sheet;
+ ngx_http_xslt_param_t *param;
+ ngx_http_script_compile_t sc;
+
+ value = cf->args->elts;
+
+ if (xlcf->sheets.elts == NULL) {
+ if (ngx_array_init(&xlcf->sheets, cf->pool, 1,
+ sizeof(ngx_http_xslt_sheet_t))
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ sheet = ngx_array_push(&xlcf->sheets);
+ if (sheet == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memzero(sheet, sizeof(ngx_http_xslt_sheet_t));
+
+ if (ngx_conf_full_name(cf->cycle, &value[1], 0) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ cln = ngx_pool_cleanup_add(cf->pool, 0);
+ if (cln == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ sheet->stylesheet = xsltParseStylesheetFile(value[1].data);
+ if (sheet->stylesheet == NULL) {
+ ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
+ "xsltParseStylesheetFile(\"%s\") failed",
+ value[1].data);
+ return NGX_CONF_ERROR;
+ }
+
+ cln->handler = ngx_http_xslt_cleanup_stylesheet;
+ cln->data = sheet->stylesheet;
+
+ n = cf->args->nelts;
+
+ if (n == 2) {
+ return NGX_CONF_OK;
+ }
+
+ if (ngx_array_init(&sheet->params, cf->pool, n - 2,
+ sizeof(ngx_http_xslt_param_t))
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 2; i < n; i++) {
+
+ param = ngx_array_push(&sheet->params);
+ if (param == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ param->lengths = NULL;
+ param->values = NULL;
+
+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+ sc.cf = cf;
+ sc.source = &value[i];
+ sc.lengths = &param->lengths;
+ sc.values = &param->values;
+ sc.variables = ngx_http_script_variables_count(&value[i]);
+ sc.complete_lengths = 1;
+ sc.complete_values = 1;
+
+ if (ngx_http_script_compile(&sc) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static void
+ngx_http_xslt_cleanup_stylesheet(void *data)
+{
+ xsltStylesheetPtr stylesheet = data;
+
+ xsltFreeStylesheet(stylesheet);
+}
+
+
+
+static void *
+ngx_http_xslt_filter_create_conf(ngx_conf_t *cf)
+{
+ ngx_http_xslt_filter_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_xslt_filter_conf_t));
+ if (conf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ /*
+ * set by ngx_pcalloc():
+ *
+ * conf->dtd
+ * conf->sheets
+ */
+
+ return conf;
+}
+
+
+static char *
+ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+ ngx_http_xslt_filter_conf_t *prev = parent;
+ ngx_http_xslt_filter_conf_t *conf = child;
+
+ if (conf->dtd == NULL) {
+ conf->dtd = prev->dtd;
+ }
+
+ if (conf->sheets.nelts == 0) {
+ conf->sheets = prev->sheets;
+ }
+
+ if (ngx_http_merge_types(cf, conf->keys, &conf->types_hash, prev->keys,
+ &prev->types_hash, ngx_http_xslt_default_types)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_xslt_filter_init(ngx_conf_t *cf)
+{
+ xmlInitParser();
+
+ ngx_http_next_header_filter = ngx_http_top_header_filter;
+ ngx_http_top_header_filter = ngx_http_xslt_header_filter;
+
+ ngx_http_next_body_filter = ngx_http_top_body_filter;
+ ngx_http_top_body_filter = ngx_http_xslt_body_filter;
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_http_xslt_filter_exit(ngx_cycle_t *cycle)
+{
+ xsltCleanupGlobals();
+ xmlCleanupParser();
+}
diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm
index 58fc8a559..f82a32810 100644
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
HTTP_INSUFFICIENT_STORAGE
);
-our $VERSION = '0.7.7';
+our $VERSION = '0.7.8';
require XSLoader;
XSLoader::load('nginx', $VERSION);
diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs
index 6e7ad7760..fbc7f59be 100644
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -247,11 +247,7 @@ header_in(r, key)
XSRETURN_UNDEF;
}
- hash = 0;
- for (i = 0; i < len; i++) {
- lowcase_key[i] = ngx_tolower(p[i]);
- hash = ngx_hash(hash, lowcase_key[i]);
- }
+ hash = ngx_hash_strlow(lowcase_key, p, len);
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
@@ -833,11 +829,7 @@ variable(r, name, value = NULL)
XSRETURN_UNDEF;
}
- hash = 0;
- for (i = 0; i < len; i++) {
- lowcase[i] = ngx_tolower(p[i]);
- hash = ngx_hash(hash, lowcase[i]);
- }
+ hash = ngx_hash_strlow(lowcase, p, len);
var.len = len;
var.data = lowcase;
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index ed4dacdbe..1a5db19bf 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1259,7 +1259,7 @@ static ngx_int_t
ngx_http_add_names(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_conf_in_addr_t *in_addr)
{
- ngx_uint_t i, n;
+ ngx_uint_t i;
ngx_http_server_name_t *server_names, *name;
if (in_addr->names.elts == NULL) {
@@ -1275,10 +1275,8 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
for (i = 0; i < cscf->server_names.nelts; i++) {
- for (n = 0; n < server_names[i].name.len; n++) {
- server_names[i].name.data[n] =
- ngx_tolower(server_names[i].name.data[n]);
- }
+ ngx_strlow(server_names[i].name.data, server_names[i].name.data,
+ server_names[i].name.len);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, cf->log, 0,
"name: %V", &server_names[i].name);
@@ -1689,3 +1687,135 @@ ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_in_port_t *in_port)
return NGX_OK;
}
+
+
+char *
+ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_array_t **types;
+ ngx_str_t *value, *default_type;
+ ngx_uint_t i, n, hash;
+ ngx_hash_key_t *type;
+
+ types = (ngx_array_t **) (p + cmd->offset);
+
+ default_type = cmd->post;
+
+ if (*types == NULL) {
+ *types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t));
+ if (*types == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (default_type) {
+ type = ngx_array_push(*types);
+ if (type == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ type->key = *default_type;
+ type->key_hash = ngx_hash_key(default_type->data,
+ default_type->len);
+ type->value = (void *) 4;
+ }
+ }
+
+ value = cf->args->elts;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len);
+ value[i].data[value[i].len] = '\0';
+
+ type = (*types)->elts;
+ for (n = 0; n < (*types)->nelts; n++) {
+
+ if (ngx_strcmp(value[i].data, type[n].key.data) == 0) {
+ ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+ "duplicate MIME type \"%V\"", &value[i]);
+ continue;
+ }
+ }
+
+ type = ngx_array_push(*types);
+ if (type == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ type->key = value[i];
+ type->key_hash = hash;
+ type->value = (void *) 4;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys, ngx_hash_t *types_hash,
+ ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash,
+ ngx_str_t *default_types)
+{
+ ngx_hash_init_t hash;
+
+ if (keys == NULL) {
+
+ if (prev_keys) {
+ *types_hash = *prev_types_hash;
+ return NGX_CONF_OK;
+ }
+
+ if (ngx_http_set_default_types(cf, &keys, default_types)
+ != NGX_CONF_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ hash.hash = types_hash;
+ hash.key = NULL;
+ hash.max_size = 2048;
+ hash.bucket_size = 64;
+ hash.name = "test_types_hash";
+ hash.pool = cf->pool;
+ hash.temp_pool = NULL;
+
+ if (ngx_hash_init(&hash, keys->elts, keys->nelts) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+
+}
+
+
+char *
+ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types,
+ ngx_str_t *default_type)
+{
+ ngx_hash_key_t *type;
+
+ *types = ngx_array_create(cf->temp_pool, 1, sizeof(ngx_hash_key_t));
+ if (*types == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ while (default_type->len) {
+
+ type = ngx_array_push(*types);
+ if (type == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ type->key = *default_type;
+ type->key_hash = ngx_hash_key(default_type->data,
+ default_type->len);
+ type->value = (void *) 4;
+
+ default_type++;
+ }
+
+ return NGX_CONF_OK;
+}
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index fe2b7cc6c..180da8194 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -107,6 +107,14 @@ ngx_int_t ngx_http_discard_request_body(ngx_http_request_t *r);
void ngx_http_block_reading(ngx_http_request_t *r);
+char *ngx_http_types_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_http_merge_types(ngx_conf_t *cf, ngx_array_t *keys,
+ ngx_hash_t *types_hash, ngx_array_t *prev_keys, ngx_hash_t *prev_types_hash,
+ ngx_str_t *default_types);
+char *ngx_http_set_default_types(ngx_conf_t *cf, ngx_array_t **types,
+ ngx_str_t *default_type);
+
+
extern ngx_module_t ngx_http_module;
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 468b3e151..776438ba0 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1302,10 +1302,48 @@ ngx_http_core_send_continue(ngx_http_request_t *r)
}
+void *
+ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash)
+{
+ u_char c, *p;
+ ngx_uint_t i, hash;
+
+ if (r->headers_out.content_type.len == 0) {
+ return NULL;
+ }
+
+ if (r->headers_out.content_type_lowcase == NULL) {
+
+ p = ngx_pnalloc(r->pool, r->headers_out.content_type_len);
+
+ if (p == NULL) {
+ return NULL;
+ }
+
+ r->headers_out.content_type_lowcase = p;
+
+ hash = 0;
+
+ for (i = 0; i < r->headers_out.content_type_len; i++) {
+ c = ngx_tolower(r->headers_out.content_type.data[i]);
+ hash = ngx_hash(hash, c);
+ *p++ = c;
+ }
+
+ r->headers_out.content_type_hash = hash;
+ }
+
+ return ngx_hash_find(types_hash,
+ r->headers_out.content_type_hash,
+ r->headers_out.content_type_lowcase,
+ r->headers_out.content_type_len);
+}
+
+
ngx_int_t
ngx_http_set_content_type(ngx_http_request_t *r)
{
- u_char c, *p, *exten;
+ u_char c, *exten;
ngx_str_t *type;
ngx_uint_t i, hash;
ngx_http_core_loc_conf_t *clcf;
@@ -1325,19 +1363,12 @@ ngx_http_set_content_type(ngx_http_request_t *r)
if (c >= 'A' && c <= 'Z') {
- p = ngx_pnalloc(r->pool, r->exten.len);
- if (p == NULL) {
+ exten = ngx_pnalloc(r->pool, r->exten.len);
+ if (exten == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- hash = 0;
- exten = p;
-
- for (i = 0; i < r->exten.len; i++) {
- c = ngx_tolower(r->exten.data[i]);
- hash = ngx_hash(hash, c);
- *p++ = c;
- }
+ hash = ngx_hash_strlow(exten, r->exten.data, r->exten.len);
r->exten.data = exten;
@@ -2316,7 +2347,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
ngx_http_core_loc_conf_t *lcf = conf;
ngx_str_t *value, *content_type, *old, file;
- ngx_uint_t i, n;
+ ngx_uint_t i, n, hash;
ngx_hash_key_t *type;
value = cf->args->elts;
@@ -2342,9 +2373,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
for (i = 1; i < cf->args->nelts; i++) {
- for (n = 0; n < value[i].len; n++) {
- value[i].data[n] = ngx_tolower(value[i].data[n]);
- }
+ hash = ngx_hash_strlow(value[i].data, value[i].data, value[i].len);
type = lcf->types->elts;
for (n = 0; n < lcf->types->nelts; n++) {
@@ -2368,7 +2397,7 @@ ngx_http_core_type(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
}
type->key = value[i];
- type->key_hash = ngx_hash_key(value[i].data, value[i].len);
+ type->key_hash = hash;
type->value = content_type;
}
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index 57ee748e7..3ecc7c33a 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -373,6 +373,8 @@ ngx_int_t ngx_http_core_post_access_phase(ngx_http_request_t *r,
ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
+
+void *ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash);
ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r);
ngx_int_t ngx_http_set_exten(ngx_http_request_t *r);
u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name,
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 9aad1a487..61a41d4b2 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -647,6 +647,7 @@ ngx_http_process_request_line(ngx_event_t *rev)
r->request_line.len = r->request_end - r->request_start;
r->request_line.data = r->request_start;
+ *r->request_end = '\0';
if (r->args_start) {
@@ -818,7 +819,6 @@ ngx_http_process_request_headers(ngx_event_t *rev)
ssize_t n;
ngx_int_t rc, rv;
ngx_str_t header;
- ngx_uint_t i;
ngx_table_elt_t *h;
ngx_connection_t *c;
ngx_http_header_t *hh;
@@ -928,9 +928,7 @@ ngx_http_process_request_headers(ngx_event_t *rev)
ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
} else {
- for (i = 0; i < h->key.len; i++) {
- h->lowcase_key[i] = ngx_tolower(h->key.data[i]);
- }
+ ngx_strlow(h->lowcase_key, h->key.data, h->key.len);
}
hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
@@ -1552,8 +1550,8 @@ ngx_http_validate_host(u_char *host, size_t len)
static ngx_int_t
ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len)
{
- u_char *server, ch;
- ngx_uint_t i, hash;
+ u_char *server;
+ ngx_uint_t hash;
ngx_http_core_loc_conf_t *clcf;
ngx_http_core_srv_conf_t *cscf;
u_char buf[32];
@@ -1572,16 +1570,7 @@ ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len)
}
}
- hash = 0;
-
- for (i = 0; i < len; i++) {
- ch = host[i];
-
- ch = ngx_tolower(ch);
- server[i] = ch;
-
- hash = ngx_hash(hash, ch);
- }
+ hash = ngx_hash_strlow(server, host, len);
cscf = ngx_hash_find_combined(&r->virtual_names->names, hash, server, len);
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index be22db636..9a6223963 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -244,6 +244,8 @@ typedef struct {
size_t content_type_len;
ngx_str_t content_type;
ngx_str_t charset;
+ u_char *content_type_lowcase;
+ ngx_uint_t content_type_hash;
ngx_array_t cache_control;
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index 0ffa07cc8..95c1cc105 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -1016,69 +1016,69 @@ ngx_http_script_file_code(ngx_http_script_engine_t *e)
case ngx_http_script_file_dir:
case ngx_http_script_file_exists:
case ngx_http_script_file_exec:
- goto false;
+ goto false_value;
case ngx_http_script_file_not_plain:
case ngx_http_script_file_not_dir:
case ngx_http_script_file_not_exists:
case ngx_http_script_file_not_exec:
- goto true;
+ goto true_value;
}
- goto false;
+ goto false_value;
}
switch (code->op) {
case ngx_http_script_file_plain:
if (of.is_file) {
- goto true;
+ goto true_value;
}
- goto false;
+ goto false_value;
case ngx_http_script_file_not_plain:
if (of.is_file) {
- goto false;
+ goto false_value;
}
- goto true;
+ goto true_value;
case ngx_http_script_file_dir:
if (of.is_dir) {
- goto true;
+ goto true_value;
}
- goto false;
+ goto false_value;
case ngx_http_script_file_not_dir:
if (of.is_dir) {
- goto false;
+ goto false_value;
}
- goto true;
+ goto true_value;
case ngx_http_script_file_exists:
if (of.is_file || of.is_dir || of.is_link) {
- goto true;
+ goto true_value;
}
- goto false;
+ goto false_value;
case ngx_http_script_file_not_exists:
if (of.is_file || of.is_dir || of.is_link) {
- goto false;
+ goto false_value;
}
- goto true;
+ goto true_value;
case ngx_http_script_file_exec:
if (of.is_exec) {
- goto true;
+ goto true_value;
}
- goto false;
+ goto false_value;
case ngx_http_script_file_not_exec:
if (of.is_exec) {
- goto false;
+ goto false_value;
}
- goto true;
+ goto true_value;
}
-false:
+false_value:
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http script file op false");
@@ -1086,7 +1086,7 @@ false:
*value = ngx_http_variable_null_value;
return;
-true:
+true_value:
*value = ngx_http_variable_true_value;
return;
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 27f27ae7e..191219b73 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -137,7 +137,8 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
ngx_http_upstream_copy_header_line, 0, 0 },
{ ngx_string("Location"),
- ngx_http_upstream_ignore_header_line, 0,
+ ngx_http_upstream_process_header_line,
+ offsetof(ngx_http_upstream_headers_in_t, location),
ngx_http_upstream_rewrite_location, 0, 0 },
{ ngx_string("Refresh"),
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index e014170a0..cd706a2a9 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -26,6 +26,8 @@ static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
@@ -277,9 +279,7 @@ ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
return NULL;
}
- for (i = 0; i < name->len; i++) {
- v->name.data[i] = ngx_tolower(name->data[i]);
- }
+ ngx_strlow(v->name.data, name->data, name->len);
v->set_handler = NULL;
v->get_handler = NULL;
@@ -344,9 +344,7 @@ ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
return NGX_ERROR;
}
- for (i = 0; i < name->len; i++) {
- v->name.data[i] = ngx_tolower(name->data[i]);
- }
+ ngx_strlow(v->name.data, name->data, name->len);
v->set_handler = NULL;
v->get_handler = NULL;
@@ -481,6 +479,15 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key,
return NULL;
}
+ if (ngx_strncmp(name->data, "arg_", 4) == 0) {
+
+ if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) {
+ return vv;
+ }
+
+ return NULL;
+ }
+
vv->not_found = 1;
if (nowarn == 0) {
@@ -712,6 +719,62 @@ ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
static ngx_int_t
+ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v,
+ uintptr_t data)
+{
+ ngx_str_t *name = (ngx_str_t *) data;
+
+ u_char *p, *arg;
+ size_t len;
+
+ if (r->args.len == 0) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ len = name->len - 1 - (sizeof("arg_") - 1);
+ arg = name->data + sizeof("arg_") - 1;
+
+ for (p = r->args.data; *p && *p != ' '; p++) {
+
+ /*
+ * although r->args.data is not null-terminated by itself,
+ * however, there is null in the end of request line
+ */
+
+ p = ngx_strcasestrn(p, (char *) arg, len);
+
+ if (p == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ if ((p == r->args.data || *(p - 1) == '&') && *(p + len + 1) == '=') {
+
+ v->data = p + len + 2;
+
+ p = (u_char *) ngx_strchr(p, '&');
+
+ if (p == NULL) {
+ p = r->args.data + r->args.len;
+ }
+
+ v->len = p - v->data;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+
+ return NGX_OK;
+ }
+ }
+
+ v->not_found = 1;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
@@ -1396,6 +1459,13 @@ ngx_http_variables_init_vars(ngx_conf_t *cf)
continue;
}
+ if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) {
+ v[i].get_handler = ngx_http_variable_argument;
+ v[i].data = (uintptr_t) &v[i].name;
+
+ continue;
+ }
+
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"unknown \"%V\" variable", &v[i].name);
diff --git a/src/os/unix/ngx_atomic.h b/src/os/unix/ngx_atomic.h
index 22b8b0144..e19fddaca 100644
--- a/src/os/unix/ngx_atomic.h
+++ b/src/os/unix/ngx_atomic.h
@@ -21,13 +21,8 @@
#include <libkern/OSAtomic.h>
-/* "bool" conflicts with perl's CORE/handy.h
- * "true" and "false" conflict with nginx, and of course we can rename them,
- * but we need to undef "bool" anyway
- */
+/* "bool" conflicts with perl's CORE/handy.h */
#undef bool
-#undef true
-#undef false
#define NGX_HAVE_ATOMIC_OPS 1
diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h
index 62af63bce..7e8407086 100644
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -199,6 +199,11 @@ ngx_int_t ngx_directio(ngx_fd_t fd);
#define ngx_directio(fd) fcntl(fd, F_NOCACHE, 1)
#define ngx_directio_n "fcntl(F_NOCACHE)"
+#elif (NGX_HAVE_DIRECTIO)
+
+#define ngx_directio(fd) directio(fd, DIRECTIO_ON)
+#define ngx_directio_n "directio(DIRECTIO_ON)"
+
#else
#define ngx_directio(fd) 0