diff options
author | Igor Sysoev <igor@sysoev.ru> | 2006-06-28 16:00:26 +0000 |
---|---|---|
committer | Igor Sysoev <igor@sysoev.ru> | 2006-06-28 16:00:26 +0000 |
commit | ef809b86c36a9584a15df6caac2eb727ceacc10d (patch) | |
tree | 80dc756ea197b259b159fb9a47b09df1a1eae7f1 /src/http/modules | |
parent | f115ebe9c3d57c0b271b03ed931ff42cdef37eb2 (diff) | |
download | nginx-release-0.3.50.tar.gz nginx-release-0.3.50.zip |
nginx-0.3.50-RELEASE importrelease-0.3.50
*) Change: the "proxy_redirect_errors" and "fastcgi_redirect_errors"
directives was renamed to the "proxy_intercept_errors" and
"fastcgi_intercept_errors" directives.
*) Feature: the ngx_http_charset_module supports the recoding from the
single byte encodings to the UTF-8 encoding and back.
*) Feature: the "X-Accel-Charset" response header line is supported in
proxy and FastCGI mode.
*) Bugfix: the "\" escape symbol in the "\"" and "\'" pairs in the SSI
command was removed only if the command also has the "$" symbol.
*) Bugfix: the "<!--" string might be added on some conditions in the
SSI after inclusion.
*) Bugfix: if the "Content-Length: 0" header line was in response, then
in nonbuffered proxying mode the client connection was not closed.
Diffstat (limited to 'src/http/modules')
-rw-r--r-- | src/http/modules/ngx_http_autoindex_module.c | 2 | ||||
-rw-r--r-- | src/http/modules/ngx_http_charset_filter_module.c | 1033 | ||||
-rw-r--r-- | src/http/modules/ngx_http_fastcgi_module.c | 21 | ||||
-rw-r--r-- | src/http/modules/ngx_http_log_module.c | 3 | ||||
-rw-r--r-- | src/http/modules/ngx_http_memcached_module.c | 2 | ||||
-rw-r--r-- | src/http/modules/ngx_http_proxy_module.c | 21 | ||||
-rw-r--r-- | src/http/modules/ngx_http_range_filter_module.c | 1 | ||||
-rw-r--r-- | src/http/modules/ngx_http_ssi_filter_module.c | 45 | ||||
-rw-r--r-- | src/http/modules/ngx_http_userid_filter_module.c | 8 |
9 files changed, 966 insertions, 170 deletions
diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c index b1ba178b9..535456827 100644 --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -319,7 +319,7 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) NGX_ESCAPE_HTML); if (r->utf8) { - entry->utf_len = ngx_utf_length(&entry->name); + entry->utf_len = ngx_utf_length(entry->name.data, entry->name.len); } else { entry->utf_len = len; } diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c index c7aa14cfb..635e6c521 100644 --- a/src/http/modules/ngx_http_charset_filter_module.c +++ b/src/http/modules/ngx_http_charset_filter_module.c @@ -9,56 +9,94 @@ #include <ngx_http.h> -#define NGX_HTTP_NO_CHARSET -2 +#define NGX_HTTP_NO_CHARSET -2 + +/* 1 byte length and up to 3 bytes for the UTF-8 encoding of the UCS-2 */ +#define NGX_UTF_LEN 4 + +#define NGX_HTML_ENTITY_LEN (sizeof("") - 1) typedef struct { - u_char **tables; - ngx_str_t name; + u_char **tables; + ngx_str_t name; - ngx_uint_t utf8; /* unsigned utf8:1; */ + unsigned length:16; + unsigned utf8:1; } ngx_http_charset_t; typedef struct { - ngx_int_t src; - ngx_int_t dst; + ngx_int_t src; + ngx_int_t dst; } ngx_http_charset_recode_t; typedef struct { - ngx_int_t src; - ngx_int_t dst; - u_char *src2dst; - u_char *dst2src; + ngx_int_t src; + ngx_int_t dst; + u_char *src2dst; + u_char *dst2src; } ngx_http_charset_tables_t; typedef struct { - ngx_array_t charsets; /* ngx_http_charset_t */ - ngx_array_t tables; /* ngx_http_charset_tables_t */ - ngx_array_t recodes; /* ngx_http_charset_recode_t */ + ngx_array_t charsets; /* ngx_http_charset_t */ + ngx_array_t tables; /* ngx_http_charset_tables_t */ + ngx_array_t recodes; /* ngx_http_charset_recode_t */ } ngx_http_charset_main_conf_t; typedef struct { - ngx_int_t charset; - ngx_int_t source_charset; - ngx_flag_t override_charset; + ngx_int_t charset; + ngx_int_t source_charset; + ngx_flag_t override_charset; } ngx_http_charset_loc_conf_t; typedef struct { - u_char *table; - ngx_int_t charset; + u_char *table; + ngx_int_t charset; + + ngx_chain_t *busy; + ngx_chain_t *free_bufs; + ngx_chain_t *free_buffers; + + size_t saved_len; + u_char saved[NGX_UTF_LEN]; + + unsigned length:16; + unsigned from_utf8:1; + unsigned to_utf8:1; } ngx_http_charset_ctx_t; +typedef struct { + ngx_http_charset_tables_t *table; + ngx_http_charset_t *charset; + ngx_uint_t characters; +} ngx_http_charset_conf_ctx_t; + + +static ngx_int_t ngx_http_charset_get_charset(ngx_http_charset_t *charsets, + ngx_uint_t n, u_char *charset); +static ngx_int_t ngx_http_charset_set_charset(ngx_http_request_t *r, + ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset); static ngx_uint_t ngx_http_charset_recode(ngx_buf_t *b, u_char *table); +static ngx_chain_t *ngx_http_charset_recode_from_utf8(ngx_pool_t *pool, + ngx_buf_t *buf, ngx_http_charset_ctx_t *ctx); +static ngx_chain_t *ngx_http_charset_recode_to_utf8(ngx_pool_t *pool, + ngx_buf_t *buf, ngx_http_charset_ctx_t *ctx); + +static ngx_chain_t *ngx_http_charset_get_buf(ngx_pool_t *pool, + ngx_http_charset_ctx_t *ctx); +static ngx_chain_t *ngx_http_charset_get_buffer(ngx_pool_t *pool, + ngx_http_charset_ctx_t *ctx, size_t size); -static char *ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, +static char *ngx_http_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); -static char *ngx_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); static char *ngx_http_set_charset_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -101,7 +139,7 @@ static ngx_command_t ngx_http_charset_filter_commands[] = { { ngx_string("charset_map"), NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, - ngx_charset_map_block, + ngx_http_charset_map_block, NGX_HTTP_MAIN_CONF_OFFSET, 0, NULL }, @@ -148,10 +186,10 @@ static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static ngx_int_t ngx_http_charset_header_filter(ngx_http_request_t *r) { - size_t len; - u_char *p; + u_char *ct; ngx_int_t charset, source_charset; - ngx_uint_t i; + ngx_str_t *mc; + ngx_uint_t n; ngx_http_charset_t *charsets; ngx_http_charset_ctx_t *ctx; ngx_http_charset_loc_conf_t *lcf, *mlcf; @@ -159,112 +197,153 @@ ngx_http_charset_header_filter(ngx_http_request_t *r) mcf = ngx_http_get_module_main_conf(r, ngx_http_charset_filter_module); - ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module); - - if (ctx == NULL) { - mlcf = ngx_http_get_module_loc_conf(r->main, - ngx_http_charset_filter_module); - charset = mlcf->charset; - - if (charset == NGX_HTTP_NO_CHARSET) { - return ngx_http_next_header_filter(r); - } - - } else { - charset = ctx->charset; - } - charsets = mcf->charsets.elts; + n = mcf->charsets.nelts; + + /* destination charset */ if (r == r->main) { + if (r->headers_out.content_type.len == 0) { return ngx_http_next_header_filter(r); } - if (ngx_strncasecmp(r->headers_out.content_type.data, "text/", 5) != 0 - && ngx_strncasecmp(r->headers_out.content_type.data, - "application/x-javascript", 24) != 0) + if (r->headers_out.override_charset + && r->headers_out.override_charset->len) { - return ngx_http_next_header_filter(r); - } + charset = ngx_http_charset_get_charset(charsets, n, + r->headers_out.override_charset->data); - } else { - if (r->headers_out.content_type.len == 0) { - mlcf = ngx_http_get_module_loc_conf(r->main, + if (charset == NGX_HTTP_NO_CHARSET) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "unknown charset \"%V\" to override", + &r->headers_out.override_charset); + + return ngx_http_next_header_filter(r); + } + + } else { + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); - source_charset = mlcf->source_charset; + charset = mlcf->charset; - goto found; - } - } + if (charset == NGX_HTTP_NO_CHARSET) { + return ngx_http_next_header_filter(r); + } - lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); + if (r->headers_out.charset.len) { + if (mlcf->override_charset == 0) { + return ngx_http_next_header_filter(r); + } - len = 0; + } else { + ct = r->headers_out.content_type.data; - for (p = r->headers_out.content_type.data; *p; p++) { - if (*p == ';') { - len = p - r->headers_out.content_type.data; + if (ngx_strncasecmp(ct, "text/", 5) != 0 + && ngx_strncasecmp(ct, "application/x-javascript", 24) != 0) + { + return ngx_http_next_header_filter(r); + } + } } - if (ngx_strncasecmp(p, "charset=", 8) != 0) { - continue; - } + } else { + ctx = ngx_http_get_module_ctx(r->main, ngx_http_charset_filter_module); - p += 8; + if (ctx == NULL) { - for (i = 0; i < mcf->charsets.nelts; i++) { + mc = &r->main->headers_out.charset; - if (ngx_strcasecmp(p, charsets[i].name.data) == 0) { + if (mc->len == 0) { + return ngx_http_next_header_filter(r); + } - if (r == r->main && lcf->override_charset == 0) { - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); - if (ctx == NULL) { - return NGX_ERROR; - } + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_charset_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } - ngx_http_set_ctx(r, ctx, ngx_http_charset_filter_module); + ngx_http_set_ctx(r->main, ctx, ngx_http_charset_filter_module); - ctx->charset = i; + charset = ngx_http_charset_get_charset(charsets, n, mc->data); - return ngx_http_next_header_filter(r); - } + ctx->charset = charset; - if (i != (ngx_uint_t) charset - && (charsets[i].tables == NULL - || charsets[i].tables[charset] == NULL)) - { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - "no \"charset_map\" between the charsets " - "\"%V\" and \"%V\"", - &charsets[i].name, &charsets[charset].name); + if (charset == NGX_HTTP_NO_CHARSET) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "unknown charset \"%V\" of main request", mc); - return ngx_http_next_header_filter(r); - } + return ngx_http_next_header_filter(r); + } + } - r->headers_out.content_type.len = len; + charset = ctx->charset; - 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 - */ + if (charset == NGX_HTTP_NO_CHARSET) { + return ngx_http_next_header_filter(r); + } + } - r->headers_out.charset.len = 0; - return ngx_http_next_header_filter(r); - } + /* source charset */ - source_charset = i; + if (r->headers_out.charset.len == 0) { + lcf = ngx_http_get_module_loc_conf(r, ngx_http_charset_filter_module); - goto found; - } - } + return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset, + lcf->source_charset); + } + + source_charset = ngx_http_charset_get_charset(charsets, n, + r->headers_out.charset.data); + + if (source_charset == NGX_HTTP_NO_CHARSET) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "unknown source charset \"%V\"", &r->headers_out.charset); return ngx_http_next_header_filter(r); } + if (source_charset != charset + && (charsets[source_charset].tables == NULL + || charsets[source_charset].tables[charset] == NULL)) + { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "no \"charset_map\" between the charsets " + "\"%V\" and \"%V\"", + &charsets[source_charset].name, &charsets[charset].name); + + return ngx_http_next_header_filter(r); + } + + r->headers_out.content_type.len = r->headers_out.content_type_len; + + return ngx_http_charset_set_charset(r, mcf->charsets.elts, charset, + source_charset); +} + + +static ngx_int_t +ngx_http_charset_get_charset(ngx_http_charset_t *charsets, ngx_uint_t n, + u_char *charset) +{ + ngx_uint_t i; + + for (i = 0; i < n; i++) { + if (ngx_strcasecmp(charsets[i].name.data, charset) == 0) { + return i; + } + } + + return NGX_HTTP_NO_CHARSET; +} + + +static ngx_int_t +ngx_http_charset_set_charset(ngx_http_request_t *r, + ngx_http_charset_t *charsets, ngx_int_t charset, ngx_int_t source_charset) +{ + ngx_http_charset_ctx_t *ctx; + if (r->headers_out.status == NGX_HTTP_MOVED_PERMANENTLY || r->headers_out.status == NGX_HTTP_MOVED_TEMPORARILY) { @@ -274,17 +353,10 @@ ngx_http_charset_header_filter(ngx_http_request_t *r) */ r->headers_out.charset.len = 0; - return ngx_http_next_header_filter(r); - } - if (r->headers_out.charset.len) { return ngx_http_next_header_filter(r); } - source_charset = lcf->source_charset; - -found: - r->headers_out.charset = charsets[charset].name; r->utf8 = charsets[charset].utf8; @@ -301,6 +373,13 @@ found: ctx->table = charsets[source_charset].tables[charset]; ctx->charset = charset; + ctx->length = charsets[charset].length; + ctx->from_utf8 = charsets[source_charset].utf8; + ctx->to_utf8 = charsets[charset].utf8; + + if ((ctx->to_utf8 || ctx->from_utf8) && r == r->main) { + ngx_http_clear_content_length(r); + } r->filter_need_in_memory = 1; @@ -311,7 +390,9 @@ found: static ngx_int_t ngx_http_charset_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { - ngx_chain_t *cl; + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t *cl, *out, **ll; ngx_http_charset_ctx_t *ctx; ctx = ngx_http_get_module_ctx(r, ngx_http_charset_filter_module); @@ -320,6 +401,84 @@ ngx_http_charset_body_filter(ngx_http_request_t *r, ngx_chain_t *in) return ngx_http_next_body_filter(r, in); } + if ((ctx->to_utf8 || ctx->from_utf8) || ctx->busy) { + + out = NULL; + ll = &out; + + for (cl = in; cl; cl = cl->next) { + b = cl->buf; + + if (ngx_buf_size(b) == 0) { + continue; + } + + if (ctx->to_utf8) { + *ll = ngx_http_charset_recode_to_utf8(r->pool, b, ctx); + + } else { + *ll = ngx_http_charset_recode_from_utf8(r->pool, b, ctx); + } + + if (*ll == NULL) { + return NGX_ERROR; + } + + while (*ll) { + ll = &(*ll)->next; + } + } + + rc = ngx_http_next_body_filter(r, out); + + if (out) { + if (ctx->busy == NULL) { + ctx->busy = out; + + } else { + for (cl = ctx->busy; cl->next; cl = cl->next) { /* void */ } + cl->next = out; + } + } + + while (ctx->busy) { + + cl = ctx->busy; + b = cl->buf; + + if (ngx_buf_size(b) != 0) { + break; + } + +#if (NGX_HAVE_WRITE_ZEROCOPY) + if (b->zerocopy_busy) { + break; + } +#endif + + ctx->busy = cl->next; + + if (b->tag != (ngx_buf_tag_t) &ngx_http_charset_filter_module) { + continue; + } + + if (b->shadow) { + b->shadow->pos = b->shadow->last; + } + + if (b->pos) { + cl->next = ctx->free_buffers; + ctx->free_buffers = cl; + continue; + } + + cl->next = ctx->free_bufs; + ctx->free_bufs = cl; + } + + return rc; + } + for (cl = in; cl; cl = cl->next) { (void) ngx_http_charset_recode(cl->buf, ctx->table); } @@ -353,17 +512,506 @@ ngx_http_charset_recode(ngx_buf_t *b, u_char *table) } +static ngx_chain_t * +ngx_http_charset_recode_from_utf8(ngx_pool_t *pool, ngx_buf_t *buf, + ngx_http_charset_ctx_t *ctx) +{ + size_t len, size; + u_char c, *p, *src, *dst, *saved, **table; + uint32_t n; + ngx_buf_t *b; + ngx_uint_t i; + ngx_chain_t *out, *cl, **ll; + + src = buf->pos; + + if (ctx->saved_len == 0) { + + for ( /* void */ ; src < buf->last; src++) { + + if (*src < 0x80) { + continue; + } + + len = src - buf->pos; + + if (len > 512) { + out = ngx_http_charset_get_buf(pool, ctx); + if (out == NULL) { + return NULL; + } + + b = out->buf; + + b->temporary = buf->temporary; + b->memory = buf->memory; + b->mmap = buf->mmap; + b->flush = buf->flush; + + b->pos = buf->pos; + b->last = src; + + out->buf = b; + out->next = NULL; + + size = buf->last - src; + + saved = src; + n = ngx_utf_decode(&saved, size); + + if (n == 0xfffffffe) { + /* incomplete UTF-8 symbol */ + + ngx_memcpy(ctx->saved, src, size); + ctx->saved_len = size; + + b->shadow = buf; + + return out; + } + + } else { + out = NULL; + size = len + buf->last - src; + src = buf->pos; + } + + if (size < NGX_HTML_ENTITY_LEN) { + size += NGX_HTML_ENTITY_LEN; + } + + cl = ngx_http_charset_get_buffer(pool, ctx, size); + if (cl == NULL) { + return NULL; + } + + if (out) { + out->next = cl; + + } else { + out = cl; + } + + b = cl->buf; + dst = b->pos; + + goto recode; + } + + out = ngx_alloc_chain_link(pool); + if (out == NULL) { + return NULL; + } + + out->buf = buf; + out->next = NULL; + + return out; + } + + /* process incomplete UTF sequence from previous buffer */ + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, + "http charset utf saved: %z", ctx->saved_len); + + p = src; + + for (i = ctx->saved_len; i < NGX_UTF_LEN; i++) { + ctx->saved[i] = *p++; + + if (p == buf->last) { + break; + } + } + + saved = ctx->saved; + n = ngx_utf_decode(&saved, i); + + c = '\0'; + + if (n < 0x10000) { + table = (u_char **) ctx->table; + p = table[n >> 8]; + + if (p) { + c = p[n & 0xff]; + } + + } else if (n == 0xfffffffe) { + + /* incomplete UTF-8 symbol */ + + if (i < NGX_UTF_LEN) { + out = ngx_http_charset_get_buf(pool, ctx); + if (out == NULL) { + return NULL; + } + + b = out->buf; + + b->pos = buf->pos; + b->last = buf->last; + b->sync = 1; + b->shadow = buf; + + ngx_memcpy(&ctx->saved[ctx->saved_len], src, i); + ctx->saved_len += i; + + return out; + } + } + + size = buf->last - buf->pos; + + if (size < NGX_HTML_ENTITY_LEN) { + size += NGX_HTML_ENTITY_LEN; + } + + cl = ngx_http_charset_get_buffer(pool, ctx, size); + if (cl == NULL) { + return NULL; + } + + out = cl; + + b = cl->buf; + dst = b->pos; + + if (c) { + *dst++ = c; + + } else if (n == 0xfffffffe) { + *dst++ = '?'; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pool->log, 0, + "http charset invalid utf 0"); + + saved = &ctx->saved[NGX_UTF_LEN]; + + } else if (n > 0x10ffff) { + *dst++ = '?'; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pool->log, 0, + "http charset invalid utf 1"); + + } else { + dst = ngx_sprintf(dst, "&#%uD;", n); + } + + src += (saved - ctx->saved) - ctx->saved_len; + ctx->saved_len = 0; + +recode: + + ll = &cl->next; + + table = (u_char **) ctx->table; + + while (src < buf->last) { + + if ((size_t) (b->end - dst) < NGX_HTML_ENTITY_LEN) { + b->last = dst; + + size = buf->last - src + NGX_HTML_ENTITY_LEN; + + cl = ngx_http_charset_get_buffer(pool, ctx, size); + if (cl == NULL) { + return NULL; + } + + *ll = cl; + ll = &cl->next; + + b = cl->buf; + dst = b->pos; + } + + if (*src < 0x80) { + *dst++ = *src++; + continue; + } + + len = buf->last - src; + + n = ngx_utf_decode(&src, len); + + if (n < 0x10000) { + + p = table[n >> 8]; + + if (p) { + c = p[n & 0xff]; + + if (c) { + *dst++ = c; + continue; + } + } + + dst = ngx_sprintf(dst, "&#%uD;", n); + + continue; + } + + if (n == 0xfffffffe) { + /* incomplete UTF-8 symbol */ + + ngx_memcpy(ctx->saved, src, len); + ctx->saved_len = len; + + if (b->pos == dst) { + b->sync = 1; + b->temporary = 0; + } + + break; + } + + if (n > 0x10ffff) { + *dst++ = '?'; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, pool->log, 0, + "http charset invalid utf 2"); + + continue; + } + + /* n > 0xffff */ + + dst = ngx_sprintf(dst, "&#%uD;", n); + } + + b->last = dst; + + b->last_buf = buf->last_buf; + b->last_in_chain = buf->last_in_chain; + b->flush = buf->flush; + + b->shadow = buf; + + return out; +} + + +static ngx_chain_t * +ngx_http_charset_recode_to_utf8(ngx_pool_t *pool, ngx_buf_t *buf, + ngx_http_charset_ctx_t *ctx) +{ + size_t len, size; + u_char *p, *src, *dst, *table; + ngx_buf_t *b; + ngx_chain_t *out, *cl, **ll; + + table = ctx->table; + + for (src = buf->pos; src < buf->last; src++) { + if (table[*src * NGX_UTF_LEN] == '\1') { + continue; + } + + goto recode; + } + + out = ngx_alloc_chain_link(pool); + if (out == NULL) { + return NULL; + } + + out->buf = buf; + out->next = NULL; + + return out; + +recode: + + /* + * we assume that there are about half of characters to be recoded, + * so we preallocate "size / 2 + size / 2 * ctx->length" + */ + + len = src - buf->pos; + + if (len > 512) { + out = ngx_http_charset_get_buf(pool, ctx); + if (out == NULL) { + return NULL; + } + + b = out->buf; + + b->temporary = buf->temporary; + b->memory = buf->memory; + b->mmap = buf->mmap; + b->flush = buf->flush; + + b->pos = buf->pos; + b->last = src; + + out->buf = b; + out->next = NULL; + + size = buf->last - src; + size = size / 2 + size / 2 * ctx->length; + + } else { + out = NULL; + + size = buf->last - src; + size = len + size / 2 + size / 2 * ctx->length; + + src = buf->pos; + } + + cl = ngx_http_charset_get_buffer(pool, ctx, size); + if (cl == NULL) { + return NULL; + } + + if (out) { + out->next = cl; + + } else { + out = cl; + } + + ll = &cl->next; + + b = cl->buf; + dst = b->pos; + + while (src < buf->last) { + + p = &table[*src++ * NGX_UTF_LEN]; + len = *p++; + + if ((size_t) (b->end - dst) < len) { + b->last = dst; + + size = buf->last - src; + size = len + size / 2 + size / 2 * ctx->length; + + cl = ngx_http_charset_get_buffer(pool, ctx, size); + if (cl == NULL) { + return NULL; + } + + *ll = cl; + ll = &cl->next; + + b = cl->buf; + dst = b->pos; + } + + while (len) { + *dst++ = *p++; + len--; + } + } + + b->last = dst; + + b->last_buf = buf->last_buf; + b->last_in_chain = buf->last_in_chain; + b->flush = buf->flush; + + b->shadow = buf; + + return out; +} + + +static ngx_chain_t * +ngx_http_charset_get_buf(ngx_pool_t *pool, ngx_http_charset_ctx_t *ctx) +{ + ngx_chain_t *cl; + + cl = ctx->free_bufs; + + if (cl) { + ctx->free_bufs = cl->next; + + cl->buf->shadow = NULL; + cl->next = NULL; + + return cl; + } + + cl = ngx_alloc_chain_link(pool); + if (cl == NULL) { + return NULL; + } + + cl->buf = ngx_calloc_buf(pool); + if (cl->buf == NULL) { + return NULL; + } + + cl->next = NULL; + + cl->buf->tag = (ngx_buf_tag_t) &ngx_http_charset_filter_module; + + return cl; +} + + +static ngx_chain_t * +ngx_http_charset_get_buffer(ngx_pool_t *pool, ngx_http_charset_ctx_t *ctx, + size_t size) +{ + ngx_buf_t *b; + ngx_chain_t *cl, **ll; + + for (ll = &ctx->free_buffers, cl = ctx->free_buffers; + cl; + ll = &cl->next, cl = cl->next) + { + b = cl->buf; + + if ((size_t) (b->end - b->start) >= size) { + *ll = cl->next; + cl->next = NULL; + + b->pos = b->start; + b->temporary = 1; + b->shadow = NULL; + + return cl; + } + } + + cl = ngx_alloc_chain_link(pool); + if (cl == NULL) { + return NULL; + } + + cl->buf = ngx_create_temp_buf(pool, size); + if (cl->buf == NULL) { + return NULL; + } + + cl->next = NULL; + + cl->buf->temporary = 1; + cl->buf->tag = (ngx_buf_tag_t) &ngx_http_charset_filter_module; + + return cl; +} + + static char * -ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_http_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_charset_main_conf_t *mcf = conf; - char *rv; - ngx_int_t src, dst; - ngx_uint_t i; - ngx_str_t *value; - ngx_conf_t pvcf; - ngx_http_charset_tables_t *table; + char *rv; + u_char *p, *dst2src, **pp; + ngx_int_t src, dst; + ngx_uint_t i, n; + ngx_str_t *value; + ngx_conf_t pvcf; + ngx_http_charset_t *charset; + ngx_http_charset_tables_t *table; + ngx_http_charset_conf_ctx_t ctx; value = cf->args->elts; @@ -404,45 +1052,98 @@ ngx_charset_map_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) table->src = src; table->dst = dst; - table->src2dst = ngx_palloc(cf->pool, 256); - if (table->src2dst == NULL) { - return NGX_CONF_ERROR; - } + if (ngx_strcasecmp(value[2].data, "utf-8") == 0) { + table->src2dst = ngx_pcalloc(cf->pool, 256 * NGX_UTF_LEN); + if (table->src2dst == NULL) { + return NGX_CONF_ERROR; + } - table->dst2src = ngx_palloc(cf->pool, 256); - if (table->dst2src == NULL) { - return NGX_CONF_ERROR; - } + table->dst2src = ngx_pcalloc(cf->pool, 256 * sizeof(void *)); + if (table->dst2src == NULL) { + return NGX_CONF_ERROR; + } - for (i = 0; i < 128; i++) { - table->src2dst[i] = (u_char) i; - table->dst2src[i] = (u_char) i; - } + dst2src = ngx_pcalloc(cf->pool, 256); + if (dst2src == NULL) { + return NGX_CONF_ERROR; + } + + pp = (u_char **) &table->dst2src[0]; + pp[0] = dst2src; - for (/* void */; i < 256; i++) { - table->src2dst[i] = '?'; - table->dst2src[i] = '?'; + for (i = 0; i < 128; i++) { + p = &table->src2dst[i * NGX_UTF_LEN]; + p[0] = '\1'; + p[1] = (u_char) i; + dst2src[i] = (u_char) i; + } + + for (/* void */; i < 256; i++) { + p = &table->src2dst[i * NGX_UTF_LEN]; + p[0] = '\1'; + p[1] = '?'; + } + + } else { + table->src2dst = ngx_palloc(cf->pool, 256); + if (table->src2dst == NULL) { + return NGX_CONF_ERROR; + } + + table->dst2src = ngx_palloc(cf->pool, 256); + if (table->dst2src == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; i < 128; i++) { + table->src2dst[i] = (u_char) i; + table->dst2src[i] = (u_char) i; + } + + for (/* void */; i < 256; i++) { + table->src2dst[i] = '?'; + table->dst2src[i] = '?'; + } } + charset = mcf->charsets.elts; + + ctx.table = table; + ctx.charset = &charset[dst]; + ctx.characters = 0; + pvcf = *cf; - cf->ctx = table; - cf->handler = ngx_charset_map; + cf->ctx = &ctx; + cf->handler = ngx_http_charset_map; cf->handler_conf = conf; rv = ngx_conf_parse(cf, NULL); *cf = pvcf; + if (ctx.characters) { + n = ctx.charset->length; + ctx.charset->length /= ctx.characters; + + if (((n * 10) / ctx.characters) % 10 > 4) { + ctx.charset->length++; + } + } + return rv; } static char * -ngx_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) +ngx_http_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { - ngx_int_t src, dst; - ngx_str_t *value; - ngx_http_charset_tables_t *table; + u_char *p, *dst2src, **pp; + uint32_t n; + ngx_int_t src, dst; + ngx_str_t *value; + ngx_uint_t i; + ngx_http_charset_tables_t *table; + ngx_http_charset_conf_ctx_t *ctx; if (cf->args->nelts != 2) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameters number"); @@ -458,17 +1159,66 @@ ngx_charset_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) return NGX_CONF_ERROR; } - dst = ngx_hextoi(value[1].data, value[1].len); - if (dst == NGX_ERROR || dst > 255) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%V\"", &value[1]); - return NGX_CONF_ERROR; - } + ctx = cf->ctx; + table = ctx->table; + + if (ctx->charset->utf8) { + p = &table->src2dst[src * NGX_UTF_LEN]; - table = cf->ctx; + *p++ = (u_char) (value[1].len / 2); - table->src2dst[src] = (u_char) dst; - table->dst2src[dst] = (u_char) src; + for (i = 0; i < value[1].len; i += 2) { + dst = ngx_hextoi(&value[1].data[i], 2); + if (dst == NGX_ERROR || dst > 255) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid value \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + *p++ = (u_char) dst; + } + + i /= 2; + + ctx->charset->length += i; + ctx->characters++; + + p = &table->src2dst[src * NGX_UTF_LEN] + 1; + + n = ngx_utf_decode(&p, i); + + if (n > 0xffff) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid value \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + pp = (u_char **) &table->dst2src[0]; + + dst2src = pp[n >> 8]; + + if (dst2src == NULL) { + dst2src = ngx_pcalloc(cf->pool, 256); + if (dst2src == NULL) { + return NGX_CONF_ERROR; + } + + pp[n >> 8] = dst2src; + } + + dst2src[n & 0xff] = (u_char) src; + + } else { + dst = ngx_hextoi(value[1].data, value[1].len); + if (dst == NGX_ERROR || dst > 255) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid value \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + table->src2dst[src] = (u_char) dst; + table->dst2src[dst] = (u_char) src; + } return NGX_CONF_OK; } @@ -538,6 +1288,7 @@ ngx_http_add_charset(ngx_array_t *charsets, ngx_str_t *name) c->tables = NULL; c->name = *name; + c->length = 0; if (ngx_strcasecmp(name->data, "utf-8") == 0) { c->utf8 = 1; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 8663f881e..085fb47e4 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -156,6 +156,10 @@ static ngx_conf_deprecated_t ngx_conf_deprecated_fastcgi_header_buffer_size = { ngx_conf_deprecated, "fastcgi_header_buffer_size", "fastcgi_buffer_size" }; +static ngx_conf_deprecated_t ngx_conf_deprecated_fastcgi_redirect_errors = { + ngx_conf_deprecated, "fastcgi_redirect_errors", "fastcgi_intercept_errors" +}; + static ngx_conf_bitmask_t ngx_http_fastcgi_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, @@ -240,13 +244,20 @@ static ngx_command_t ngx_http_fastcgi_commands[] = { offsetof(ngx_http_fastcgi_loc_conf_t, upstream.pass_request_body), NULL }, - { ngx_string("fastcgi_redirect_errors"), + { ngx_string("fastcgi_intercept_errors"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.redirect_errors), + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.intercept_errors), NULL }, + { ngx_string("fastcgi_redirect_errors"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.intercept_errors), + &ngx_conf_deprecated_fastcgi_redirect_errors }, + { ngx_string("fastcgi_read_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -1534,7 +1545,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_request_headers = NGX_CONF_UNSET; conf->upstream.pass_request_body = NGX_CONF_UNSET; - conf->upstream.redirect_errors = NGX_CONF_UNSET; + conf->upstream.intercept_errors = NGX_CONF_UNSET; /* "fastcgi_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; @@ -1708,8 +1719,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->upstream.pass_request_body, prev->upstream.pass_request_body, 1); - ngx_conf_merge_value(conf->upstream.redirect_errors, - prev->upstream.redirect_errors, 0); + ngx_conf_merge_value(conf->upstream.intercept_errors, + prev->upstream.intercept_errors, 0); ngx_conf_merge_str_value(conf->index, prev->index, ""); diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c index 3afb6a3db..5e1636385 100644 --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -16,17 +16,20 @@ typedef struct { ngx_array_t *ops; /* array of ngx_http_log_op_t */ } ngx_http_log_fmt_t; + typedef struct { ngx_array_t formats; /* array of ngx_http_log_fmt_t */ ngx_uint_t combined_used; /* unsigned combined_used:1 */ } ngx_http_log_main_conf_t; + typedef struct { ngx_open_file_t *file; time_t disk_full_time; ngx_array_t *ops; /* array of ngx_http_log_op_t */ } ngx_http_log_t; + typedef struct { ngx_array_t *logs; /* array of ngx_http_log_t */ ngx_uint_t off; /* unsigned off:1 */ diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c index 6384af03e..5b07dbc52 100644 --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -524,7 +524,7 @@ ngx_http_memcached_create_loc_conf(ngx_conf_t *cf) conf->upstream.busy_buffers_size = 0; conf->upstream.max_temp_file_size = 0; conf->upstream.temp_file_write_size = 0; - conf->upstream.redirect_errors = 1; + conf->upstream.intercept_errors = 1; conf->upstream.redirect_404 = 1; conf->upstream.pass_request_headers = 0; conf->upstream.pass_request_body = 0; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 31a4355e5..f14151ae8 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -115,6 +115,10 @@ static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_header_buffer_size = { ngx_conf_deprecated, "proxy_header_buffer_size", "proxy_buffer_size" }; +static ngx_conf_deprecated_t ngx_conf_deprecated_proxy_redirect_errors = { + ngx_conf_deprecated, "proxy_redirect_errors", "proxy_intercept_errors" +}; + static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, @@ -178,13 +182,20 @@ static ngx_command_t ngx_http_proxy_commands[] = { offsetof(ngx_http_proxy_loc_conf_t, upstream.send_lowat), &ngx_http_proxy_lowat_post }, - { ngx_string("proxy_redirect_errors"), + { ngx_string("proxy_intercept_errors"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, upstream.redirect_errors), + offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors), NULL }, + { ngx_string("proxy_redirect_errors"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.intercept_errors), + &ngx_conf_deprecated_proxy_redirect_errors }, + { ngx_string("proxy_set_header"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, ngx_conf_set_keyval_slot, @@ -1486,7 +1497,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf) conf->upstream.pass_request_headers = NGX_CONF_UNSET; conf->upstream.pass_request_body = NGX_CONF_UNSET; - conf->upstream.redirect_errors = NGX_CONF_UNSET; + conf->upstream.intercept_errors = NGX_CONF_UNSET; /* "proxy_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; @@ -1670,8 +1681,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_value(conf->upstream.pass_request_body, prev->upstream.pass_request_body, 1); - ngx_conf_merge_value(conf->upstream.redirect_errors, - prev->upstream.redirect_errors, 0); + ngx_conf_merge_value(conf->upstream.intercept_errors, + prev->upstream.intercept_errors, 0); ngx_conf_merge_value(conf->redirect, prev->redirect, 1); diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index a76b67a87..7beb091ca 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -145,7 +145,6 @@ ngx_http_range_header_filter(ngx_http_request_t *r) || r->headers_in.range->value.len < 7 || ngx_strncasecmp(r->headers_in.range->value.data, "bytes=", 6) != 0) { - r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers); if (r->headers_out.accept_ranges == NULL) { return NGX_ERROR; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index 817045e95..63c2dd138 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -788,7 +788,8 @@ ngx_http_ssi_output(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx) while (ctx->busy) { - b = ctx->busy->buf; + cl = ctx->busy; + b = cl->buf; if (ngx_buf_size(b) != 0) { break; @@ -804,7 +805,6 @@ ngx_http_ssi_output(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx) b->shadow->pos = b->shadow->last; } - cl = ctx->busy; ctx->busy = cl->next; if (ngx_buf_in_memory(b) || b->in_file) { @@ -942,9 +942,7 @@ ngx_http_ssi_parse(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx) case ssi_sharp_state: switch (ch) { case '#': - if (ctx->copy_start) { - ctx->saved = 0; - } + ctx->saved = 0; looked = 0; state = ssi_precommand_state; break; @@ -1417,11 +1415,11 @@ ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, if (n == 0) { - if (!(flags & NGX_HTTP_SSI_ADD_PREFIX)) { - return NGX_OK; - } + data = text->data; + p = data; + + if ((flags & NGX_HTTP_SSI_ADD_PREFIX) && text->data[0] != '/') { - if (text->data[0] != '/') { for (prefix = r->uri.len; prefix; prefix--) { if (r->uri.data[prefix - 1] == '/') { break; @@ -1437,13 +1435,35 @@ ngx_http_ssi_evaluate_string(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, } p = ngx_copy(data, r->uri.data, prefix); - ngx_memcpy(p, text->data, text->len); + } + } + + quoted = 0; - text->len = len; - text->data = data; + for (i = 0 ; i < text->len; i++) { + ch = text->data[i]; + + if (!quoted) { + + if (ch == '\\') { + quoted = 1; + continue; + } + + } else { + quoted = 0; + + if (ch != '\\' && ch != '\'' && ch != '"' && ch != '$') { + *p++ = '\\'; + } } + + *p++ = ch; } + text->len = p - data; + text->data = data; + return NGX_OK; } @@ -2140,6 +2160,7 @@ ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, v->len = ngx_sprintf(v->data, "%T", tp->sec + (gmt ? 0 : tp->gmtoff)) - v->data; + return NGX_OK; } diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c index 810eb3ad1..92c53f83e 100644 --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -594,10 +594,6 @@ ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, ngx_http_userid_ctx_t *ctx; ngx_http_userid_conf_t *conf; - v->valid = 1; - v->no_cachable = 0; - v->not_found = 0; - ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); uid = (uint32_t *) ((char *) ctx + data); @@ -615,6 +611,10 @@ ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, return NGX_ERROR; } + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + ngx_sprintf(v->data, "%V=%08XD%08XD%08XD%08XD", &conf->name, uid[0], uid[1], uid[2], uid[3]); |