diff options
author | nginx <nginx@nginx.org> | 2013-02-19 15:28:29 +0000 |
---|---|---|
committer | Jon Kolb <jon@b0g.us> | 2013-02-19 15:28:29 +0000 |
commit | a36b88c56061d08f8fbe96a51489bf3381792aca (patch) | |
tree | fe157c41a9e920b0b05a343f2dc85312f080b6f4 | |
parent | bf3178867712d61cd5bb7692e6f837c4b0c51d8c (diff) | |
download | nginx-a36b88c56061d08f8fbe96a51489bf3381792aca.tar.gz |
Changes with nginx 1.3.13 19 Feb 2013v1.3.13
*) Change: a compiler with name "cc" is now used by default.
*) Feature: support for proxying of WebSocket connections.
Thanks to Apcera and CloudBees for sponsoring this work.
*) Feature: the "auth_basic_user_file" directive supports "{SHA}"
password encryption method.
Thanks to Louis Opter.
-rw-r--r-- | CHANGES | 12 | ||||
-rw-r--r-- | CHANGES.ru | 13 | ||||
-rw-r--r-- | auto/lib/perl/make | 3 | ||||
-rw-r--r-- | auto/options | 2 | ||||
-rw-r--r-- | src/core/nginx.h | 4 | ||||
-rw-r--r-- | src/core/ngx_crypt.c | 37 | ||||
-rw-r--r-- | src/http/modules/ngx_http_autoindex_module.c | 7 | ||||
-rw-r--r-- | src/http/modules/ngx_http_chunked_filter_module.c | 1 | ||||
-rw-r--r-- | src/http/modules/ngx_http_proxy_module.c | 8 | ||||
-rw-r--r-- | src/http/modules/perl/nginx.pm | 2 | ||||
-rw-r--r-- | src/http/ngx_http_header_filter_module.c | 11 | ||||
-rw-r--r-- | src/http/ngx_http_request.c | 4 | ||||
-rw-r--r-- | src/http/ngx_http_request.h | 5 | ||||
-rw-r--r-- | src/http/ngx_http_upstream.c | 287 | ||||
-rw-r--r-- | src/http/ngx_http_upstream.h | 3 | ||||
-rw-r--r-- | src/http/ngx_http_variables.c | 6 |
16 files changed, 395 insertions, 10 deletions
@@ -1,4 +1,16 @@ +Changes with nginx 1.3.13 19 Feb 2013 + + *) Change: a compiler with name "cc" is now used by default. + + *) Feature: support for proxying of WebSocket connections. + Thanks to Apcera and CloudBees for sponsoring this work. + + *) Feature: the "auth_basic_user_file" directive supports "{SHA}" + password encryption method. + Thanks to Louis Opter. + + Changes with nginx 1.3.12 05 Feb 2013 *) Feature: variables support in the "proxy_bind", "fastcgi_bind", diff --git a/CHANGES.ru b/CHANGES.ru index 881866e14..1d1a3a025 100644 --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,17 @@ +Изменения в nginx 1.3.13 19.02.2013 + + *) Изменение: теперь для сборки по умолчанию используется компилятор с + именем "cc". + + *) Добавление: поддержка проксирования WebSocket-соединений. + Спасибо Apcera и CloudBees за спонсирование разработки. + + *) Добавление: директива auth_basic_user_file поддерживает шифрование + паролей методом "{SHA}". + Спасибо Louis Opter. + + Изменения в nginx 1.3.12 05.02.2013 *) Добавление: директивы proxy_bind, fastcgi_bind, memcached_bind, diff --git a/auto/lib/perl/make b/auto/lib/perl/make index 6fe95af0e..b40352abf 100644 --- a/auto/lib/perl/make +++ b/auto/lib/perl/make @@ -6,11 +6,12 @@ cat << END >> $NGX_MAKEFILE $NGX_OBJS/src/http/modules/perl/blib/arch/auto/nginx/nginx.so: \ + \$(CORE_DEPS) \$(HTTP_DEPS) \ src/http/modules/perl/nginx.pm \ src/http/modules/perl/nginx.xs \ src/http/modules/perl/ngx_http_perl_module.h \ $NGX_OBJS/src/http/modules/perl/Makefile - cp -p src/http/modules/perl/nginx.* $NGX_OBJS/src/http/modules/perl/ + cp src/http/modules/perl/nginx.* $NGX_OBJS/src/http/modules/perl/ cd $NGX_OBJS/src/http/modules/perl && \$(MAKE) diff --git a/auto/options b/auto/options index a75bead54..150286d7b 100644 --- a/auto/options +++ b/auto/options @@ -15,7 +15,7 @@ NGX_LOCK_PATH= NGX_USER= NGX_GROUP= -CC=${CC:-gcc} +CC=${CC:-cc} CPP= NGX_OBJS=objs diff --git a/src/core/nginx.h b/src/core/nginx.h index 9c9df6356..f522433e2 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1003012 -#define NGINX_VERSION "1.3.12" +#define nginx_version 1003013 +#define NGINX_VERSION "1.3.13" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_crypt.c b/src/core/ngx_crypt.c index b2e25b901..629d160e8 100644 --- a/src/core/ngx_crypt.c +++ b/src/core/ngx_crypt.c @@ -24,6 +24,8 @@ static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted); +static ngx_int_t ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, + u_char **encrypted); #endif @@ -43,6 +45,9 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) #if (NGX_HAVE_SHA1) } else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) { return ngx_crypt_ssha(pool, key, salt, encrypted); + + } else if (ngx_strncmp(salt, "{SHA}", sizeof("{SHA}") - 1) == 0) { + return ngx_crypt_sha(pool, key, salt, encrypted); #endif } @@ -241,6 +246,38 @@ ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) return NGX_OK; } + +static ngx_int_t +ngx_crypt_sha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +{ + size_t len; + ngx_str_t encoded, decoded; + ngx_sha1_t sha1; + u_char digest[20]; + + /* "{SHA}" base64(SHA1(key)) */ + + decoded.len = sizeof(digest); + decoded.data = digest; + + ngx_sha1_init(&sha1); + ngx_sha1_update(&sha1, key, ngx_strlen(key)); + ngx_sha1_final(digest, &sha1); + + len = sizeof("{SHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1; + + *encrypted = ngx_pnalloc(pool, len); + if (*encrypted == NULL) { + return NGX_ERROR; + } + + encoded.data = ngx_cpymem(*encrypted, "{SHA}", sizeof("{SHA}") - 1); + ngx_encode_base64(&encoded, &decoded); + encoded.data[encoded.len] = '\0'; + + return NGX_OK; +} + #endif /* NGX_HAVE_SHA1 */ #endif /* NGX_CRYPT */ diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c index 450a48e50..fb46d65d1 100644 --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -489,8 +489,11 @@ ngx_http_autoindex_handler(ngx_http_request_t *r) } b->last = ngx_cpymem(b->last, "</a>", sizeof("</a>") - 1); - ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len); - b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len; + + if (NGX_HTTP_AUTOINDEX_NAME_LEN - len > 0) { + ngx_memset(b->last, ' ', NGX_HTTP_AUTOINDEX_NAME_LEN - len); + b->last += NGX_HTTP_AUTOINDEX_NAME_LEN - len; + } } *b->last++ = ' '; diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c index 94313a8f6..a7dc5bf4d 100644 --- a/src/http/modules/ngx_http_chunked_filter_module.c +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -62,6 +62,7 @@ ngx_http_chunked_header_filter(ngx_http_request_t *r) if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED || r->headers_out.status == NGX_HTTP_NO_CONTENT + || r->headers_out.status < NGX_HTTP_OK || r != r->main || (r->method & NGX_HTTP_HEAD)) { diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index ce47a9e34..a623adc34 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -1474,6 +1474,14 @@ ngx_http_proxy_process_header(ngx_http_request_t *r) u->keepalive = !u->headers_in.connection_close; } + if (u->headers_in.status_n == NGX_HTTP_SWITCHING_PROTOCOLS) { + u->keepalive = 0; + + if (r->headers_in.upgrade) { + u->upgrade = 1; + } + } + return NGX_OK; } diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm index 87ce2c115..353cadb9d 100644 --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -50,7 +50,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.3.12'; +our $VERSION = '1.3.13'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c index e3efbba5b..707a81313 100644 --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -379,7 +379,10 @@ ngx_http_header_filter(ngx_http_request_t *r) len += sizeof("Transfer-Encoding: chunked" CRLF) - 1; } - if (r->keepalive) { + if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) { + len += sizeof("Connection: upgrade" CRLF) - 1; + + } else if (r->keepalive) { len += sizeof("Connection: keep-alive" CRLF) - 1; /* @@ -548,7 +551,11 @@ ngx_http_header_filter(ngx_http_request_t *r) sizeof("Transfer-Encoding: chunked" CRLF) - 1); } - if (r->keepalive) { + if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) { + b->last = ngx_cpymem(b->last, "Connection: upgrade" CRLF, + sizeof("Connection: upgrade" CRLF) - 1); + + } else if (r->keepalive) { b->last = ngx_cpymem(b->last, "Connection: keep-alive" CRLF, sizeof("Connection: keep-alive" CRLF) - 1); diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index e94e7fcce..763e7bf11 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -130,6 +130,10 @@ ngx_http_header_t ngx_http_headers_in[] = { offsetof(ngx_http_headers_in_t, expect), ngx_http_process_unique_header_line }, + { ngx_string("Upgrade"), + offsetof(ngx_http_headers_in_t, upgrade), + ngx_http_process_header_line }, + #if (NGX_HTTP_GZIP) { ngx_string("Accept-Encoding"), offsetof(ngx_http_headers_in_t, accept_encoding), diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index f234840c1..f0c39adaf 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -64,6 +64,10 @@ #define NGX_HTTP_LOG_UNSAFE 8 +#define NGX_HTTP_CONTINUE 100 +#define NGX_HTTP_SWITCHING_PROTOCOLS 101 +#define NGX_HTTP_PROCESSING 102 + #define NGX_HTTP_OK 200 #define NGX_HTTP_CREATED 201 #define NGX_HTTP_ACCEPTED 202 @@ -184,6 +188,7 @@ typedef struct { ngx_table_elt_t *transfer_encoding; ngx_table_elt_t *expect; + ngx_table_elt_t *upgrade; #if (NGX_HTTP_GZIP) ngx_table_elt_t *accept_encoding; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 4f167a2b1..6a77f7f03 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -46,6 +46,16 @@ static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r, ngx_http_upstream_t *u); static void ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u); +static void ngx_http_upstream_upgrade(ngx_http_request_t *r, + ngx_http_upstream_t *u); +static void ngx_http_upstream_upgraded_read_downstream(ngx_http_request_t *r); +static void ngx_http_upstream_upgraded_write_downstream(ngx_http_request_t *r); +static void ngx_http_upstream_upgraded_read_upstream(ngx_http_request_t *r, + ngx_http_upstream_t *u); +static void ngx_http_upstream_upgraded_write_upstream(ngx_http_request_t *r, + ngx_http_upstream_t *u); +static void ngx_http_upstream_process_upgraded(ngx_http_request_t *r, + ngx_uint_t from_upstream, ngx_uint_t do_write); static void ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r); static void @@ -1327,6 +1337,7 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u) } u->keepalive = 0; + u->upgrade = 0; ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t)); u->headers_in.content_length_n = -1; @@ -2078,6 +2089,11 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) return; } + if (u->upgrade) { + ngx_http_upstream_upgrade(r, u); + return; + } + c = r->connection; if (r->header_only) { @@ -2361,6 +2377,277 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) static void +ngx_http_upstream_upgrade(ngx_http_request_t *r, ngx_http_upstream_t *u) +{ + int tcp_nodelay; + ngx_connection_t *c; + ngx_http_core_loc_conf_t *clcf; + + c = r->connection; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + /* TODO: prevent upgrade if not requested or not possible */ + + r->keepalive = 0; + c->log->action = "proxying upgraded connection"; + + u->read_event_handler = ngx_http_upstream_upgraded_read_upstream; + u->write_event_handler = ngx_http_upstream_upgraded_write_upstream; + r->read_event_handler = ngx_http_upstream_upgraded_read_downstream; + r->write_event_handler = ngx_http_upstream_upgraded_write_downstream; + + if (clcf->tcp_nodelay && c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "tcp_nodelay"); + + tcp_nodelay = 1; + + if (setsockopt(c->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) == -1) + { + ngx_connection_error(c, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + c->tcp_nodelay = NGX_TCP_NODELAY_SET; + + if (setsockopt(u->peer.connection->fd, IPPROTO_TCP, TCP_NODELAY, + (const void *) &tcp_nodelay, sizeof(int)) == -1) + { + ngx_connection_error(u->peer.connection, ngx_socket_errno, + "setsockopt(TCP_NODELAY) failed"); + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + u->peer.connection->tcp_nodelay = NGX_TCP_NODELAY_SET; + } + + if (ngx_http_send_special(r, NGX_HTTP_FLUSH) == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (u->peer.connection->read->ready + || u->buffer.pos != u->buffer.last) + { + ngx_http_upstream_process_upgraded(r, 1, 1); + } + + if (c->read->ready + || r->header_in->pos != r->header_in->last) + { + ngx_http_upstream_process_upgraded(r, 0, 1); + } +} + + +static void +ngx_http_upstream_upgraded_read_downstream(ngx_http_request_t *r) +{ + ngx_http_upstream_process_upgraded(r, 0, 0); +} + + +static void +ngx_http_upstream_upgraded_write_downstream(ngx_http_request_t *r) +{ + ngx_http_upstream_process_upgraded(r, 1, 1); +} + + +static void +ngx_http_upstream_upgraded_read_upstream(ngx_http_request_t *r, + ngx_http_upstream_t *u) +{ + ngx_http_upstream_process_upgraded(r, 1, 0); +} + + +static void +ngx_http_upstream_upgraded_write_upstream(ngx_http_request_t *r, + ngx_http_upstream_t *u) +{ + ngx_http_upstream_process_upgraded(r, 0, 1); +} + + +static void +ngx_http_upstream_process_upgraded(ngx_http_request_t *r, + ngx_uint_t from_upstream, ngx_uint_t do_write) +{ + size_t size; + ssize_t n; + ngx_buf_t *b; + ngx_connection_t *c, *downstream, *upstream, *dst, *src; + ngx_http_upstream_t *u; + ngx_http_core_loc_conf_t *clcf; + + c = r->connection; + u = r->upstream; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream process upgraded, fu:%ui", from_upstream); + + downstream = c; + upstream = u->peer.connection; + + if (downstream->write->timedout) { + c->timedout = 1; + ngx_connection_error(c, NGX_ETIMEDOUT, "client timed out"); + ngx_http_upstream_finalize_request(r, u, NGX_HTTP_REQUEST_TIME_OUT); + return; + } + + if (upstream->read->timedout || upstream->write->timedout) { + ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (from_upstream) { + src = upstream; + dst = downstream; + b = &u->buffer; + + } else { + src = downstream; + dst = upstream; + b = &u->from_client; + + if (r->header_in->last > r->header_in->pos) { + b = r->header_in; + b->end = b->last; + do_write = 1; + } + + if (b->start == NULL) { + b->start = ngx_palloc(r->pool, u->conf->buffer_size); + if (b->start == NULL) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + b->pos = b->start; + b->last = b->start; + b->end = b->start + u->conf->buffer_size; + b->temporary = 1; + b->tag = u->output.tag; + } + } + + for ( ;; ) { + + if (do_write) { + + size = b->last - b->pos; + + if (size && dst->write->ready) { + + n = dst->send(dst, b->pos, size); + + if (n == NGX_ERROR) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (n > 0) { + b->pos += n; + + if (b->pos == b->last) { + b->pos = b->start; + b->last = b->start; + } + } + } + } + + size = b->end - b->last; + + if (size && src->read->ready) { + + n = src->recv(src, b->last, size); + + if (n == NGX_AGAIN || n == 0) { + break; + } + + if (n > 0) { + do_write = 1; + b->last += n; + + continue; + } + + if (n == NGX_ERROR) { + src->read->eof = 1; + } + } + + break; + } + + if ((upstream->read->eof && u->buffer.pos == u->buffer.last) + || (downstream->read->eof && u->from_client.pos == u->from_client.last) + || (downstream->read->eof && upstream->read->eof)) + { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream upgraded done"); + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (ngx_handle_write_event(upstream->write, u->conf->send_lowat) + != NGX_OK) + { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (upstream->write->active && !upstream->write->ready) { + ngx_add_timer(upstream->write, u->conf->send_timeout); + + } else if (upstream->write->timer_set) { + ngx_del_timer(upstream->write); + } + + if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (upstream->read->active && !upstream->read->ready) { + ngx_add_timer(upstream->read, u->conf->read_timeout); + + } else if (upstream->read->timer_set) { + ngx_del_timer(upstream->read); + } + + if (ngx_handle_write_event(downstream->write, clcf->send_lowat) + != NGX_OK) + { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, 0); + return; + } + + if (downstream->write->active && !downstream->write->ready) { + ngx_add_timer(downstream->write, clcf->send_timeout); + + } else if (downstream->write->timer_set) { + ngx_del_timer(downstream->write); + } +} + + +static void ngx_http_upstream_process_non_buffered_downstream(ngx_http_request_t *r) { ngx_event_t *wev; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h index 2c910cd9c..29ebf9bd9 100644 --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -284,6 +284,8 @@ struct ngx_http_upstream_s { ngx_http_upstream_resolved_t *resolved; + ngx_buf_t from_client; + ngx_buf_t buffer; off_t length; @@ -329,6 +331,7 @@ struct ngx_http_upstream_s { unsigned buffering:1; unsigned keepalive:1; + unsigned upgrade:1; unsigned request_sent:1; unsigned header_sent:1; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index 0c6872fe2..b8190b030 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -1747,7 +1747,11 @@ ngx_http_variable_sent_connection(ngx_http_request_t *r, size_t len; char *p; - if (r->keepalive) { + if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) { + len = sizeof("upgrade") - 1; + p = "upgrade"; + + } else if (r->keepalive) { len = sizeof("keep-alive") - 1; p = "keep-alive"; |