From piotrsikora at google.com Mon Aug 1 04:58:23 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Sun, 31 Jul 2016 21:58:23 -0700 Subject: [PATCH] HTTP: add support for trailers in HTTP responses In-Reply-To: <20160721134430.GV57459@mdounin.ru> References: <20160721134430.GV57459@mdounin.ru> Message-ID: # HG changeset patch # User Piotr Sikora # Date 1466735480 25200 # Thu Jun 23 19:31:20 2016 -0700 # Node ID fc15b8aa8f020bbc1cdb8aba0123fce7a58f51c8 # Parent d43ee392e825186545d81e683b88cc58ef8479bc HTTP: add support for trailers in HTTP responses. Example: ngx_table_elt_t *h; h = ngx_list_push(&r->headers_out.trailers); if (h == NULL) { return NGX_ERROR; } ngx_str_set(&h->key, "Fun"); ngx_str_set(&h->value, "with trailers"); h->hash = ngx_hash_key_lc(h->key.data, h->key.len); The code above adds "Fun: with trailers" trailer to the response to the request with "TE: trailers" header (which indicates support for trailers). Note that trailers MUST be added before last buffer of the response (last_buf = 1) reaches chunked or v2 output filters, otherwise they are going to be ignored. Signed-off-by: Piotr Sikora diff -r d43ee392e825 -r fc15b8aa8f02 src/http/modules/ngx_http_chunked_filter_module.c --- a/src/http/modules/ngx_http_chunked_filter_module.c +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -17,6 +17,7 @@ typedef struct { static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf); +static ngx_chain_t *ngx_http_chunked_create_trailers(ngx_http_request_t *r); static ngx_http_module_t ngx_http_chunked_filter_module_ctx = { @@ -69,28 +70,31 @@ ngx_http_chunked_header_filter(ngx_http_ return ngx_http_next_header_filter(r); } - if (r->headers_out.content_length_n == -1) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->chunked_transfer_encoding && r->trailers_ok) { + ngx_http_clear_content_length(r); + r->chunked = 1; + + } else if (r->headers_out.content_length_n == -1) { if (r->http_version < NGX_HTTP_VERSION_11) { r->keepalive = 0; + } else if (clcf->chunked_transfer_encoding) { + r->chunked = 1; + } else { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + r->keepalive = 0; + } + } - if (clcf->chunked_transfer_encoding) { - r->chunked = 1; + if (r->chunked) { + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } - ctx = ngx_pcalloc(r->pool, - sizeof(ngx_http_chunked_filter_ctx_t)); - if (ctx == NULL) { - return NGX_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module); - - } else { - r->keepalive = 0; - } - } + ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module); } return ngx_http_next_header_filter(r); @@ -201,6 +205,15 @@ ngx_http_chunked_body_filter(ngx_http_re b->pos += 2; } + if (r->trailers_ok) { + tl->next = ngx_http_chunked_create_trailers(r); + + if (tl->next != NULL) { + b->last -= 2; + b->last_buf = 0; + } + } + } else if (size > 0) { tl = ngx_chain_get_free_buf(r->pool, &ctx->free); if (tl == NULL) { @@ -230,6 +243,108 @@ ngx_http_chunked_body_filter(ngx_http_re } +static ngx_chain_t * +ngx_http_chunked_create_trailers(ngx_http_request_t *r) +{ + size_t len; + ngx_buf_t *b; + ngx_uint_t i; + ngx_chain_t *cl; + ngx_list_part_t *part; + ngx_table_elt_t *header; + ngx_http_chunked_filter_ctx_t *ctx; + + len = 0; + + part = &r->headers_out.trailers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + len += header[i].key.len + sizeof(": ") - 1 + header[i].value.len + + sizeof(CRLF) - 1; + } + + if (len == 0) { + return NULL; + } + + len += sizeof(CRLF) - 1; + + ctx = ngx_http_get_module_ctx(r, ngx_http_chunked_filter_module); + + cl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NULL; + } + + b = cl->buf; + + b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module; + b->temporary = 0; + b->memory = 1; + b->last_buf = 1; + + b->start = ngx_palloc(r->pool, len); + if (b->start == NULL) { + return NULL; + } + + b->end = b->last + len; + b->pos = b->start; + b->last = b->start; + + part = &r->headers_out.trailers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http trailer: \"%V: %V\"", + &header[i].key, &header[i].value); + + b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); + *b->last++ = ':'; *b->last++ = ' '; + + b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); + *b->last++ = CR; *b->last++ = LF; + } + + /* the end of HTTP trailer */ + *b->last++ = CR; *b->last++ = LF; + + return cl; +} + + static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf) { diff -r d43ee392e825 -r fc15b8aa8f02 src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -29,6 +29,8 @@ static ngx_int_t ngx_http_process_connec ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_process_te(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc); @@ -125,6 +127,10 @@ ngx_http_header_t ngx_http_headers_in[] offsetof(ngx_http_headers_in_t, if_range), ngx_http_process_unique_header_line }, + { ngx_string("TE"), + offsetof(ngx_http_headers_in_t, te), + ngx_http_process_te }, + { ngx_string("Transfer-Encoding"), offsetof(ngx_http_headers_in_t, transfer_encoding), ngx_http_process_header_line }, @@ -559,6 +565,14 @@ ngx_http_create_request(ngx_connection_t return NULL; } + if (ngx_list_init(&r->headers_out.trailers, r->pool, 4, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + ngx_destroy_pool(r->pool); + return NULL; + } + r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); if (r->ctx == NULL) { ngx_destroy_pool(r->pool); @@ -1737,6 +1751,59 @@ ngx_http_process_user_agent(ngx_http_req static ngx_int_t +ngx_http_process_te(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + u_char *p; + + if (ngx_http_process_multi_header_lines(r, h, offset) != NGX_OK) { + return NGX_ERROR; + } + + if (r->http_version < NGX_HTTP_VERSION_11) { + return NGX_OK; + } + + if (h->value.len == sizeof("trailers") - 1 + && ngx_memcmp(h->value.data, "trailers", sizeof("trailers") - 1) == 0) + { + r->trailers_ok = 1; + return NGX_OK; + } + + if (r->http_version >= NGX_HTTP_VERSION_20) { + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent HTTP/2 request with invalid value \"%V\" " + "in \"TE\" header", &h->value); + + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return NGX_ERROR; + } + + if (h->value.len < sizeof("trailers") - 1) { + return NGX_OK; + } + + p = ngx_strcasestrn(h->value.data, "trailers", sizeof("trailers") - 2); + if (p == NULL) { + return NGX_OK; + } + + if (p == h->value.data || *(p - 1) == ',' || *(p - 1) == ' ') { + + p += sizeof("trailers") - 1; + + if (p == h->value.data + h->value.len || *p == ',' || *p == ' ') { + r->trailers_ok = 1; + return NGX_OK; + } + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_process_multi_header_lines(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { diff -r d43ee392e825 -r fc15b8aa8f02 src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -189,6 +189,7 @@ typedef struct { ngx_table_elt_t *range; ngx_table_elt_t *if_range; + ngx_array_t te; ngx_table_elt_t *transfer_encoding; ngx_table_elt_t *expect; ngx_table_elt_t *upgrade; @@ -245,6 +246,7 @@ typedef struct { typedef struct { ngx_list_t headers; + ngx_list_t trailers; ngx_uint_t status; ngx_str_t status_line; @@ -514,6 +516,7 @@ struct ngx_http_request_s { unsigned pipeline:1; unsigned chunked:1; unsigned header_only:1; + unsigned trailers_ok:1; unsigned keepalive:1; unsigned lingering_close:1; unsigned discard_body:1; diff -r d43ee392e825 -r fc15b8aa8f02 src/http/v2/ngx_http_v2_filter_module.c --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -56,7 +56,9 @@ static u_char *ngx_http_v2_string_encode static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value); static ngx_http_v2_out_frame_t *ngx_http_v2_create_headers_frame( - ngx_http_request_t *r, u_char *pos, u_char *end); + ngx_http_request_t *r, u_char *pos, u_char *end, ngx_uint_t fin); +static ngx_http_v2_out_frame_t *ngx_http_v2_create_trailers_frame( + ngx_http_request_t *r); static ngx_chain_t *ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit); @@ -575,7 +577,7 @@ ngx_http_v2_header_filter(ngx_http_reque header[i].value.len, tmp); } - frame = ngx_http_v2_create_headers_frame(r, start, pos); + frame = ngx_http_v2_create_headers_frame(r, start, pos, r->header_only); if (frame == NULL) { return NGX_ERROR; } @@ -599,6 +601,121 @@ ngx_http_v2_header_filter(ngx_http_reque } +static ngx_http_v2_out_frame_t * +ngx_http_v2_create_trailers_frame(ngx_http_request_t *r) +{ + u_char *pos, *start, *tmp; + size_t len, tmp_len; + ngx_uint_t i; + ngx_list_part_t *part; + ngx_table_elt_t *header; + + len = 0; + tmp_len = 0; + + part = &r->headers_out.trailers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "ignoring too long response trailer name: \"%V\"", + &header[i].key); + continue; + } + + if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) { + ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, + "ignoring too long response trailer value: " + "\"%V: %V\"", &header[i].key, &header[i].value); + continue; + } + + len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len + + NGX_HTTP_V2_INT_OCTETS + header[i].value.len; + + if (header[i].key.len > tmp_len) { + tmp_len = header[i].key.len; + } + + if (header[i].value.len > tmp_len) { + tmp_len = header[i].value.len; + } + } + + if (len == 0) { + return NULL; + } + + tmp = ngx_palloc(r->pool, tmp_len); + pos = ngx_pnalloc(r->pool, len); + + if (pos == NULL || tmp == NULL) { + return NULL; + } + + start = pos; + + part = &r->headers_out.trailers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0 + || header[i].key.len > NGX_HTTP_V2_MAX_FIELD + || header[i].value.len > NGX_HTTP_V2_MAX_FIELD) + { + continue; + } + +#if (NGX_DEBUG) + if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) { + ngx_strlow(tmp, header[i].key.data, header[i].key.len); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2 output trailer: \"%*s: %V\"", + header[i].key.len, tmp, &header[i].value); + } +#endif + + *pos++ = 0; + + pos = ngx_http_v2_write_name(pos, header[i].key.data, + header[i].key.len, tmp); + + pos = ngx_http_v2_write_value(pos, header[i].value.data, + header[i].value.len, tmp); + } + + return ngx_http_v2_create_headers_frame(r, start, pos, 1); +} + + static u_char * ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, ngx_uint_t lower) @@ -649,7 +766,7 @@ ngx_http_v2_write_int(u_char *pos, ngx_u static ngx_http_v2_out_frame_t * ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos, - u_char *end) + u_char *end, ngx_uint_t fin) { u_char type, flags; size_t rest, frame_size; @@ -670,12 +787,12 @@ ngx_http_v2_create_headers_frame(ngx_htt frame->stream = stream; frame->length = rest; frame->blocked = 1; - frame->fin = r->header_only; + frame->fin = fin; ll = &frame->first; type = NGX_HTTP_V2_HEADERS_FRAME; - flags = r->header_only ? NGX_HTTP_V2_END_STREAM_FLAG : NGX_HTTP_V2_NO_FLAG; + flags = fin ? NGX_HTTP_V2_END_STREAM_FLAG : NGX_HTTP_V2_NO_FLAG; frame_size = stream->connection->frame_size; for ( ;; ) { @@ -737,7 +854,7 @@ ngx_http_v2_create_headers_frame(ngx_htt continue; } - b->last_buf = r->header_only; + b->last_buf = fin; cl->next = NULL; frame->last = cl; @@ -759,7 +876,7 @@ ngx_http_v2_send_chain(ngx_connection_t ngx_http_request_t *r; ngx_http_v2_stream_t *stream; ngx_http_v2_loc_conf_t *h2lcf; - ngx_http_v2_out_frame_t *frame; + ngx_http_v2_out_frame_t *frame, *trailers; ngx_http_v2_connection_t *h2c; r = fc->data; @@ -833,6 +950,8 @@ ngx_http_v2_send_chain(ngx_connection_t frame_size = (h2lcf->chunk_size < h2c->frame_size) ? h2lcf->chunk_size : h2c->frame_size; + trailers = NULL; + #if (NGX_SUPPRESS_WARN) cl = NULL; #endif @@ -895,17 +1014,31 @@ ngx_http_v2_send_chain(ngx_connection_t size -= rest; } - frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, out, cl); - if (frame == NULL) { - return NGX_CHAIN_ERROR; + if (cl->buf->last_buf && r->trailers_ok) { + trailers = ngx_http_v2_create_trailers_frame(r); + if (trailers) { + cl->buf->last_buf = 0; + } } - ngx_http_v2_queue_frame(h2c, frame); + if (frame_size || cl->buf->last_buf) { + frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, out, cl); + if (frame == NULL) { + return NGX_CHAIN_ERROR; + } - h2c->send_window -= frame_size; + ngx_http_v2_queue_frame(h2c, frame); - stream->send_window -= frame_size; - stream->queued++; + h2c->send_window -= frame_size; + + stream->send_window -= frame_size; + stream->queued++; + } + + if (trailers) { + ngx_http_v2_queue_frame(h2c, trailers); + stream->queued++; + } if (in == NULL) { break; From piotrsikora at google.com Mon Aug 1 07:33:45 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Mon, 1 Aug 2016 00:33:45 -0700 Subject: [PATCH] HTTP: add support for trailers in HTTP responses In-Reply-To: References: <20160721134430.GV57459@mdounin.ru> Message-ID: Hey Maxim, what do you need in order to move forward with this patch? Best regards, Piotr Sikora From mdounin at mdounin.ru Mon Aug 1 13:21:55 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 1 Aug 2016 16:21:55 +0300 Subject: [PATCH] HTTP: add support for trailers in HTTP responses In-Reply-To: References: <20160721134430.GV57459@mdounin.ru> Message-ID: <20160801132154.GH57459@mdounin.ru> Hello! On Mon, Aug 01, 2016 at 12:33:45AM -0700, Piotr Sikora wrote: > Hey Maxim, > what do you need in order to move forward with this patch? I still don't see any real world usage example reported. Additionally, quick look suggests that the patch still unconditionally removes Content-Length from a response if client advertizes trailers support. As I previously wrote, I found this approach to be wrong. -- Maxim Dounin http://nginx.org/ From piotrsikora at google.com Mon Aug 1 17:56:21 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Mon, 1 Aug 2016 10:56:21 -0700 Subject: [PATCH] HTTP: add support for trailers in HTTP responses In-Reply-To: <20160801132154.GH57459@mdounin.ru> References: <20160721134430.GV57459@mdounin.ru> <20160801132154.GH57459@mdounin.ru> Message-ID: Hey Maxim, > I still don't see any real world usage example reported. That's because you chose to ignore those provided to you. 1) As of right now, trailers are ignored by the browsers, so there is no point in "leaking" them to the public Internet. And indeed, the most popular use case for trailers is within complex systems, where trailers are used for logging, tracing, debug messages & signaling end-of-response... those are usually stripped at the proxies facing public Internet. 2) You're asking for real world examples of trailers on a mailing list dedicated to NGINX development, which means that noone here uses trailers in production, unless they maintain their own version of NGINX... and yet, you had 4 people (out of a few hundred?) expressing interest in this feature. 3) Trailers are used in gRPC [1], Fetch API [2] and Server Timing [3], but I guess none of those is "real world" enough for you. > Additionally, quick look suggests that the patch still > unconditionally removes Content-Length from a response if client > advertizes trailers support. As I previously wrote, I found this > approach to be wrong. Yes, the only change in the patch I sent yesterday is a bugfix to avoid sending empty DATA frame in case when trailers were generated but there was no payload to send. Like I said before, I'm happy to add "r->expect_trailers" or whatever else mechanism you choose to signal that NGINX is configured to produce trailers, but if you don't want to add trailers in the first place, then there is no point in me spending time working on that... is there? [1] http://www.grpc.io/docs/guides/wire.html [2] https://github.com/whatwg/fetch/pull/344 [3] https://www.w3.org/TR/server-timing/ Best regards, Piotr Sikora From piotrsikora at google.com Tue Aug 2 22:24:55 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Tue, 02 Aug 2016 15:24:55 -0700 Subject: [PATCH] SSL: fix order of checks during SSL certificate verification Message-ID: # HG changeset patch # User Piotr Sikora # Date 1470107238 25200 # Mon Aug 01 20:07:18 2016 -0700 # Node ID cd72e0a1164abd70aafdb391b3470869508532e5 # Parent d43ee392e825186545d81e683b88cc58ef8479bc SSL: fix order of checks during SSL certificate verification. SSL_get_verify_result() should be called only if certificate was presented by the peer, otherwise returned value is the default one, which happens to be X509_V_OK, but it doesn't indicate success and it's considered a bug: https://www.openssl.org/docs/manmaster/ssl/SSL_get_verify_result.html While there, move common verification logic to ngx_ssl_verify_client() and ngx_ssl_check_host() in order to make the callers crypto-library-agnostic. Signed-off-by: Piotr Sikora diff -r d43ee392e825 -r cd72e0a1164a src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3054,12 +3054,70 @@ ngx_ssl_cleanup_ctx(void *data) ngx_int_t +ngx_ssl_verify_client(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_uint_t verify) +{ + long rc; + X509 *cert; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + + if (verify != 1) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent no required SSL certificate"); + + ngx_ssl_remove_cached_session(ssl->ctx, + SSL_get0_session(c->ssl->connection)); + + return NGX_DECLINED; + } + + X509_free(cert); + + rc = SSL_get_verify_result(c->ssl->connection); + + if (rc != X509_V_OK + && (verify != 3 || !ngx_ssl_verify_error_optional(rc))) + { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client SSL certificate verify error: (%l:%s)", + rc, X509_verify_cert_error_string(rc)); + + ngx_ssl_remove_cached_session(ssl->ctx, + SSL_get0_session(c->ssl->connection)); + + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name) { + long rc; X509 *cert; cert = SSL_get_peer_certificate(c->ssl->connection); if (cert == NULL) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "upstream sent no required SSL certificate"); + + return NGX_ERROR; + } + + rc = SSL_get_verify_result(c->ssl->connection); + + if (rc != X509_V_OK) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "upstream SSL certificate verify error: (%l:%s)", + rc, X509_verify_cert_error_string(rc)); + + X509_free(cert); return NGX_ERROR; } @@ -3170,6 +3228,10 @@ ngx_ssl_check_host(ngx_connection_t *c, failed: + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "upstream SSL certificate does not match \"%V\"", + name); + X509_free(cert); return NGX_ERROR; @@ -3566,22 +3628,20 @@ ngx_ssl_get_client_verify(ngx_connection { X509 *cert; + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + ngx_str_set(s, "NONE"); + return NGX_OK; + } + + X509_free(cert); + if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) { ngx_str_set(s, "FAILED"); return NGX_OK; } - cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert) { - ngx_str_set(s, "SUCCESS"); - - } else { - ngx_str_set(s, "NONE"); - } - - X509_free(cert); - + ngx_str_set(s, "SUCCESS"); return NGX_OK; } diff -r d43ee392e825 -r cd72e0a1164a src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -184,6 +184,8 @@ ngx_int_t ngx_ssl_set_session(ngx_connec || n == X509_V_ERR_CERT_UNTRUSTED \ || n == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) +ngx_int_t ngx_ssl_verify_client(ngx_connection_t *c, ngx_ssl_t *ssl, + ngx_uint_t verify); ngx_int_t ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name); diff -r d43ee392e825 -r cd72e0a1164a src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1845,8 +1845,7 @@ ngx_http_process_request(ngx_http_reques #if (NGX_HTTP_SSL) if (r->http_connection->ssl) { - long rc; - X509 *cert; + ngx_int_t rc; ngx_http_ssl_srv_conf_t *sscf; if (c->ssl == NULL) { @@ -1859,38 +1858,13 @@ ngx_http_process_request(ngx_http_reques sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (sscf->verify) { - rc = SSL_get_verify_result(c->ssl->connection); - - if (rc != X509_V_OK - && (sscf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) - { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client SSL certificate verify error: (%l:%s)", - rc, X509_verify_cert_error_string(rc)); - - ngx_ssl_remove_cached_session(sscf->ssl.ctx, - (SSL_get0_session(c->ssl->connection))); - - ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); + rc = ngx_ssl_verify_client(c, &sscf->ssl, sscf->verify); + if (rc != NGX_OK) { + ngx_http_finalize_request(r, (rc == NGX_ERROR) + ? NGX_HTTPS_CERT_ERROR + : NGX_HTTPS_NO_CERT); return; } - - if (sscf->verify == 1) { - cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert == NULL) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent no required SSL certificate"); - - ngx_ssl_remove_cached_session(sscf->ssl.ctx, - (SSL_get0_session(c->ssl->connection))); - - ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); - return; - } - - X509_free(cert); - } } } diff -r d43ee392e825 -r cd72e0a1164a src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1561,7 +1561,6 @@ ngx_http_upstream_ssl_init_connection(ng static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c) { - long rc; ngx_http_request_t *r; ngx_http_upstream_t *u; @@ -1573,19 +1572,7 @@ ngx_http_upstream_ssl_handshake(ngx_conn if (c->ssl->handshaked) { if (u->conf->ssl_verify) { - rc = SSL_get_verify_result(c->ssl->connection); - - if (rc != X509_V_OK) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "upstream SSL certificate verify error: (%l:%s)", - rc, X509_verify_cert_error_string(rc)); - goto failed; - } - if (ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "upstream SSL certificate does not match \"%V\"", - &u->ssl_name); goto failed; } } diff -r d43ee392e825 -r cd72e0a1164a src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -16,8 +16,6 @@ static void ngx_mail_init_session(ngx_co #if (NGX_MAIL_SSL) static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c); -static ngx_int_t ngx_mail_verify_cert(ngx_mail_session_t *s, - ngx_connection_t *c); #endif @@ -247,15 +245,31 @@ ngx_mail_ssl_init_connection(ngx_ssl_t * static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c) { + ngx_int_t rc; ngx_mail_session_t *s; + ngx_mail_ssl_conf_t *sslcf; ngx_mail_core_srv_conf_t *cscf; if (c->ssl->handshaked) { s = c->data; - if (ngx_mail_verify_cert(s, c) != NGX_OK) { - return; + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); + + if (sslcf->verify) { + rc = ngx_ssl_verify_client(c, &sslcf->ssl, sslcf->verify); + if (rc != NGX_OK) { + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + s->out = (rc == NGX_ERROR) ? cscf->protocol->cert_error + : cscf->protocol->no_cert; + s->quit = 1; + + c->write->handler = ngx_mail_send; + + ngx_mail_send(s->connection->write); + return; + } } if (s->starttls) { @@ -278,71 +292,6 @@ ngx_mail_ssl_handshake_handler(ngx_conne ngx_mail_close_connection(c); } - -static ngx_int_t -ngx_mail_verify_cert(ngx_mail_session_t *s, ngx_connection_t *c) -{ - long rc; - X509 *cert; - ngx_mail_ssl_conf_t *sslcf; - ngx_mail_core_srv_conf_t *cscf; - - sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); - - if (!sslcf->verify) { - return NGX_OK; - } - - rc = SSL_get_verify_result(c->ssl->connection); - - if (rc != X509_V_OK - && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) - { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client SSL certificate verify error: (%l:%s)", - rc, X509_verify_cert_error_string(rc)); - - ngx_ssl_remove_cached_session(sslcf->ssl.ctx, - (SSL_get0_session(c->ssl->connection))); - - cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); - - s->out = cscf->protocol->cert_error; - s->quit = 1; - - c->write->handler = ngx_mail_send; - - ngx_mail_send(s->connection->write); - return NGX_ERROR; - } - - if (sslcf->verify == 1) { - cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert == NULL) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent no required SSL certificate"); - - ngx_ssl_remove_cached_session(sslcf->ssl.ctx, - (SSL_get0_session(c->ssl->connection))); - - cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); - - s->out = cscf->protocol->no_cert; - s->quit = 1; - - c->write->handler = ngx_mail_send; - - ngx_mail_send(s->connection->write); - return NGX_ERROR; - } - - X509_free(cert); - } - - return NGX_OK; -} - #endif diff -r d43ee392e825 -r cd72e0a1164a src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -986,7 +986,6 @@ ngx_stream_proxy_ssl_init_connection(ngx static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc) { - long rc; ngx_stream_session_t *s; ngx_stream_upstream_t *u; ngx_stream_proxy_srv_conf_t *pscf; @@ -998,21 +997,7 @@ ngx_stream_proxy_ssl_handshake(ngx_conne if (pc->ssl->handshaked) { if (pscf->ssl_verify) { - rc = SSL_get_verify_result(pc->ssl->connection); - - if (rc != X509_V_OK) { - ngx_log_error(NGX_LOG_ERR, pc->log, 0, - "upstream SSL certificate verify error: (%l:%s)", - rc, X509_verify_cert_error_string(rc)); - goto failed; - } - - u = s->upstream; - - if (ngx_ssl_check_host(pc, &u->ssl_name) != NGX_OK) { - ngx_log_error(NGX_LOG_ERR, pc->log, 0, - "upstream SSL certificate does not match \"%V\"", - &u->ssl_name); + if (ngx_ssl_check_host(pc, &s->upstream->ssl_name) != NGX_OK) { goto failed; } } From mdounin at mdounin.ru Thu Aug 4 02:24:12 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 4 Aug 2016 05:24:12 +0300 Subject: [PATCH] HTTP: add support for trailers in HTTP responses In-Reply-To: References: <20160721134430.GV57459@mdounin.ru> <20160801132154.GH57459@mdounin.ru> Message-ID: <20160804022412.GW57459@mdounin.ru> Hello! On Mon, Aug 01, 2016 at 10:56:21AM -0700, Piotr Sikora wrote: > Hey Maxim, > > > I still don't see any real world usage example reported. > > That's because you chose to ignore those provided to you. > > 1) As of right now, trailers are ignored by the browsers, so there is > no point in "leaking" them to the public Internet. And indeed, the > most popular use case for trailers is within complex systems, where > trailers are used for logging, tracing, debug messages & signaling > end-of-response... By saying "most popular use case" you are talking about something real-world you are aware of? > those are usually stripped at the proxies facing public Internet. And this probably an additional thing to consider when introducing trailers: right now nginx strips all trailers. Changing this may be a surprise for those who use trailers internally, if any. > 2) You're asking for real world examples of trailers on a mailing list > dedicated to NGINX development, which means that noone here uses > trailers in production, unless they maintain their own version of > NGINX... and yet, you had 4 people (out of a few hundred?) expressing > interest in this feature. In my practice, "expressing interest" generally means something close to nothing. > 3) Trailers are used in gRPC [1], Fetch API [2] and Server Timing [3], > but I guess none of those is "real world" enough for you. We've already talked about gRPC. Fetch API and Server Timing are just specifications being developed which allow use of trailers, not much different from HTTP/1.1 itself. On the other hand, here is a good discussion of trailers and their security in this Fetch API ticket: https://github.com/whatwg/fetch/issues/34 And here is a linked HTTPbis ticket to reconsider "TE: trailers" as it looks unneded: https://github.com/httpwg/http11bis/issues/18 This is somewhat in line with what I think about it, as previously discussed in this thread. > > Additionally, quick look suggests that the patch still > > unconditionally removes Content-Length from a response if client > > advertizes trailers support. As I previously wrote, I found this > > approach to be wrong. > > Yes, the only change in the patch I sent yesterday is a bugfix to > avoid sending empty DATA frame in case when trailers were generated > but there was no payload to send. > > Like I said before, I'm happy to add "r->expect_trailers" or whatever > else mechanism you choose to signal that NGINX is configured to > produce trailers, but if you don't want to add trailers in the first > place, then there is no point in me spending time working on that... > is there? I'm still not convinced that trailers are needed. As previously said, this HTTP feature was mostly unused for 17 years, and this suggests something is wrong with the feature. So it may be a good idea to postpone this at least till some real user will appear. In either case, I do not think that added trailers should by itself change transfer encoding used and remove Content-Length. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Thu Aug 4 03:53:52 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 4 Aug 2016 06:53:52 +0300 Subject: [PATCH] SSL: fix order of checks during SSL certificate verification In-Reply-To: References: Message-ID: <20160804035352.GY57459@mdounin.ru> Hello! On Tue, Aug 02, 2016 at 03:24:55PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1470107238 25200 > # Mon Aug 01 20:07:18 2016 -0700 > # Node ID cd72e0a1164abd70aafdb391b3470869508532e5 > # Parent d43ee392e825186545d81e683b88cc58ef8479bc > SSL: fix order of checks during SSL certificate verification. > > SSL_get_verify_result() should be called only if certificate was presented > by the peer, otherwise returned value is the default one, which happens to > be X509_V_OK, but it doesn't indicate success and it's considered a bug: > https://www.openssl.org/docs/manmaster/ssl/SSL_get_verify_result.html This behaviour is explicitly documented for years. The BUGS section outlines that the API is not intuitive and requires use of SSL_get_peer_certificate() in addition ot SSL_get_verify_result(). And this is what nginx does. I don't see compelling reasons to change the order of the calls here. > While there, move common verification logic to ngx_ssl_verify_client() and > ngx_ssl_check_host() in order to make the callers crypto-library-agnostic. This looks like a separate patch, or two patches. Though I'm somewhat sceptical about the use of "upstream" and "client" in error messages introduced, this looks like a wrong approach for a generic SSL code. As well as magic values in the "verify" argument, and the change of the ngx_ssl_check_host() semantics. -- Maxim Dounin http://nginx.org/ From igor at sysoev.ru Thu Aug 4 13:06:17 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 04 Aug 2016 13:06:17 +0000 Subject: [njs] njs_parser_is_lvalue(). Message-ID: details: http://hg.nginx.org/njs/rev/f171ddad457e branches: changeset: 138:f171ddad457e user: Igor Sysoev date: Thu Aug 04 14:43:20 2016 +0300 description: njs_parser_is_lvalue(). diffstat: njs/njs_parser.h | 7 ++----- njs/njs_parser_expression.c | 12 +++--------- 2 files changed, 5 insertions(+), 14 deletions(-) diffs (53 lines): diff -r e4f1fda52fe8 -r f171ddad457e njs/njs_parser.h --- a/njs/njs_parser.h Tue Jul 26 16:25:58 2016 +0300 +++ b/njs/njs_parser.h Thu Aug 04 14:43:20 2016 +0300 @@ -213,11 +213,8 @@ typedef enum { } njs_variable_node_state_t; -typedef enum { - NJS_LVALUE_NONE = 0, - NJS_LVALUE_ENABLED, - NJS_LVALUE_ASSIGNED, -} njs_lvalue_state_t; +#define njs_parser_is_lvalue(node) \ + ((node)->token == NJS_TOKEN_NAME || (node)->token == NJS_TOKEN_PROPERTY) typedef struct njs_parser_node_s njs_parser_node_t; diff -r e4f1fda52fe8 -r f171ddad457e njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Tue Jul 26 16:25:58 2016 +0300 +++ b/njs/njs_parser_expression.c Thu Aug 04 14:43:20 2016 +0300 @@ -437,9 +437,7 @@ njs_parser_assignment_expression(njs_vm_ node = parser->node; - if (parser->node->token != NJS_TOKEN_NAME - && parser->node->token != NJS_TOKEN_PROPERTY) - { + if (!njs_parser_is_lvalue(parser->node)) { return njs_parser_invalid_lvalue(vm, parser, "assignment"); } @@ -811,9 +809,7 @@ njs_parser_inc_dec_expression(njs_vm_t * return next; } - if (parser->node->token != NJS_TOKEN_NAME - && parser->node->token != NJS_TOKEN_PROPERTY) - { + if (!njs_parser_is_lvalue(parser->node)) { return njs_parser_invalid_lvalue(vm, parser, "prefix operation"); } @@ -865,9 +861,7 @@ njs_parser_post_inc_dec_expression(njs_v return token; } - if (parser->node->token != NJS_TOKEN_NAME - && parser->node->token != NJS_TOKEN_PROPERTY) - { + if (!njs_parser_is_lvalue(parser->node)) { return njs_parser_invalid_lvalue(vm, parser, "postfix operation"); } From igor at sysoev.ru Thu Aug 4 13:06:19 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 04 Aug 2016 13:06:19 +0000 Subject: [njs] nxt_str_t changes. Message-ID: details: http://hg.nginx.org/njs/rev/016339472304 branches: changeset: 139:016339472304 user: Igor Sysoev date: Thu Aug 04 14:45:27 2016 +0300 description: nxt_str_t changes. diffstat: nginx/ngx_http_js_module.c | 73 ++++++++++++++++++++++-------------------- nginx/ngx_stream_js_module.c | 23 +++++++------ njs/njs_array.c | 4 +- njs/njs_boolean.c | 1 + njs/njs_builtin.c | 1 + njs/njs_date.c | 4 +- njs/njs_disassembler.c | 10 +++-- njs/njs_extern.c | 13 ++++--- njs/njs_function.c | 1 + njs/njs_generator.c | 1 + njs/njs_lexer.c | 21 ++++++----- njs/njs_lexer_keyword.c | 3 +- njs/njs_math.c | 1 + njs/njs_nonrecursive_parser.c | 1 + njs/njs_number.c | 1 + njs/njs_object.c | 25 +++++++------- njs/njs_parser.c | 28 ++++++++------- njs/njs_parser_expression.c | 1 + njs/njs_regexp.c | 23 ++++++------- njs/njs_string.c | 13 ++++--- njs/njs_variable.c | 17 +++++---- njs/njs_vm.c | 39 +++++++++++----------- njs/njscript.c | 1 + njs/test/njs_unit_test.c | 49 ++++++++++++++-------------- nxt/Makefile | 1 + nxt/nxt_djb_hash.c | 1 + nxt/nxt_lvlhsh.c | 1 + nxt/nxt_lvlhsh.h | 6 +-- nxt/nxt_string.h | 48 ++++++++++++++++++++++++++++ nxt/nxt_stub.h | 45 -------------------------- 30 files changed, 240 insertions(+), 216 deletions(-) diffs (truncated from 1428 to 1000 lines): diff -r f171ddad457e -r 016339472304 nginx/ngx_http_js_module.c --- a/nginx/ngx_http_js_module.c Thu Aug 04 14:43:20 2016 +0300 +++ b/nginx/ngx_http_js_module.c Thu Aug 04 14:45:27 2016 +0300 @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -432,8 +433,8 @@ ngx_http_js_handler(ngx_http_request_t * ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); - name.data = jlcf->content.data; - name.len = jlcf->content.len; + name.start = jlcf->content.data; + name.length = jlcf->content.len; func = njs_vm_function(ctx->vm, &name); if (func == NULL) { @@ -446,7 +447,7 @@ ngx_http_js_handler(ngx_http_request_t * njs_vm_exception(ctx->vm, &exception); ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "js exception: %*s", exception.len, exception.data); + "js exception: %*s", exception.length, exception.start); return NGX_ERROR; } @@ -482,8 +483,8 @@ ngx_http_js_variable(ngx_http_request_t ctx = ngx_http_get_module_ctx(r, ngx_http_js_module); - name.data = fname->data; - name.len = fname->len; + name.start = fname->data; + name.length = fname->len; func = njs_vm_function(ctx->vm, &name); if (func == NULL) { @@ -497,7 +498,7 @@ ngx_http_js_variable(ngx_http_request_t njs_vm_exception(ctx->vm, &exception); ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "js exception: %*s", exception.len, exception.data); + "js exception: %*s", exception.length, exception.start); v->not_found = 1; return NGX_OK; @@ -507,11 +508,11 @@ ngx_http_js_variable(ngx_http_request_t return NGX_ERROR; } - v->len = value.len; + v->len = value.length; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - v->data = value.data; + v->data = value.start; return NGX_OK; } @@ -640,14 +641,14 @@ ngx_http_js_ext_set_string(njs_vm_t *vm, r = (ngx_http_request_t *) obj; field = (ngx_str_t *) (p + data); - field->len = value->len; + field->len = value->length; - field->data = ngx_pnalloc(r->pool, value->len); + field->data = ngx_pnalloc(r->pool, value->length); if (field->data == NULL) { return NJS_ERROR; } - ngx_memcpy(field->data, value->data, value->len); + ngx_memcpy(field->data, value->start, value->length); return NJS_OK; } @@ -757,7 +758,8 @@ ngx_http_js_ext_get_header_out(njs_vm_t r = (ngx_http_request_t *) obj; v = (nxt_str_t *) data; - h = ngx_http_js_get_header(&r->headers_out.headers.part, v->data, v->len); + h = ngx_http_js_get_header(&r->headers_out.headers.part, v->start, + v->length); if (h == NULL) { return njs_string_create(vm, value, NULL, 0, 0); } @@ -778,7 +780,8 @@ ngx_http_js_ext_set_header_out(njs_vm_t r = (ngx_http_request_t *) obj; v = (nxt_str_t *) data; - h = ngx_http_js_get_header(&r->headers_out.headers.part, v->data, v->len); + h = ngx_http_js_get_header(&r->headers_out.headers.part, v->start, + v->length); if (h == NULL || h->hash == 0) { h = ngx_list_push(&r->headers_out.headers); @@ -786,28 +789,28 @@ ngx_http_js_ext_set_header_out(njs_vm_t return NJS_ERROR; } - p = ngx_pnalloc(r->pool, v->len); + p = ngx_pnalloc(r->pool, v->length); if (p == NULL) { return NJS_ERROR; } - ngx_memcpy(p, v->data, v->len); + ngx_memcpy(p, v->start, v->length); h->key.data = p; - h->key.len = v->len; + h->key.len = v->length; h->hash = 1; } - p = ngx_pnalloc(r->pool, value->len); + p = ngx_pnalloc(r->pool, value->length); if (p == NULL) { return NJS_ERROR; } - ngx_memcpy(p, value->data, value->len); + ngx_memcpy(p, value->start, value->length); h->value.data = p; - h->value.len = value->len; + h->value.len = value->length; return NJS_OK; } @@ -849,7 +852,7 @@ ngx_http_js_ext_set_status(njs_vm_t *vm, ngx_int_t n; ngx_http_request_t *r; - n = ngx_atoi(value->data, value->len); + n = ngx_atoi(value->start, value->length); if (n == NGX_ERROR) { return NJS_ERROR; } @@ -890,7 +893,7 @@ ngx_http_js_ext_set_content_length(njs_v ngx_int_t n; ngx_http_request_t *r; - n = ngx_atoi(value->data, value->len); + n = ngx_atoi(value->start, value->length); if (n == NGX_ERROR) { return NJS_ERROR; } @@ -953,16 +956,16 @@ ngx_http_js_ext_send(njs_vm_t *vm, njs_v /* TODO: njs_value_release(vm, value) in buf completion */ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http js send: \"%*s\"", s.len, s.data); + "http js send: \"%*s\"", s.length, s.start); b = ngx_calloc_buf(r->pool); if (b == NULL) { return NJS_ERROR; } - b->start = s.data; + b->start = s.start; b->pos = b->start; - b->end = s.data + s.len; + b->end = s.start + s.length; b->last = b->end; b->memory = 1; @@ -1024,7 +1027,7 @@ ngx_http_js_ext_log(njs_vm_t *vm, njs_va handler = c->log->handler; c->log->handler = NULL; - ngx_log_error(NGX_LOG_INFO, c->log, 0, "js: %*s", msg.len, msg.data); + ngx_log_error(NGX_LOG_INFO, c->log, 0, "js: %*s", msg.length, msg.start); c->log->handler = handler; @@ -1085,7 +1088,8 @@ ngx_http_js_ext_get_header_in(njs_vm_t * r = (ngx_http_request_t *) obj; v = (nxt_str_t *) data; - h = ngx_http_js_get_header(&r->headers_in.headers.part, v->data, v->len); + h = ngx_http_js_get_header(&r->headers_in.headers.part, v->start, + v->length); if (h == NULL) { return njs_string_create(vm, value, NULL, 0, 0); } @@ -1112,7 +1116,7 @@ ngx_http_js_ext_get_arg(njs_vm_t *vm, nj r = (ngx_http_request_t *) obj; v = (nxt_str_t *) data; - if (ngx_http_arg(r, v->data, v->len, &arg) == NGX_OK) { + if (ngx_http_arg(r, v->start, v->length, &arg) == NGX_OK) { return njs_string_create(vm, value, arg.data, arg.len, 0); } @@ -1196,8 +1200,8 @@ ngx_http_js_ext_get_variable(njs_vm_t *v r = (ngx_http_request_t *) obj; v = (nxt_str_t *) data; - name.data = v->data; - name.len = v->len; + name.data = v->start; + name.len = v->length; key = ngx_hash_strlow(name.data, name.data, name.len); @@ -1324,7 +1328,7 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%*s, included", - text.len, text.data); + text.length, text.start); return NGX_CONF_ERROR; } @@ -1335,21 +1339,22 @@ ngx_http_js_include(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } - nxt_str_set(&ext, "$r"); + ext = nxt_string_value("$r"); if (njs_vm_external(jlcf->vm, NULL, &ext, &jlcf->args[0]) != NJS_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "js external \"%*s\" not found", ext.len, ext.data); + "js external \"%*s\" not found", + ext.length, ext.start); return NGX_CONF_ERROR; } - nxt_str_set(&ext, "response"); + ext = nxt_string_value("response"); rc = njs_vm_external(jlcf->vm, &jlcf->args[0], &ext, &jlcf->args[1]); if (rc != NXT_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "js external \"$r.%*s\" not found", - ext.len, ext.data); + ext.length, ext.start); return NGX_CONF_ERROR; } diff -r f171ddad457e -r 016339472304 nginx/ngx_stream_js_module.c --- a/nginx/ngx_stream_js_module.c Thu Aug 04 14:43:20 2016 +0300 +++ b/nginx/ngx_stream_js_module.c Thu Aug 04 14:45:27 2016 +0300 @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -216,8 +217,8 @@ ngx_stream_js_variable(ngx_stream_sessio ctx = ngx_stream_get_module_ctx(s, ngx_stream_js_module); - name.data = fname->data; - name.len = fname->len; + name.start = fname->data; + name.length = fname->len; func = njs_vm_function(ctx->vm, &name); if (func == NULL) { @@ -231,7 +232,7 @@ ngx_stream_js_variable(ngx_stream_sessio njs_vm_exception(ctx->vm, &exception); ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, - "js exception: %*s", exception.len, exception.data); + "js exception: %*s", exception.length, exception.start); v->not_found = 1; return NGX_OK; @@ -241,11 +242,11 @@ ngx_stream_js_variable(ngx_stream_sessio return NGX_ERROR; } - v->len = value.len; + v->len = value.length; v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - v->data = value.data; + v->data = value.start; return NGX_OK; } @@ -382,7 +383,7 @@ ngx_stream_js_ext_log(njs_vm_t *vm, njs_ handler = c->log->handler; c->log->handler = NULL; - ngx_log_error(NGX_LOG_INFO, c->log, 0, "js: %*s", msg.len, msg.data); + ngx_log_error(NGX_LOG_INFO, c->log, 0, "js: %*s", msg.length, msg.start); c->log->handler = handler; @@ -403,8 +404,8 @@ ngx_stream_js_ext_get_variable(njs_vm_t s = (ngx_stream_session_t *) obj; v = (nxt_str_t *) data; - name.data = v->data; - name.len = v->len; + name.data = v->start; + name.len = v->length; key = ngx_hash_strlow(name.data, name.data, name.len); @@ -531,7 +532,7 @@ ngx_stream_js_include(ngx_conf_t *cf, ng ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%*s, included", - text.len, text.data); + text.length, text.start); return NGX_CONF_ERROR; } @@ -542,11 +543,11 @@ ngx_stream_js_include(ngx_conf_t *cf, ng return NGX_CONF_ERROR; } - nxt_str_set(&ext, "$s"); + ext = nxt_string_value("$s"); if (njs_vm_external(jscf->vm, NULL, &ext, &jscf->arg) != NJS_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "js external \"%*s\" not found", ext.len, ext.data); + "js external \"%*s\" not found", ext.length, ext.start); return NGX_CONF_ERROR; } diff -r f171ddad457e -r 016339472304 njs/njs_array.c --- a/njs/njs_array.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_array.c Thu Aug 04 14:45:27 2016 +0300 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -517,8 +518,7 @@ njs_array_prototype_to_string(njs_vm_t * if (njs_is_object(&args[0])) { lhq.key_hash = NJS_JOIN_HASH; - lhq.key.len = sizeof("join") - 1; - lhq.key.data = (u_char *) "join"; + lhq.key = nxt_string_value("join"); prop = njs_object_property(vm, args[0].data.u.object, &lhq); diff -r f171ddad457e -r 016339472304 njs/njs_boolean.c --- a/njs/njs_boolean.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_boolean.c Thu Aug 04 14:45:27 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff -r f171ddad457e -r 016339472304 njs/njs_builtin.c --- a/njs/njs_builtin.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_builtin.c Thu Aug 04 14:45:27 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff -r f171ddad457e -r 016339472304 njs/njs_date.c --- a/njs/njs_date.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_date.c Thu Aug 04 14:45:27 2016 +0300 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -1754,8 +1755,7 @@ njs_date_prototype_to_json(njs_vm_t *vm, if (njs_is_object(&args[0])) { lhq.key_hash = NJS_TO_ISO_STRING_HASH; - lhq.key.len = sizeof("toISOString") - 1; - lhq.key.data = (u_char *) "toISOString"; + lhq.key = nxt_string_value("toISOString"); prop = njs_object_property(vm, args[0].data.u.object, &lhq); diff -r f171ddad457e -r 016339472304 njs/njs_disassembler.c --- a/njs/njs_disassembler.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_disassembler.c Thu Aug 04 14:45:27 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -352,21 +353,22 @@ njs_disassemble(u_char *start, u_char *e code3 = (njs_vmcode_3addr_t *) p; printf("%*s %04zX %04zX %04zX\n", - (int) name->len, name->data, (size_t) code3->dst, - (size_t) code3->src1, (size_t) code3->src2); + (int) name->length, name->start, + (size_t) code3->dst, (size_t) code3->src1, + (size_t) code3->src2); } else if (code_name->size == sizeof(njs_vmcode_2addr_t)) { code2 = (njs_vmcode_2addr_t *) p; printf("%*s %04zX %04zX\n", - (int) name->len, name->data, + (int) name->length, name->start, (size_t) code2->dst, (size_t) code2->src); } else if (code_name->size == sizeof(njs_vmcode_1addr_t)) { code1 = (njs_vmcode_1addr_t *) p; printf("%*s %04zX\n", - (int) name->len, name->data, + (int) name->length, name->start, (size_t) code1->index); } diff -r f171ddad457e -r 016339472304 njs/njs_extern.c --- a/njs/njs_extern.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_extern.c Thu Aug 04 14:45:27 2016 +0300 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -65,13 +66,13 @@ njs_vm_external_add(nxt_lvlhsh_t *hash, return NXT_ERROR; } - ext->name.len = external->name.len; - ext->name.data = nxt_mem_cache_alloc(mcp, external->name.len); - if (nxt_slow_path(ext->name.data == NULL)) { + ext->name.length = external->name.length; + ext->name.start = nxt_mem_cache_alloc(mcp, external->name.length); + if (nxt_slow_path(ext->name.start == NULL)) { return NXT_ERROR; } - memcpy(ext->name.data, external->name.data, external->name.len); + memcpy(ext->name.start, external->name.start, external->name.length); ext->value.type = NJS_EXTERNAL; ext->value.data.truth = 1; @@ -98,7 +99,7 @@ njs_vm_external_add(nxt_lvlhsh_t *hash, ext->object = object; ext->data = external->data; - lhq.key_hash = nxt_djb_hash(external->name.data, external->name.len); + lhq.key_hash = nxt_djb_hash(external->name.start, external->name.length); lhq.key = ext->name; lhq.replace = 0; lhq.value = ext; @@ -155,7 +156,7 @@ njs_vm_external(njs_vm_t *vm, njs_opaque } } - lhq.key_hash = key_hash(property->data, property->len); + lhq.key_hash = key_hash(property->start, property->length); lhq.key = *property; lhq.proto = &njs_extern_hash_proto; diff -r f171ddad457e -r 016339472304 njs/njs_function.c --- a/njs/njs_function.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_function.c Thu Aug 04 14:45:27 2016 +0300 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff -r f171ddad457e -r 016339472304 njs/njs_generator.c --- a/njs/njs_generator.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_generator.c Thu Aug 04 14:45:27 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff -r f171ddad457e -r 016339472304 njs/njs_lexer.c --- a/njs/njs_lexer.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_lexer.c Thu Aug 04 14:45:27 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -300,7 +301,7 @@ njs_lexer_next_token(njs_lexer_t *lexer) njs_token_t token; const njs_lexer_multi_t *multi; - lexer->text.data = lexer->start; + lexer->text.start = lexer->start; while (lexer->start < lexer->end) { c = *lexer->start++; @@ -310,7 +311,7 @@ njs_lexer_next_token(njs_lexer_t *lexer) switch (token) { case NJS_TOKEN_SPACE: - lexer->text.data = lexer->start; + lexer->text.start = lexer->start; continue; case NJS_TOKEN_LETTER: @@ -415,7 +416,7 @@ njs_lexer_next_token(njs_lexer_t *lexer) case NJS_TOKEN_COLON: case NJS_TOKEN_SEMICOLON: case NJS_TOKEN_CONDITIONAL: - lexer->text.len = lexer->start - lexer->text.data; + lexer->text.length = lexer->start - lexer->text.start; return token; default: /* NJS_TOKEN_ILLEGAL */ @@ -459,7 +460,7 @@ njs_lexer_word(njs_lexer_t *lexer, u_cha lexer->token_line = lexer->line; lexer->key_hash = nxt_djb_hash_add(NXT_DJB_HASH_INIT, c); - lexer->text.data = lexer->start - 1; + lexer->text.start = lexer->start - 1; for (p = lexer->start; p < lexer->end; p++) { c = *p; @@ -472,7 +473,7 @@ njs_lexer_word(njs_lexer_t *lexer, u_cha } lexer->start = p; - lexer->text.len = p - lexer->text.data; + lexer->text.length = p - lexer->text.start; if (lexer->property) { return NJS_TOKEN_NAME; @@ -489,7 +490,7 @@ njs_lexer_string(njs_lexer_t *lexer, u_c nxt_bool_t escape; escape = 0; - lexer->text.data = lexer->start; + lexer->text.start = lexer->start; p = lexer->start; while (p < lexer->end) { @@ -509,7 +510,7 @@ njs_lexer_string(njs_lexer_t *lexer, u_c if (c == quote) { lexer->start = p; - lexer->text.len = (p - 1) - lexer->text.data; + lexer->text.length = (p - 1) - lexer->text.start; if (escape == 0) { return NJS_TOKEN_STRING; @@ -519,8 +520,8 @@ njs_lexer_string(njs_lexer_t *lexer, u_c } } - lexer->text.data--; - lexer->text.len = p - lexer->text.data; + lexer->text.start--; + lexer->text.length = p - lexer->text.start; return NJS_TOKEN_UNTERMINATED_STRING; } @@ -616,7 +617,7 @@ njs_lexer_multi(njs_lexer_t *lexer, njs_ } while (n != 0); } - lexer->text.len = lexer->start - lexer->text.data; + lexer->text.length = lexer->start - lexer->text.start; return token; } diff -r f171ddad457e -r 016339472304 njs/njs_lexer_keyword.c --- a/njs/njs_lexer_keyword.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_lexer_keyword.c Thu Aug 04 14:45:27 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -170,7 +171,7 @@ njs_lexer_keywords_init(nxt_mem_cache_po lhq.pool = mcp; do { - lhq.key_hash = nxt_djb_hash(keyword->name.data, keyword->name.len); + lhq.key_hash = nxt_djb_hash(keyword->name.start, keyword->name.length); lhq.key = keyword->name; lhq.value = (void *) keyword; diff -r f171ddad457e -r 016339472304 njs/njs_math.c --- a/njs/njs_math.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_math.c Thu Aug 04 14:45:27 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff -r f171ddad457e -r 016339472304 njs/njs_nonrecursive_parser.c --- a/njs/njs_nonrecursive_parser.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_nonrecursive_parser.c Thu Aug 04 14:45:27 2016 +0300 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff -r f171ddad457e -r 016339472304 njs/njs_number.c --- a/njs/njs_number.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_number.c Thu Aug 04 14:45:27 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include diff -r f171ddad457e -r 016339472304 njs/njs_object.c --- a/njs/njs_object.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_object.c Thu Aug 04 14:45:27 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -101,17 +102,17 @@ njs_object_hash_create(njs_vm_t *vm, nxt lhq.pool = vm->mem_cache_pool; do { - lhq.key.len = prop->name.short_string.size; + lhq.key.length = prop->name.short_string.size; - if (lhq.key.len != NJS_STRING_LONG) { - lhq.key.data = (u_char *) prop->name.short_string.start; + if (lhq.key.length != NJS_STRING_LONG) { + lhq.key.start = (u_char *) prop->name.short_string.start; } else { - lhq.key.len = prop->name.data.string_size; - lhq.key.data = prop->name.data.u.string->start; + lhq.key.length = prop->name.data.string_size; + lhq.key.start = prop->name.data.u.string->start; } - lhq.key_hash = nxt_djb_hash(lhq.key.data, lhq.key.len); + lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); lhq.value = (void *) prop; ret = nxt_lvlhsh_insert(hash, &lhq); @@ -150,21 +151,21 @@ njs_object_hash_test(nxt_lvlhsh_query_t size = prop->name.short_string.size; if (size != NJS_STRING_LONG) { - if (lhq->key.len != size) { + if (lhq->key.length != size) { return NXT_DECLINED; } start = prop->name.short_string.start; } else { - if (lhq->key.len != prop->name.data.string_size) { + if (lhq->key.length != prop->name.data.string_size) { return NXT_DECLINED; } start = prop->name.data.u.string->start; } - if (memcmp(start, lhq->key.data, lhq->key.len) == 0) { + if (memcmp(start, lhq->key.start, lhq->key.length) == 0) { return NXT_OK; } @@ -403,8 +404,7 @@ njs_property_prototype_create(njs_vm_t * lhq.value = prop; lhq.key_hash = NJS_PROTOTYPE_HASH; - lhq.key.len = sizeof("prototype") - 1; - lhq.key.data = (u_char *) "prototype"; + lhq.key = nxt_string_value("prototype"); lhq.replace = 0; lhq.pool = vm->mem_cache_pool; lhq.proto = &njs_object_hash_proto; @@ -551,8 +551,7 @@ njs_property_constructor_create(njs_vm_t lhq.value = prop; lhq.key_hash = NJS_CONSTRUCTOR_HASH; - lhq.key.len = sizeof("constructor") - 1; - lhq.key.data = (u_char *) "constructor"; + lhq.key = nxt_string_value("constructor"); lhq.replace = 0; lhq.pool = vm->mem_cache_pool; lhq.proto = &njs_object_hash_proto; diff -r f171ddad457e -r 016339472304 njs/njs_parser.c --- a/njs/njs_parser.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_parser.c Thu Aug 04 14:45:27 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -493,13 +494,13 @@ njs_parser_function_lambda(njs_vm_t *vm, name = &parser->lexer->text; - arg->name_start = nxt_mem_cache_alloc(vm->mem_cache_pool, name->len); + arg->name_start = nxt_mem_cache_alloc(vm->mem_cache_pool, name->length); if (nxt_slow_path(arg->name_start == NULL)) { return NJS_TOKEN_ERROR; } - memcpy(arg->name_start, name->data, name->len); - arg->name_len = name->len; + memcpy(arg->name_start, name->start, name->length); + arg->name_len = name->length; arg->state = NJS_VARIABLE_DECLARED; arg->index = index; @@ -1108,7 +1109,7 @@ njs_parser_for_in_statement(njs_vm_t *vm size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, "ReferenceError: Invalid left-hand side \"%.*s\" " "in for-in statement in %u", - (int) name->len, name->data, parser->lexer->line); + (int) name->length, name->start, parser->lexer->line); (void) njs_vm_throw_exception(vm, buf, size); @@ -1966,19 +1967,19 @@ njs_parser_string_create(njs_vm_t *vm, n src = &vm->parser->lexer->text; - length = nxt_utf8_length(src->data, src->len); + length = nxt_utf8_length(src->start, src->length); if (nxt_slow_path(length < 0)) { length = 0; } - p = njs_string_alloc(vm, value, src->len, length); + p = njs_string_alloc(vm, value, src->length, length); if (nxt_fast_path(p != NULL)) { - memcpy(p, src->data, src->len); - - if (length > NJS_STRING_MAP_OFFSET && (size_t) length != src->len) { - njs_string_offset_map_init(p, src->len); + memcpy(p, src->start, src->length); + + if (length > NJS_STRING_MAP_OFFSET && (size_t) length != src->length) { + njs_string_offset_map_init(p, src->length); } return NXT_OK; @@ -2008,8 +2009,8 @@ njs_parser_escape_string_create(njs_vm_t size = 0; length = 0; - src = parser->lexer->text.data; - end = src + parser->lexer->text.len; + src = parser->lexer->text.start; + end = src + parser->lexer->text.length; while (src < end) { c = *src++; @@ -2245,7 +2246,8 @@ njs_parser_error(njs_vm_t *vm, njs_parse lexer = parser->lexer; size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - msg, (int) lexer->text.len, lexer->text.data, lexer->line); + msg, (int) lexer->text.length, lexer->text.start, + lexer->line); (void) njs_vm_throw_exception(vm, buf, size); diff -r f171ddad457e -r 016339472304 njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_parser_expression.c Thu Aug 04 14:45:27 2016 +0300 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include diff -r f171ddad457e -r 016339472304 njs/njs_regexp.c --- a/njs/njs_regexp.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_regexp.c Thu Aug 04 14:45:27 2016 +0300 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -152,24 +153,24 @@ njs_regexp_literal(njs_vm_t *vm, njs_par } if (*p == '/') { - lexer->text.data = lexer->start; - lexer->text.len = p - lexer->text.data; + lexer->text.start = lexer->start; + lexer->text.length = p - lexer->text.start; p++; lexer->start = p; flags = njs_regexp_flags(&p, lexer->end, 0); if (nxt_slow_path(flags < 0)) { - lexer->text.data = lexer->start; - lexer->text.len = p - lexer->text.data; + lexer->text.start = lexer->start; + lexer->text.length = p - lexer->text.start; return njs_parser_error(vm, parser, NJS_PARSER_ERROR_REGEXP_FLAGS); } lexer->start = p; - pattern = njs_regexp_pattern_create(vm, lexer->text.data, - lexer->text.len, flags); + pattern = njs_regexp_pattern_create(vm, lexer->text.start, + lexer->text.length, flags); if (nxt_slow_path(pattern == NULL)) { return NJS_TOKEN_ILLEGAL; } @@ -180,8 +181,8 @@ njs_regexp_literal(njs_vm_t *vm, njs_par } } - lexer->text.data = lexer->start - 1; - lexer->text.len = p - lexer->text.data; + lexer->text.start = lexer->start - 1; + lexer->text.length = p - lexer->text.start; return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNTERMINATED_REGEXP); } @@ -676,8 +677,7 @@ njs_regexp_exec_result(njs_vm_t *vm, njs } lhq.key_hash = NJS_INDEX_HASH; - lhq.key.len = sizeof("index") - 1; - lhq.key.data = (u_char *) "index"; + lhq.key = nxt_string_value("index"); lhq.replace = 0; lhq.value = prop; lhq.pool = vm->mem_cache_pool; @@ -696,8 +696,7 @@ njs_regexp_exec_result(njs_vm_t *vm, njs njs_string_copy(&prop->value, ®exp->string); lhq.key_hash = NJS_INPUT_HASH; - lhq.key.len = sizeof("input") - 1; - lhq.key.data = (u_char *) "input"; + lhq.key = nxt_string_value("input"); lhq.value = prop; ret = nxt_lvlhsh_insert(&array->object.hash, &lhq); diff -r f171ddad457e -r 016339472304 njs/njs_string.c --- a/njs/njs_string.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_string.c Thu Aug 04 14:45:27 2016 +0300 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -2119,15 +2120,15 @@ njs_values_hash_test(nxt_lvlhsh_query_t value = data; - if (lhq->key.len == sizeof(njs_value_t) - && memcmp(lhq->key.data, value, sizeof(njs_value_t)) == 0) + if (lhq->key.length == sizeof(njs_value_t) + && memcmp(lhq->key.start, value, sizeof(njs_value_t)) == 0) { return NXT_OK; } if (value->type == NJS_STRING - && value->data.string_size == lhq->key.len - && memcmp(value->data.u.string->start, lhq->key.data, lhq->key.len) + && value->data.string_size == lhq->key.length + && memcmp(value->data.u.string->start, lhq->key.start, lhq->key.length) == 0) { return NXT_OK; @@ -2174,8 +2175,8 @@ njs_value_index(njs_vm_t *vm, njs_parser } lhq.key_hash = nxt_djb_hash(start, size); - lhq.key.len = size; - lhq.key.data = start; + lhq.key.length = size; + lhq.key.start = start; lhq.proto = &njs_values_hash_proto; if (nxt_lvlhsh_find(&vm->shared->values_hash, &lhq) == NXT_OK) { diff -r f171ddad457e -r 016339472304 njs/njs_variable.c --- a/njs/njs_variable.c Thu Aug 04 14:43:20 2016 +0300 +++ b/njs/njs_variable.c Thu Aug 04 14:45:27 2016 +0300 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -32,8 +33,8 @@ njs_variables_hash_test(nxt_lvlhsh_query var = data; - if (lhq->key.len == var->name_len - && memcmp(var->name_start, lhq->key.data, lhq->key.len) == 0) + if (lhq->key.length == var->name_len + && memcmp(var->name_start, lhq->key.start, lhq->key.length) == 0) { return NXT_OK; } @@ -106,8 +107,8 @@ njs_parser_variable(njs_vm_t *vm, njs_pa n = scope->arguments->items; while (n != 0) { - if (lhq.key.len == var->name_len - && memcmp(var->name_start, lhq.key.data, lhq.key.len) == 0) + if (lhq.key.length == var->name_len + && memcmp(var->name_start, lhq.key.start, lhq.key.length) == 0) { return var; } @@ -157,7 +158,7 @@ njs_vm_function(njs_vm_t *vm, nxt_str_t njs_variable_t *var; nxt_lvlhsh_query_t lhq; - lhq.key_hash = nxt_djb_hash(name->data, name->len); + lhq.key_hash = nxt_djb_hash(name->start, name->length); lhq.key = *name; lhq.proto = &njs_variables_hash_proto; @@ -187,12 +188,12 @@ njs_variable_alloc(njs_vm_t *vm, njs_par var = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_variable_t)); if (nxt_fast_path(var != NULL)) { - var->name_start = nxt_mem_cache_alloc(vm->mem_cache_pool, name->len); + var->name_start = nxt_mem_cache_alloc(vm->mem_cache_pool, name->length); if (nxt_fast_path(var->name_start != NULL)) { - memcpy(var->name_start, name->data, name->len); - var->name_len = name->len; From igor at sysoev.ru Thu Aug 4 13:06:21 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 04 Aug 2016 13:06:21 +0000 Subject: [njs] nxt_trace interface. nxt_regex, RegExp, and parser use it ... Message-ID: details: http://hg.nginx.org/njs/rev/23598cfcfd15 branches: changeset: 140:23598cfcfd15 user: Igor Sysoev date: Thu Aug 04 16:05:38 2016 +0300 description: nxt_trace interface. nxt_regex, RegExp, and parser use it now. diffstat: Makefile | 2 + njs/njs_generator.c | 41 ++--------- njs/njs_parser.c | 158 +++++++++++++++++++------------------------ njs/njs_parser.h | 14 +--- njs/njs_parser_expression.c | 37 +++------ njs/njs_regexp.c | 136 +++++++++++++++++++++++++++---------- njs/njs_regexp.h | 3 +- njs/njs_string.c | 19 ++-- njs/njs_variable.c | 4 +- njs/njs_vm.c | 19 ++--- njs/njs_vm.h | 7 +- njs/njscript.c | 10 ++ njs/test/njs_unit_test.c | 3 + nxt/Makefile | 15 ++++ nxt/nxt_clang.h | 1 + nxt/nxt_pcre.c | 63 ++++------------- nxt/nxt_regex.h | 2 +- 17 files changed, 263 insertions(+), 271 deletions(-) diffs (truncated from 1095 to 1000 lines): diff -r 016339472304 -r 23598cfcfd15 Makefile --- a/Makefile Thu Aug 04 14:45:27 2016 +0300 +++ b/Makefile Thu Aug 04 16:05:38 2016 +0300 @@ -169,6 +169,7 @@ dist: njs/njs_object_hash.h \ njs/njs_array.h \ njs/njs_function.h \ + njs/njs_regexp.h \ njs/njs_parser.h \ njs/njs_string.c \ @@ -404,6 +405,7 @@ dist: -I$(NXT_LIB) -Injs \ njs/test/njs_unit_test.c \ $(NXT_BUILDDIR)/libnjs.a \ + $(NXT_BUILDDIR)/libnxt.a \ -lm $(NXT_PCRE_LIB) include $(NXT_LIB)/Makefile diff -r 016339472304 -r 23598cfcfd15 njs/njs_generator.c --- a/njs/njs_generator.c Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njs_generator.c Thu Aug 04 16:05:38 2016 +0300 @@ -21,13 +21,6 @@ #include #include #include -#include - - -typedef enum { - NJS_GENERATOR_ERROR_ILLEGAL_CONTINUE = 0, - NJS_GENERATOR_ERROR_ILLEGAL_BREAK, -} njs_generator_error_t; static nxt_int_t njs_generator(njs_vm_t *vm, njs_parser_t *parser, @@ -125,8 +118,6 @@ static nxt_noinline nxt_int_t njs_genera static nxt_noinline nxt_int_t njs_generator_index_release(njs_vm_t *vm, njs_parser_t *parser, njs_index_t index); nxt_inline nxt_bool_t njs_generator_is_constant(njs_parser_node_t *node); -static nxt_int_t njs_generator_error(njs_vm_t *vm, njs_parser_node_t *node, - njs_generator_error_t err); static const nxt_str_t no_label = { 0, NULL }; @@ -1085,7 +1076,10 @@ njs_generate_continue_statement(njs_vm_t } } - return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_CONTINUE); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Illegal continue statement"); + + return NXT_ERROR; found: @@ -1126,7 +1120,10 @@ njs_generate_break_statement(njs_vm_t *v } } - return njs_generator_error(vm, node, NJS_GENERATOR_ERROR_ILLEGAL_BREAK); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Illegal break statement"); + + return NXT_ERROR; found: @@ -2476,25 +2473,3 @@ njs_generator_is_constant(njs_parser_nod return (node->token >= NJS_TOKEN_FIRST_CONST && node->token <= NJS_TOKEN_LAST_CONST); } - - -static nxt_int_t -njs_generator_error(njs_vm_t *vm, njs_parser_node_t *node, - njs_generator_error_t err) -{ - uint32_t size; - const char *msg; - u_char buf[NJS_EXCEPTION_BUF_LENGTH]; - - static const char *errors[] = { - "SyntaxError: Illegal continue statement in %u", - "SyntaxError: Illegal break statement in %u", - }; - - msg = errors[err]; - - size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - msg, node->token_line); - - return njs_vm_throw_exception(vm, buf, size); -} diff -r 016339472304 -r 23598cfcfd15 njs/njs_parser.c --- a/njs/njs_parser.c Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njs_parser.c Thu Aug 04 16:05:38 2016 +0300 @@ -54,8 +54,6 @@ static njs_token_t njs_parser_var_statem static njs_token_t njs_parser_if_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_switch_statement(njs_vm_t *vm, njs_parser_t *parser); -static njs_token_t njs_parser_duplicate_default_branch(njs_vm_t *vm, - njs_parser_t *parser); static njs_token_t njs_parser_while_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_do_while_statement(njs_vm_t *vm, @@ -68,8 +66,6 @@ static njs_token_t njs_parser_continue_s static njs_token_t njs_parser_break_statement(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_try_statement(njs_vm_t *vm, njs_parser_t *parser); -static njs_token_t njs_parser_missing_catch_or_finally(njs_vm_t *vm, - njs_parser_t *parser); static njs_token_t njs_parser_try_block(njs_vm_t *vm, njs_parser_t *parser); static njs_token_t njs_parser_throw_statement(njs_vm_t *vm, njs_parser_t *parser); @@ -844,7 +840,11 @@ njs_parser_switch_statement(njs_vm_t *vm } else { if (dflt != NULL) { - return njs_parser_duplicate_default_branch(vm, parser); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: More than one default clause " + "in switch statement"); + + return NJS_TOKEN_ILLEGAL; } branch = node; @@ -890,22 +890,6 @@ njs_parser_switch_statement(njs_vm_t *vm static njs_token_t -njs_parser_duplicate_default_branch(njs_vm_t *vm, njs_parser_t *parser) -{ - uint32_t size; - u_char buf[NJS_EXCEPTION_BUF_LENGTH]; - - size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - "SyntaxError: More than one default clause " - "in switch statement in %u", parser->lexer->line); - - (void) njs_vm_throw_exception(vm, buf, size); - - return NJS_TOKEN_ILLEGAL; -} - - -static njs_token_t njs_parser_while_statement(njs_vm_t *vm, njs_parser_t *parser) { njs_token_t token; @@ -1099,19 +1083,14 @@ static njs_token_t njs_parser_for_in_statement(njs_vm_t *vm, njs_parser_t *parser, nxt_str_t *name, njs_token_t token) { - uint32_t size; njs_parser_node_t *node; - u_char buf[NJS_EXCEPTION_BUF_LENGTH]; node = parser->node->left; if (node->token != NJS_TOKEN_NAME) { - size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - "ReferenceError: Invalid left-hand side \"%.*s\" " - "in for-in statement in %u", - (int) name->length, name->start, parser->lexer->line); - - (void) njs_vm_throw_exception(vm, buf, size); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, "ReferenceError: Invalid " + "left-hand side \"%.*s\" in for-in statement", + (int) name->length, name->start); return NJS_TOKEN_ILLEGAL; } @@ -1326,29 +1305,15 @@ njs_parser_try_statement(njs_vm_t *vm, n } if (try->right == NULL) { - return njs_parser_missing_catch_or_finally(vm, parser); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Missing catch or finally after try"); + + return NJS_TOKEN_ILLEGAL; } parser->node = try; return token; - -} - - -static njs_token_t -njs_parser_missing_catch_or_finally(njs_vm_t *vm, njs_parser_t *parser) -{ - uint32_t size; - u_char buf[NJS_EXCEPTION_BUF_LENGTH]; - - size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - "SyntaxError: Missing catch or finally after try in %u", - parser->lexer->line); - - (void) njs_vm_throw_exception(vm, buf, size); - - return NJS_TOKEN_ILLEGAL; } @@ -1612,8 +1577,11 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa break; case NJS_TOKEN_UNTERMINATED_STRING: - return njs_parser_error(vm, parser, - NJS_PARSER_ERROR_UNTERMINATED_STRING); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Unterminated string \"%.*s\"", + (int) parser->lexer->text.length, parser->lexer->text.start); + + return NJS_TOKEN_ILLEGAL; case NJS_TOKEN_NUMBER: nxt_thread_log_debug("JS: %f", parser->lexer->number); @@ -2042,8 +2010,7 @@ njs_parser_escape_string_create(njs_vm_t } if (hex_length == 0 || hex_length > 6) { - return njs_parser_error(vm, parser, - NJS_PARSER_ERROR_UNICODE); + goto invalid; } skip = 1; @@ -2118,12 +2085,12 @@ njs_parser_escape_string_create(njs_vm_t hex_end = src + hex_length; if (hex_end > end) { - return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNICODE); + goto invalid; } u = njs_number_radix_parse(src, hex_end, 16, 1); if (nxt_slow_path(u < 0)) { - return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNICODE); + goto invalid; } src = hex_end + skip; @@ -2150,6 +2117,14 @@ njs_parser_escape_string_create(njs_vm_t dst = start; } + +invalid: + + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Invalid Unicode code point \"%.*s\"", + (int) parser->lexer->text.length, parser->lexer->text.start); + + return NJS_TOKEN_ILLEGAL; } @@ -2208,48 +2183,53 @@ static njs_token_t njs_parser_unexpected_token(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { - uint32_t size; - u_char buf[NJS_EXCEPTION_BUF_LENGTH]; - if (token != NJS_TOKEN_END) { - return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNEXPECTED_TOKEN); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Unexpected token \"%.*s\"", + (int) parser->lexer->text.length, parser->lexer->text.start); + + } else { + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Unexpected end of input"); } - size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - "SyntaxError: Unexpected end of input in %u", - parser->lexer->line); - - (void) njs_vm_throw_exception(vm, buf, size); - return NJS_TOKEN_ILLEGAL; } -njs_token_t -njs_parser_error(njs_vm_t *vm, njs_parser_t *parser, njs_parser_error_t err) +u_char * +njs_parser_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td, + u_char *start) { - uint32_t size; - njs_lexer_t *lexer; - const char *msg; - u_char buf[NJS_EXCEPTION_BUF_LENGTH]; - - static const char *errors[] = { - "SyntaxError: Unexpected token \"%.*s\" in %u", - "SyntaxError: Unterminated string \"%.*s\" in %u", - "SyntaxError: Invalid Unicode code point \"%.*s\" in %u", - "SyntaxError: Unterminated RegExp \"%.*s\" in %u", - "SyntaxError: Invalid RegExp flags \"%.*s\" in %u", - "SyntaxError: Duplicate declaration \"%.*s\" in %u", - }; - - msg = errors[err]; - lexer = parser->lexer; - - size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - msg, (int) lexer->text.length, lexer->text.start, - lexer->line); - - (void) njs_vm_throw_exception(vm, buf, size); - - return NJS_TOKEN_ILLEGAL; + int n; + u_char *p; + ssize_t size; + njs_vm_t *vm; + + p = start; + + if (td->level == NXT_LEVEL_CRIT) { + size = sizeof("InternalError: ") - 1; + memcpy(p, "InternalError: ", size); + p = start + size; + } + + vm = trace->data; + + trace = trace->next; + p = trace->handler(trace, td, p); + + if (vm->parser != NULL) { + size = td->end - start; + + n = snprintf((char *) p, size, " in %u", vm->parser->lexer->line); + + if (n < size) { + p += n; + } + } + + njs_vm_throw_exception(vm, start, p - start); + + return p; } diff -r 016339472304 -r 23598cfcfd15 njs/njs_parser.h --- a/njs/njs_parser.h Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njs_parser.h Thu Aug 04 16:05:38 2016 +0300 @@ -314,16 +314,6 @@ struct njs_parser_s { }; -typedef enum { - NJS_PARSER_ERROR_UNEXPECTED_TOKEN = 0, - NJS_PARSER_ERROR_UNTERMINATED_STRING, - NJS_PARSER_ERROR_UNICODE, - NJS_PARSER_ERROR_UNTERMINATED_REGEXP, - NJS_PARSER_ERROR_REGEXP_FLAGS, - NJS_PARSER_ERROR_DUPLICATE_DECLARATION, -} njs_parser_error_t; - - njs_token_t njs_lexer_token(njs_lexer_t *lexer); nxt_int_t njs_lexer_keywords_init(nxt_mem_cache_pool_t *mcp, nxt_lvlhsh_t *hash); @@ -350,8 +340,8 @@ njs_token_t njs_parser_token(njs_parser_ nxt_int_t njs_parser_string_create(njs_vm_t *vm, njs_value_t *value); njs_index_t njs_parser_index(njs_parser_t *parser, uint32_t scope); nxt_bool_t njs_parser_has_side_effect(njs_parser_node_t *node); -njs_token_t njs_parser_error(njs_vm_t *vm, njs_parser_t *parser, - njs_parser_error_t err); +u_char *njs_parser_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td, + u_char *start); nxt_int_t njs_generate_scope(njs_vm_t *vm, njs_parser_t *parser, njs_parser_node_t *node); diff -r 016339472304 -r 23598cfcfd15 njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njs_parser_expression.c Thu Aug 04 16:05:38 2016 +0300 @@ -24,7 +24,6 @@ #include #include #include -#include typedef struct { @@ -75,8 +74,6 @@ static njs_token_t njs_parser_property_e njs_parser_t *parser, njs_token_t token); static njs_token_t njs_parser_property_brackets(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token); -static njs_token_t njs_parser_invalid_lvalue(njs_vm_t *vm, - njs_parser_t *parser, const char* operation); static const njs_parser_expression_t @@ -294,7 +291,9 @@ njs_parser_var_expression(njs_vm_t *vm, node = parser->node; if (parser->node->token != NJS_TOKEN_NAME) { - return njs_parser_invalid_lvalue(vm, parser, "assignment"); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "ReferenceError: Invalid left-hand side in assignment"); + return NJS_TOKEN_ILLEGAL; } pending = NULL; @@ -439,7 +438,9 @@ njs_parser_assignment_expression(njs_vm_ node = parser->node; if (!njs_parser_is_lvalue(parser->node)) { - return njs_parser_invalid_lvalue(vm, parser, "assignment"); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "ReferenceError: Invalid left-hand side in assignment"); + return NJS_TOKEN_ILLEGAL; } pending = NULL; @@ -811,7 +812,9 @@ njs_parser_inc_dec_expression(njs_vm_t * } if (!njs_parser_is_lvalue(parser->node)) { - return njs_parser_invalid_lvalue(vm, parser, "prefix operation"); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "ReferenceError: Invalid left-hand side in prefix operation"); + return NJS_TOKEN_ILLEGAL; } node = njs_parser_node_alloc(vm); @@ -863,7 +866,9 @@ njs_parser_post_inc_dec_expression(njs_v } if (!njs_parser_is_lvalue(parser->node)) { - return njs_parser_invalid_lvalue(vm, parser, "postfix operation"); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "ReferenceError: Invalid left-hand side in postfix operation"); + return NJS_TOKEN_ILLEGAL; } node = njs_parser_node_alloc(vm); @@ -1143,21 +1148,3 @@ njs_parser_arguments(njs_vm_t *vm, njs_p return token; } - - -static njs_token_t -njs_parser_invalid_lvalue(njs_vm_t *vm, njs_parser_t *parser, - const char *operation) -{ - uint32_t size; - u_char buf[NJS_EXCEPTION_BUF_LENGTH]; - - size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - "ReferenceError: Invalid left-hand side in %s in %u", - operation, parser->lexer->line); - - (void) njs_vm_throw_exception(vm, buf, size); - - return NJS_TOKEN_ILLEGAL; - -} diff -r 016339472304 -r 23598cfcfd15 njs/njs_regexp.c --- a/njs/njs_regexp.c Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njs_regexp.c Thu Aug 04 16:05:38 2016 +0300 @@ -39,6 +39,10 @@ static njs_regexp_flags_t njs_regexp_fla nxt_bool_t bound); static int njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex, u_char *source, int options); +static u_char *njs_regexp_compile_trace_handler(nxt_trace_t *trace, + nxt_trace_data_t *td, u_char *start); +static u_char *njs_regexp_match_trace_handler(nxt_trace_t *trace, + nxt_trace_data_t *td, u_char *start); static njs_ret_t njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp, u_char *string, nxt_regex_match_data_t *match_data, nxt_uint_t utf8); static njs_ret_t njs_regexp_string_create(njs_vm_t *vm, njs_value_t *value, @@ -59,6 +63,8 @@ njs_regexp_init(njs_vm_t *vm) return NXT_ERROR; } + vm->regex_context->trace = &vm->trace; + return NXT_OK; } @@ -161,10 +167,11 @@ njs_regexp_literal(njs_vm_t *vm, njs_par flags = njs_regexp_flags(&p, lexer->end, 0); if (nxt_slow_path(flags < 0)) { - lexer->text.start = lexer->start; - lexer->text.length = p - lexer->text.start; - return njs_parser_error(vm, parser, - NJS_PARSER_ERROR_REGEXP_FLAGS); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Invalid RegExp flags \"%.*s\"", + p - lexer->start, lexer->start); + + return NJS_TOKEN_ILLEGAL; } lexer->start = p; @@ -181,10 +188,11 @@ njs_regexp_literal(njs_vm_t *vm, njs_par } } - lexer->text.start = lexer->start - 1; - lexer->text.length = p - lexer->text.start; + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Unterminated RegExp \"%.*s\"", + p - lexer->start - 1, lexer->start - 1); - return njs_parser_error(vm, parser, NJS_PARSER_ERROR_UNTERMINATED_REGEXP); + return NJS_TOKEN_ILLEGAL; } @@ -345,28 +353,97 @@ static int njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex, u_char *source, int options) { - uint32_t size; - nxt_int_t ret; - u_char buf[NJS_EXCEPTION_BUF_LENGTH]; + nxt_int_t ret; + nxt_trace_handler_t handler; + + handler = vm->trace.handler; + vm->trace.handler = njs_regexp_compile_trace_handler; /* Zero length means a zero-terminated string. */ ret = nxt_regex_compile(regex, source, 0, options, vm->regex_context); + vm->trace.handler = handler; + if (nxt_fast_path(ret == NXT_OK)) { return regex->ncaptures; } + return ret; +} + + +static u_char * +njs_regexp_compile_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td, + u_char *start) +{ + int n; + u_char *p; + ssize_t size; + njs_vm_t *vm; + + size = sizeof("SyntaxError: ") - 1; + memcpy(start, "SyntaxError: ", size); + p = start + size; + + vm = trace->data; + + trace = trace->next; + p = trace->handler(trace, td, p); + if (vm->parser != NULL) { - size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - "SyntaxError: %s in %u", - vm->regex_context->error, vm->parser->lexer->line); + size = td->end - start; - } else { - size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - "SyntaxError: %s", vm->regex_context->error); + n = snprintf((char *) p, size, " in %u", vm->parser->lexer->line); + + if (n < size) { + p += n; + } } - return njs_vm_throw_exception(vm, buf, size); + njs_vm_throw_exception(vm, start, p - start); + + return p; +} + + +nxt_int_t +njs_regexp_match(njs_vm_t *vm, nxt_regex_t *regex, u_char *subject, size_t len, + nxt_regex_match_data_t *match_data) +{ + nxt_int_t ret; + nxt_trace_handler_t handler; + + handler = vm->trace.handler; + vm->trace.handler = njs_regexp_match_trace_handler; + + ret = nxt_regex_match(regex, subject, len, match_data, vm->regex_context); + + vm->trace.handler = handler; + + return ret; +} + + +static u_char * +njs_regexp_match_trace_handler(nxt_trace_t *trace, nxt_trace_data_t *td, + u_char *start) +{ + u_char *p; + size_t size; + njs_vm_t *vm; + + size = sizeof("RegExpError: ") - 1; + memcpy(start, "RegExpError: ", size); + p = start + size; + + vm = trace->data; + + trace = trace->next; + p = trace->handler(trace, td, p); + + njs_vm_throw_exception(vm, start, p - start); + + return p; } @@ -517,13 +594,13 @@ njs_regexp_prototype_test(njs_vm_t *vm, pattern = args[0].data.u.regexp->pattern; if (nxt_regex_is_valid(&pattern->regex[n])) { - ret = nxt_regex_match(&pattern->regex[n], string.start, string.size, - vm->single_match_data, vm->regex_context); + ret = njs_regexp_match(vm, &pattern->regex[n], string.start, + string.size, vm->single_match_data); if (ret >= 0) { retval = &njs_value_true; } else if (ret != NGX_REGEX_NOMATCH) { - return njs_regexp_match_error(vm); + return NXT_ERROR; } } @@ -589,8 +666,8 @@ njs_regexp_prototype_exec(njs_vm_t *vm, return NXT_ERROR; } - ret = nxt_regex_match(&pattern->regex[n], string.start, string.size, - match_data, vm->regex_context); + ret = njs_regexp_match(vm, &pattern->regex[n], string.start, + string.size, match_data); if (ret >= 0) { return njs_regexp_exec_result(vm, regexp, string.start, match_data, utf8); @@ -599,7 +676,7 @@ njs_regexp_prototype_exec(njs_vm_t *vm, if (nxt_slow_path(ret != NGX_REGEX_NOMATCH)) { nxt_regex_match_data_free(match_data, vm->regex_context); - return njs_regexp_match_error(vm); + return NXT_ERROR; } } @@ -736,19 +813,6 @@ njs_regexp_string_create(njs_vm_t *vm, n } -njs_ret_t -njs_regexp_match_error(njs_vm_t *vm) -{ - uint32_t size; - u_char buf[NJS_EXCEPTION_BUF_LENGTH]; - - size = snprintf((char *) buf, NJS_EXCEPTION_BUF_LENGTH, - "RegExpError: %s", vm->regex_context->error); - - return njs_vm_throw_exception(vm, buf, size); -} - - static const njs_object_prop_t njs_regexp_constructor_properties[] = { /* RegExp.name == "RegExp". */ diff -r 016339472304 -r 23598cfcfd15 njs/njs_regexp.h --- a/njs/njs_regexp.h Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njs_regexp.h Thu Aug 04 16:05:38 2016 +0300 @@ -39,10 +39,11 @@ njs_token_t njs_regexp_literal(njs_vm_t njs_value_t *value); njs_regexp_pattern_t *njs_regexp_pattern_create(njs_vm_t *vm, u_char *string, size_t length, njs_regexp_flags_t flags); +nxt_int_t njs_regexp_match(njs_vm_t *vm, nxt_regex_t *regex, u_char *subject, + size_t len, nxt_regex_match_data_t *match_data); njs_regexp_t *njs_regexp_alloc(njs_vm_t *vm, njs_regexp_pattern_t *pattern); njs_ret_t njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); -njs_ret_t njs_regexp_match_error(njs_vm_t *vm); extern const njs_object_init_t njs_regexp_constructor_init; diff -r 016339472304 -r 23598cfcfd15 njs/njs_string.c --- a/njs/njs_string.c Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njs_string.c Thu Aug 04 16:05:38 2016 +0300 @@ -31,7 +31,6 @@ #include #include #include -#include static nxt_noinline void njs_string_slice_prop(njs_string_prop_t *string, @@ -1455,14 +1454,14 @@ njs_string_prototype_search(njs_vm_t *vm n = (string.length != 0); if (nxt_regex_is_valid(&pattern->regex[n])) { - ret = nxt_regex_match(&pattern->regex[n], string.start, string.size, - vm->single_match_data, vm->regex_context); + ret = njs_regexp_match(vm, &pattern->regex[n], string.start, + string.size, vm->single_match_data); if (ret >= 0) { captures = nxt_regex_captures(vm->single_match_data); index = njs_string_index(&string, captures[0]); } else if (ret != NGX_REGEX_NOMATCH) { - return njs_regexp_match_error(vm); + return NXT_ERROR; } } } @@ -1555,8 +1554,8 @@ njs_string_prototype_match(njs_vm_t *vm, array = NULL; do { - ret = nxt_regex_match(&pattern->regex[n], string.start, string.size, - vm->single_match_data, vm->regex_context); + ret = njs_regexp_match(vm, &pattern->regex[n], string.start, + string.size, vm->single_match_data); if (ret >= 0) { if (array != NULL) { if (array->length == array->size) { @@ -1617,7 +1616,7 @@ njs_string_prototype_match(njs_vm_t *vm, break; } else { - return njs_regexp_match_error(vm); + return NXT_ERROR; } } while (string.size > 0); @@ -1756,8 +1755,8 @@ njs_string_prototype_split(njs_vm_t *vm, end = string.start + string.size; do { - ret = nxt_regex_match(&pattern->regex[n], start, end - start, - vm->single_match_data, vm->regex_context); + ret = njs_regexp_match(vm, &pattern->regex[n], start, + end - start, vm->single_match_data); if (ret >= 0) { captures = nxt_regex_captures(vm->single_match_data); @@ -1769,7 +1768,7 @@ njs_string_prototype_split(njs_vm_t *vm, next = (u_char *) end + 1; } else { - return njs_regexp_match_error(vm); + return NXT_ERROR; } /* Empty split regexp. */ diff -r 016339472304 -r 23598cfcfd15 njs/njs_variable.c --- a/njs/njs_variable.c Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njs_variable.c Thu Aug 04 16:05:38 2016 +0300 @@ -79,7 +79,9 @@ njs_parser_name_alloc(njs_vm_t *vm, njs_ return var; } - (void) njs_parser_error(vm, parser, NJS_PARSER_ERROR_DUPLICATE_DECLARATION); + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Duplicate declaration \"%.*s\"", + (int) parser->lexer->text.length, parser->lexer->text.start); return NULL; } diff -r 016339472304 -r 23598cfcfd15 njs/njs_vm.c --- a/njs/njs_vm.c Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njs_vm.c Thu Aug 04 16:05:38 2016 +0300 @@ -3316,24 +3316,21 @@ njs_value_string_copy(njs_vm_t *vm, nxt_ } -njs_ret_t +void njs_vm_throw_exception(njs_vm_t *vm, u_char *buf, uint32_t size) { uint32_t length; njs_value_t *value; value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t)); - if (nxt_slow_path(value == NULL)) { - return NJS_TOKEN_ERROR; + + if (nxt_fast_path(value != NULL)) { + vm->exception = value; + + length = nxt_utf8_length(buf, size); + + (void) njs_string_new(vm, value, buf, size, length); } - - vm->exception = value; - - length = nxt_utf8_length(buf, size); - - (void) njs_string_new(vm, value, buf, size, length); - - return NXT_ERROR; } diff -r 016339472304 -r 23598cfcfd15 njs/njs_vm.h --- a/njs/njs_vm.h Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njs_vm.h Thu Aug 04 16:05:38 2016 +0300 @@ -8,6 +8,7 @@ #define _NJS_VM_H_INCLUDED_ +#include #include @@ -799,6 +800,7 @@ struct njs_vm_s { nxt_array_t *code; /* of njs_vm_code_t */ + nxt_trace_t trace; nxt_random_t random; }; @@ -827,9 +829,6 @@ struct njs_vm_shared_s { }; -#define NJS_EXCEPTION_BUF_LENGTH 2048 - - nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm); void njs_value_retain(njs_value_t *value); @@ -969,7 +968,7 @@ njs_ret_t njs_value_to_ext_string(njs_vm const njs_value_t *src); void njs_number_set(njs_value_t *value, double num); -njs_ret_t njs_vm_throw_exception(njs_vm_t *vm, u_char *buf, uint32_t size); +void njs_vm_throw_exception(njs_vm_t *vm, u_char *buf, uint32_t size); nxt_int_t njs_builtin_objects_create(njs_vm_t *vm); nxt_int_t njs_builtin_objects_clone(njs_vm_t *vm); diff -r 016339472304 -r 23598cfcfd15 njs/njscript.c --- a/njs/njscript.c Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/njscript.c Thu Aug 04 16:05:38 2016 +0300 @@ -155,6 +155,11 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp, if (externals != NULL) { vm->externals_hash = *externals; } + + vm->trace.level = NXT_LEVEL_TRACE; + vm->trace.size = 2048; + vm->trace.handler = njs_parser_trace_handler; + vm->trace.data = vm; } return vm; @@ -325,6 +330,11 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache goto fail; } + nvm->trace.level = NXT_LEVEL_TRACE; + nvm->trace.size = 2048; + nvm->trace.handler = njs_parser_trace_handler; + nvm->trace.data = nvm; + return nvm; } diff -r 016339472304 -r 23598cfcfd15 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Aug 04 14:45:27 2016 +0300 +++ b/njs/test/njs_unit_test.c Thu Aug 04 16:05:38 2016 +0300 @@ -3511,6 +3511,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("/(/.test('')"), nxt_string("SyntaxError: pcre_compile(\"(\") failed: missing ) in 1") }, + { nxt_string("/+/.test('')"), + nxt_string("SyntaxError: pcre_compile(\"+\") failed: nothing to repeat at \"+\" in 1") }, + { nxt_string("/^$/.test('')"), nxt_string("true") }, diff -r 016339472304 -r 23598cfcfd15 nxt/Makefile --- a/nxt/Makefile Thu Aug 04 14:45:27 2016 +0300 +++ b/nxt/Makefile Thu Aug 04 16:05:38 2016 +0300 @@ -12,6 +12,7 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_random.o \ $(NXT_BUILDDIR)/nxt_pcre.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ + $(NXT_BUILDDIR)/nxt_trace.o \ $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ ar -r -c $(NXT_BUILDDIR)/libnxt.a \ @@ -23,6 +24,7 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_random.o \ $(NXT_BUILDDIR)/nxt_pcre.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ + $(NXT_BUILDDIR)/nxt_trace.o \ $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ $(NXT_BUILDDIR)/nxt_murmur_hash.o: \ @@ -111,6 +113,7 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_pcre.o: \ $(NXT_LIB)/nxt_types.h \ $(NXT_LIB)/nxt_clang.h \ + $(NXT_LIB)/nxt_trace.h \ $(NXT_LIB)/nxt_regex.h \ $(NXT_LIB)/nxt_pcre.h \ $(NXT_LIB)/nxt_pcre.c \ @@ -130,6 +133,18 @@ NXT_LIB = nxt -I$(NXT_LIB) \ $(NXT_LIB)/nxt_malloc.c +$(NXT_BUILDDIR)/nxt_trace.o: \ + $(NXT_LIB)/nxt_auto_config.h \ + $(NXT_LIB)/nxt_types.h \ + $(NXT_LIB)/nxt_clang.h \ + $(NXT_LIB)/nxt_malloc.h \ + $(NXT_LIB)/nxt_trace.h \ + $(NXT_LIB)/nxt_trace.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_trace.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) \ + $(NXT_LIB)/nxt_trace.c + $(NXT_BUILDDIR)/nxt_mem_cache_pool.o: \ $(NXT_LIB)/nxt_types.h \ $(NXT_LIB)/nxt_clang.h \ diff -r 016339472304 -r 23598cfcfd15 nxt/nxt_clang.h --- a/nxt/nxt_clang.h Thu Aug 04 14:45:27 2016 +0300 +++ b/nxt/nxt_clang.h Thu Aug 04 16:05:38 2016 +0300 @@ -8,6 +8,7 @@ #define _NXT_CLANG_H_INCLUDED_ +#include #include /* offsetof(). */ #include /* NULL. */ diff -r 016339472304 -r 23598cfcfd15 nxt/nxt_pcre.c --- a/nxt/nxt_pcre.c Thu Aug 04 14:45:27 2016 +0300 +++ b/nxt/nxt_pcre.c Thu Aug 04 16:05:38 2016 +0300 @@ -7,9 +7,9 @@ #include #include #include +#include #include #include -#include #include @@ -53,7 +53,6 @@ nxt_regex_compile(nxt_regex_t *regex, u_ char *pattern, *error; void *(*saved_malloc)(size_t size); void (*saved_free)(void *p); - size_t size; const char *errstr; ret = NXT_ERROR; @@ -82,22 +81,14 @@ nxt_regex_compile(nxt_regex_t *regex, u_ if (nxt_slow_path(regex->code == NULL)) { error = pattern + erroff; - size = sizeof("pcre_compile(\"\") failed: at \"\"") - + strlen(errstr) + strlen(error) * 2 + erroff; - - ctx->error = ctx->private_malloc(size, ctx->memory_data); - if (nxt_slow_path(ctx->error == NULL)) { - goto done; - } + if (*error != '\0') { + nxt_alert(ctx->trace, NXT_LEVEL_ERROR, + "pcre_compile(\"%s\") failed: %s at \"%s\"", + pattern, errstr, error); - if (*error != '\0') { - (void) snprintf((char *) ctx->error, size, - "pcre_compile(\"%s\") failed: %s at \"%s\"", From igor at sysoev.ru Thu Aug 4 13:32:07 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 04 Aug 2016 13:32:07 +0000 Subject: [njs] nxt_trace files have been missed in the previous commit. Message-ID: details: http://hg.nginx.org/njs/rev/b33ba39a1108 branches: changeset: 141:b33ba39a1108 user: Igor Sysoev date: Thu Aug 04 16:27:38 2016 +0300 description: nxt_trace files have been missed in the previous commit. diffstat: nxt/nxt_trace.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ nxt/nxt_trace.h | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 0 deletions(-) diffs (133 lines): diff -r 23598cfcfd15 -r b33ba39a1108 nxt/nxt_trace.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_trace.c Thu Aug 04 16:27:38 2016 +0300 @@ -0,0 +1,57 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include +#include +#include +#include +#include + + +static u_char * +nxt_last_handler(nxt_trace_t *trace, nxt_trace_data_t *td, u_char *start) +{ + int n; + ssize_t size; + + size = td->end - start; + n = vsnprintf((char *) start, size, td->fmt, td->args); + + if (n < size) { + start += n; + } + + return start; +} + + +void +nxt_trace_handler(nxt_trace_t *trace, uint32_t level, const char *fmt, ...) +{ + u_char *start; + nxt_trace_t last; + nxt_trace_data_t td; + + td.level = level; + td.fmt = fmt; + + va_start(td.args, fmt); + + start = alloca(trace->size); + td.end = start + trace->size; + + last.handler = nxt_last_handler; + trace->next = &last; + + while (trace->prev != NULL) { + trace = trace->prev; + } + + (void) trace->handler(trace, &td, start); + + va_end(td.args); +} diff -r 23598cfcfd15 -r b33ba39a1108 nxt/nxt_trace.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_trace.h Thu Aug 04 16:27:38 2016 +0300 @@ -0,0 +1,68 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#ifndef _NXT_TRACE_H_INCLUDED_ +#define _NXT_TRACE_H_INCLUDED_ + + +typedef enum { + NXT_LEVEL_CRIT = 0, + NXT_LEVEL_ERROR, + NXT_LEVEL_WARN, + NXT_LEVEL_INFO, + NXT_LEVEL_TRACE, +} nxt_trace_level_t; + + +typedef struct { + uint32_t level; + u_char *end; + const char *fmt; + va_list args; +} nxt_trace_data_t; + + +typedef struct nxt_trace_s nxt_trace_t; + +typedef u_char *(*nxt_trace_handler_t)(nxt_trace_t *trace, nxt_trace_data_t *td, + u_char *start); + +struct nxt_trace_s { + uint32_t level; + uint32_t size; + nxt_trace_handler_t handler; + void *data; + nxt_trace_t *prev; + nxt_trace_t *next; +}; + + +#define nxt_alert(_trace, _level, ...) \ + do { \ + nxt_trace_t *_trace_ = _trace; \ + uint32_t _level_ = _level; \ + \ + if (nxt_slow_path(_trace_->level >= _level_)) { \ + nxt_trace_handler(_trace_, _level_, __VA_ARGS__); \ + } \ + } while (0) + + +#define nxt_trace(_trace, ...) \ + do { \ + nxt_trace_t *_trace_ = _trace; \ + \ + if (nxt_slow_path(_trace_->level == NXT_LEVEL_TRACE)) { \ + nxt_trace_handler(_trace_, NXT_LEVEL_TRACE, __VA_ARGS__); \ + } \ + } while (0) + + +NXT_EXPORT void nxt_trace_handler(nxt_trace_t *trace, uint32_t level, + const char *fmt, ...); + + +#endif /* _NXT_TRACE_H_INCLUDED_ */ From igor at sysoev.ru Thu Aug 4 13:32:08 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 04 Aug 2016 13:32:08 +0000 Subject: [njs] The lvlhsh unit test has been updated after nxt_str_t chan... Message-ID: details: http://hg.nginx.org/njs/rev/19175c06b532 branches: changeset: 142:19175c06b532 user: Igor Sysoev date: Thu Aug 04 16:31:48 2016 +0300 description: The lvlhsh unit test has been updated after nxt_str_t changes. diffstat: nxt/test/lvlhsh_unit_test.c | 15 ++++++++------- 1 files changed, 8 insertions(+), 7 deletions(-) diffs (53 lines): diff -r b33ba39a1108 -r 19175c06b532 nxt/test/lvlhsh_unit_test.c --- a/nxt/test/lvlhsh_unit_test.c Thu Aug 04 16:27:38 2016 +0300 +++ b/nxt/test/lvlhsh_unit_test.c Thu Aug 04 16:31:48 2016 +0300 @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -19,7 +20,7 @@ static nxt_int_t lvlhsh_unit_test_key_test(nxt_lvlhsh_query_t *lhq, void *data) { - if (*(uintptr_t *) lhq->key.data == (uintptr_t) data) { + if (*(uintptr_t *) lhq->key.start == (uintptr_t) data) { return NXT_OK; } @@ -58,8 +59,8 @@ lvlhsh_unit_test_add(nxt_lvlhsh_t *lh, c lhq.key_hash = key; lhq.replace = 0; - lhq.key.len = sizeof(uintptr_t); - lhq.key.data = (u_char *) &key; + lhq.key.length = sizeof(uintptr_t); + lhq.key.start = (u_char *) &key; lhq.value = (void *) key; lhq.proto = proto; lhq.pool = pool; @@ -86,8 +87,8 @@ lvlhsh_unit_test_get(nxt_lvlhsh_t *lh, c nxt_lvlhsh_query_t lhq; lhq.key_hash = key; - lhq.key.len = sizeof(uintptr_t); - lhq.key.data = (u_char *) &key; + lhq.key.length = sizeof(uintptr_t); + lhq.key.start = (u_char *) &key; lhq.proto = proto; if (nxt_lvlhsh_find(lh, &lhq) == NXT_OK) { @@ -112,8 +113,8 @@ lvlhsh_unit_test_delete(nxt_lvlhsh_t *lh nxt_lvlhsh_query_t lhq; lhq.key_hash = key; - lhq.key.len = sizeof(uintptr_t); - lhq.key.data = (u_char *) &key; + lhq.key.length = sizeof(uintptr_t); + lhq.key.start = (u_char *) &key; lhq.proto = proto; lhq.pool = pool; From igor at sysoev.ru Thu Aug 4 14:00:22 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 04 Aug 2016 14:00:22 +0000 Subject: [njs] nxt_trace.o has been added to the libnjs. Message-ID: details: http://hg.nginx.org/njs/rev/73b0fd4c2ea6 branches: changeset: 143:73b0fd4c2ea6 user: Igor Sysoev date: Thu Aug 04 16:59:15 2016 +0300 description: nxt_trace.o has been added to the libnjs. diffstat: Makefile | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diffs (27 lines): diff -r 19175c06b532 -r 73b0fd4c2ea6 Makefile --- a/Makefile Thu Aug 04 16:31:48 2016 +0300 +++ b/Makefile Thu Aug 04 16:59:15 2016 +0300 @@ -41,6 +41,7 @@ main: $(NXT_BUILDDIR)/libnjs.a $(NXT_BUILDDIR)/nxt_array.o \ $(NXT_BUILDDIR)/nxt_rbtree.o \ $(NXT_BUILDDIR)/nxt_lvlhsh.o \ + $(NXT_BUILDDIR)/nxt_trace.o \ $(NXT_BUILDDIR)/nxt_random.o \ $(NXT_BUILDDIR)/nxt_pcre.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ @@ -73,6 +74,7 @@ main: $(NXT_BUILDDIR)/libnjs.a $(NXT_BUILDDIR)/nxt_array.o \ $(NXT_BUILDDIR)/nxt_rbtree.o \ $(NXT_BUILDDIR)/nxt_lvlhsh.o \ + $(NXT_BUILDDIR)/nxt_trace.o \ $(NXT_BUILDDIR)/nxt_random.o \ $(NXT_BUILDDIR)/nxt_pcre.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ @@ -405,7 +407,6 @@ dist: -I$(NXT_LIB) -Injs \ njs/test/njs_unit_test.c \ $(NXT_BUILDDIR)/libnjs.a \ - $(NXT_BUILDDIR)/libnxt.a \ -lm $(NXT_PCRE_LIB) include $(NXT_LIB)/Makefile From wandenberg at gmail.com Thu Aug 4 14:45:49 2016 From: wandenberg at gmail.com (Wandenberg Peixoto) Date: Thu, 4 Aug 2016 11:45:49 -0300 Subject: 500 response with HIT status and cached file is with 200 status Message-ID: Hey, I'm with a weird situation on an nginx instance. The object on the cache was stored with 200 OK status, but sometimes when a client request this same object nginx log something like 500 as status, HIT as cache status, 0 bytes sent and 0 ms as response time. Have any of you seen an error like that? What may be causing this situation? Where I can look for more information? One possibility I have thought about is an error when nginx tries to write on the user socket, but I don't know if this would be the expected response. I'm using nginx 1.8.0 version and RedHat 6.5 on this environment. Any tips would be appreciate. Kind regards, Wandenberg -------------- next part -------------- An HTML attachment was scrubbed... URL: From bartw at xs4all.nl Thu Aug 4 15:07:35 2016 From: bartw at xs4all.nl (Bart Warmerdam) Date: Thu, 04 Aug 2016 17:07:35 +0200 Subject: SSL Alternative Subject Name validation Message-ID: <01a5afd06bc7f6272ffb51c212d4c7f2@xs4all.nl> Hello, According to src/event/ngx_event_openssl.c (line ~ 3094) /* * As per RFC6125 and RFC2818, we check subjectAltName extension, * and if it's not present - commonName in Subject is checked. */ But according to the https://tools.ietf.org/html/rfc6125 the validation this case is more restrictive: 0 If a subjectAltName extension of type dNSName is present in the certificate, it SHOULD be used as the source of the server's identity. This means that if e.g. an email address (GEN_EMAIL) is part of the subjectAltName, and no DNSName is present, the CN name is never checked in this case. I'd expect the CN to be checked in this case. The jump to the failed label should only be done if there was at least one DNSName. Do you share this view and do you accept a patch for this? Regards, B. From oscaretu at gmail.com Thu Aug 4 19:59:10 2016 From: oscaretu at gmail.com (oscaretu .) Date: Thu, 4 Aug 2016 21:59:10 +0200 Subject: This documents seems to be interesting to HTTP/2 server implementers Message-ID: Rules of Thumb for HTTP/2 Push -- *The intended audience is HTTP/2 server implementers, who want to support server push in their servers, and web developers, who think their pages may be benefit from server push.* (via Eric Bidelman ) Seen in https://www.oreilly.com/ideas/four-short-links-4-august-2016 -- Oscar Fernandez Sierra oscaretu at gmail.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From Jakub.Moscicki at cern.ch Fri Aug 5 10:14:36 2016 From: Jakub.Moscicki at cern.ch (Jakub Moscicki) Date: Fri, 5 Aug 2016 10:14:36 +0000 Subject: [PATCH] optionally avoid sending body of PUT request before X-Accel redirect Message-ID: Hello, Would this kind of patch make sense to include in nginx upstream? If yes, then we would prepare it properly as an option (similar to proxy_pass_request_body). Use-case: at CERN we use nginx as a reverse proxy for Webdav/HTTP access to our large-scale storage system (https://eos.readthedocs.io, https://eos.web.cern.ch) and in particular for Sync&Share service called CERNBox (https://www.researchgate.net/publication/288020928_CERNBox_EOS_end-user_storage_for_science). All client file transfer requests (PUT and GET) are first passed to a metadata upstream server which performs an (internal) redirect to a (calculated) storage node (http upstream server). In case of PUT we do not want and need to send the body to the metadata server but only to the storage node after internal X-Accel redirect. Hence, we have made this patch (on 1.6.2): --- a/src/http/ngx_http_upstream.c 2015-01-27 16:24:56.000000001 +0100 +++ b/src/http/ngx_http_upstream.c 2014-09-16 14:23:20.000000001 +0200 @@ -525,8 +525,10 @@ ngx_http_upstream_init_request(ngx_http_ r->write_event_handler = ngx_http_upstream_wr_check_broken_connection; } - if (r->request_body) { - u->request_bufs = r->request_body->bufs; + if (r->method != NGX_HTTP_PUT) { + if (r->request_body) { + u->request_bufs = r->request_body->bufs; + } } if (u->create_request(r) != NGX_OK) { Thank you for your comments. Jakub Moscicki & Andreas Peters -------------- next part -------------- An HTML attachment was scrubbed... URL: From doppelbauer at gmx.net Fri Aug 5 15:00:01 2016 From: doppelbauer at gmx.net (Markus Doppelbauer) Date: Fri, 05 Aug 2016 17:00:01 +0200 Subject: Video streaming feature request Message-ID: <1470409201.7403.31.camel@gmx.net> Hello, I think Nginx misses a small feature when used as a video caching proxy. MP4 files have a MOOV atom on top - so it would be great to tell a caching proxy to throttle the bandwidth only after sending the MOOV atom (the MOOV atom should be shipped as fast as possible). An nginx server can use "limit_rate_after " - but can't tell a caching proxy to do so. It would be great if "X-Accel-Limit-Rate" could support an optional second parameter: "limit-rate-after", e.g.: X-Accel-Limit-Rate: A small patch should be attached. Thanks a lot Markus -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: x-accel-limit-rate-after.patch Type: text/x-patch Size: 1418 bytes Desc: not available URL: From mdounin at mdounin.ru Sat Aug 6 12:45:09 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sat, 6 Aug 2016 15:45:09 +0300 Subject: 500 response with HIT status and cached file is with 200 status In-Reply-To: References: Message-ID: <20160806124509.GB57459@mdounin.ru> Hello! On Thu, Aug 04, 2016 at 11:45:49AM -0300, Wandenberg Peixoto wrote: > I'm with a weird situation on an nginx instance. > The object on the cache was stored with 200 OK status, but sometimes when a > client request this same object nginx log something like 500 as status, HIT > as cache status, 0 bytes sent and 0 ms as response time. > > Have any of you seen an error like that? > What may be causing this situation? This can happen, e.g., due to a memory allocation error. > Where I can look for more information? Try looking into the error log for details. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Sat Aug 6 13:29:55 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sat, 6 Aug 2016 16:29:55 +0300 Subject: SSL Alternative Subject Name validation In-Reply-To: <01a5afd06bc7f6272ffb51c212d4c7f2@xs4all.nl> References: <01a5afd06bc7f6272ffb51c212d4c7f2@xs4all.nl> Message-ID: <20160806132955.GC57459@mdounin.ru> Hello! On Thu, Aug 04, 2016 at 05:07:35PM +0200, Bart Warmerdam wrote: > Hello, > > According to src/event/ngx_event_openssl.c (line ~ 3094) > > /* > * As per RFC6125 and RFC2818, we check subjectAltName extension, > * and if it's not present - commonName in Subject is checked. > */ > > > But according to the https://tools.ietf.org/html/rfc6125 the validation this > case is more restrictive: > > 0 If a subjectAltName extension of type dNSName is present in the > certificate, it SHOULD be used as the source of the server's > identity. > > This means that if e.g. an email address (GEN_EMAIL) is part of the > subjectAltName, and no DNSName is present, the CN name is never checked in > this case. I'd expect the CN to be checked in this case. The jump to the > failed label should only be done if there was at least one DNSName. Do you > share this view and do you accept a patch for this? The quote above seems to be from a previous RFC as incorporated in RFC 6125, Appendix B. This section is non-normative. On the other hand, section 6.3 says: Security Warning: A client MUST NOT seek a match for a reference identifier of CN-ID if the presented identifiers include a DNS-ID, SRV-ID, URI-ID, or any application-specific identifier types supported by the client. Moreover, use of CN-ID is strictly optional as per section 6.2.1: o The list MAY include a CN-ID, mainly for the sake of backward compatibility with deployed infrastructure. That is, not checking CN at all is still perfectly compatible with RFC 6125. The above is additionally summarized in the section 6.4.4, "Checking of Common Names". The current code only checks CN if there are no subjectAltName extension at all, and this approach looks safe while still providing backward compatibility. I don't think this should be changed unless there are good practical reasons to do so. Note well that the code in question exists only to support old versions of OpenSSL. With OpenSSL 1.0.2+ the X509_check_host() function will be used instead. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Sat Aug 6 14:39:48 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sat, 6 Aug 2016 17:39:48 +0300 Subject: [PATCH] optionally avoid sending body of PUT request before X-Accel redirect In-Reply-To: References: Message-ID: <20160806143948.GF57459@mdounin.ru> Hello! On Fri, Aug 05, 2016 at 10:14:36AM +0000, Jakub Moscicki wrote: > Hello, > > Would this kind of patch make sense to include in nginx upstream? If yes, then we would prepare it properly as an option (similar to proxy_pass_request_body). > > Use-case: at CERN we use nginx as a reverse proxy for Webdav/HTTP access to our large-scale storage system (https://eos.readthedocs.io, https://eos.web.cern.ch) and in particular for Sync&Share service called CERNBox (https://www.researchgate.net/publication/288020928_CERNBox_EOS_end-user_storage_for_science). > > All client file transfer requests (PUT and GET) are first passed to a metadata upstream server which performs an (internal) redirect to a (calculated) storage node (http upstream server). > > In case of PUT we do not want and need to send the body to the metadata server but only to the storage node after internal X-Accel redirect. Hence, we have made this patch (on 1.6.2): Consider using "proxy_pass_request_body off" instead, see http://nginx.org/r/proxy_pass_request_body. -- Maxim Dounin http://nginx.org/ From ru at nginx.com Mon Aug 8 08:18:24 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 08 Aug 2016 08:18:24 +0000 Subject: [nginx] Win32: added per-thread random seeding. Message-ID: details: http://hg.nginx.org/nginx/rev/09c918460cc6 branches: changeset: 6649:09c918460cc6 user: Ruslan Ermilov date: Thu Aug 04 01:15:41 2016 +0300 description: Win32: added per-thread random seeding. The change in b91bcba29351 was not enough to fix random() seeding. On Windows, the srand() seeds the PRNG only in the current thread, and worse, is not inherited from the calling thread. Due to this, worker threads were not properly seeded. Reported by Marc Bevand. diffstat: src/os/win32/ngx_process_cycle.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (12 lines): diff -r d43ee392e825 -r 09c918460cc6 src/os/win32/ngx_process_cycle.c --- a/src/os/win32/ngx_process_cycle.c Tue Jul 26 19:34:12 2016 +0300 +++ b/src/os/win32/ngx_process_cycle.c Thu Aug 04 01:15:41 2016 +0300 @@ -764,6 +764,8 @@ ngx_worker_thread(void *data) ngx_int_t n; ngx_cycle_t *cycle; + srand((ngx_pid << 16) ^ (unsigned) ngx_time()); + cycle = (ngx_cycle_t *) ngx_cycle; for (n = 0; cycle->modules[n]; n++) { From ru at nginx.com Mon Aug 8 08:18:27 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 08 Aug 2016 08:18:27 +0000 Subject: [nginx] Fixed undefined behavior when left shifting signed integer. Message-ID: details: http://hg.nginx.org/nginx/rev/1a1d55834b5c branches: changeset: 6650:1a1d55834b5c user: Ruslan Ermilov date: Thu Aug 04 23:42:00 2016 +0300 description: Fixed undefined behavior when left shifting signed integer. diffstat: src/os/unix/ngx_process_cycle.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 09c918460cc6 -r 1a1d55834b5c src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c Thu Aug 04 01:15:41 2016 +0300 +++ b/src/os/unix/ngx_process_cycle.c Thu Aug 04 23:42:00 2016 +0300 @@ -884,7 +884,7 @@ ngx_worker_process_init(ngx_cycle_t *cyc "sigprocmask() failed"); } - srandom((ngx_pid << 16) ^ ngx_time()); + srandom(((unsigned) ngx_pid << 16) ^ ngx_time()); /* * disable deleting previous events for the listening sockets because From ru at nginx.com Mon Aug 8 08:18:30 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 08 Aug 2016 08:18:30 +0000 Subject: [nginx] Always seed PRNG with PID, seconds, and milliseconds. Message-ID: details: http://hg.nginx.org/nginx/rev/7d4e33092e2a branches: changeset: 6651:7d4e33092e2a user: Ruslan Ermilov date: Thu Aug 04 23:43:10 2016 +0300 description: Always seed PRNG with PID, seconds, and milliseconds. diffstat: src/os/unix/ngx_posix_init.c | 6 ++++-- src/os/unix/ngx_process_cycle.c | 4 +++- src/os/win32/ngx_process_cycle.c | 4 +++- src/os/win32/ngx_win32_init.c | 16 +++++++++------- 4 files changed, 19 insertions(+), 11 deletions(-) diffs (93 lines): diff -r 1a1d55834b5c -r 7d4e33092e2a src/os/unix/ngx_posix_init.c --- a/src/os/unix/ngx_posix_init.c Thu Aug 04 23:42:00 2016 +0300 +++ b/src/os/unix/ngx_posix_init.c Thu Aug 04 23:43:10 2016 +0300 @@ -33,7 +33,8 @@ ngx_os_io_t ngx_os_io = { ngx_int_t ngx_os_init(ngx_log_t *log) { - ngx_uint_t n; + ngx_time_t *tp; + ngx_uint_t n; #if (NGX_HAVE_OS_SPECIFIC_INIT) if (ngx_os_specific_init(log) != NGX_OK) { @@ -76,7 +77,8 @@ ngx_os_init(ngx_log_t *log) ngx_inherited_nonblocking = 0; #endif - srandom(ngx_time()); + tp = ngx_timeofday(); + srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec); return NGX_OK; } diff -r 1a1d55834b5c -r 7d4e33092e2a src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c Thu Aug 04 23:42:00 2016 +0300 +++ b/src/os/unix/ngx_process_cycle.c Thu Aug 04 23:43:10 2016 +0300 @@ -785,6 +785,7 @@ ngx_worker_process_init(ngx_cycle_t *cyc { sigset_t set; ngx_int_t n; + ngx_time_t *tp; ngx_uint_t i; ngx_cpuset_t *cpu_affinity; struct rlimit rlmt; @@ -884,7 +885,8 @@ ngx_worker_process_init(ngx_cycle_t *cyc "sigprocmask() failed"); } - srandom(((unsigned) ngx_pid << 16) ^ ngx_time()); + tp = ngx_timeofday(); + srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec); /* * disable deleting previous events for the listening sockets because diff -r 1a1d55834b5c -r 7d4e33092e2a src/os/win32/ngx_process_cycle.c --- a/src/os/win32/ngx_process_cycle.c Thu Aug 04 23:42:00 2016 +0300 +++ b/src/os/win32/ngx_process_cycle.c Thu Aug 04 23:43:10 2016 +0300 @@ -762,9 +762,11 @@ static ngx_thread_value_t __stdcall ngx_worker_thread(void *data) { ngx_int_t n; + ngx_time_t *tp; ngx_cycle_t *cycle; - srand((ngx_pid << 16) ^ (unsigned) ngx_time()); + tp = ngx_timeofday(); + srand((ngx_pid << 16) ^ (unsigned) tp->sec ^ tp->msec); cycle = (ngx_cycle_t *) ngx_cycle; diff -r 1a1d55834b5c -r 7d4e33092e2a src/os/win32/ngx_win32_init.c --- a/src/os/win32/ngx_win32_init.c Thu Aug 04 23:42:00 2016 +0300 +++ b/src/os/win32/ngx_win32_init.c Thu Aug 04 23:43:10 2016 +0300 @@ -59,12 +59,13 @@ static GUID dx_guid = WSAID_DISCONNECTEX ngx_int_t ngx_os_init(ngx_log_t *log) { - DWORD bytes; - SOCKET s; - WSADATA wsd; - ngx_err_t err; - ngx_uint_t n; - SYSTEM_INFO si; + DWORD bytes; + SOCKET s; + WSADATA wsd; + ngx_err_t err; + ngx_time_t *tp; + ngx_uint_t n; + SYSTEM_INFO si; /* get Windows version */ @@ -237,7 +238,8 @@ ngx_os_init(ngx_log_t *log) ngx_sprintf((u_char *) ngx_unique, "%P%Z", ngx_pid); } - srand((ngx_pid << 16) ^ (unsigned) ngx_time()); + tp = ngx_timeofday(); + srand((ngx_pid << 16) ^ (unsigned) tp->sec ^ tp->msec); return NGX_OK; } From pluknet at nginx.com Mon Aug 8 10:49:22 2016 From: pluknet at nginx.com (Sergey Kandaurov) Date: Mon, 08 Aug 2016 10:49:22 +0000 Subject: [nginx] SSL: guarded SSL_R_NO_CIPHERS_PASSED not present in OpenSSL 1.1.0. Message-ID: details: http://hg.nginx.org/nginx/rev/1891b2892b68 branches: changeset: 6652:1891b2892b68 user: Sergey Kandaurov date: Mon Aug 08 13:44:49 2016 +0300 description: SSL: guarded SSL_R_NO_CIPHERS_PASSED not present in OpenSSL 1.1.0. It was removed in OpenSSL 1.1.0 Beta 3 (pre-release 6). It was not used since OpenSSL 1.0.1n and 1.0.2b. diffstat: src/event/ngx_event_openssl.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (13 lines): diff -r 7d4e33092e2a -r 1891b2892b68 src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Thu Aug 04 23:43:10 2016 +0300 +++ b/src/event/ngx_event_openssl.c Mon Aug 08 13:44:49 2016 +0300 @@ -2023,7 +2023,9 @@ ngx_ssl_connection_error(ngx_connection_ || n == SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST /* 151 */ || n == SSL_R_EXCESSIVE_MESSAGE_SIZE /* 152 */ || n == SSL_R_LENGTH_MISMATCH /* 159 */ +#ifdef SSL_R_NO_CIPHERS_PASSED || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ +#endif || n == SSL_R_NO_CIPHERS_SPECIFIED /* 183 */ || n == SSL_R_NO_COMPRESSION_SPECIFIED /* 187 */ || n == SSL_R_NO_SHARED_CIPHER /* 193 */ From igor at sysoev.ru Tue Aug 9 12:49:55 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 09 Aug 2016 12:49:55 +0000 Subject: [njs] Array iterator functions update. Message-ID: details: http://hg.nginx.org/njs/rev/2f40b153a7c1 branches: changeset: 144:2f40b153a7c1 user: Igor Sysoev date: Tue Aug 09 14:10:21 2016 +0300 description: Array iterator functions update. diffstat: njs/njs_array.c | 108 ++++++++++++++++++++++++++-------------------- njs/test/njs_unit_test.c | 8 +++ 2 files changed, 70 insertions(+), 46 deletions(-) diffs (290 lines): diff -r 73b0fd4c2ea6 -r 2f40b153a7c1 njs/njs_array.c --- a/njs/njs_array.c Thu Aug 04 16:59:15 2016 +0300 +++ b/njs/njs_array.c Tue Aug 09 14:10:21 2016 +0300 @@ -37,10 +37,15 @@ typedef struct { njs_continuation_t cont; u_char padding[NJS_CONTINUATION_SIZE]; } u; + /* + * This retval value must be aligned so the continuation is padded + * to aligned size. + */ njs_value_t retval; - int32_t index; + + uint32_t next_index; uint32_t length; -} njs_array_next_t; +} njs_array_iter_t; static njs_ret_t @@ -57,11 +62,11 @@ static nxt_noinline njs_ret_t njs_array_ static nxt_noinline njs_ret_t njs_array_prototype_every_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm, - njs_value_t * args, nxt_uint_t nargs); -static nxt_noinline nxt_int_t njs_array_iterator_next(njs_value_t *value, - nxt_uint_t n, nxt_uint_t length); + njs_value_t *args, nxt_uint_t nargs); +static nxt_noinline uint32_t njs_array_iterator_next(njs_array_t *array, + uint32_t n, uint32_t length); static nxt_noinline njs_ret_t njs_array_iterator_apply(njs_vm_t *vm, - njs_array_next_t *next, njs_value_t *args, nxt_uint_t nargs); + njs_array_iter_t *iter, njs_value_t *args, nxt_uint_t nargs); nxt_noinline njs_array_t * @@ -778,15 +783,15 @@ njs_array_prototype_for_each(njs_vm_t *v njs_index_t unused) { nxt_int_t ret; - njs_array_next_t *next; + njs_array_iter_t *iter; ret = njs_array_iterator_args(vm, args, nargs); if (nxt_slow_path(ret != NXT_OK)) { return ret; } - next = njs_continuation(vm->frame); - next->u.cont.function = njs_array_prototype_for_each_cont; + iter = njs_continuation(vm->frame); + iter->u.cont.function = njs_array_prototype_for_each_cont; return njs_array_prototype_for_each_cont(vm, args, nargs, unused); } @@ -796,16 +801,16 @@ static njs_ret_t njs_array_prototype_for_each_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - njs_array_next_t *next; + njs_array_iter_t *iter; - next = njs_continuation(vm->frame); + iter = njs_continuation(vm->frame); - if (next->index < 0) { + if (iter->next_index >= args[0].data.u.array->length) { vm->retval = njs_value_void; return NXT_OK; } - return njs_array_iterator_apply(vm, next, args, nargs); + return njs_array_iterator_apply(vm, iter, args, nargs); } @@ -814,16 +819,16 @@ njs_array_prototype_some(njs_vm_t *vm, n njs_index_t unused) { nxt_int_t ret; - njs_array_next_t *next; + njs_array_iter_t *iter; ret = njs_array_iterator_args(vm, args, nargs); if (nxt_slow_path(ret != NXT_OK)) { return ret; } - next = njs_continuation(vm->frame); - next->u.cont.function = njs_array_prototype_some_cont; - next->retval.data.truth = 0; + iter = njs_continuation(vm->frame); + iter->u.cont.function = njs_array_prototype_some_cont; + iter->retval.data.truth = 0; return njs_array_prototype_some_cont(vm, args, nargs, unused); } @@ -833,19 +838,19 @@ static njs_ret_t njs_array_prototype_some_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - njs_array_next_t *next; + njs_array_iter_t *iter; const njs_value_t *retval; - next = njs_continuation(vm->frame); + iter = njs_continuation(vm->frame); - if (njs_is_true(&next->retval)) { + if (njs_is_true(&iter->retval)) { retval = &njs_value_true; - } else if (next->index < 0) { + } else if (iter->next_index >= args[0].data.u.array->length) { retval = &njs_value_false; } else { - return njs_array_iterator_apply(vm, next, args, nargs); + return njs_array_iterator_apply(vm, iter, args, nargs); } vm->retval = *retval; @@ -859,16 +864,16 @@ njs_array_prototype_every(njs_vm_t *vm, njs_index_t unused) { nxt_int_t ret; - njs_array_next_t *next; + njs_array_iter_t *iter; ret = njs_array_iterator_args(vm, args, nargs); if (nxt_slow_path(ret != NXT_OK)) { return ret; } - next = njs_continuation(vm->frame); - next->u.cont.function = njs_array_prototype_every_cont; - next->retval.data.truth = 1; + iter = njs_continuation(vm->frame); + iter->u.cont.function = njs_array_prototype_every_cont; + iter->retval.data.truth = 1; return njs_array_prototype_every_cont(vm, args, nargs, unused); } @@ -878,19 +883,19 @@ static njs_ret_t njs_array_prototype_every_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - njs_array_next_t *next; + njs_array_iter_t *iter; const njs_value_t *retval; - next = njs_continuation(vm->frame); + iter = njs_continuation(vm->frame); - if (!njs_is_true(&next->retval)) { + if (!njs_is_true(&iter->retval)) { retval = &njs_value_false; - } else if (next->index < 0) { + } else if (iter->next_index >= args[0].data.u.array->length) { retval = &njs_value_true; } else { - return njs_array_iterator_apply(vm, next, args, nargs); + return njs_array_iterator_apply(vm, iter, args, nargs); } vm->retval = *retval; @@ -900,17 +905,17 @@ njs_array_prototype_every_cont(njs_vm_t static nxt_noinline njs_ret_t -njs_array_iterator_args(njs_vm_t *vm, njs_value_t * args, nxt_uint_t nargs) +njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs) { njs_array_t *array; - njs_array_next_t *next; + njs_array_iter_t *iter; if (nargs > 1 && njs_is_array(&args[0]) && njs_is_function(&args[1])) { array = args[0].data.u.array; - next = njs_continuation(vm->frame); - next->length = array->length; - next->index = njs_array_iterator_next(array->start, 0, array->length); + iter = njs_continuation(vm->frame); + iter->length = array->length; + iter->next_index = njs_array_iterator_next(array, 0, array->length); return NXT_OK; } @@ -921,11 +926,13 @@ njs_array_iterator_args(njs_vm_t *vm, nj } -static nxt_noinline nxt_int_t -njs_array_iterator_next(njs_value_t *value, nxt_uint_t n, nxt_uint_t length) +static nxt_noinline uint32_t +njs_array_iterator_next(njs_array_t *array, uint32_t n, uint32_t length) { + length = nxt_min(length, array->length); + while (n < length) { - if (njs_is_valid(&value[n])) { + if (njs_is_valid(&array->start[n])) { return n; } @@ -937,7 +944,7 @@ njs_array_iterator_next(njs_value_t *val static nxt_noinline njs_ret_t -njs_array_iterator_apply(njs_vm_t *vm, njs_array_next_t *next, +njs_array_iterator_apply(njs_vm_t *vm, njs_array_iter_t *iter, njs_value_t *args, nxt_uint_t nargs) { nxt_int_t n; @@ -950,16 +957,25 @@ njs_array_iterator_apply(njs_vm_t *vm, n */ arguments[0] = (nargs > 2) ? args[2] : *(njs_value_t *) &njs_value_void; /* GC: array elt, array */ + + /* + * All array iterators functions call njs_array_iterator_args() + * function which set a correct iter->next_index value. A large + * value of iter->next_index must be checked before calling + * njs_array_iterator_apply(). + */ array = args[0].data.u.array; - n = next->index; + n = iter->next_index; arguments[1] = array->start[n]; + njs_number_set(&arguments[2], n); + arguments[3] = args[0]; - next->index = njs_array_iterator_next(array->start, ++n, next->length); + iter->next_index = njs_array_iterator_next(array, n + 1, iter->length); return njs_function_apply(vm, args[1].data.u.function, arguments, 4, - (njs_index_t) &next->retval); + (njs_index_t) &iter->retval); } @@ -1034,21 +1050,21 @@ static const njs_object_prop_t njs_arra .type = NJS_METHOD, .name = njs_string("forEach"), .value = njs_native_function(njs_array_prototype_for_each, - njs_continuation_size(njs_array_next_t), 0), + njs_continuation_size(njs_array_iter_t), 0), }, { .type = NJS_METHOD, .name = njs_string("some"), .value = njs_native_function(njs_array_prototype_some, - njs_continuation_size(njs_array_next_t), 0), + njs_continuation_size(njs_array_iter_t), 0), }, { .type = NJS_METHOD, .name = njs_string("every"), .value = njs_native_function(njs_array_prototype_every, - njs_continuation_size(njs_array_next_t), 0), + njs_continuation_size(njs_array_iter_t), 0), }, }; diff -r 73b0fd4c2ea6 -r 2f40b153a7c1 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Aug 04 16:59:15 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Aug 09 14:10:21 2016 +0300 @@ -2293,6 +2293,14 @@ static njs_unit_test_t njs_test[] = "s.sum"), nxt_string("6") }, + { nxt_string("var a = []; var c = 0;" + "a.forEach(function(v, i, a) { c++ }); c"), + nxt_string("0") }, + + { nxt_string("var a = [,,,,]; var c = 0;" + "a.forEach(function(v, i, a) { c++ }); c"), + nxt_string("0") }, + { nxt_string("var a = [];" "a.some(function(v, i, a) { return v > 1 })"), nxt_string("false") }, From igor at sysoev.ru Tue Aug 9 12:49:57 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 09 Aug 2016 12:49:57 +0000 Subject: [njs] Array.filter() function. Message-ID: details: http://hg.nginx.org/njs/rev/6e212d387b88 branches: changeset: 145:6e212d387b88 user: Igor Sysoev date: Tue Aug 09 14:10:29 2016 +0300 description: Array.filter() function. diffstat: njs/njs_array.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ njs/test/njs_unit_test.c | 32 ++++++++++++++++++ 2 files changed, 116 insertions(+), 0 deletions(-) diffs (171 lines): diff -r 2f40b153a7c1 -r 6e212d387b88 njs/njs_array.c --- a/njs/njs_array.c Tue Aug 09 14:10:21 2016 +0300 +++ b/njs/njs_array.c Tue Aug 09 14:10:29 2016 +0300 @@ -43,6 +43,8 @@ typedef struct { */ njs_value_t retval; + njs_value_t value; + njs_array_t *array; uint32_t next_index; uint32_t length; } njs_array_iter_t; @@ -61,6 +63,8 @@ static nxt_noinline njs_ret_t njs_array_ njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline njs_ret_t njs_array_prototype_every_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_array_prototype_filter_cont(njs_vm_t *vm, + njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs); static nxt_noinline uint32_t njs_array_iterator_next(njs_array_t *array, @@ -100,6 +104,25 @@ njs_array_alloc(njs_vm_t *vm, uint32_t l } +static njs_ret_t +njs_array_add(njs_vm_t *vm, njs_array_t *array, njs_value_t *value) +{ + njs_ret_t ret; + + if (array->size == array->length) { + ret = njs_array_realloc(vm, array, 0, array->size + 1); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + } + + /* GC: retain value. */ + array->start[array->length++] = *value; + + return NXT_OK; +} + + njs_ret_t njs_array_string_add(njs_vm_t *vm, njs_array_t *array, u_char *start, size_t size, size_t length) @@ -904,6 +927,59 @@ njs_array_prototype_every_cont(njs_vm_t } +static njs_ret_t +njs_array_prototype_filter(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + nxt_int_t ret; + njs_array_iter_t *iter; + + ret = njs_array_iterator_args(vm, args, nargs); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + iter = njs_continuation(vm->frame); + iter->u.cont.function = njs_array_prototype_filter_cont; + iter->retval.data.truth = 0; + + iter->array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); + if (nxt_slow_path(iter->array == NULL)) { + return NXT_ERROR; + } + + return njs_array_prototype_filter_cont(vm, args, nargs, unused); +} + + +static njs_ret_t +njs_array_prototype_filter_cont(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + nxt_int_t ret; + njs_array_iter_t *iter; + + iter = njs_continuation(vm->frame); + + if (njs_is_true(&iter->retval)) { + ret = njs_array_add(vm, iter->array, &iter->value); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + } + + if (iter->next_index >= args[0].data.u.array->length) { + vm->retval.data.u.array = iter->array; + vm->retval.type = NJS_ARRAY; + vm->retval.data.truth = 1; + + return NXT_OK; + } + + return njs_array_iterator_apply(vm, iter, args, nargs); +} + + static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs) { @@ -966,6 +1042,7 @@ njs_array_iterator_apply(njs_vm_t *vm, n */ array = args[0].data.u.array; n = iter->next_index; + iter->value = array->start[n]; arguments[1] = array->start[n]; njs_number_set(&arguments[2], n); @@ -1066,6 +1143,13 @@ static const njs_object_prop_t njs_arra .value = njs_native_function(njs_array_prototype_every, njs_continuation_size(njs_array_iter_t), 0), }, + + { + .type = NJS_METHOD, + .name = njs_string("filter"), + .value = njs_native_function(njs_array_prototype_filter, + njs_continuation_size(njs_array_iter_t), 0), + }, }; diff -r 2f40b153a7c1 -r 6e212d387b88 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 09 14:10:21 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Aug 09 14:10:29 2016 +0300 @@ -2333,6 +2333,38 @@ static njs_unit_test_t njs_test[] = "a.every(function(v, i, a) { return v > 0 })"), nxt_string("true") }, + { nxt_string("var a = [];" + "a.filter(function(v, i, a) { return v > 1 })"), + nxt_string("") }, + + { nxt_string("var a = [1,2,3,-1,5];" + "a.filter(function(v, i, a) { return v > 1 })"), + nxt_string("2,3,5") }, + + { nxt_string("var a = [1,2,3,4,5,6,7,8];" + "a.filter(function(v, i, a) { a.pop(); return v > 1 })"), + nxt_string("2,3,4") }, + + { nxt_string("var a = [1,2,3,4,5,6,7,8];" + "a.filter(function(v, i, a) { a.shift(); return v > 1 })"), + nxt_string("3,5,7") }, + + { nxt_string("var a = [1,2,3,4,5,6,7];" + "a.filter(function(v, i, a) { a.pop(); return v > 1 })"), + nxt_string("2,3,4") }, + + { nxt_string("var a = [1,2,3,4,5,6,7];" + "a.filter(function(v, i, a) { a.shift(); return v > 1 })"), + nxt_string("3,5,7") }, + + { nxt_string("var a = [1,2,3,4,5,6,7];" + "a.filter(function(v, i, a) { a[i] = v + 1; return true })"), + nxt_string("1,2,3,4,5,6,7") }, + + { nxt_string("var a = [1,2,3,4,5,6,7];" + "a.filter(function(v, i, a) { a[i+1] = v+10; return true })"), + nxt_string("1,11,21,31,41,51,61") }, + /* Strings. */ { nxt_string("var a = '0123456789' + '012345'" From igor at sysoev.ru Tue Aug 9 12:49:58 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 09 Aug 2016 12:49:58 +0000 Subject: [njs] Array.map() function. Message-ID: details: http://hg.nginx.org/njs/rev/43b3a67ee1f1 branches: changeset: 146:43b3a67ee1f1 user: Igor Sysoev date: Tue Aug 09 14:10:31 2016 +0300 description: Array.map() function. diffstat: njs/njs_array.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ njs/test/njs_unit_test.c | 20 ++++++++++++ 2 files changed, 94 insertions(+), 0 deletions(-) diffs (142 lines): diff -r 6e212d387b88 -r 43b3a67ee1f1 njs/njs_array.c --- a/njs/njs_array.c Tue Aug 09 14:10:29 2016 +0300 +++ b/njs/njs_array.c Tue Aug 09 14:10:31 2016 +0300 @@ -47,6 +47,7 @@ typedef struct { njs_array_t *array; uint32_t next_index; uint32_t length; + uint32_t index; } njs_array_iter_t; @@ -65,6 +66,8 @@ static nxt_noinline njs_ret_t njs_array_ njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static njs_ret_t njs_array_prototype_filter_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_array_prototype_map_cont(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs); static nxt_noinline uint32_t njs_array_iterator_next(njs_array_t *array, @@ -980,6 +983,69 @@ njs_array_prototype_filter_cont(njs_vm_t } +static njs_ret_t +njs_array_prototype_map(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + size_t size; + nxt_int_t ret; + njs_value_t *value; + njs_array_t *array; + njs_array_iter_t *iter; + + ret = njs_array_iterator_args(vm, args, nargs); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + iter = njs_continuation(vm->frame); + iter->u.cont.function = njs_array_prototype_map_cont; + njs_set_invalid(&iter->retval); + + array = args[0].data.u.array; + + iter->array = njs_array_alloc(vm, array->length, 0); + if (nxt_slow_path(iter->array == NULL)) { + return NXT_ERROR; + } + + value = iter->array->start; + size = array->length; + + while (size != 0) { + njs_set_invalid(value); + value++; + size--; + } + + return njs_array_prototype_map_cont(vm, args, nargs, unused); +} + + +static njs_ret_t +njs_array_prototype_map_cont(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + njs_array_iter_t *iter; + + iter = njs_continuation(vm->frame); + + if (njs_is_valid(&iter->retval)) { + iter->array->start[iter->index] = iter->retval; + } + + if (iter->next_index >= args[0].data.u.array->length) { + vm->retval.data.u.array = iter->array; + vm->retval.type = NJS_ARRAY; + vm->retval.data.truth = 1; + + return NXT_OK; + } + + return njs_array_iterator_apply(vm, iter, args, nargs); +} + + static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs) { @@ -1042,6 +1108,7 @@ njs_array_iterator_apply(njs_vm_t *vm, n */ array = args[0].data.u.array; n = iter->next_index; + iter->index = n; iter->value = array->start[n]; arguments[1] = array->start[n]; @@ -1150,6 +1217,13 @@ static const njs_object_prop_t njs_arra .value = njs_native_function(njs_array_prototype_filter, njs_continuation_size(njs_array_iter_t), 0), }, + + { + .type = NJS_METHOD, + .name = njs_string("map"), + .value = njs_native_function(njs_array_prototype_map, + njs_continuation_size(njs_array_iter_t), 0), + }, }; diff -r 6e212d387b88 -r 43b3a67ee1f1 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 09 14:10:29 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Aug 09 14:10:31 2016 +0300 @@ -2365,6 +2365,26 @@ static njs_unit_test_t njs_test[] = "a.filter(function(v, i, a) { a[i+1] = v+10; return true })"), nxt_string("1,11,21,31,41,51,61") }, + { nxt_string("var a = [];" + "a.map(function(v, i, a) { return v + 1 })"), + nxt_string("") }, + + { nxt_string("var a = [,,,];" + "a.map(function(v, i, a) { return v + 1 })"), + nxt_string(",,") }, + + { nxt_string("var a = [,,,1];" + "a.map(function(v, i, a) { return v + 1 })"), + nxt_string(",,,2") }, + + { nxt_string("var a = [1,2,3];" + "a.map(function(v, i, a) { return v + 1 })"), + nxt_string("2,3,4") }, + + { nxt_string("var a = [1,2,3,4,5,6];" + "a.map(function(v, i, a) { a.pop(); return v + 1 })"), + nxt_string("2,3,4,,,") }, + /* Strings. */ { nxt_string("var a = '0123456789' + '012345'" From igor at sysoev.ru Tue Aug 9 12:50:00 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 09 Aug 2016 12:50:00 +0000 Subject: [njs] Array.reduce() function. Message-ID: details: http://hg.nginx.org/njs/rev/5bd9c6bea8a6 branches: changeset: 147:5bd9c6bea8a6 user: Igor Sysoev date: Tue Aug 09 14:10:32 2016 +0300 description: Array.reduce() function. diffstat: njs/njs_array.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++ njs/test/njs_unit_test.c | 36 +++++++++++++++++++ 2 files changed, 126 insertions(+), 0 deletions(-) diffs (160 lines): diff -r 43b3a67ee1f1 -r 5bd9c6bea8a6 njs/njs_array.c --- a/njs/njs_array.c Tue Aug 09 14:10:31 2016 +0300 +++ b/njs/njs_array.c Tue Aug 09 14:10:32 2016 +0300 @@ -68,6 +68,8 @@ static njs_ret_t njs_array_prototype_fil njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static njs_ret_t njs_array_prototype_map_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_array_prototype_reduce_cont(njs_vm_t *vm, + njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs); static nxt_noinline uint32_t njs_array_iterator_next(njs_array_t *array, @@ -1046,6 +1048,87 @@ njs_array_prototype_map_cont(njs_vm_t *v } +static njs_ret_t +njs_array_prototype_reduce(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + uint32_t n; + nxt_int_t ret; + njs_array_t *array; + njs_array_iter_t *iter; + + ret = njs_array_iterator_args(vm, args, nargs); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + + iter = njs_continuation(vm->frame); + iter->u.cont.function = njs_array_prototype_reduce_cont; + + if (nargs > 2) { + iter->retval = args[2]; + + } else { + array = args[0].data.u.array; + n = iter->next_index; + + if (n >= array->length) { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + + iter->retval = array->start[n]; + + iter->next_index = njs_array_iterator_next(array, n + 1, array->length); + } + + return njs_array_prototype_reduce_cont(vm, args, nargs, unused); +} + + +static njs_ret_t +njs_array_prototype_reduce_cont(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + nxt_int_t n; + njs_array_t *array; + njs_value_t arguments[5]; + njs_array_iter_t *iter; + + iter = njs_continuation(vm->frame); + + if (iter->next_index >= args[0].data.u.array->length) { + vm->retval = iter->retval; + return NXT_OK; + } + + arguments[0] = njs_value_void; + + /* GC: array elt, array */ + arguments[1] = iter->retval; + + /* + * All array iterators functions call njs_array_iterator_args() + * function which set a correct iter->next_index value. A large + * value of iter->next_index must be checked before calling + * njs_array_iterator_apply(). + */ + array = args[0].data.u.array; + n = iter->next_index; + + arguments[2] = array->start[n]; + + njs_number_set(&arguments[3], n); + + arguments[4] = args[0]; + + iter->next_index = njs_array_iterator_next(array, n + 1, iter->length); + + return njs_function_apply(vm, args[1].data.u.function, arguments, 5, + (njs_index_t) &iter->retval); +} + + static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs) { @@ -1224,6 +1307,13 @@ static const njs_object_prop_t njs_arra .value = njs_native_function(njs_array_prototype_map, njs_continuation_size(njs_array_iter_t), 0), }, + + { + .type = NJS_METHOD, + .name = njs_string("reduce"), + .value = njs_native_function(njs_array_prototype_reduce, + njs_continuation_size(njs_array_iter_t), 0), + }, }; diff -r 43b3a67ee1f1 -r 5bd9c6bea8a6 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 09 14:10:31 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Aug 09 14:10:32 2016 +0300 @@ -2385,6 +2385,42 @@ static njs_unit_test_t njs_test[] = "a.map(function(v, i, a) { a.pop(); return v + 1 })"), nxt_string("2,3,4,,,") }, + { nxt_string("var a = [];" + "a.reduce(function(p, v, i, a) { return p + v })"), + nxt_string("TypeError") }, + + { nxt_string("var a = [];" + "a.reduce(function(p, v, i, a) { return p + v }, 10)"), + nxt_string("10") }, + + { nxt_string("var a = [,,];" + "a.reduce(function(p, v, i, a) { return p + v })"), + nxt_string("TypeError") }, + + { nxt_string("var a = [,,];" + "a.reduce(function(p, v, i, a) { return p + v }, 10)"), + nxt_string("10") }, + + { nxt_string("var a = [1];" + "a.reduce(function(p, v, i, a) { return p + v })"), + nxt_string("1") }, + + { nxt_string("var a = [1];" + "a.reduce(function(p, v, i, a) { return p + v }, 10)"), + nxt_string("11") }, + + { nxt_string("var a = [1,2,3];" + "a.reduce(function(p, v, i, a) { return p + v })"), + nxt_string("6") }, + + { nxt_string("var a = [1,2,3];" + "a.reduce(function(p, v, i, a) { return p + v }, 10)"), + nxt_string("16") }, + + { nxt_string("[[0, 1], [2, 3], [4, 5]].reduce(function(a, b)" + " { return a.concat(b) }, [])"), + nxt_string("0,1,2,3,4,5") }, + /* Strings. */ { nxt_string("var a = '0123456789' + '012345'" From igor at sysoev.ru Tue Aug 9 12:50:01 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 09 Aug 2016 12:50:01 +0000 Subject: [njs] Array.reduceRight() function. Message-ID: details: http://hg.nginx.org/njs/rev/f23c723cf833 branches: changeset: 148:f23c723cf833 user: Igor Sysoev date: Tue Aug 09 14:10:33 2016 +0300 description: Array.reduceRight() function. diffstat: njs/njs_array.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++ njs/test/njs_unit_test.c | 42 ++++++++++++++++++ 2 files changed, 147 insertions(+), 0 deletions(-) diffs (187 lines): diff -r 5bd9c6bea8a6 -r f23c723cf833 njs/njs_array.c --- a/njs/njs_array.c Tue Aug 09 14:10:32 2016 +0300 +++ b/njs/njs_array.c Tue Aug 09 14:10:33 2016 +0300 @@ -70,12 +70,15 @@ static njs_ret_t njs_array_prototype_map nxt_uint_t nargs, njs_index_t unused); static njs_ret_t njs_array_prototype_reduce_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_array_prototype_reduce_right_cont(njs_vm_t *vm, + njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs); static nxt_noinline uint32_t njs_array_iterator_next(njs_array_t *array, uint32_t n, uint32_t length); static nxt_noinline njs_ret_t njs_array_iterator_apply(njs_vm_t *vm, njs_array_iter_t *iter, njs_value_t *args, nxt_uint_t nargs); +static uint32_t njs_array_reduce_right_next(njs_array_t *array, int32_t n); nxt_noinline njs_array_t * @@ -1206,6 +1209,101 @@ njs_array_iterator_apply(njs_vm_t *vm, n } +static njs_ret_t +njs_array_prototype_reduce_right(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + int32_t n; + njs_array_t *array; + njs_array_iter_t *iter; + + if (nargs > 1 && njs_is_array(&args[0]) && njs_is_function(&args[1])) { + array = args[0].data.u.array; + iter = njs_continuation(vm->frame); + iter->next_index = njs_array_reduce_right_next(array, array->length); + + } else { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + + iter = njs_continuation(vm->frame); + iter->u.cont.function = njs_array_prototype_reduce_right_cont; + + if (nargs > 2) { + iter->retval = args[2]; + + } else { + array = args[0].data.u.array; + n = iter->next_index; + + if (n < 0) { + vm->exception = &njs_exception_type_error; + return NXT_ERROR; + } + + iter->retval = array->start[n]; + + iter->next_index = njs_array_reduce_right_next(array, n); + } + + return njs_array_prototype_reduce_right_cont(vm, args, nargs, unused); +} + + +static njs_ret_t +njs_array_prototype_reduce_right_cont(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + nxt_int_t n; + njs_array_t *array; + njs_value_t arguments[5]; + njs_array_iter_t *iter; + + iter = njs_continuation(vm->frame); + + if ((int32_t) iter->next_index < 0) { + vm->retval = iter->retval; + return NXT_OK; + } + + arguments[0] = njs_value_void; + + /* GC: array elt, array */ + arguments[1] = iter->retval; + + array = args[0].data.u.array; + n = iter->next_index; + arguments[2] = array->start[n]; + + njs_number_set(&arguments[3], n); + + arguments[4] = args[0]; + + iter->next_index = njs_array_reduce_right_next(array, n); + + return njs_function_apply(vm, args[1].data.u.function, arguments, 5, + (njs_index_t) &iter->retval); +} + + +static nxt_noinline uint32_t +njs_array_reduce_right_next(njs_array_t *array, int32_t n) +{ + n = nxt_min(n, (int32_t) array->length) - 1; + + while (n >= 0) { + if (njs_is_valid(&array->start[n])) { + return n; + } + + n--; + } + + return n; +} + + static const njs_object_prop_t njs_array_prototype_properties[] = { { @@ -1314,6 +1412,13 @@ static const njs_object_prop_t njs_arra .value = njs_native_function(njs_array_prototype_reduce, njs_continuation_size(njs_array_iter_t), 0), }, + + { + .type = NJS_METHOD, + .name = njs_string("reduceRight"), + .value = njs_native_function(njs_array_prototype_reduce_right, + njs_continuation_size(njs_array_iter_t), 0), + }, }; diff -r 5bd9c6bea8a6 -r f23c723cf833 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 09 14:10:32 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Aug 09 14:10:33 2016 +0300 @@ -2421,6 +2421,48 @@ static njs_unit_test_t njs_test[] = " { return a.concat(b) }, [])"), nxt_string("0,1,2,3,4,5") }, + { nxt_string("var a = [];" + "a.reduceRight(function(p, v, i, a) { return p + v })"), + nxt_string("TypeError") }, + + { nxt_string("var a = [];" + "a.reduceRight(function(p, v, i, a) { return p + v }, 10)"), + nxt_string("10") }, + + { nxt_string("var a = [,,];" + "a.reduceRight(function(p, v, i, a) { return p + v })"), + nxt_string("TypeError") }, + + { nxt_string("var a = [,,];" + "a.reduceRight(function(p, v, i, a) { return p + v }, 10)"), + nxt_string("10") }, + + { nxt_string("var a = [1];" + "a.reduceRight(function(p, v, i, a) { return p + v })"), + nxt_string("1") }, + + { nxt_string("var a = [1];" + "a.reduceRight(function(p, v, i, a) { return p + v }, 10)"), + nxt_string("11") }, + + { nxt_string("var a = [1,2,3];" + "a.reduceRight(function(p, v, i, a) { return p + v })"), + nxt_string("6") }, + + { nxt_string("var a = [1,2,3];" + "a.reduceRight(function(p, v, i, a) { return p + v }, 10)"), + nxt_string("16") }, + + { nxt_string("var a = [1,2,3];" + "a.reduceRight(function(p, v, i, a)" + " { a.shift(); return p + v })"), + nxt_string("7") }, + + { nxt_string("var a = [1,2,3];" + "a.reduceRight(function(p, v, i, a)" + " { a.shift(); return p + v }, 10)"), + nxt_string("19") }, + /* Strings. */ { nxt_string("var a = '0123456789' + '012345'" From piotrsikora at google.com Tue Aug 9 19:51:38 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Tue, 9 Aug 2016 12:51:38 -0700 Subject: [PATCH] SSL: fix order of checks during SSL certificate verification In-Reply-To: <20160804035352.GY57459@mdounin.ru> References: <20160804035352.GY57459@mdounin.ru> Message-ID: Hey Maxim, > This behaviour is explicitly documented for years. The BUGS > section outlines that the API is not intuitive and requires use of > SSL_get_peer_certificate() in addition ot SSL_get_verify_result(). Exactly. > And this is what nginx does. I don't see compelling reasons to > change the order of the calls here. No, it doesn't, which is the reason for this patch in the first place... NGINX uses the result of SSL_get_verify_result() without calling SSL_get_peer_certificate(), which is what the BUGS section requires. Also, this breaks implementations (i.e. BoringSSL) that are a bit more strict and don't use X509_V_OK as the initial value. > This looks like a separate patch, or two patches. Fair enough. > Though I'm > somewhat sceptical about the use of "upstream" and "client" in > error messages introduced, this looks like a wrong approach for a > generic SSL code. What you would prefer, then? 1. Returning error string back the the caller? 2. Returning "rc" back to the caller and adding another function to abstract X509_verify_cert_error_string()? 3. Adding the caller string ("client" or "upstream") as the parameter and writing error from within the function? > As well as magic values in the "verify" argument, Good call. > and the change of the ngx_ssl_check_host() semantics. You mean the introduction of error logs? If so, then it seems that returning "rc" and adding another function to retrieve the error string would be the best way to keep the behavior as close to the existing one as possible. Best regards, Piotr Sikora From whissi at gentoo.org Tue Aug 9 22:11:25 2016 From: whissi at gentoo.org (Thomas Deutschmann) Date: Wed, 10 Aug 2016 00:11:25 +0200 Subject: Should nginx' default shipped fastcgi_param file updated to mitigate httpoxy? In-Reply-To: <20160719141655.GK57459@mdounin.ru> References: <20160719141655.GK57459@mdounin.ru> Message-ID: <482a256b-d91f-de79-cee1-f7cb16c25fdc@gentoo.org> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 Hi, thank you for your response. For the sake of completeness: For Gentoo we decided to patch the default configuration, see [1]. [1] https://gitweb.gentoo.org/repo/gentoo.git/tree/www-servers/nginx/files/nginx-httpoxy-mitigation.patch?id=c4b897dc39a939d0f409e1bcd9f6bd9c75679cf9 - -- Regards, Thomas -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.1 iQJ8BAEBCgBmBQJXqlTTXxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25zLm9w ZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXQzM0M1ODQ4MkM0MDIyOTJEMkUzQzVDMDY5 NzA5RjkwQzNDOTZGRkM4AAoJEJcJ+Qw8lv/IrwsP/RDIf+O4RzjTaAPxcj4yiM8i 34OfVu5stvsWpkk5kMgaV2Pvoj4JZxf3fs+J/A/+iVDOcXW+bFlA8VVrgQA1CnZf PJAF3fYEn8KCberllHBYxVBRySsRKc8WdBrAwVYGnXpcT9+GA18tC3JbmnZM+ZLJ Y07MZdDjwyyFEMH2IlPM7ltaY7xTVSG6JigYS/m0jZ6alURE+v7rdSdvMlHh4mmG cuBOFgYRA1CKuHWXJPYAS+LW57NImbolPiLpOl6CuzsOqfs/cTwzlgOIMRAiWnob G5S739sz/nyeSqXnt6FLS1Rb+B3emEFYnnr2cjxTIGRiVf9Wf8AN4U7s7YkxQsE1 T9L29k5TgWuFhk+EEA7QtZ1Jn+Uw0NLoSauNyrWYLL/QdI0odTEroi86vdk9Ut6i tVmzZibCYOnXsC8zpZ781NroAgch/F3G8zeGFdvJkBKHEfD8vKTQW2Lm5QlNr/O4 7ZTRjm9hmPuBuF4QXOfo5GVoXbuI25bfNYoLEtQGtudOnWHN8+HnsPEDagD8N6iJ 628YlqY8C5P3v4KfcfwD138bMIrf8oY68bNFq1FRlakiNSJtiQ+U6LKrA5hXRx2R 47sxYE6ycx+3ybzsCyn13qiKxvGSddBOoCjMKOlEUJOJ/pRa3OSrWpWXHAcSc0A+ vNaEfk1LiyJdG/yUlnB6 =G2Ht -----END PGP SIGNATURE----- From Jakub.Moscicki at cern.ch Wed Aug 10 08:58:31 2016 From: Jakub.Moscicki at cern.ch (Jakub Moscicki) Date: Wed, 10 Aug 2016 08:58:31 +0000 Subject: [PATCH] optionally avoid sending body of PUT request before X-Accel redirect In-Reply-To: <20160806143948.GF57459@mdounin.ru> References: <20160806143948.GF57459@mdounin.ru> Message-ID: <14A4F1C8-26D5-44CC-BA16-7ED354B51BD3@cern.ch> Hello, Thank you for your suggestion. Experimenting I have stumbled on the config question: What is the easiest way of *conditionally* adding "proxy_pass_request_body off? to a location? If method is PUT then I want to set: "proxy_pass_request_body off?. I have quite a complex location block which I would like to avoid to copy/paste in my configuration. I would like to do something like this: location ~/my-uri(*.) { if ($request_method = PUT) { proxy_pass_request_body off; } ? complex and long location handler ... } The only way I imagined so far is with conditional rewrite in front of my original location - but that complicates my config file a lot with huge copy/paste blocks. Something like that: location ~ ^my-uri(*.) { if ($request_method = PUT) { rewrite ^ /internal_location_put$1; } rewrite ^ /internal_location_other$1; } location ~ ^/internal_location_put(.*) { proxy_pass_request_body off; ? complex and long location handler ... } location ~ ^/internal_location_other(.*) { ? complex and long location handler ... } Thank you, kuba -- > On 06 Aug 2016, at 16:39, Maxim Dounin wrote: > > Hello! > > On Fri, Aug 05, 2016 at 10:14:36AM +0000, Jakub Moscicki wrote: > >> Hello, >> >> Would this kind of patch make sense to include in nginx upstream? If yes, then we would prepare it properly as an option (similar to proxy_pass_request_body). >> >> Use-case: at CERN we use nginx as a reverse proxy for Webdav/HTTP access to our large-scale storage system (https://eos.readthedocs.io, https://eos.web.cern.ch) and in particular for Sync&Share service called CERNBox (https://www.researchgate.net/publication/288020928_CERNBox_EOS_end-user_storage_for_science). >> >> All client file transfer requests (PUT and GET) are first passed to a metadata upstream server which performs an (internal) redirect to a (calculated) storage node (http upstream server). >> >> In case of PUT we do not want and need to send the body to the metadata server but only to the storage node after internal X-Accel redirect. Hence, we have made this patch (on 1.6.2): > > Consider using "proxy_pass_request_body off" instead, see > http://nginx.org/r/proxy_pass_request_body. > > -- > Maxim Dounin > http://nginx.org/ > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel From vbart at nginx.com Wed Aug 10 09:00:49 2016 From: vbart at nginx.com (Valentin V. Bartenev) Date: Wed, 10 Aug 2016 12:00:49 +0300 Subject: Should nginx' default shipped fastcgi_param file updated to mitigate httpoxy? In-Reply-To: <482a256b-d91f-de79-cee1-f7cb16c25fdc@gentoo.org> References: <20160719141655.GK57459@mdounin.ru> <482a256b-d91f-de79-cee1-f7cb16c25fdc@gentoo.org> Message-ID: <4747966.JonH64itGs@vbart-workstation> On Wednesday 10 August 2016 00:11:25 Thomas Deutschmann wrote: > Hi, > > thank you for your response. > > For the sake of completeness: For Gentoo we decided to patch the > default configuration, see [1]. > [..] Why have you decided to patch "fastcgi_params" and left untouched other similar protocols like scgi, uwsgi? wbr, Valentin V. Bartenev From rudolfs.bundulis at gmail.com Wed Aug 10 09:09:54 2016 From: rudolfs.bundulis at gmail.com (=?UTF-8?Q?R=C5=ABdolfs_Bundulis?=) Date: Wed, 10 Aug 2016 12:09:54 +0300 Subject: Dynamic module and obtaining http core module configuration Message-ID: Hi, I am trying to make a dynamic nginx module. After reading all the tutorials and stuff available I set up a working minimal sample and started hooking up my http handlers. The question that arose is, in the static modules the http module configuration is retrieved like this (in a lets say postconfiguration handler): static ngx_int_t postconfiguration_handler(ngx_conf_t* cf) { ngx_http_core_main_conf_t* nginx_http_configuration = reinterpret_cast(ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module)); ... If I'm not overlooking something this will not work (and in my case does not) with a dynamic module the ngx_http_core_module.ctx_index is not initialized since the initialized version of ngx_http_core_module lives inside nginx.exe (where it is set by ngx_count_modules) and my dll does not see that. If could run through the module list and find what I need, but I just wanted to know if there is a better solution already in place. Best Regards, Rudolfs Bundulis -------------- next part -------------- An HTML attachment was scrubbed... URL: From doppelbauer at gmx.net Wed Aug 10 12:30:48 2016 From: doppelbauer at gmx.net (Markus Doppelbauer) Date: Wed, 10 Aug 2016 14:30:48 +0200 Subject: Video streaming feature request In-Reply-To: References: <1470409201.7403.31.camel@gmx.net> Message-ID: <1470832248.7403.57.camel@gmx.net> Am Freitag, den 05.08.2016, 18:31 +0300 schrieb Oleksandr V. Typlyns'kyi: > >? > >?????X-Accel-Limit-Rate: > > > ?It will works only when request proxied to upstream. Yes. Upstream should tell the proxy-cache to throttle the video- playback only after sending the mp4-moov atom. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ru at nginx.com Wed Aug 10 12:53:04 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Wed, 10 Aug 2016 12:53:04 +0000 Subject: [nginx] Simplified extraction of current time. Message-ID: details: http://hg.nginx.org/nginx/rev/7a6456398fc3 branches: changeset: 6653:7a6456398fc3 user: Ruslan Ermilov date: Mon Aug 08 17:11:29 2016 +0300 description: Simplified extraction of current time. diffstat: src/http/modules/ngx_http_limit_req_module.c | 14 +++----------- src/http/modules/ngx_http_ssi_filter_module.c | 10 +++++----- 2 files changed, 8 insertions(+), 16 deletions(-) diffs (98 lines): diff -r 1891b2892b68 -r 7a6456398fc3 src/http/modules/ngx_http_limit_req_module.c --- a/src/http/modules/ngx_http_limit_req_module.c Mon Aug 08 13:44:49 2016 +0300 +++ b/src/http/modules/ngx_http_limit_req_module.c Mon Aug 08 17:11:29 2016 +0300 @@ -362,15 +362,13 @@ ngx_http_limit_req_lookup(ngx_http_limit { size_t size; ngx_int_t rc, excess; - ngx_time_t *tp; ngx_msec_t now; ngx_msec_int_t ms; ngx_rbtree_node_t *node, *sentinel; ngx_http_limit_req_ctx_t *ctx; ngx_http_limit_req_node_t *lr; - tp = ngx_timeofday(); - now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); + now = ngx_current_msec; ctx = limit->shm_zone->data; @@ -483,7 +481,6 @@ ngx_http_limit_req_account(ngx_http_limi ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit) { ngx_int_t excess; - ngx_time_t *tp; ngx_msec_t now, delay, max_delay; ngx_msec_int_t ms; ngx_http_limit_req_ctx_t *ctx; @@ -509,9 +506,7 @@ ngx_http_limit_req_account(ngx_http_limi ngx_shmtx_lock(&ctx->shpool->mutex); - tp = ngx_timeofday(); - - now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); + now = ngx_current_msec; ms = (ngx_msec_int_t) (now - lr->last); excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; @@ -549,16 +544,13 @@ static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) { ngx_int_t excess; - ngx_time_t *tp; ngx_msec_t now; ngx_queue_t *q; ngx_msec_int_t ms; ngx_rbtree_node_t *node; ngx_http_limit_req_node_t *lr; - tp = ngx_timeofday(); - - now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); + now = ngx_current_msec; /* * n == 1 deletes one or two zero rate entries diff -r 1891b2892b68 -r 7a6456398fc3 src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c Mon Aug 08 13:44:49 2016 +0300 +++ b/src/http/modules/ngx_http_ssi_filter_module.c Mon Aug 08 17:11:29 2016 +0300 @@ -2722,8 +2722,8 @@ static ngx_int_t ngx_http_ssi_date_gmt_local_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t gmt) { + time_t now; ngx_http_ssi_ctx_t *ctx; - ngx_time_t *tp; ngx_str_t *timefmt; struct tm tm; char buf[NGX_HTTP_SSI_DATE_LEN]; @@ -2732,7 +2732,7 @@ ngx_http_ssi_date_gmt_local_variable(ngx v->no_cacheable = 0; v->not_found = 0; - tp = ngx_timeofday(); + now = ngx_time(); ctx = ngx_http_get_module_ctx(r, ngx_http_ssi_filter_module); @@ -2746,15 +2746,15 @@ ngx_http_ssi_date_gmt_local_variable(ngx return NGX_ERROR; } - v->len = ngx_sprintf(v->data, "%T", tp->sec) - v->data; + v->len = ngx_sprintf(v->data, "%T", now) - v->data; return NGX_OK; } if (gmt) { - ngx_libc_gmtime(tp->sec, &tm); + ngx_libc_gmtime(now, &tm); } else { - ngx_libc_localtime(tp->sec, &tm); + ngx_libc_localtime(now, &tm); } v->len = strftime(buf, NGX_HTTP_SSI_DATE_LEN, From whissi at gentoo.org Wed Aug 10 13:11:32 2016 From: whissi at gentoo.org (Thomas Deutschmann) Date: Wed, 10 Aug 2016 15:11:32 +0200 Subject: Should nginx' default shipped fastcgi_param file updated to mitigate httpoxy? In-Reply-To: <4747966.JonH64itGs@vbart-workstation> References: <20160719141655.GK57459@mdounin.ru> <482a256b-d91f-de79-cee1-f7cb16c25fdc@gentoo.org> <4747966.JonH64itGs@vbart-workstation> Message-ID: -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA512 On 2016-08-10 11:00, Valentin V. Bartenev wrote: > Why have you decided to patch "fastcgi_params" and left untouched > other similar protocols like scgi, uwsgi? Uhm, good catch. Thanks! Will update our patch to https://git.io/v6Wp9 (i.e. patch will be extended to modify {scgi,uwsgi}_params as well). - -- Regards, Thomas -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.1 iQJ8BAEBCgBmBQJXqyf9XxSAAAAAAC4AKGlzc3Vlci1mcHJAbm90YXRpb25zLm9w ZW5wZ3AuZmlmdGhob3JzZW1hbi5uZXQzM0M1ODQ4MkM0MDIyOTJEMkUzQzVDMDY5 NzA5RjkwQzNDOTZGRkM4AAoJEJcJ+Qw8lv/IAFkP/RQqir+W9vjN1LN7d8oe64vm Ml4nqMR/6lpbGFrk+r5AOwgftyf4YC9tm/1svO9hToUPV7lf6/g9X4Sx5XhC+j5c NT7jgTSqJSWfI764fmaOszc5eKFpwBlOeyUJVI7g8FSOxEBXypRCh+Tfwoj2NDAA G1mM9Ip9oCpJfeLU78eRaxjkpf6DvqumszALgCoQdG643vvO6Oi3mbY1b1+Zdi58 AVL155geTP+8wGRvs3TEUveVpvXHD9/G+SFpayVT2S66iyFCWTplGvewl3t1nBbF FdC+jKo5n8n/rZVoTmPjRA29sUkFP8TTfYP/fv0F7MsSFydAFDr1LiLrWWNHTg7X nTRHamuY98l7GH3KBZHN3IYdQbxlaPjtz9H5Wmt6gaeYw2uHekR2YUjxhodaqsO6 YyjcSghB/a3cbBglBKsrcq22Z09mBW3JdAW5+cBD+/rLMNGNBnX6CLJ9yjEjm7W+ 8H5J4M6dZiregDqNOz8HyIj7SKpDd92RaGVJb416ynYWk7skkmNTpmhHfWBlHNeN igBEDdJmq31oPmmmCMpKPMoclQjfCbc5s0GALizp432zjKc2PXGP1cYYrwZEstcR VQW9W69GCaAdA0j1VqaMp4fP8jkU/b0BWDg3ZlmLu0RRDgc0q5dZLhZ7xJD/8sst 5d9neX5g4nnovNf8bWfZ =CWb2 -----END PGP SIGNATURE----- From vl at nginx.com Wed Aug 10 13:47:37 2016 From: vl at nginx.com (Vladimir Homutov) Date: Wed, 10 Aug 2016 13:47:37 +0000 Subject: [nginx] Upstream: the $upstream_bytes_received variable. Message-ID: details: http://hg.nginx.org/nginx/rev/c131f20c9562 branches: changeset: 6654:c131f20c9562 user: Vladimir Homutov date: Wed Aug 10 16:46:39 2016 +0300 description: Upstream: the $upstream_bytes_received variable. Unlike $upstream_response_length that only counts the body size, the new variable also counts the size of response header and data received after switching protocols when proxying WebSockets. diffstat: src/http/ngx_http_upstream.c | 22 +++++++++++++++++++++- src/http/ngx_http_upstream.h | 1 + 2 files changed, 22 insertions(+), 1 deletions(-) diffs (85 lines): diff -r 7a6456398fc3 -r c131f20c9562 src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c Mon Aug 08 17:11:29 2016 +0300 +++ b/src/http/ngx_http_upstream.c Wed Aug 10 16:46:39 2016 +0300 @@ -391,6 +391,10 @@ static ngx_http_variable_t ngx_http_ups ngx_http_upstream_response_length_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("upstream_bytes_received"), NULL, + ngx_http_upstream_response_length_variable, 1, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + #if (NGX_HTTP_CACHE) { ngx_string("upstream_cache_status"), NULL, @@ -2136,6 +2140,8 @@ ngx_http_upstream_process_header(ngx_htt return; } + u->state->bytes_received += n; + u->buffer.last += n; #if 0 @@ -2642,6 +2648,7 @@ ngx_http_upstream_process_body_in_memory return; } + u->state->bytes_received += n; u->state->response_length += n; if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) { @@ -3215,6 +3222,10 @@ ngx_http_upstream_process_upgraded(ngx_h do_write = 1; b->last += n; + if (from_upstream) { + u->state->bytes_received += n; + } + continue; } @@ -3411,6 +3422,7 @@ ngx_http_upstream_process_non_buffered_r } if (n > 0) { + u->state->bytes_received += n; u->state->response_length += n; if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) { @@ -4095,6 +4107,8 @@ ngx_http_upstream_finalize_request(ngx_h u->state->response_time = ngx_current_msec - u->state->response_time; if (u->pipe && u->pipe->read_length) { + u->state->bytes_received += u->pipe->read_length + - u->pipe->preread_size; u->state->response_length = u->pipe->read_length; } } @@ -5242,7 +5256,13 @@ ngx_http_upstream_response_length_variab state = r->upstream_states->elts; for ( ;; ) { - p = ngx_sprintf(p, "%O", state[i].response_length); + + if (data == 1) { + p = ngx_sprintf(p, "%O", state[i].bytes_received); + + } else { + p = ngx_sprintf(p, "%O", state[i].response_length); + } if (++i == r->upstream_states->nelts) { break; diff -r 7a6456398fc3 -r c131f20c9562 src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h Mon Aug 08 17:11:29 2016 +0300 +++ b/src/http/ngx_http_upstream.h Wed Aug 10 16:46:39 2016 +0300 @@ -63,6 +63,7 @@ typedef struct { ngx_msec_t connect_time; ngx_msec_t header_time; off_t response_length; + off_t bytes_received; ngx_str_t *peer; } ngx_http_upstream_state_t; From igor at sysoev.ru Thu Aug 11 13:39:50 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 11 Aug 2016 13:39:50 +0000 Subject: [njs] Array.isArray() function. Message-ID: details: http://hg.nginx.org/njs/rev/bd3464a20ad2 branches: changeset: 149:bd3464a20ad2 user: Igor Sysoev date: Wed Aug 10 11:57:56 2016 +0300 description: Array.isArray() function. diffstat: njs/njs_array.c | 26 ++++++++++++++++++++++++++ njs/test/njs_unit_test.c | 9 +++++++++ 2 files changed, 35 insertions(+), 0 deletions(-) diffs (62 lines): diff -r f23c723cf833 -r bd3464a20ad2 njs/njs_array.c --- a/njs/njs_array.c Tue Aug 09 14:10:33 2016 +0300 +++ b/njs/njs_array.c Wed Aug 10 11:57:56 2016 +0300 @@ -257,6 +257,25 @@ njs_array_constructor(njs_vm_t *vm, njs_ } +static njs_ret_t +njs_array_is_array(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + const njs_value_t *value; + + if (nargs > 1 && njs_is_array(&args[1])) { + value = &njs_string_true; + + } else { + value = &njs_string_false; + } + + vm->retval = *value; + + return NXT_OK; +} + + static const njs_object_prop_t njs_array_constructor_properties[] = { /* Array.name == "Array". */ @@ -279,6 +298,13 @@ static const njs_object_prop_t njs_arra .name = njs_string("prototype"), .value = njs_native_getter(njs_object_prototype_create), }, + + /* Array.isArray(). */ + { + .type = NJS_METHOD, + .name = njs_string("isArray"), + .value = njs_native_function(njs_array_is_array, 0, 0), + }, }; diff -r f23c723cf833 -r bd3464a20ad2 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 09 14:10:33 2016 +0300 +++ b/njs/test/njs_unit_test.c Wed Aug 10 11:57:56 2016 +0300 @@ -2215,6 +2215,15 @@ static njs_unit_test_t njs_test[] = /**/ + { nxt_string("Array.isArray()"), + nxt_string("false") }, + + { nxt_string("Array.isArray(1)"), + nxt_string("false") }, + + { nxt_string("Array.isArray([])"), + nxt_string("true") }, + { nxt_string("a = [1,2,3]; a.concat(4, [5, 6, 7], 8)"), nxt_string("1,2,3,4,5,6,7,8") }, From igor at sysoev.ru Thu Aug 11 13:39:52 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 11 Aug 2016 13:39:52 +0000 Subject: [njs] Array.indexOf() and Array.lastIndexOf() functions. Message-ID: details: http://hg.nginx.org/njs/rev/050db82b0d46 branches: changeset: 150:050db82b0d46 user: Igor Sysoev date: Wed Aug 10 15:52:25 2016 +0300 description: Array.indexOf() and Array.lastIndexOf() functions. diffstat: njs/njs_array.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ njs/njs_vm.c | 4 +- njs/njs_vm.h | 2 + njs/test/njs_unit_test.c | 30 ++++++++++++++++++ 4 files changed, 113 insertions(+), 3 deletions(-) diffs (177 lines): diff -r bd3464a20ad2 -r 050db82b0d46 njs/njs_array.c --- a/njs/njs_array.c Wed Aug 10 11:57:56 2016 +0300 +++ b/njs/njs_array.c Wed Aug 10 15:52:25 2016 +0300 @@ -58,6 +58,8 @@ static njs_ret_t njs_array_prototype_joi njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline njs_value_t *njs_array_copy(njs_value_t *dst, njs_value_t *src); +static njs_ret_t njs_array_index_of(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, nxt_bool_t first); static nxt_noinline njs_ret_t njs_array_prototype_for_each_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline njs_ret_t njs_array_prototype_some_cont(njs_vm_t *vm, @@ -836,6 +838,70 @@ njs_array_copy(njs_value_t *dst, njs_val static njs_ret_t +njs_array_prototype_index_of(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + return njs_array_index_of(vm, args, nargs, 1); +} + + +static njs_ret_t +njs_array_prototype_last_index_of(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + return njs_array_index_of(vm, args, nargs, 0); +} + + +static njs_ret_t +njs_array_index_of(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + nxt_bool_t first) +{ + nxt_int_t i, index, length; + njs_value_t *value; + njs_array_t *array; + + index = -1; + + if (nargs > 1) { + i = 0; + array = args[0].data.u.array; + length = array->length; + + if (nargs > 2) { + i = args[2].data.u.number; + + if (i < 0) { + i += length; + + if (i < 0) { + i = 0; + } + } + } + + value = &args[1]; + + while (i < length) { + if (njs_values_strict_equal(value, &array->start[i])) { + index = i; + + if (first) { + break; + } + } + + i++; + } + } + + njs_number_set(&vm->retval, index); + + return NXT_OK; +} + + +static njs_ret_t njs_array_prototype_for_each(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { @@ -1399,6 +1465,20 @@ static const njs_object_prop_t njs_arra { .type = NJS_METHOD, + .name = njs_string("indexOf"), + .value = njs_native_function(njs_array_prototype_index_of, 0, + NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_INTEGER_ARG), + }, + + { + .type = NJS_METHOD, + .name = njs_string("lastIndexOf"), + .value = njs_native_function(njs_array_prototype_last_index_of, 0, + NJS_OBJECT_ARG, NJS_SKIP_ARG, NJS_INTEGER_ARG), + }, + + { + .type = NJS_METHOD, .name = njs_string("forEach"), .value = njs_native_function(njs_array_prototype_for_each, njs_continuation_size(njs_array_iter_t), 0), diff -r bd3464a20ad2 -r 050db82b0d46 njs/njs_vm.c --- a/njs/njs_vm.c Wed Aug 10 11:57:56 2016 +0300 +++ b/njs/njs_vm.c Wed Aug 10 15:52:25 2016 +0300 @@ -82,8 +82,6 @@ static nxt_noinline njs_ret_t njs_values njs_value_t *val2); static nxt_noinline njs_ret_t njs_values_compare(njs_value_t *val1, njs_value_t *val2); -static nxt_noinline nxt_bool_t njs_values_strict_equal(njs_value_t *val1, - njs_value_t *val2); static njs_object_t *njs_function_new_object(njs_vm_t *vm, njs_value_t *value); static njs_ret_t njs_vmcode_continuation(njs_vm_t *vm, njs_value_t *invld1, njs_value_t *invld2); @@ -2006,7 +2004,7 @@ njs_vmcode_strict_not_equal(njs_vm_t *vm } -static nxt_noinline nxt_bool_t +nxt_noinline nxt_bool_t njs_values_strict_equal(njs_value_t *val1, njs_value_t *val2) { size_t size; diff -r bd3464a20ad2 -r 050db82b0d46 njs/njs_vm.h --- a/njs/njs_vm.h Wed Aug 10 11:57:56 2016 +0300 +++ b/njs/njs_vm.h Wed Aug 10 15:52:25 2016 +0300 @@ -958,6 +958,8 @@ njs_ret_t njs_vmcode_catch(njs_vm_t *vm, njs_ret_t njs_vmcode_finally(njs_vm_t *vm, njs_value_t *invld, njs_value_t *retval); +nxt_bool_t njs_values_strict_equal(njs_value_t *val1, njs_value_t *val2); + njs_ret_t njs_normalize_args(njs_vm_t *vm, njs_value_t *args, uint8_t *args_types, nxt_uint_t nargs); diff -r bd3464a20ad2 -r 050db82b0d46 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Aug 10 11:57:56 2016 +0300 +++ b/njs/test/njs_unit_test.c Wed Aug 10 15:52:25 2016 +0300 @@ -2271,6 +2271,36 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = [1,2,3,4]; a.reverse()"), nxt_string("4,3,2,1") }, + { nxt_string("var a = [1,2,3,4]; a.indexOf()"), + nxt_string("-1") }, + + { nxt_string("var a = [1,2,3,4]; a.indexOf(5)"), + nxt_string("-1") }, + + { nxt_string("var a = [1,2,3,4,3,4]; a.indexOf(3, '2')"), + nxt_string("2") }, + + { nxt_string("var a = [1,2,3,4,3,4]; a.indexOf(4, -1)"), + nxt_string("5") }, + + { nxt_string("var a = [1,2,3,4,3,4]; a.indexOf(3, -10)"), + nxt_string("2") }, + + { nxt_string("var a = [1,2,3,4]; a.lastIndexOf()"), + nxt_string("-1") }, + + { nxt_string("var a = [1,2,3,4]; a.lastIndexOf(5)"), + nxt_string("-1") }, + + { nxt_string("var a = [1,2,3,4,3,4]; a.lastIndexOf(3, '2')"), + nxt_string("4") }, + + { nxt_string("var a = [1,2,3,4,3,4]; a.lastIndexOf(4, -1)"), + nxt_string("5") }, + + { nxt_string("var a = [1,2,3,4,3,4]; a.lastIndexOf(3, -10)"), + nxt_string("4") }, + { nxt_string("var a = []; var s = { sum: 0 };" "a.forEach(function(v, i, a) { this.sum += v }, s); s.sum"), nxt_string("0") }, From igor at sysoev.ru Thu Aug 11 13:39:53 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 11 Aug 2016 13:39:53 +0000 Subject: [njs] Array.splice() function. Message-ID: details: http://hg.nginx.org/njs/rev/3dc4385c805c branches: changeset: 151:3dc4385c805c user: Igor Sysoev date: Wed Aug 10 18:03:54 2016 +0300 description: Array.splice() function. diffstat: njs/njs_array.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ njs/test/njs_unit_test.c | 15 ++++++++ 2 files changed, 103 insertions(+), 0 deletions(-) diffs (130 lines): diff -r 050db82b0d46 -r 3dc4385c805c njs/njs_array.c --- a/njs/njs_array.c Wed Aug 10 15:52:25 2016 +0300 +++ b/njs/njs_array.c Wed Aug 10 18:03:54 2016 +0300 @@ -530,6 +530,87 @@ njs_array_prototype_shift(njs_vm_t *vm, static njs_ret_t +njs_array_prototype_splice(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + njs_ret_t ret; + nxt_int_t items, delta; + nxt_uint_t i, n, start, delete, length; + njs_array_t *array, *deleted; + + array = NULL; + start = 0; + delete = 0; + + if (njs_is_array(&args[0])) { + array = args[0].data.u.array; + + if (nargs > 1) { + start = args[1].data.u.number; + + if (nargs > 2) { + delete = args[2].data.u.number; + + } else { + delete = array->length - start; + } + } + } + + deleted = njs_array_alloc(vm, delete, 0); + if (nxt_slow_path(deleted == NULL)) { + return NXT_ERROR; + } + + if (array != NULL && (delete != 0 || nargs > 3)) { + length = array->length; + + /* Move deleted items to a new array to return. */ + for (i = 0, n = start; i < delete && n < length; i++, n++) { + /* No retention required. */ + deleted->start[i] = array->start[n]; + } + + items = nargs - 3; + items = items >= 0 ? items : 0; + delta = items - delete; + + if (delta != 0) { + /* + * Relocate the rest of items. + * Index of the first item is in "n". + */ + if (delta > 0) { + ret = njs_array_realloc(vm, array, 0, array->size + delta); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + } + + memmove(&array->start[start + items], &array->start[n], + (array->length - n) * sizeof(njs_value_t)); + + array->length += delta; + } + + /* Copy new items. */ + n = start; + + for (i = 3; i < nargs; i++) { + /* GC: njs_retain(&args[i]); */ + array->start[n++] = args[i]; + } + } + + vm->retval.data.u.array = deleted; + vm->retval.type = NJS_ARRAY; + vm->retval.data.truth = 1; + + return NXT_OK; +} + + +static njs_ret_t njs_array_prototype_reverse(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { @@ -1437,6 +1518,13 @@ static const njs_object_prop_t njs_arra { .type = NJS_METHOD, + .name = njs_string("splice"), + .value = njs_native_function(njs_array_prototype_splice, 0, + NJS_OBJECT_ARG, NJS_INTEGER_ARG, NJS_INTEGER_ARG), + }, + + { + .type = NJS_METHOD, .name = njs_string("reverse"), .value = njs_native_function(njs_array_prototype_reverse, 0, NJS_OBJECT_ARG), diff -r 050db82b0d46 -r 3dc4385c805c njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Aug 10 15:52:25 2016 +0300 +++ b/njs/test/njs_unit_test.c Wed Aug 10 18:03:54 2016 +0300 @@ -2256,6 +2256,21 @@ static njs_unit_test_t njs_test[] = "len +' '+ a +' '+ a.shift()"), nxt_string("5 3,4,5,1,2 3") }, + { nxt_string("var a = []; a.splice()"), + nxt_string("") }, + + { nxt_string("var a = [0,1,2,3,4,5,6,7];" + "a.splice(3).join(':') + '|' + a"), + nxt_string("3:4:5:6:7|0,1,2") }, + + { nxt_string("var a = [0,1,2,3,4,5,6,7];" + "a.splice(3, 2).join(':') + '|' + a"), + nxt_string("3:4|0,1,2,5,6,7") }, + + { nxt_string("var a = [0,1,2,3,4,5,6,7];" + "a.splice(3, 2, 8, 9, 10, 11 ).join(':') + '|' + a"), + nxt_string("3:4|0,1,2,8,9,10,11,5,6,7") }, + { nxt_string("var a = []; a.reverse()"), nxt_string("") }, From igor at sysoev.ru Thu Aug 11 13:39:54 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 11 Aug 2016 13:39:54 +0000 Subject: [njs] Array.sort() function. Message-ID: details: http://hg.nginx.org/njs/rev/18ac628bcb6c branches: changeset: 152:18ac628bcb6c user: Igor Sysoev date: Thu Aug 11 10:58:29 2016 +0300 description: Array.sort() function. diffstat: njs/njs_array.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++ njs/test/njs_unit_test.c | 31 +++++++++ 2 files changed, 190 insertions(+), 0 deletions(-) diffs (231 lines): diff -r 3dc4385c805c -r 18ac628bcb6c njs/njs_array.c --- a/njs/njs_array.c Wed Aug 10 18:03:54 2016 +0300 +++ b/njs/njs_array.c Thu Aug 11 10:58:29 2016 +0300 @@ -51,6 +51,23 @@ typedef struct { } njs_array_iter_t; +typedef struct { + union { + njs_continuation_t cont; + u_char padding[NJS_CONTINUATION_SIZE]; + } u; + /* + * This retval value must be aligned so the continuation is padded + * to aligned size. + */ + njs_value_t retval; + + njs_function_t *function; + int32_t index; + uint32_t current; +} njs_array_sort_t; + + static njs_ret_t njs_array_prototype_to_string_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t retval); @@ -81,6 +98,8 @@ static nxt_noinline uint32_t njs_array_i static nxt_noinline njs_ret_t njs_array_iterator_apply(njs_vm_t *vm, njs_array_iter_t *iter, njs_value_t *args, nxt_uint_t nargs); static uint32_t njs_array_reduce_right_next(njs_array_t *array, int32_t n); +static njs_ret_t njs_array_prototype_sort_cont(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); nxt_noinline njs_array_t * @@ -1477,6 +1496,139 @@ njs_array_reduce_right_next(njs_array_t } +static njs_ret_t +njs_array_string_sort(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + nxt_int_t ret; + nxt_uint_t i; + + for (i = 1; i < nargs; i++) { + if (!njs_is_string(&args[i])) { + vm->frame->trap_scratch.data.u.value = &args[i]; + return NJS_TRAP_STRING_ARG; + } + } + + ret = njs_string_cmp(&args[1], &args[2]); + + njs_number_set(&vm->retval, ret); + + return NXT_OK; +} + + +static const njs_function_t njs_array_string_sort_function = { + .object.shared = 1, + .native = 1, + .continuation_size = NJS_CONTINUATION_SIZE, + .args_types = { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG }, + .args_offset = 1, + .u.native = njs_array_string_sort, +}; + + +static njs_ret_t +njs_array_prototype_sort(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + njs_array_sort_t *sort; + + if (njs_is_array(&args[0]) && args[0].data.u.array->length > 1) { + + sort = njs_continuation(vm->frame); + sort->u.cont.function = njs_array_prototype_sort_cont; + sort->current = 0; + sort->retval = njs_value_zero; + + if (nargs > 1 && njs_is_function(&args[1])) { + sort->function = args[1].data.u.function; + + } else { + sort->function = (njs_function_t *) &njs_array_string_sort_function; + } + + return njs_array_prototype_sort_cont(vm, args, nargs, unused); + } + + vm->retval = args[0]; + + return NXT_OK; +} + + +static njs_ret_t +njs_array_prototype_sort_cont(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + nxt_int_t n; + njs_array_t *array; + njs_value_t value, *start, arguments[3]; + njs_array_sort_t *sort; + + array = args[0].data.u.array; + start = array->start; + + sort = njs_continuation(vm->frame); + + if (njs_is_number(&sort->retval)) { + + /* + * The sort function is impelemented with the insertion sort algorithm. + * Its worst and average computational complexity is O^2. This point + * should be considired as return point from comparison function so + * "goto next" moves control to the appropriate step of the algorithm. + * The first iteration also goes there because sort->retval is zero. + */ + if (sort->retval.data.u.number <= 0) { + goto next; + } + + n = sort->index; + + swap: + + value = start[n]; + start[n] = start[n - 1]; + n--; + start[n] = value; + + do { + if (n > 0) { + + if (njs_is_valid(&start[n]) && njs_is_valid(&start[n - 1])) { + arguments[0] = njs_value_void; + + /* GC: array elt, array */ + arguments[1] = start[n - 1]; + arguments[2] = start[n]; + + sort->index = n; + + return njs_function_apply(vm, sort->function, arguments, 3, + (njs_index_t) &sort->retval); + } + + if (!njs_is_valid(&start[n - 1]) && njs_is_valid(&start[n])) { + /* Move invalid values to the end of array. */ + goto swap; + } + } + + next: + + sort->current++; + n = sort->current; + + } while (sort->current < array->length); + } + + vm->retval = args[0]; + + return NXT_OK; +} + + static const njs_object_prop_t njs_array_prototype_properties[] = { { @@ -1613,6 +1765,13 @@ static const njs_object_prop_t njs_arra .value = njs_native_function(njs_array_prototype_reduce_right, njs_continuation_size(njs_array_iter_t), 0), }, + + { + .type = NJS_METHOD, + .name = njs_string("sort"), + .value = njs_native_function(njs_array_prototype_sort, + njs_continuation_size(njs_array_iter_t), 0), + }, }; diff -r 3dc4385c805c -r 18ac628bcb6c njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Aug 10 18:03:54 2016 +0300 +++ b/njs/test/njs_unit_test.c Thu Aug 11 10:58:29 2016 +0300 @@ -2517,6 +2517,37 @@ static njs_unit_test_t njs_test[] = " { a.shift(); return p + v }, 10)"), nxt_string("19") }, + { nxt_string("var a = ['1','2','3','4','5','6']; a.sort()"), + nxt_string("1,2,3,4,5,6") }, + + { nxt_string("var o = { toString: function() { return 5 } }" + "var a = [6,o,4,3,2,1]; a.sort()"), + nxt_string("1,2,3,4,5,6") }, + + { nxt_string("var a = [1,2,3,4,5,6];" + "a.sort(function(x, y) { return x - y })"), + nxt_string("1,2,3,4,5,6") }, + + { nxt_string("var a = [6,5,4,3,2,1];" + "a.sort(function(x, y) { return x - y })"), + nxt_string("1,2,3,4,5,6") }, + + { nxt_string("var a = [2,2,2,1,1,1];" + "a.sort(function(x, y) { return x - y })"), + nxt_string("1,1,1,2,2,2") }, + + { nxt_string("var a = [,,,2,2,2,1,1,1];" + "a.sort(function(x, y) { return x - y })"), + nxt_string("1,1,1,2,2,2,,,") }, + + { nxt_string("var a = [,,,,];" + "a.sort(function(x, y) { return x - y })"), + nxt_string(",,,") }, + + { nxt_string("var a = [1,,];" + "a.sort(function(x, y) { return x - y })"), + nxt_string("1,") }, + /* Strings. */ { nxt_string("var a = '0123456789' + '012345'" From igor at sysoev.ru Thu Aug 11 13:39:56 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 11 Aug 2016 13:39:56 +0000 Subject: [njs] Array.join() now treats "null" and "undefined" as empty va... Message-ID: details: http://hg.nginx.org/njs/rev/87df6b787943 branches: changeset: 153:87df6b787943 user: Igor Sysoev date: Thu Aug 11 13:21:46 2016 +0300 description: Array.join() now treats "null" and "undefined" as empty values. diffstat: njs/njs_array.c | 14 ++++++++++---- njs/test/njs_unit_test.c | 11 +++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) diffs (66 lines): diff -r 18ac628bcb6c -r 87df6b787943 njs/njs_array.c --- a/njs/njs_array.c Thu Aug 11 10:58:29 2016 +0300 +++ b/njs/njs_array.c Thu Aug 11 13:21:46 2016 +0300 @@ -734,7 +734,10 @@ njs_array_prototype_join(njs_vm_t *vm, n for (i = 0; i < array->length; i++) { value = &array->start[i]; - if (njs_is_valid(value) && !njs_is_string(value)) { + if (!njs_is_string(value) + && njs_is_valid(value) + && !njs_is_null_or_void(value)) + { max++; } } @@ -755,7 +758,10 @@ njs_array_prototype_join(njs_vm_t *vm, n for (i = 0; i < array->length; i++) { value = &array->start[i]; - if (njs_is_valid(value) && !njs_is_string(value)) { + if (!njs_is_string(value) + && njs_is_valid(value) + && !njs_is_null_or_void(value)) + { values[n++] = *value; if (n >= max) { @@ -802,7 +808,7 @@ njs_array_prototype_join_continuation(nj for (i = 0; i < array->length; i++) { value = &array->start[i]; - if (njs_is_valid(value)) { + if (njs_is_valid(value) && !njs_is_null_or_void(value)) { if (!njs_is_string(value)) { value = &values[n++]; @@ -849,7 +855,7 @@ njs_array_prototype_join_continuation(nj for (i = 0; i < array->length; i++) { value = &array->start[i]; - if (njs_is_valid(value)) { + if (njs_is_valid(value) && !njs_is_null_or_void(value)) { if (!njs_is_string(value)) { value = &values[n++]; } diff -r 18ac628bcb6c -r 87df6b787943 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Aug 11 10:58:29 2016 +0300 +++ b/njs/test/njs_unit_test.c Thu Aug 11 13:21:46 2016 +0300 @@ -2124,6 +2124,17 @@ static njs_unit_test_t njs_test[] = { nxt_string("a = []; a[5] = 5; a.join()"), nxt_string(",,,,,5") }, + { nxt_string("var a = [,null,undefined,false,true,0,1]; a.join()"), + nxt_string(",,,false,true,0,1") }, + + { nxt_string("var o = { toString: function() { return null } };" + "[o].join()"), + nxt_string("null") }, + + { nxt_string("var o = { toString: function() { return undefined } };" + "[o].join()"), + nxt_string("undefined") }, + { nxt_string("a = []; a[5] = 5; a"), nxt_string(",,,,,5") }, From igor at sysoev.ru Thu Aug 11 13:39:57 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Thu, 11 Aug 2016 13:39:57 +0000 Subject: [njs] Array iterator functions optimizations. Message-ID: details: http://hg.nginx.org/njs/rev/0c9a771b7664 branches: changeset: 154:0c9a771b7664 user: Igor Sysoev date: Thu Aug 11 13:57:36 2016 +0300 description: Array iterator functions optimizations. diffstat: njs/njs_array.c | 126 ++++++++++++++++++++++++++++++------------------------- 1 files changed, 69 insertions(+), 57 deletions(-) diffs (262 lines): diff -r 87df6b787943 -r 0c9a771b7664 njs/njs_array.c --- a/njs/njs_array.c Thu Aug 11 13:21:46 2016 +0300 +++ b/njs/njs_array.c Thu Aug 11 13:57:36 2016 +0300 @@ -43,12 +43,23 @@ typedef struct { */ njs_value_t retval; + uint32_t next_index; + uint32_t length; +} njs_array_iter_t; + + +typedef struct { + njs_array_iter_t iter; njs_value_t value; njs_array_t *array; - uint32_t next_index; - uint32_t length; +} njs_array_filter_t; + + +typedef struct { + njs_array_iter_t iter; + njs_array_t *array; uint32_t index; -} njs_array_iter_t; +} njs_array_map_t; typedef struct { @@ -1137,20 +1148,20 @@ static njs_ret_t njs_array_prototype_filter(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - nxt_int_t ret; - njs_array_iter_t *iter; + nxt_int_t ret; + njs_array_filter_t *filter; ret = njs_array_iterator_args(vm, args, nargs); if (nxt_slow_path(ret != NXT_OK)) { return ret; } - iter = njs_continuation(vm->frame); - iter->u.cont.function = njs_array_prototype_filter_cont; - iter->retval.data.truth = 0; + filter = njs_continuation(vm->frame); + filter->iter.u.cont.function = njs_array_prototype_filter_cont; + filter->iter.retval.data.truth = 0; - iter->array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); - if (nxt_slow_path(iter->array == NULL)) { + filter->array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); + if (nxt_slow_path(filter->array == NULL)) { return NXT_ERROR; } @@ -1162,27 +1173,33 @@ static njs_ret_t njs_array_prototype_filter_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - nxt_int_t ret; - njs_array_iter_t *iter; + nxt_int_t ret; + njs_array_t *array; + njs_array_filter_t *filter; - iter = njs_continuation(vm->frame); + filter = njs_continuation(vm->frame); - if (njs_is_true(&iter->retval)) { - ret = njs_array_add(vm, iter->array, &iter->value); + if (njs_is_true(&filter->iter.retval)) { + ret = njs_array_add(vm, filter->array, &filter->value); if (nxt_slow_path(ret != NXT_OK)) { return ret; } } - if (iter->next_index >= args[0].data.u.array->length) { - vm->retval.data.u.array = iter->array; + array = args[0].data.u.array; + + if (filter->iter.next_index >= array->length) { + vm->retval.data.u.array = filter->array; vm->retval.type = NJS_ARRAY; vm->retval.data.truth = 1; return NXT_OK; } - return njs_array_iterator_apply(vm, iter, args, nargs); + /* GC: filter->value */ + filter->value = array->start[filter->iter.next_index]; + + return njs_array_iterator_apply(vm, &filter->iter, args, nargs); } @@ -1190,29 +1207,29 @@ static njs_ret_t njs_array_prototype_map(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - size_t size; - nxt_int_t ret; - njs_value_t *value; - njs_array_t *array; - njs_array_iter_t *iter; + size_t size; + nxt_int_t ret; + njs_value_t *value; + njs_array_t *array; + njs_array_map_t *map; ret = njs_array_iterator_args(vm, args, nargs); if (nxt_slow_path(ret != NXT_OK)) { return ret; } - iter = njs_continuation(vm->frame); - iter->u.cont.function = njs_array_prototype_map_cont; - njs_set_invalid(&iter->retval); + map = njs_continuation(vm->frame); + map->iter.u.cont.function = njs_array_prototype_map_cont; + njs_set_invalid(&map->iter.retval); array = args[0].data.u.array; - iter->array = njs_array_alloc(vm, array->length, 0); - if (nxt_slow_path(iter->array == NULL)) { + map->array = njs_array_alloc(vm, array->length, 0); + if (nxt_slow_path(map->array == NULL)) { return NXT_ERROR; } - value = iter->array->start; + value = map->array->start; size = array->length; while (size != 0) { @@ -1229,23 +1246,25 @@ static njs_ret_t njs_array_prototype_map_cont(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - njs_array_iter_t *iter; + njs_array_map_t *map; - iter = njs_continuation(vm->frame); + map = njs_continuation(vm->frame); - if (njs_is_valid(&iter->retval)) { - iter->array->start[iter->index] = iter->retval; + if (njs_is_valid(&map->iter.retval)) { + map->array->start[map->index] = map->iter.retval; } - if (iter->next_index >= args[0].data.u.array->length) { - vm->retval.data.u.array = iter->array; + if (map->iter.next_index >= args[0].data.u.array->length) { + vm->retval.data.u.array = map->array; vm->retval.type = NJS_ARRAY; vm->retval.data.truth = 1; return NXT_OK; } - return njs_array_iterator_apply(vm, iter, args, nargs); + map->index = map->iter.next_index; + + return njs_array_iterator_apply(vm, &map->iter, args, nargs); } @@ -1308,12 +1327,6 @@ njs_array_prototype_reduce_cont(njs_vm_t /* GC: array elt, array */ arguments[1] = iter->retval; - /* - * All array iterators functions call njs_array_iterator_args() - * function which set a correct iter->next_index value. A large - * value of iter->next_index must be checked before calling - * njs_array_iterator_apply(). - */ array = args[0].data.u.array; n = iter->next_index; @@ -1392,8 +1405,6 @@ njs_array_iterator_apply(njs_vm_t *vm, n */ array = args[0].data.u.array; n = iter->next_index; - iter->index = n; - iter->value = array->start[n]; arguments[1] = array->start[n]; njs_number_set(&arguments[2], n); @@ -1415,29 +1426,24 @@ njs_array_prototype_reduce_right(njs_vm_ njs_array_t *array; njs_array_iter_t *iter; - if (nargs > 1 && njs_is_array(&args[0]) && njs_is_function(&args[1])) { - array = args[0].data.u.array; - iter = njs_continuation(vm->frame); - iter->next_index = njs_array_reduce_right_next(array, array->length); - - } else { - vm->exception = &njs_exception_type_error; - return NXT_ERROR; + if (nargs < 2 || !njs_is_array(&args[0]) || !njs_is_function(&args[1])) { + goto type_error; } iter = njs_continuation(vm->frame); iter->u.cont.function = njs_array_prototype_reduce_right_cont; + array = args[0].data.u.array; + iter->next_index = njs_array_reduce_right_next(array, array->length); + if (nargs > 2) { iter->retval = args[2]; } else { - array = args[0].data.u.array; n = iter->next_index; if (n < 0) { - vm->exception = &njs_exception_type_error; - return NXT_ERROR; + goto type_error; } iter->retval = array->start[n]; @@ -1446,6 +1452,12 @@ njs_array_prototype_reduce_right(njs_vm_ } return njs_array_prototype_reduce_right_cont(vm, args, nargs, unused); + +type_error: + + vm->exception = &njs_exception_type_error; + + return NXT_ERROR; } @@ -1748,14 +1760,14 @@ static const njs_object_prop_t njs_arra .type = NJS_METHOD, .name = njs_string("filter"), .value = njs_native_function(njs_array_prototype_filter, - njs_continuation_size(njs_array_iter_t), 0), + njs_continuation_size(njs_array_filter_t), 0), }, { .type = NJS_METHOD, .name = njs_string("map"), .value = njs_native_function(njs_array_prototype_map, - njs_continuation_size(njs_array_iter_t), 0), + njs_continuation_size(njs_array_map_t), 0), }, { From pgnet.dev at gmail.com Thu Aug 11 15:51:40 2016 From: pgnet.dev at gmail.com (pgndev) Date: Thu, 11 Aug 2016 08:51:40 -0700 Subject: =?UTF-8?B?bmdpbnggMS4xMS4zIGJ1aWxkLCBsaW5raW5nIG9wZW5zc2wgMS4xLjAgKGJldGEv?= =?UTF-8?B?cHJlLTYpIGZhaWxzIEAg4oCYU1NMX1JfTk9fQ0lQSEVSU19QQVNTRUTigJk=?= Message-ID: I'm testing soon-to-be-released (Aug 25) openssl 1.1 beta openssl version OpenSSL 1.1.0-pre6 (beta) 4 Aug 2016 After an openssl re-build, nginx restart fails Aug 11 08:22:29 dev.loc nginx[23758]: /usr/local/sbin/nginx: symbol lookup error: /usr/local/sbin/nginx: undefined symbol: SSL_CTX_set_alpn_select_cb Rebuild of nginx 1.11.3 from source, linking openssl 1.1.0-pre6' libs, fails at ... /usr/bin/gcc-6 -c -O3 -Wall -fstack-protector -funwind-tables -fasynchronous-unwind-tables -fmessage-length=0 -grecord-gcc-switches -march=native -mtune=native -fPIC -DPIC -D_GNU_SOURCE -fno-strict-aliasing -Wall -fexceptions --param=ssp-buffer-size=4 -I/usr/local/ssl/include -I/usr/local/include -I src/core -I src/event -I src/event/modules -I src/os/unix -I src/http/modules/perl -I /usr/local/src/ngx_devel_kit/objs -I objs/addon/ndk -I /usr/local/src/ngx_devel_kit/src -I /usr/local/src/ngx_devel_kit/objs -I objs/addon/ndk -I objs -I src/http -I src/http/modules -I src/http/v2 -I /usr/local/src/ngx_devel_kit/src \ -o objs/src/http/ngx_http_core_module.o \ src/http/ngx_http_core_module.c src/event/ngx_event_openssl.c: In function ?ngx_ssl_connection_error?: src/event/ngx_event_openssl.c:2026:21: error: ?SSL_R_NO_CIPHERS_PASSED? undeclared (first use in this function) || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ ^~~~~~~~~~~~~~~~~~~~~~~ src/event/ngx_event_openssl.c:2026:21: note: each undeclared identifier is reported only once for each function it appears in objs/Makefile:912: recipe for target 'objs/src/event/ngx_event_openssl.o' failed make[1]: *** [objs/src/event/ngx_event_openssl.o] Error 1 make[1]: Leaving directory '/usr/local/src/nginx-1.11.3' Makefile:8: recipe for target 'build' failed make: *** [build] Error 2 Just fyi 4 now From vbart at nginx.com Thu Aug 11 16:33:31 2016 From: vbart at nginx.com (Valentin V. Bartenev) Date: Thu, 11 Aug 2016 19:33:31 +0300 Subject: =?UTF-8?B?UmU6IG5naW54IDEuMTEuMyBidWlsZCwgbGlua2luZyBvcGVuc3NsIDEuMS4wIChi?= =?UTF-8?B?ZXRhL3ByZS02KSBmYWlscyBAIOKAmFNTTF9SX05PX0NJUEhFUlNfUEFTU0VE?= =?UTF-8?B?4oCZ?= In-Reply-To: References: Message-ID: <183870035.XUKdTpMJss@vbart-workstation> On Thursday 11 August 2016 08:51:40 pgndev wrote: > I'm testing soon-to-be-released (Aug 25) openssl 1.1 beta > > openssl version > OpenSSL 1.1.0-pre6 (beta) 4 Aug 2016 > > After an openssl re-build, nginx restart fails > > Aug 11 08:22:29 dev.loc nginx[23758]: /usr/local/sbin/nginx: > symbol lookup error: /usr/local/sbin/nginx: undefined symbol: > SSL_CTX_set_alpn_select_cb > > Rebuild of nginx 1.11.3 from source, linking openssl 1.1.0-pre6' libs, fails at > > ... > /usr/bin/gcc-6 -c -O3 -Wall -fstack-protector -funwind-tables > -fasynchronous-unwind-tables -fmessage-length=0 -grecord-gcc-switches > -march=native -mtune=native -fPIC -DPIC -D_GNU_SOURCE > -fno-strict-aliasing -Wall -fexceptions --param=ssp-buffer-size=4 > -I/usr/local/ssl/include -I/usr/local/include -I src/core -I > src/event -I src/event/modules -I src/os/unix -I src/http/modules/perl > -I /usr/local/src/ngx_devel_kit/objs -I objs/addon/ndk -I > /usr/local/src/ngx_devel_kit/src -I /usr/local/src/ngx_devel_kit/objs > -I objs/addon/ndk -I objs -I src/http -I src/http/modules -I > src/http/v2 -I /usr/local/src/ngx_devel_kit/src \ > -o objs/src/http/ngx_http_core_module.o \ > src/http/ngx_http_core_module.c > src/event/ngx_event_openssl.c: In function ?ngx_ssl_connection_error?: > src/event/ngx_event_openssl.c:2026:21: error: > ?SSL_R_NO_CIPHERS_PASSED? undeclared (first use in this function) > || n == SSL_R_NO_CIPHERS_PASSED /* 182 */ > ^~~~~~~~~~~~~~~~~~~~~~~ > src/event/ngx_event_openssl.c:2026:21: note: each undeclared > identifier is reported only once for each function it appears in > objs/Makefile:912: recipe for target > 'objs/src/event/ngx_event_openssl.o' failed > make[1]: *** [objs/src/event/ngx_event_openssl.o] Error 1 > make[1]: Leaving directory '/usr/local/src/nginx-1.11.3' > Makefile:8: recipe for target 'build' failed > make: *** [build] Error 2 > > Just fyi 4 now > This was already fixed a few days ago. http://hg.nginx.org/nginx/rev/1891b2892b68 wbr, Valentin V. Bartenev From pgnet.dev at gmail.com Thu Aug 11 16:52:38 2016 From: pgnet.dev at gmail.com (PGNet Dev) Date: Thu, 11 Aug 2016 09:52:38 -0700 Subject: =?UTF-8?B?UmU6IG5naW54IDEuMTEuMyBidWlsZCwgbGlua2luZyBvcGVuc3NsIDEuMS4wIChi?= =?UTF-8?B?ZXRhL3ByZS02KSBmYWlscyBAIOKAmFNTTF9SX05PX0NJUEhFUlNfUEFTU0VE?= =?UTF-8?B?4oCZ?= In-Reply-To: <183870035.XUKdTpMJss@vbart-workstation> References: <183870035.XUKdTpMJss@vbart-workstation> Message-ID: <8e744b1d-03a7-95b7-0f27-38e03b7f3277@gmail.com> On 08/11/2016 09:33 AM, Valentin V. Bartenev wrote: > On Thursday 11 August 2016 08:51:40 pgndev wrote: > This was already fixed a few days ago. > http://hg.nginx.org/nginx/rev/1891b2892b68 > > wbr, Valentin V. Bartenev Didn't see that / Applies cleanly to 1.11.3 release, nginx -V nginx version: nginx/1.11.3 built with OpenSSL 1.1.0-pre6 (beta) 4 Aug 2016 ... & serves up chacha cipher nicely. Thanks. From igor at sysoev.ru Tue Aug 16 16:14:34 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 16 Aug 2016 16:14:34 +0000 Subject: [njs] A return statement has been disabled outside of function. Message-ID: details: http://hg.nginx.org/njs/rev/e6e192a55774 branches: changeset: 155:e6e192a55774 user: Igor Sysoev date: Mon Aug 15 11:33:37 2016 +0300 description: A return statement has been disabled outside of function. diffstat: njs/njs_parser.c | 7 +++++++ njs/test/njs_unit_test.c | 3 +++ 2 files changed, 10 insertions(+), 0 deletions(-) diffs (30 lines): diff -r 0c9a771b7664 -r e6e192a55774 njs/njs_parser.c --- a/njs/njs_parser.c Thu Aug 11 13:57:36 2016 +0300 +++ b/njs/njs_parser.c Mon Aug 15 11:33:37 2016 +0300 @@ -584,6 +584,13 @@ njs_parser_return_statement(njs_vm_t *vm njs_token_t token; njs_parser_node_t *node; + if (parser->scope == NJS_SCOPE_GLOBAL) { + nxt_alert(&vm->trace, NXT_LEVEL_ERROR, + "SyntaxError: Illegal return statement"); + + return NXT_ERROR; + } + node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; diff -r 0c9a771b7664 -r e6e192a55774 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Aug 11 13:57:36 2016 +0300 +++ b/njs/test/njs_unit_test.c Mon Aug 15 11:33:37 2016 +0300 @@ -3290,6 +3290,9 @@ static njs_unit_test_t njs_test[] = /* Functions. */ + { nxt_string("return"), + nxt_string("SyntaxError: Illegal return statement in 1") }, + { nxt_string("function () { } f()"), nxt_string("SyntaxError: Unexpected token \"(\" in 1") }, From igor at sysoev.ru Tue Aug 16 16:14:35 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 16 Aug 2016 16:14:35 +0000 Subject: [njs] Style fixes. Message-ID: details: http://hg.nginx.org/njs/rev/dcd8a105b5e7 branches: changeset: 156:dcd8a105b5e7 user: Igor Sysoev date: Tue Aug 16 18:09:35 2016 +0300 description: Style fixes. diffstat: njs/njs_array.c | 84 +++++++++++++++++++++++------------------------ njs/njs_string.c | 20 ++++++---- njs/njs_vm.h | 2 +- nxt/nxt_djb_hash.h | 2 +- nxt/nxt_lvlhsh.c | 46 +++++++++++++------------- nxt/nxt_lvlhsh.h | 36 ++++++++++---------- nxt/nxt_mem_cache_pool.c | 6 +- nxt/nxt_rbtree.c | 2 +- nxt/nxt_rbtree.h | 4 +- 9 files changed, 102 insertions(+), 100 deletions(-) diffs (606 lines): diff -r e6e192a55774 -r dcd8a105b5e7 njs/njs_array.c --- a/njs/njs_array.c Mon Aug 15 11:33:37 2016 +0300 +++ b/njs/njs_array.c Tue Aug 16 18:09:35 2016 +0300 @@ -79,28 +79,26 @@ typedef struct { } njs_array_sort_t; -static njs_ret_t -njs_array_prototype_to_string_continuation(njs_vm_t *vm, njs_value_t *args, - nxt_uint_t nargs, njs_index_t retval); +static njs_ret_t njs_array_prototype_to_string_continuation(njs_vm_t *vm, + njs_value_t *args, nxt_uint_t nargs, njs_index_t retval); static njs_ret_t njs_array_prototype_join_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); -static nxt_noinline njs_value_t *njs_array_copy(njs_value_t *dst, - njs_value_t *src); +static njs_value_t *njs_array_copy(njs_value_t *dst, njs_value_t *src); static njs_ret_t njs_array_index_of(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, nxt_bool_t first); -static nxt_noinline njs_ret_t njs_array_prototype_for_each_cont(njs_vm_t *vm, - njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); -static nxt_noinline njs_ret_t njs_array_prototype_some_cont(njs_vm_t *vm, - njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); -static nxt_noinline njs_ret_t njs_array_prototype_every_cont(njs_vm_t *vm, +static njs_ret_t njs_array_prototype_for_each_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); -static njs_ret_t njs_array_prototype_filter_cont(njs_vm_t *vm, +static njs_ret_t njs_array_prototype_some_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); -static njs_ret_t njs_array_prototype_map_cont(njs_vm_t *vm, njs_value_t *args, - nxt_uint_t nargs, njs_index_t unused); -static njs_ret_t njs_array_prototype_reduce_cont(njs_vm_t *vm, +static njs_ret_t njs_array_prototype_every_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); -static njs_ret_t njs_array_prototype_reduce_right_cont(njs_vm_t *vm, +static njs_ret_t njs_array_prototype_filter_continuation(njs_vm_t *vm, + njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_array_prototype_map_continuation(njs_vm_t *vm, + njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_array_prototype_reduce_continuation(njs_vm_t *vm, + njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_array_prototype_reduce_right_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline njs_ret_t njs_array_iterator_args(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs); @@ -109,8 +107,8 @@ static nxt_noinline uint32_t njs_array_i static nxt_noinline njs_ret_t njs_array_iterator_apply(njs_vm_t *vm, njs_array_iter_t *iter, njs_value_t *args, nxt_uint_t nargs); static uint32_t njs_array_reduce_right_next(njs_array_t *array, int32_t n); -static njs_ret_t njs_array_prototype_sort_cont(njs_vm_t *vm, njs_value_t *args, - nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_array_prototype_sort_continuation(njs_vm_t *vm, + njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); nxt_noinline njs_array_t * @@ -932,7 +930,7 @@ njs_array_prototype_concat(njs_vm_t *vm, } -static nxt_noinline njs_value_t * +static njs_value_t * njs_array_copy(njs_value_t *dst, njs_value_t *src) { nxt_uint_t n; @@ -1031,14 +1029,14 @@ njs_array_prototype_for_each(njs_vm_t *v } iter = njs_continuation(vm->frame); - iter->u.cont.function = njs_array_prototype_for_each_cont; + iter->u.cont.function = njs_array_prototype_for_each_continuation; - return njs_array_prototype_for_each_cont(vm, args, nargs, unused); + return njs_array_prototype_for_each_continuation(vm, args, nargs, unused); } static njs_ret_t -njs_array_prototype_for_each_cont(njs_vm_t *vm, njs_value_t *args, +njs_array_prototype_for_each_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { njs_array_iter_t *iter; @@ -1067,15 +1065,15 @@ njs_array_prototype_some(njs_vm_t *vm, n } iter = njs_continuation(vm->frame); - iter->u.cont.function = njs_array_prototype_some_cont; + iter->u.cont.function = njs_array_prototype_some_continuation; iter->retval.data.truth = 0; - return njs_array_prototype_some_cont(vm, args, nargs, unused); + return njs_array_prototype_some_continuation(vm, args, nargs, unused); } static njs_ret_t -njs_array_prototype_some_cont(njs_vm_t *vm, njs_value_t *args, +njs_array_prototype_some_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { njs_array_iter_t *iter; @@ -1112,15 +1110,15 @@ njs_array_prototype_every(njs_vm_t *vm, } iter = njs_continuation(vm->frame); - iter->u.cont.function = njs_array_prototype_every_cont; + iter->u.cont.function = njs_array_prototype_every_continuation; iter->retval.data.truth = 1; - return njs_array_prototype_every_cont(vm, args, nargs, unused); + return njs_array_prototype_every_continuation(vm, args, nargs, unused); } static njs_ret_t -njs_array_prototype_every_cont(njs_vm_t *vm, njs_value_t *args, +njs_array_prototype_every_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { njs_array_iter_t *iter; @@ -1157,7 +1155,7 @@ njs_array_prototype_filter(njs_vm_t *vm, } filter = njs_continuation(vm->frame); - filter->iter.u.cont.function = njs_array_prototype_filter_cont; + filter->iter.u.cont.function = njs_array_prototype_filter_continuation; filter->iter.retval.data.truth = 0; filter->array = njs_array_alloc(vm, 0, NJS_ARRAY_SPARE); @@ -1165,12 +1163,12 @@ njs_array_prototype_filter(njs_vm_t *vm, return NXT_ERROR; } - return njs_array_prototype_filter_cont(vm, args, nargs, unused); + return njs_array_prototype_filter_continuation(vm, args, nargs, unused); } static njs_ret_t -njs_array_prototype_filter_cont(njs_vm_t *vm, njs_value_t *args, +njs_array_prototype_filter_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { nxt_int_t ret; @@ -1219,7 +1217,7 @@ njs_array_prototype_map(njs_vm_t *vm, nj } map = njs_continuation(vm->frame); - map->iter.u.cont.function = njs_array_prototype_map_cont; + map->iter.u.cont.function = njs_array_prototype_map_continuation; njs_set_invalid(&map->iter.retval); array = args[0].data.u.array; @@ -1238,12 +1236,12 @@ njs_array_prototype_map(njs_vm_t *vm, nj size--; } - return njs_array_prototype_map_cont(vm, args, nargs, unused); + return njs_array_prototype_map_continuation(vm, args, nargs, unused); } static njs_ret_t -njs_array_prototype_map_cont(njs_vm_t *vm, njs_value_t *args, +njs_array_prototype_map_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { njs_array_map_t *map; @@ -1283,7 +1281,7 @@ njs_array_prototype_reduce(njs_vm_t *vm, } iter = njs_continuation(vm->frame); - iter->u.cont.function = njs_array_prototype_reduce_cont; + iter->u.cont.function = njs_array_prototype_reduce_continuation; if (nargs > 2) { iter->retval = args[2]; @@ -1302,12 +1300,12 @@ njs_array_prototype_reduce(njs_vm_t *vm, iter->next_index = njs_array_iterator_next(array, n + 1, array->length); } - return njs_array_prototype_reduce_cont(vm, args, nargs, unused); + return njs_array_prototype_reduce_continuation(vm, args, nargs, unused); } static njs_ret_t -njs_array_prototype_reduce_cont(njs_vm_t *vm, njs_value_t *args, +njs_array_prototype_reduce_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { nxt_int_t n; @@ -1431,7 +1429,7 @@ njs_array_prototype_reduce_right(njs_vm_ } iter = njs_continuation(vm->frame); - iter->u.cont.function = njs_array_prototype_reduce_right_cont; + iter->u.cont.function = njs_array_prototype_reduce_right_continuation; array = args[0].data.u.array; iter->next_index = njs_array_reduce_right_next(array, array->length); @@ -1451,8 +1449,8 @@ njs_array_prototype_reduce_right(njs_vm_ iter->next_index = njs_array_reduce_right_next(array, n); } - return njs_array_prototype_reduce_right_cont(vm, args, nargs, unused); - + return njs_array_prototype_reduce_right_continuation(vm, args, nargs, + unused); type_error: vm->exception = &njs_exception_type_error; @@ -1462,7 +1460,7 @@ type_error: static njs_ret_t -njs_array_prototype_reduce_right_cont(njs_vm_t *vm, njs_value_t *args, +njs_array_prototype_reduce_right_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { nxt_int_t n; @@ -1555,7 +1553,7 @@ njs_array_prototype_sort(njs_vm_t *vm, n if (njs_is_array(&args[0]) && args[0].data.u.array->length > 1) { sort = njs_continuation(vm->frame); - sort->u.cont.function = njs_array_prototype_sort_cont; + sort->u.cont.function = njs_array_prototype_sort_continuation; sort->current = 0; sort->retval = njs_value_zero; @@ -1566,7 +1564,7 @@ njs_array_prototype_sort(njs_vm_t *vm, n sort->function = (njs_function_t *) &njs_array_string_sort_function; } - return njs_array_prototype_sort_cont(vm, args, nargs, unused); + return njs_array_prototype_sort_continuation(vm, args, nargs, unused); } vm->retval = args[0]; @@ -1576,7 +1574,7 @@ njs_array_prototype_sort(njs_vm_t *vm, n static njs_ret_t -njs_array_prototype_sort_cont(njs_vm_t *vm, njs_value_t *args, +njs_array_prototype_sort_continuation(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { nxt_int_t n; diff -r e6e192a55774 -r dcd8a105b5e7 njs/njs_string.c --- a/njs/njs_string.c Mon Aug 15 11:33:37 2016 +0300 +++ b/njs/njs_string.c Tue Aug 16 18:09:35 2016 +0300 @@ -37,7 +37,7 @@ static nxt_noinline void njs_string_slic njs_slice_prop_t *slice, njs_value_t *args, nxt_uint_t nargs); static nxt_noinline void njs_string_slice_args(njs_slice_prop_t *slice, njs_value_t *args, nxt_uint_t nargs); -static njs_ret_t njs_string_prototype_from_char_code(njs_vm_t *vm, +static njs_ret_t njs_string_from_char_code(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline ssize_t njs_string_index_of(njs_vm_t *vm, njs_value_t *src, njs_value_t *search_string, size_t index); @@ -334,18 +334,18 @@ static const njs_object_prop_t njs_stri .value = njs_native_getter(njs_object_prototype_create), }, + /* String.fromCharCode(). */ { .type = NJS_METHOD, .name = njs_string("fromCharCode"), - .value = njs_native_function(njs_string_prototype_from_char_code, 0, 0), + .value = njs_native_function(njs_string_from_char_code, 0, 0), }, - - /* ECMAScript 6, fromCodePoint(). */ + /* String.fromCodePoint(), ECMAScript 6. */ { .type = NJS_METHOD, .name = njs_string("fromCodePoint"), - .value = njs_native_function(njs_string_prototype_from_char_code, 0, 0), + .value = njs_native_function(njs_string_from_char_code, 0, 0), }, }; @@ -1064,7 +1064,7 @@ done: static njs_ret_t -njs_string_prototype_from_char_code(njs_vm_t *vm, njs_value_t *args, +njs_string_from_char_code(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { u_char *p; @@ -1409,6 +1409,10 @@ njs_string_prototype_to_upper_case(njs_v } +/* + * String.search([regexp]) + */ + static njs_ret_t njs_string_prototype_search(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) @@ -1482,6 +1486,7 @@ static njs_ret_t njs_string_prototype_match(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { + int *captures; u_char *start; int32_t size, length; njs_ret_t ret; @@ -1490,7 +1495,6 @@ njs_string_prototype_match(njs_vm_t *vm, njs_array_t *array; njs_string_prop_t string; njs_regexp_pattern_t *pattern; - int *captures; if (nargs == 1) { goto empty; @@ -2047,7 +2051,7 @@ static const njs_object_prop_t njs_stri NJS_STRING_OBJECT_ARG, NJS_INTEGER_ARG), }, - /* ECMAScript 6, codePointAt(). */ + /* String.codePointAt(), ECMAScript 6. */ { .type = NJS_METHOD, .name = njs_string("codePointAt"), diff -r e6e192a55774 -r dcd8a105b5e7 njs/njs_vm.h --- a/njs/njs_vm.h Mon Aug 15 11:33:37 2016 +0300 +++ b/njs/njs_vm.h Tue Aug 16 18:09:35 2016 +0300 @@ -780,7 +780,7 @@ struct njs_vm_s { nxt_lvlhsh_t values_hash; /* - * The prototypes and constructors arrays must be togther because + * The prototypes and constructors arrays must be together because * they are copied from njs_vm_shared_t by single memcpy() * in njs_builtin_objects_clone(). */ diff -r e6e192a55774 -r dcd8a105b5e7 nxt/nxt_djb_hash.h --- a/nxt/nxt_djb_hash.h Mon Aug 15 11:33:37 2016 +0300 +++ b/nxt/nxt_djb_hash.h Tue Aug 16 18:09:35 2016 +0300 @@ -18,7 +18,7 @@ NXT_EXPORT uint32_t nxt_djb_hash_lowcase #define NXT_DJB_HASH_INIT 5381 -#define nxt_djb_hash_add(hash, val) \ +#define nxt_djb_hash_add(hash, val) \ ((uint32_t) ((((hash) << 5) + (hash)) ^ (uint32_t) (val))) diff -r e6e192a55774 -r dcd8a105b5e7 nxt/nxt_lvlhsh.c --- a/nxt/nxt_lvlhsh.c Mon Aug 15 11:33:37 2016 +0300 +++ b/nxt/nxt_lvlhsh.c Tue Aug 16 18:09:35 2016 +0300 @@ -48,98 +48,98 @@ * several levels. */ -#define nxt_lvlhsh_is_bucket(p) \ +#define nxt_lvlhsh_is_bucket(p) \ ((uintptr_t) (p) & 1) -#define nxt_lvlhsh_count_inc(n) \ +#define nxt_lvlhsh_count_inc(n) \ n = (void *) ((uintptr_t) (n) + 2) -#define nxt_lvlhsh_count_dec(n) \ +#define nxt_lvlhsh_count_dec(n) \ n = (void *) ((uintptr_t) (n) - 2) -#define nxt_lvlhsh_level_size(proto, nlvl) \ +#define nxt_lvlhsh_level_size(proto, nlvl) \ ((uintptr_t) 1 << proto->shift[nlvl]) -#define nxt_lvlhsh_level(lvl, mask) \ +#define nxt_lvlhsh_level(lvl, mask) \ (void **) ((uintptr_t) lvl & (~mask << 2)) -#define nxt_lvlhsh_level_entries(lvl, mask) \ +#define nxt_lvlhsh_level_entries(lvl, mask) \ ((uintptr_t) lvl & (mask << 1)) -#define nxt_lvlhsh_store_bucket(slot, bkt) \ +#define nxt_lvlhsh_store_bucket(slot, bkt) \ slot = (void **) ((uintptr_t) bkt | 2 | 1) -#define nxt_lvlhsh_bucket_size(proto) \ +#define nxt_lvlhsh_bucket_size(proto) \ proto->bucket_size -#define nxt_lvlhsh_bucket(proto, bkt) \ +#define nxt_lvlhsh_bucket(proto, bkt) \ (uint32_t *) ((uintptr_t) bkt & ~(uintptr_t) proto->bucket_mask) -#define nxt_lvlhsh_bucket_entries(proto, bkt) \ +#define nxt_lvlhsh_bucket_entries(proto, bkt) \ (((uintptr_t) bkt & (uintptr_t) proto->bucket_mask) >> 1) -#define nxt_lvlhsh_bucket_end(proto, bkt) \ +#define nxt_lvlhsh_bucket_end(proto, bkt) \ &bkt[proto->bucket_end] -#define nxt_lvlhsh_free_entry(e) \ +#define nxt_lvlhsh_free_entry(e) \ (!(nxt_lvlhsh_valid_entry(e))) -#define nxt_lvlhsh_next_bucket(proto, bkt) \ +#define nxt_lvlhsh_next_bucket(proto, bkt) \ ((void **) &bkt[proto->bucket_end]) #if (NXT_64BIT) -#define nxt_lvlhsh_valid_entry(e) \ +#define nxt_lvlhsh_valid_entry(e) \ (((e)[0] | (e)[1]) != 0) -#define nxt_lvlhsh_entry_value(e) \ +#define nxt_lvlhsh_entry_value(e) \ (void *) (((uintptr_t) (e)[1] << 32) + (e)[0]) -#define nxt_lvlhsh_set_entry_value(e, n) \ +#define nxt_lvlhsh_set_entry_value(e, n) \ (e)[0] = (uint32_t) (uintptr_t) n; \ (e)[1] = (uint32_t) ((uintptr_t) n >> 32) -#define nxt_lvlhsh_entry_key(e) \ +#define nxt_lvlhsh_entry_key(e) \ (e)[2] -#define nxt_lvlhsh_set_entry_key(e, n) \ +#define nxt_lvlhsh_set_entry_key(e, n) \ (e)[2] = n #else -#define nxt_lvlhsh_valid_entry(e) \ +#define nxt_lvlhsh_valid_entry(e) \ ((e)[0] != 0) -#define nxt_lvlhsh_entry_value(e) \ +#define nxt_lvlhsh_entry_value(e) \ (void *) (e)[0] -#define nxt_lvlhsh_set_entry_value(e, n) \ +#define nxt_lvlhsh_set_entry_value(e, n) \ (e)[0] = (uint32_t) n -#define nxt_lvlhsh_entry_key(e) \ +#define nxt_lvlhsh_entry_key(e) \ (e)[1] -#define nxt_lvlhsh_set_entry_key(e, n) \ +#define nxt_lvlhsh_set_entry_key(e, n) \ (e)[1] = n #endif diff -r e6e192a55774 -r dcd8a105b5e7 nxt/nxt_lvlhsh.h --- a/nxt/nxt_lvlhsh.h Mon Aug 15 11:33:37 2016 +0300 +++ b/nxt/nxt_lvlhsh.h Tue Aug 16 18:09:35 2016 +0300 @@ -69,11 +69,11 @@ typedef void (*nxt_lvlhsh_free_t)(void * typedef struct { - uint32_t bucket_end; - uint32_t bucket_size; - uint32_t bucket_mask; - uint8_t shift[8]; - uint32_t nalloc; + uint32_t bucket_end; + uint32_t bucket_size; + uint32_t bucket_mask; + uint8_t shift[8]; + uint32_t nalloc; nxt_lvlhsh_test_t test; nxt_lvlhsh_alloc_t alloc; @@ -87,28 +87,28 @@ typedef struct { nxt_lvlhsh_free_t free; /* The maximum allowed aligned shift. */ - uint32_t max_shift; - uint32_t nalloc; + uint32_t max_shift; + uint32_t nalloc; } nxt_lvlhsh_ctx_t; typedef struct { - void *slot; + void *slot; } nxt_lvlhsh_t; struct nxt_lvlhsh_query_s { - uint32_t key_hash; - nxt_str_t key; + uint32_t key_hash; + nxt_str_t key; - uint8_t replace; /* 1 bit */ - void *value; + uint8_t replace; /* 1 bit */ + void *value; const nxt_lvlhsh_proto_t *proto; - void *pool; + void *pool; /* Opaque data passed for the test function. */ - void *data; + void *data; }; @@ -166,10 +166,10 @@ typedef struct { * bits, because entry positions are not aligned. A current level is * stored as key bit path from the root. */ - uint32_t *bucket; - uint32_t current; - uint32_t entry; - uint32_t entries; + uint32_t *bucket; + uint32_t current; + uint32_t entry; + uint32_t entries; } nxt_lvlhsh_each_t; diff -r e6e192a55774 -r dcd8a105b5e7 nxt/nxt_mem_cache_pool.c --- a/nxt/nxt_mem_cache_pool.c Mon Aug 15 11:33:37 2016 +0300 +++ b/nxt/nxt_mem_cache_pool.c Tue Aug 16 18:09:35 2016 +0300 @@ -110,15 +110,15 @@ struct nxt_mem_cache_pool_s { #define NXT_MEM_CACHE_EMBEDDED_BLOCK 2 -#define nxt_mem_cache_chunk_is_free(map, chunk) \ +#define nxt_mem_cache_chunk_is_free(map, chunk) \ ((map[chunk / 8] & (0x80 >> (chunk & 7))) == 0) -#define nxt_mem_cache_chunk_set_free(map, chunk) \ +#define nxt_mem_cache_chunk_set_free(map, chunk) \ map[chunk / 8] &= ~(0x80 >> (chunk & 7)) -#define nxt_mem_cache_free_junk(p, size) \ +#define nxt_mem_cache_free_junk(p, size) \ memset((p), 0x5A, size) diff -r e6e192a55774 -r dcd8a105b5e7 nxt/nxt_rbtree.c --- a/nxt/nxt_rbtree.c Mon Aug 15 11:33:37 2016 +0300 +++ b/nxt/nxt_rbtree.c Tue Aug 16 18:09:35 2016 +0300 @@ -54,7 +54,7 @@ nxt_rbtree_init(nxt_rbtree_t *tree, nxt_ /* * The sentinel's right child is never used so - * or comparison callback can be safely stored here. + * comparison callback can be safely stored here. */ tree->sentinel.right = (void *) compare; diff -r e6e192a55774 -r dcd8a105b5e7 nxt/nxt_rbtree.h --- a/nxt/nxt_rbtree.h Mon Aug 15 11:33:37 2016 +0300 +++ b/nxt/nxt_rbtree.h Tue Aug 16 18:09:35 2016 +0300 @@ -15,7 +15,7 @@ struct nxt_rbtree_node_s { nxt_rbtree_node_t *right; nxt_rbtree_node_t *parent; - uint8_t color; + uint8_t color; }; @@ -28,7 +28,7 @@ typedef struct { #define NXT_RBTREE_NODE(node) \ nxt_rbtree_part_t node; \ - uint8_t node##_color + uint8_t node##_color #define NXT_RBTREE_NODE_INIT { NULL, NULL, NULL }, 0 From igor at sysoev.ru Tue Aug 16 16:14:37 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 16 Aug 2016 16:14:37 +0000 Subject: [njs] String.match() fixes. Message-ID: details: http://hg.nginx.org/njs/rev/5d9e4adf25c2 branches: changeset: 157:5d9e4adf25c2 user: Igor Sysoev date: Tue Aug 16 18:58:30 2016 +0300 description: String.match() fixes. diffstat: njs/njs_regexp.c | 69 +++++++++++++---------- njs/njs_regexp.h | 2 + njs/njs_string.c | 133 +++++++++++++++++++++------------------------- njs/njs_vm.h | 1 + njs/test/njs_unit_test.c | 9 +++ 5 files changed, 112 insertions(+), 102 deletions(-) diffs (331 lines): diff -r dcd8a105b5e7 -r 5d9e4adf25c2 njs/njs_regexp.c --- a/njs/njs_regexp.c Tue Aug 16 18:09:35 2016 +0300 +++ b/njs/njs_regexp.c Tue Aug 16 18:58:30 2016 +0300 @@ -65,7 +65,8 @@ njs_regexp_init(njs_vm_t *vm) vm->regex_context->trace = &vm->trace; - return NXT_OK; + return njs_regexp_create(vm, &vm->empty_regexp, (u_char *) "(?:)", + sizeof("(?:)") - 1, 0); } @@ -87,20 +88,22 @@ njs_ret_t njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - size_t length; - njs_regexp_t *regexp; - njs_string_prop_t string; - njs_regexp_flags_t flags; - njs_regexp_pattern_t *pattern; + njs_string_prop_t string; + njs_regexp_flags_t flags; flags = 0; switch (nargs) { + case 1: + string.start = NULL; + string.size = 0; + break; + default: - length = njs_string_prop(&string, &args[2]); + (void) njs_string_prop(&string, &args[2]); - flags = njs_regexp_flags(&string.start, string.start + length, 1); + flags = njs_regexp_flags(&string.start, string.start + string.size, 1); if (nxt_slow_path(flags < 0)) { return NXT_ERROR; } @@ -108,36 +111,42 @@ njs_regexp_constructor(njs_vm_t *vm, njs /* Fall through. */ case 2: - string.length = njs_string_prop(&string, &args[1]); - - if (string.length != 0) { - break; - } - - /* Fall through. */ - - case 1: - string.start = (u_char *) "(?:)"; - string.length = sizeof("(?:)") - 1; + (void) njs_string_prop(&string, &args[1]); break; } - pattern = njs_regexp_pattern_create(vm, string.start, string.length, flags); - - if (nxt_fast_path(pattern != NULL)) { - - regexp = njs_regexp_alloc(vm, pattern); + return njs_regexp_create(vm, &vm->retval, string.start, string.size, flags); +} - if (nxt_fast_path(regexp != NULL)) { - vm->retval.data.u.regexp = regexp; - vm->retval.type = NJS_REGEXP; - vm->retval.data.truth = 1; - return NXT_OK; +nxt_int_t +njs_regexp_create(njs_vm_t *vm, njs_value_t *value, u_char *start, + size_t length, njs_regexp_flags_t flags) +{ + njs_regexp_t *regexp; + njs_regexp_pattern_t *pattern; + + if (length != 0) { + pattern = njs_regexp_pattern_create(vm, start, length, flags); + + if (nxt_fast_path(pattern != NULL)) { + regexp = njs_regexp_alloc(vm, pattern); + + if (nxt_fast_path(regexp != NULL)) { + value->data.u.regexp = regexp; + value->type = NJS_REGEXP; + value->data.truth = 1; + + return NXT_OK; + } } + + return NXT_ERROR; } - return NXT_ERROR; + *value = vm->empty_regexp; + + return NXT_OK; } diff -r dcd8a105b5e7 -r 5d9e4adf25c2 njs/njs_regexp.h --- a/njs/njs_regexp.h Tue Aug 16 18:09:35 2016 +0300 +++ b/njs/njs_regexp.h Tue Aug 16 18:58:30 2016 +0300 @@ -35,6 +35,8 @@ struct njs_regexp_s { njs_ret_t njs_regexp_init(njs_vm_t *vm); njs_ret_t njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +nxt_int_t njs_regexp_create(njs_vm_t *vm, njs_value_t *value, u_char *start, + size_t length, njs_regexp_flags_t flags); njs_token_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, njs_value_t *value); njs_regexp_pattern_t *njs_regexp_pattern_create(njs_vm_t *vm, diff -r dcd8a105b5e7 -r 5d9e4adf25c2 njs/njs_string.c --- a/njs/njs_string.c Tue Aug 16 18:09:35 2016 +0300 +++ b/njs/njs_string.c Tue Aug 16 18:58:30 2016 +0300 @@ -41,6 +41,8 @@ static njs_ret_t njs_string_from_char_co njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); static nxt_noinline ssize_t njs_string_index_of(njs_vm_t *vm, njs_value_t *src, njs_value_t *search_string, size_t index); +static njs_ret_t njs_string_match_multiple(njs_vm_t *vm, njs_value_t *args, + njs_regexp_pattern_t *pattern); static njs_ret_t njs_string_split_part_add(njs_vm_t *vm, njs_array_t *array, u_char *start, size_t size, nxt_uint_t utf8); @@ -1429,26 +1431,27 @@ njs_string_prototype_search(njs_vm_t *vm switch (args[1].type) { - case NJS_VOID: - goto done; + case NJS_REGEXP: + pattern = args[1].data.u.regexp->pattern; + break; case NJS_STRING: (void) njs_string_prop(&string, &args[1]); - if (string.size == 0) { - goto done; + if (string.size != 0) { + pattern = njs_regexp_pattern_create(vm, string.start, + string.size, 0); + if (nxt_slow_path(pattern == NULL)) { + return NXT_ERROR; + } + + break; } - pattern = njs_regexp_pattern_create(vm, string.start, - string.length, 0); - if (nxt_slow_path(pattern == NULL)) { - return NXT_ERROR; - } - - break; - - default: /* NJS_REGEXP */ - pattern = args[1].data.u.regexp->pattern; + goto done; + + default: /* NJS_VOID */ + goto done; } index = -1; @@ -1486,55 +1489,61 @@ static njs_ret_t njs_string_prototype_match(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - int *captures; - u_char *start; - int32_t size, length; njs_ret_t ret; - nxt_uint_t n, utf8; - njs_value_t tmp; - njs_array_t *array; + njs_value_t arguments[2]; njs_string_prop_t string; njs_regexp_pattern_t *pattern; - if (nargs == 1) { - goto empty; - } - - switch (args[1].type) { - - case NJS_VOID: - goto empty; - - case NJS_STRING: - (void) njs_string_prop(&string, &args[1]); - - if (string.size == 0) { - goto empty; - } - - pattern = njs_regexp_pattern_create(vm, string.start, string.length, 0); - if (nxt_slow_path(pattern == NULL)) { - return NXT_ERROR; - } - - break; - - default: /* NJS_REGEXP */ - pattern = args[1].data.u.regexp->pattern; - - if (!pattern->global) { + arguments[0] = vm->empty_regexp; + arguments[1] = args[0]; + + if (nargs > 1) { + + if (njs_is_regexp(&args[1])) { + pattern = args[1].data.u.regexp->pattern; + + if (pattern->global) { + return njs_string_match_multiple(vm, args, pattern); + } + /* * string.match(regexp) is the same as regexp.exec(string) * if the regexp has no global flag. */ - tmp = args[0]; - args[0] = args[1]; - args[1] = tmp; - - return njs_regexp_prototype_exec(vm, args, nargs, unused); + arguments[0] = args[1]; + + } else if (njs_is_string(&args[1])) { + /* string1.match(string2) is the same as /string2/.exec(string1). */ + + (void) njs_string_prop(&string, &args[1]); + + ret = njs_regexp_create(vm, &arguments[0], string.start, + string.size, 0); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } } + + /* A void value. */ } + return njs_regexp_prototype_exec(vm, arguments, nargs, unused); +} + + +static njs_ret_t +njs_string_match_multiple(njs_vm_t *vm, njs_value_t *args, + njs_regexp_pattern_t *pattern) +{ + int *captures; + u_char *start; + int32_t size, length; + njs_ret_t ret; + nxt_uint_t n, utf8; + njs_array_t *array; + njs_string_prop_t string; + + args[1].data.u.regexp->last_index = 0; vm->retval = njs_value_null; (void) njs_string_prop(&string, &args[0]); @@ -1626,26 +1635,6 @@ njs_string_prototype_match(njs_vm_t *vm, } while (string.size > 0); } - if (njs_is_regexp(&args[1])) { - args[1].data.u.regexp->last_index = 0; - } - - return NXT_OK; - -empty: - - array = njs_array_alloc(vm, 1, 0); - if (nxt_slow_path(array == NULL)) { - return NXT_ERROR; - } - - array->length = 1; - array->start[0] = njs_string_empty; - - vm->retval.data.u.array = array; - vm->retval.type = NJS_ARRAY; - vm->retval.data.truth = 1; - return NXT_OK; } diff -r dcd8a105b5e7 -r 5d9e4adf25c2 njs/njs_vm.h --- a/njs/njs_vm.h Tue Aug 16 18:09:35 2016 +0300 +++ b/njs/njs_vm.h Tue Aug 16 18:58:30 2016 +0300 @@ -797,6 +797,7 @@ struct njs_vm_s { nxt_regex_context_t *regex_context; nxt_regex_match_data_t *single_match_data; + njs_value_t empty_regexp; nxt_array_t *code; /* of njs_vm_code_t */ diff -r dcd8a105b5e7 -r 5d9e4adf25c2 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 16 18:09:35 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Aug 16 18:58:30 2016 +0300 @@ -3229,6 +3229,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("'abcdefgh'.match(/def/)"), nxt_string("def") }, + { nxt_string("'abc abc abc'.match('abc')"), + nxt_string("abc") }, + + { nxt_string("'abc abc abc'.match(/abc/)"), + nxt_string("abc") }, + + { nxt_string("'abc abc abc'.match(/abc/g)"), + nxt_string("abc,abc,abc") }, + { nxt_string("'abc ABC aBc'.match(/abc/ig)"), nxt_string("abc,ABC,aBc") }, From igor at sysoev.ru Tue Aug 16 16:14:38 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 16 Aug 2016 16:14:38 +0000 Subject: [njs] Version 0.1.1. Message-ID: details: http://hg.nginx.org/njs/rev/0039a747d25a branches: changeset: 158:0039a747d25a user: Igor Sysoev date: Tue Aug 16 19:09:03 2016 +0300 description: Version 0.1.1. diffstat: Makefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (10 lines): diff -r 5d9e4adf25c2 -r 0039a747d25a Makefile --- a/Makefile Tue Aug 16 18:58:30 2016 +0300 +++ b/Makefile Tue Aug 16 19:09:03 2016 +0300 @@ -1,5 +1,5 @@ -NJS_VER = 0.1.0 +NJS_VER = 0.1.1 NXT_LIB = nxt From igor at sysoev.ru Tue Aug 16 16:14:39 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Tue, 16 Aug 2016 16:14:39 +0000 Subject: [njs] Added tag 0.1.1 for changeset 0039a747d25a Message-ID: details: http://hg.nginx.org/njs/rev/7cce82b6b40b branches: changeset: 159:7cce82b6b40b user: Igor Sysoev date: Tue Aug 16 19:13:41 2016 +0300 description: Added tag 0.1.1 for changeset 0039a747d25a diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (6 lines): diff -r 0039a747d25a -r 7cce82b6b40b .hgtags --- a/.hgtags Tue Aug 16 19:09:03 2016 +0300 +++ b/.hgtags Tue Aug 16 19:13:41 2016 +0300 @@ -1,1 +1,2 @@ cdb8d20935ee96f1fa0c99d994d4b11cefcbc119 0.1.0 +0039a747d25a3e08792c23c43b75768896724031 0.1.1 From mdounin at mdounin.ru Wed Aug 17 23:44:59 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 18 Aug 2016 02:44:59 +0300 Subject: Dynamic module and obtaining http core module configuration In-Reply-To: References: Message-ID: <20160817234458.GD24741@mdounin.ru> Hello! On Wed, Aug 10, 2016 at 12:09:54PM +0300, R?dolfs Bundulis wrote: > Hi, > > I am trying to make a dynamic nginx module. After reading all the tutorials > and stuff available I set up a working minimal sample and started hooking > up my http handlers. The question that arose is, in the static modules the > http module configuration is retrieved like this (in a lets say > postconfiguration handler): > > static ngx_int_t postconfiguration_handler(ngx_conf_t* cf) > { > ngx_http_core_main_conf_t* nginx_http_configuration = > reinterpret_cast(ngx_http_conf_get_module_main_conf(cf, > ngx_http_core_module)); > ... > > If I'm not overlooking something this will not work (and in my case does > not) with a dynamic module > the ngx_http_core_module.ctx_index is not initialized since the initialized > version of ngx_http_core_module lives inside nginx.exe (where it is set by > ngx_count_modules) and my dll does not see that. If could run through the > module list and find what I need, but I just wanted to know if there is a > better solution already in place. The ngx_http_core_module symbol from the main binary is expected to be available in modules as well, imported there from the main binary. This is how it works on Unix. On the other hand, on Windows there may be unexpected effects. We don't really support dynamic modules on Windows now - they can be only build using mingw-gcc with "-Wl,--export-all-symbols", and I've seen reports that "--export-all-symbols" may produce incorrect code in some cases. If you are trying to make nginx modules, consider doing this on Unix, not on Windows. -- Maxim Dounin http://nginx.org/ From piotrsikora at google.com Thu Aug 18 00:29:22 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 17 Aug 2016 17:29:22 -0700 Subject: [PATCH 1 of 6] SSL: define NGX_SSL_VERIFY constants Message-ID: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> # HG changeset patch # User Piotr Sikora # Date 1471428975 25200 # Wed Aug 17 03:16:15 2016 -0700 # Node ID 653b04653271346c63ab5f3daced807228eed5ac # Parent c131f20c9562387f94a268440594c288725d3ba8 SSL: define NGX_SSL_VERIFY constants. No binary changes. Signed-off-by: Piotr Sikora diff -r c131f20c9562 -r 653b04653271 src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -125,17 +125,21 @@ typedef struct { #endif -#define NGX_SSL_SSLv2 0x0002 -#define NGX_SSL_SSLv3 0x0004 -#define NGX_SSL_TLSv1 0x0008 -#define NGX_SSL_TLSv1_1 0x0010 -#define NGX_SSL_TLSv1_2 0x0020 +#define NGX_SSL_SSLv2 0x0002 +#define NGX_SSL_SSLv3 0x0004 +#define NGX_SSL_TLSv1 0x0008 +#define NGX_SSL_TLSv1_1 0x0010 +#define NGX_SSL_TLSv1_2 0x0020 +#define NGX_SSL_VERIFY_OFF 0 +#define NGX_SSL_VERIFY_REQUIRED 1 +#define NGX_SSL_VERIFY_OPTIONAL 2 +#define NGX_SSL_VERIFY_OPTIONAL_NO_CA 3 -#define NGX_SSL_BUFFER 1 -#define NGX_SSL_CLIENT 2 +#define NGX_SSL_BUFFER 1 +#define NGX_SSL_CLIENT 2 -#define NGX_SSL_BUFSIZE 16384 +#define NGX_SSL_BUFSIZE 16384 ngx_int_t ngx_ssl_init(ngx_log_t *log); diff -r c131f20c9562 -r 653b04653271 src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -62,10 +62,10 @@ static ngx_conf_bitmask_t ngx_http_ssl_ static ngx_conf_enum_t ngx_http_ssl_verify[] = { - { ngx_string("off"), 0 }, - { ngx_string("on"), 1 }, - { ngx_string("optional"), 2 }, - { ngx_string("optional_no_ca"), 3 }, + { ngx_string("off"), NGX_SSL_VERIFY_OFF }, + { ngx_string("on"), NGX_SSL_VERIFY_REQUIRED }, + { ngx_string("optional"), NGX_SSL_VERIFY_OPTIONAL }, + { ngx_string("optional_no_ca"), NGX_SSL_VERIFY_OPTIONAL_NO_CA }, { ngx_null_string, 0 } }; @@ -570,7 +570,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, NGX_SSL_BUFSIZE); - ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); + ngx_conf_merge_uint_value(conf->verify, prev->verify, NGX_SSL_VERIFY_OFF); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL); @@ -700,7 +700,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * if (conf->verify) { - if (conf->client_certificate.len == 0 && conf->verify != 3) { + if (conf->client_certificate.len == 0 + && conf->verify != NGX_SSL_VERIFY_OPTIONAL_NO_CA) + { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no ssl_client_certificate for ssl_client_verify"); return NGX_CONF_ERROR; diff -r c131f20c9562 -r 653b04653271 src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1862,7 +1862,8 @@ ngx_http_process_request(ngx_http_reques rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK - && (sscf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) + && (sscf->verify != NGX_SSL_VERIFY_OPTIONAL_NO_CA + || !ngx_ssl_verify_error_optional(rc))) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client SSL certificate verify error: (%l:%s)", @@ -1875,7 +1876,7 @@ ngx_http_process_request(ngx_http_reques return; } - if (sscf->verify == 1) { + if (sscf->verify == NGX_SSL_VERIFY_REQUIRED) { cert = SSL_get_peer_certificate(c->ssl->connection); if (cert == NULL) { diff -r c131f20c9562 -r 653b04653271 src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -296,7 +296,8 @@ ngx_mail_verify_cert(ngx_mail_session_t rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK - && (sslcf->verify != 3 || !ngx_ssl_verify_error_optional(rc))) + && (sslcf->verify != NGX_SSL_VERIFY_OPTIONAL_NO_CA + || !ngx_ssl_verify_error_optional(rc))) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client SSL certificate verify error: (%l:%s)", @@ -316,7 +317,7 @@ ngx_mail_verify_cert(ngx_mail_session_t return NGX_ERROR; } - if (sslcf->verify == 1) { + if (sslcf->verify == NGX_SSL_VERIFY_REQUIRED) { cert = SSL_get_peer_certificate(c->ssl->connection); if (cert == NULL) { diff -r c131f20c9562 -r 653b04653271 src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -47,10 +47,10 @@ static ngx_conf_bitmask_t ngx_mail_ssl_ static ngx_conf_enum_t ngx_mail_ssl_verify[] = { - { ngx_string("off"), 0 }, - { ngx_string("on"), 1 }, - { ngx_string("optional"), 2 }, - { ngx_string("optional_no_ca"), 3 }, + { ngx_string("off"), NGX_SSL_VERIFY_OFF }, + { ngx_string("on"), NGX_SSL_VERIFY_REQUIRED }, + { ngx_string("optional"), NGX_SSL_VERIFY_OPTIONAL }, + { ngx_string("optional_no_ca"), NGX_SSL_VERIFY_OPTIONAL_NO_CA }, { ngx_null_string, 0 } }; @@ -287,7 +287,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); - ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); + ngx_conf_merge_uint_value(conf->verify, prev->verify, NGX_SSL_VERIFY_OFF); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL); @@ -395,7 +395,9 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, if (conf->verify) { - if (conf->client_certificate.len == 0 && conf->verify != 3) { + if (conf->client_certificate.len == 0 + && conf->verify != NGX_SSL_VERIFY_OPTIONAL_NO_CA) + { ngx_log_error(NGX_LOG_EMERG, cf->log, 0, "no ssl_client_certificate for ssl_client_verify"); return NGX_CONF_ERROR; From piotrsikora at google.com Thu Aug 18 00:29:23 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 17 Aug 2016 17:29:23 -0700 Subject: [PATCH 2 of 6] SSL: pull common SSL defines into OpenSSL module In-Reply-To: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> References: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> Message-ID: <788c6187bdbd72787ba2.1471480163@piotrsikora.sfo.corp.google.com> # HG changeset patch # User Piotr Sikora # Date 1471428980 25200 # Wed Aug 17 03:16:20 2016 -0700 # Node ID 788c6187bdbd72787ba24505731e42b6a2307be3 # Parent 653b04653271346c63ab5f3daced807228eed5ac SSL: pull common SSL defines into OpenSSL module. Those values are OpenSSL-specific anyway. No binary changes (without reorder in ngx_mail_ssl_module). Signed-off-by: Piotr Sikora diff -r 653b04653271 -r 788c6187bdbd src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -131,6 +131,13 @@ typedef struct { #define NGX_SSL_TLSv1_1 0x0010 #define NGX_SSL_TLSv1_2 0x0020 +#define NGX_SSL_DEFAULT_PROTOCOLS \ + (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1|NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2) + +#define NGX_SSL_DEFAULT_ECDH_CURVE "auto" +#define NGX_SSL_DEFAULT_SERVER_CIPHERS "HIGH:!aNULL:!MD5" +#define NGX_SSL_DEFAULT_CLIENT_CIPHERS "DEFAULT" + #define NGX_SSL_VERIFY_OFF 0 #define NGX_SSL_VERIFY_REQUIRED 1 #define NGX_SSL_VERIFY_OPTIONAL 2 diff -r 653b04653271 -r 788c6187bdbd src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -3174,11 +3174,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t prev->upstream.ssl_session_reuse, 1); ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + NGX_SSL_DEFAULT_PROTOCOLS); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, - "DEFAULT"); + NGX_SSL_DEFAULT_CLIENT_CIPHERS); if (conf->upstream.ssl_name == NULL) { conf->upstream.ssl_name = prev->upstream.ssl_name; diff -r 653b04653271 -r 788c6187bdbd src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -14,9 +14,6 @@ typedef ngx_int_t (*ngx_ssl_variable_han ngx_pool_t *pool, ngx_str_t *s); -#define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" -#define NGX_DEFAULT_ECDH_CURVE "auto" - #define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1" @@ -564,8 +561,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + NGX_SSL_DEFAULT_PROTOCOLS); ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, NGX_SSL_BUFSIZE); @@ -588,9 +584,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_conf_merge_str_value(conf->crl, prev->crl, ""); ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, - NGX_DEFAULT_ECDH_CURVE); + NGX_SSL_DEFAULT_ECDH_CURVE); - ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, + NGX_SSL_DEFAULT_SERVER_CIPHERS); ngx_conf_merge_value(conf->stapling, prev->stapling, 0); ngx_conf_merge_value(conf->stapling_verify, prev->stapling_verify, 0); diff -r 653b04653271 -r 788c6187bdbd src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -1726,11 +1726,10 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t prev->upstream.ssl_session_reuse, 1); ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + NGX_SSL_DEFAULT_PROTOCOLS); ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, - "DEFAULT"); + NGX_SSL_DEFAULT_CLIENT_CIPHERS); if (conf->upstream.ssl_name == NULL) { conf->upstream.ssl_name = prev->upstream.ssl_name; diff -r 653b04653271 -r 788c6187bdbd src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -10,10 +10,6 @@ #include -#define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" -#define NGX_DEFAULT_ECDH_CURVE "auto" - - static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -284,8 +280,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + NGX_SSL_DEFAULT_PROTOCOLS); ngx_conf_merge_uint_value(conf->verify, prev->verify, NGX_SSL_VERIFY_OFF); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); @@ -299,7 +294,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, - NGX_DEFAULT_ECDH_CURVE); + NGX_SSL_DEFAULT_ECDH_CURVE); + + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, + NGX_SSL_DEFAULT_SERVER_CIPHERS); ngx_conf_merge_str_value(conf->client_certificate, prev->client_certificate, ""); @@ -307,9 +305,6 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, prev->trusted_certificate, ""); ngx_conf_merge_str_value(conf->crl, prev->crl, ""); - ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); - - conf->ssl.log = cf->log; if (conf->enable) { diff -r 653b04653271 -r 788c6187bdbd src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -1794,10 +1794,10 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf prev->ssl_session_reuse, 1); ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); - - ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); + NGX_SSL_DEFAULT_PROTOCOLS); + + ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, + NGX_SSL_DEFAULT_CLIENT_CIPHERS); if (conf->ssl_name == NULL) { conf->ssl_name = prev->ssl_name; diff -r 653b04653271 -r 788c6187bdbd src/stream/ngx_stream_ssl_module.c --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -14,10 +14,6 @@ typedef ngx_int_t (*ngx_ssl_variable_han ngx_pool_t *pool, ngx_str_t *s); -#define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" -#define NGX_DEFAULT_ECDH_CURVE "auto" - - static ngx_int_t ngx_stream_ssl_static_variable(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_ssl_variable(ngx_stream_session_t *s, @@ -327,8 +323,7 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf prev->prefer_server_ciphers, 0); ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols, - (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1 - |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2)); + NGX_SSL_DEFAULT_PROTOCOLS); ngx_conf_merge_ptr_value(conf->certificates, prev->certificates, NULL); ngx_conf_merge_ptr_value(conf->certificate_keys, prev->certificate_keys, @@ -339,10 +334,10 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); ngx_conf_merge_str_value(conf->ecdh_curve, prev->ecdh_curve, - NGX_DEFAULT_ECDH_CURVE); + NGX_SSL_DEFAULT_ECDH_CURVE); - ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); - + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, + NGX_SSL_DEFAULT_SERVER_CIPHERS); conf->ssl.log = cf->log; From piotrsikora at google.com Thu Aug 18 00:29:25 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 17 Aug 2016 17:29:25 -0700 Subject: [PATCH 4 of 6] SSL: add ngx_ssl_verify_client() In-Reply-To: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> References: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> Message-ID: # HG changeset patch # User Piotr Sikora # Date 1471428990 25200 # Wed Aug 17 03:16:30 2016 -0700 # Node ID a9f36e1dd744130aa2ba080ae2a63f07986c8e83 # Parent 99c2f52beae28567bf2f8501d1a182cd20004c71 SSL: add ngx_ssl_verify_client(). No functional changes. Signed-off-by: Piotr Sikora diff -r 99c2f52beae2 -r a9f36e1dd744 src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3075,6 +3075,39 @@ ngx_ssl_cleanup_ctx(void *data) ngx_int_t +ngx_ssl_verify_client(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_uint_t verify) +{ + long rc; + X509 *cert; + + rc = SSL_get_verify_result(c->ssl->connection); + + if (rc != X509_V_OK + && (verify != NGX_SSL_VERIFY_OPTIONAL_NO_CA + || !ngx_ssl_verify_error_optional(rc))) + { + ngx_ssl_remove_cached_session(ssl->ctx, + SSL_get0_session(c->ssl->connection)); + return (ngx_int_t) rc; + } + + if (verify == NGX_SSL_VERIFY_REQUIRED) { + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert == NULL) { + ngx_ssl_remove_cached_session(ssl->ctx, + SSL_get0_session(c->ssl->connection)); + return NGX_DECLINED; + } + + X509_free(cert); + } + + return NGX_OK; +} + + +ngx_int_t ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name) { X509 *cert; diff -r 99c2f52beae2 -r a9f36e1dd744 src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -188,12 +188,15 @@ ngx_int_t ngx_ssl_set_session(ngx_connec #define ngx_ssl_get_server_conf(ssl_ctx) \ SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_server_conf_index) +ngx_int_t ngx_ssl_verify_client(ngx_connection_t *c, ngx_ssl_t *ssl, + ngx_uint_t verify); #define ngx_ssl_verify_error_optional(n) \ (n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT \ || n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN \ || n == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY \ || n == X509_V_ERR_CERT_UNTRUSTED \ || n == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) +#define ngx_ssl_verify_error_string(n) X509_verify_cert_error_string((long) n) ngx_int_t ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name); diff -r 99c2f52beae2 -r a9f36e1dd744 src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1845,8 +1845,7 @@ ngx_http_process_request(ngx_http_reques #if (NGX_HTTP_SSL) if (r->http_connection->ssl) { - long rc; - X509 *cert; + ngx_int_t rc; ngx_http_ssl_srv_conf_t *sscf; if (c->ssl == NULL) { @@ -1859,39 +1858,23 @@ ngx_http_process_request(ngx_http_reques sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); if (sscf->verify) { - rc = SSL_get_verify_result(c->ssl->connection); - - if (rc != X509_V_OK - && (sscf->verify != NGX_SSL_VERIFY_OPTIONAL_NO_CA - || !ngx_ssl_verify_error_optional(rc))) - { + rc = ngx_ssl_verify_client(c, &sscf->ssl, sscf->verify); + + if (rc == NGX_DECLINED) { ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client SSL certificate verify error: (%l:%s)", - rc, X509_verify_cert_error_string(rc)); - - ngx_ssl_remove_cached_session(sscf->ssl.ctx, - (SSL_get0_session(c->ssl->connection))); + "client sent no required SSL certificate"); + + ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); + return; + + } else if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client SSL certificate verify error: (%i:%s)", + rc, ngx_ssl_verify_error_string(rc)); ngx_http_finalize_request(r, NGX_HTTPS_CERT_ERROR); return; } - - if (sscf->verify == NGX_SSL_VERIFY_REQUIRED) { - cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert == NULL) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent no required SSL certificate"); - - ngx_ssl_remove_cached_session(sscf->ssl.ctx, - (SSL_get0_session(c->ssl->connection))); - - ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); - return; - } - - X509_free(cert); - } } } diff -r 99c2f52beae2 -r a9f36e1dd744 src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -16,8 +16,6 @@ static void ngx_mail_init_session(ngx_co #if (NGX_MAIL_SSL) static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c); static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c); -static ngx_int_t ngx_mail_verify_cert(ngx_mail_session_t *s, - ngx_connection_t *c); #endif @@ -247,15 +245,44 @@ ngx_mail_ssl_init_connection(ngx_ssl_t * static void ngx_mail_ssl_handshake_handler(ngx_connection_t *c) { + ngx_int_t rc; ngx_mail_session_t *s; + ngx_mail_ssl_conf_t *sslcf; ngx_mail_core_srv_conf_t *cscf; if (c->ssl->handshaked) { s = c->data; - if (ngx_mail_verify_cert(s, c) != NGX_OK) { - return; + sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); + + if (sslcf->verify) { + rc = ngx_ssl_verify_client(c, &sslcf->ssl, sslcf->verify); + + if (rc != NGX_OK) { + cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); + + if (rc == NGX_DECLINED) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent no required SSL certificate"); + + s->out = cscf->protocol->no_cert; + + } else { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client SSL certificate verify error: (%i:%s)", + rc, ngx_ssl_verify_error_string(rc)); + + s->out = cscf->protocol->cert_error; + } + + s->quit = 1; + + c->write->handler = ngx_mail_send; + + ngx_mail_send(s->connection->write); + return; + } } if (s->starttls) { @@ -278,72 +305,6 @@ ngx_mail_ssl_handshake_handler(ngx_conne ngx_mail_close_connection(c); } - -static ngx_int_t -ngx_mail_verify_cert(ngx_mail_session_t *s, ngx_connection_t *c) -{ - long rc; - X509 *cert; - ngx_mail_ssl_conf_t *sslcf; - ngx_mail_core_srv_conf_t *cscf; - - sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); - - if (!sslcf->verify) { - return NGX_OK; - } - - rc = SSL_get_verify_result(c->ssl->connection); - - if (rc != X509_V_OK - && (sslcf->verify != NGX_SSL_VERIFY_OPTIONAL_NO_CA - || !ngx_ssl_verify_error_optional(rc))) - { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client SSL certificate verify error: (%l:%s)", - rc, X509_verify_cert_error_string(rc)); - - ngx_ssl_remove_cached_session(sslcf->ssl.ctx, - (SSL_get0_session(c->ssl->connection))); - - cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); - - s->out = cscf->protocol->cert_error; - s->quit = 1; - - c->write->handler = ngx_mail_send; - - ngx_mail_send(s->connection->write); - return NGX_ERROR; - } - - if (sslcf->verify == NGX_SSL_VERIFY_REQUIRED) { - cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert == NULL) { - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "client sent no required SSL certificate"); - - ngx_ssl_remove_cached_session(sslcf->ssl.ctx, - (SSL_get0_session(c->ssl->connection))); - - cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module); - - s->out = cscf->protocol->no_cert; - s->quit = 1; - - c->write->handler = ngx_mail_send; - - ngx_mail_send(s->connection->write); - return NGX_ERROR; - } - - X509_free(cert); - } - - return NGX_OK; -} - #endif From piotrsikora at google.com Thu Aug 18 00:29:26 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 17 Aug 2016 17:29:26 -0700 Subject: [PATCH 5 of 6] SSL: add ngx_ssl_verify_host() In-Reply-To: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> References: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> Message-ID: <5550dfc1414afcd5471b.1471480166@piotrsikora.sfo.corp.google.com> # HG changeset patch # User Piotr Sikora # Date 1471428995 25200 # Wed Aug 17 03:16:35 2016 -0700 # Node ID 5550dfc1414afcd5471b7fc8ca4482f7e18ba865 # Parent a9f36e1dd744130aa2ba080ae2a63f07986c8e83 SSL: add ngx_ssl_verify_host(). No functional changes. Signed-off-by: Piotr Sikora diff -r a9f36e1dd744 -r 5550dfc1414a src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3108,6 +3108,24 @@ ngx_ssl_verify_client(ngx_connection_t * ngx_int_t +ngx_ssl_verify_host(ngx_connection_t *c, ngx_str_t *name) +{ + long rc; + + rc = SSL_get_verify_result(c->ssl->connection); + if (rc != X509_V_OK) { + return (ngx_int_t) rc; + } + + if (ngx_ssl_check_host(c, name) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_int_t ngx_ssl_check_host(ngx_connection_t *c, ngx_str_t *name) { X509 *cert; diff -r a9f36e1dd744 -r 5550dfc1414a src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -190,6 +190,7 @@ ngx_int_t ngx_ssl_set_session(ngx_connec ngx_int_t ngx_ssl_verify_client(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_uint_t verify); +ngx_int_t ngx_ssl_verify_host(ngx_connection_t *c, ngx_str_t *name); #define ngx_ssl_verify_error_optional(n) \ (n == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT \ || n == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN \ diff -r a9f36e1dd744 -r 5550dfc1414a src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1565,7 +1565,7 @@ ngx_http_upstream_ssl_init_connection(ng static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c) { - long rc; + ngx_int_t rc; ngx_http_request_t *r; ngx_http_upstream_t *u; @@ -1577,20 +1577,19 @@ ngx_http_upstream_ssl_handshake(ngx_conn if (c->ssl->handshaked) { if (u->conf->ssl_verify) { - rc = SSL_get_verify_result(c->ssl->connection); - - if (rc != X509_V_OK) { - ngx_log_error(NGX_LOG_ERR, c->log, 0, - "upstream SSL certificate verify error: (%l:%s)", - rc, X509_verify_cert_error_string(rc)); - goto failed; - } - - if (ngx_ssl_check_host(c, &u->ssl_name) != NGX_OK) { + rc = ngx_ssl_verify_host(c, &u->ssl_name); + + if (rc == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "upstream SSL certificate does not match \"%V\"", &u->ssl_name); goto failed; + + } else if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "upstream SSL certificate verify error: (%i:%s)", + rc, ngx_ssl_verify_error_string(rc)); + goto failed; } } diff -r a9f36e1dd744 -r 5550dfc1414a src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -976,7 +976,7 @@ ngx_stream_proxy_ssl_init_connection(ngx static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc) { - long rc; + ngx_int_t rc; ngx_stream_session_t *s; ngx_stream_upstream_t *u; ngx_stream_proxy_srv_conf_t *pscf; @@ -988,21 +988,18 @@ ngx_stream_proxy_ssl_handshake(ngx_conne if (pc->ssl->handshaked) { if (pscf->ssl_verify) { - rc = SSL_get_verify_result(pc->ssl->connection); - - if (rc != X509_V_OK) { - ngx_log_error(NGX_LOG_ERR, pc->log, 0, - "upstream SSL certificate verify error: (%l:%s)", - rc, X509_verify_cert_error_string(rc)); - goto failed; - } - - u = s->upstream; - - if (ngx_ssl_check_host(pc, &u->ssl_name) != NGX_OK) { + rc = ngx_ssl_verify_host(pc, &s->upstream->ssl_name); + + if (rc == NGX_ERROR) { ngx_log_error(NGX_LOG_ERR, pc->log, 0, "upstream SSL certificate does not match \"%V\"", - &u->ssl_name); + &s->upstream->ssl_name); + goto failed; + + } else if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, pc->log, 0, + "upstream SSL certificate verify error: (%i:%s)", + rc, ngx_ssl_verify_error_string(rc)); goto failed; } } From piotrsikora at google.com Thu Aug 18 00:29:27 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 17 Aug 2016 17:29:27 -0700 Subject: [PATCH 6 of 6] SSL: fix order of checks during SSL certificate verification In-Reply-To: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> References: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> Message-ID: <7bc55832b01ad62ac85f.1471480167@piotrsikora.sfo.corp.google.com> # HG changeset patch # User Piotr Sikora # Date 1471429000 25200 # Wed Aug 17 03:16:40 2016 -0700 # Node ID 7bc55832b01ad62ac85f7fe5c72cbc4a7f212c3b # Parent 5550dfc1414afcd5471b7fc8ca4482f7e18ba865 SSL: fix order of checks during SSL certificate verification. SSL_get_verify_result() should be called only if certificate was presented by the peer, otherwise returned value is the default one, which happens to be X509_V_OK, but it doesn't indicate success and it's considered a bug: https://www.openssl.org/docs/manmaster/ssl/SSL_get_verify_result.html Signed-off-by: Piotr Sikora diff -r 5550dfc1414a -r 7bc55832b01a src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3080,6 +3080,21 @@ ngx_ssl_verify_client(ngx_connection_t * long rc; X509 *cert; + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert == NULL) { + + if (verify != NGX_SSL_VERIFY_REQUIRED) { + return NGX_OK; + } + + ngx_ssl_remove_cached_session(ssl->ctx, + SSL_get0_session(c->ssl->connection)); + return NGX_DECLINED; + } + + X509_free(cert); + rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK @@ -3091,18 +3106,6 @@ ngx_ssl_verify_client(ngx_connection_t * return (ngx_int_t) rc; } - if (verify == NGX_SSL_VERIFY_REQUIRED) { - cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert == NULL) { - ngx_ssl_remove_cached_session(ssl->ctx, - SSL_get0_session(c->ssl->connection)); - return NGX_DECLINED; - } - - X509_free(cert); - } - return NGX_OK; } @@ -3110,7 +3113,15 @@ ngx_ssl_verify_client(ngx_connection_t * ngx_int_t ngx_ssl_verify_host(ngx_connection_t *c, ngx_str_t *name) { - long rc; + long rc; + X509 *cert; + + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + return NGX_ERROR; + } + + X509_free(cert); rc = SSL_get_verify_result(c->ssl->connection); if (rc != X509_V_OK) { @@ -3638,22 +3649,20 @@ ngx_ssl_get_client_verify(ngx_connection { X509 *cert; + cert = SSL_get_peer_certificate(c->ssl->connection); + if (cert == NULL) { + ngx_str_set(s, "NONE"); + return NGX_OK; + } + + X509_free(cert); + if (SSL_get_verify_result(c->ssl->connection) != X509_V_OK) { ngx_str_set(s, "FAILED"); return NGX_OK; } - cert = SSL_get_peer_certificate(c->ssl->connection); - - if (cert) { - ngx_str_set(s, "SUCCESS"); - - } else { - ngx_str_set(s, "NONE"); - } - - X509_free(cert); - + ngx_str_set(s, "SUCCESS"); return NGX_OK; } From piotrsikora at google.com Thu Aug 18 00:29:24 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 17 Aug 2016 17:29:24 -0700 Subject: [PATCH 3 of 6] SSL: pull common SSL options into OpenSSL module In-Reply-To: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> References: <653b04653271346c63ab.1471480162@piotrsikora.sfo.corp.google.com> Message-ID: <99c2f52beae28567bf2f.1471480164@piotrsikora.sfo.corp.google.com> # HG changeset patch # User Piotr Sikora # Date 1471428985 25200 # Wed Aug 17 03:16:25 2016 -0700 # Node ID 99c2f52beae28567bf2f8501d1a182cd20004c71 # Parent 788c6187bdbd72787ba24505731e42b6a2307be3 SSL: pull common SSL options into OpenSSL module. No functional changes. Signed-off-by: Piotr Sikora diff -r 788c6187bdbd -r 99c2f52beae2 src/core/ngx_core.h --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -79,11 +79,11 @@ typedef void (*ngx_connection_handler_pt #include #include #include +#include #if (NGX_OPENSSL) #include #endif #include -#include #include #include #include diff -r 788c6187bdbd -r 99c2f52beae2 src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -64,6 +64,25 @@ static char *ngx_openssl_engine(ngx_conf static void ngx_openssl_exit(ngx_cycle_t *cycle); +ngx_conf_bitmask_t ngx_ssl_protocol_masks[] = { + { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, + { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, + { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, + { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, + { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, + { ngx_null_string, 0 } +}; + + +ngx_conf_enum_t ngx_ssl_verify_options[] = { + { ngx_string("off"), NGX_SSL_VERIFY_OFF }, + { ngx_string("on"), NGX_SSL_VERIFY_REQUIRED }, + { ngx_string("optional"), NGX_SSL_VERIFY_OPTIONAL }, + { ngx_string("optional_no_ca"), NGX_SSL_VERIFY_OPTIONAL_NO_CA }, + { ngx_null_string, 0 } +}; + + static ngx_command_t ngx_openssl_commands[] = { { ngx_string("ssl_engine"), diff -r 788c6187bdbd -r 99c2f52beae2 src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -237,6 +237,10 @@ void ngx_cdecl ngx_ssl_error(ngx_uint_t void ngx_ssl_cleanup_ctx(void *data); +extern ngx_conf_bitmask_t ngx_ssl_protocol_masks[]; +extern ngx_conf_enum_t ngx_ssl_verify_options[]; + + extern int ngx_ssl_connection_index; extern int ngx_ssl_server_conf_index; extern int ngx_ssl_session_cache_index; diff -r 788c6187bdbd -r 99c2f52beae2 src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -226,20 +226,6 @@ static ngx_conf_bitmask_t ngx_http_prox }; -#if (NGX_HTTP_SSL) - -static ngx_conf_bitmask_t ngx_http_proxy_ssl_protocols[] = { - { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, - { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, - { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, - { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, - { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, - { ngx_null_string, 0 } -}; - -#endif - - static ngx_conf_enum_t ngx_http_proxy_http_version[] = { { ngx_string("1.0"), NGX_HTTP_VERSION_10 }, { ngx_string("1.1"), NGX_HTTP_VERSION_11 }, @@ -627,7 +613,7 @@ static ngx_command_t ngx_http_proxy_com ngx_conf_set_bitmask_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_proxy_loc_conf_t, ssl_protocols), - &ngx_http_proxy_ssl_protocols }, + &ngx_ssl_protocol_masks }, { ngx_string("proxy_ssl_ciphers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, diff -r 788c6187bdbd -r 99c2f52beae2 src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -48,25 +48,6 @@ static char *ngx_http_ssl_session_cache( static ngx_int_t ngx_http_ssl_init(ngx_conf_t *cf); -static ngx_conf_bitmask_t ngx_http_ssl_protocols[] = { - { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, - { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, - { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, - { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, - { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, - { ngx_null_string, 0 } -}; - - -static ngx_conf_enum_t ngx_http_ssl_verify[] = { - { ngx_string("off"), NGX_SSL_VERIFY_OFF }, - { ngx_string("on"), NGX_SSL_VERIFY_REQUIRED }, - { ngx_string("optional"), NGX_SSL_VERIFY_OPTIONAL }, - { ngx_string("optional_no_ca"), NGX_SSL_VERIFY_OPTIONAL_NO_CA }, - { ngx_null_string, 0 } -}; - - static ngx_command_t ngx_http_ssl_commands[] = { { ngx_string("ssl"), @@ -116,7 +97,7 @@ static ngx_command_t ngx_http_ssl_comma ngx_conf_set_bitmask_slot, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, protocols), - &ngx_http_ssl_protocols }, + &ngx_ssl_protocol_masks }, { ngx_string("ssl_ciphers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, @@ -137,7 +118,7 @@ static ngx_command_t ngx_http_ssl_comma ngx_conf_set_enum_slot, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, verify), - &ngx_http_ssl_verify }, + &ngx_ssl_verify_options }, { ngx_string("ssl_verify_depth"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, diff -r 788c6187bdbd -r 99c2f52beae2 src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -120,20 +120,6 @@ static ngx_conf_bitmask_t ngx_http_uwsgi }; -#if (NGX_HTTP_SSL) - -static ngx_conf_bitmask_t ngx_http_uwsgi_ssl_protocols[] = { - { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, - { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, - { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, - { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, - { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, - { ngx_null_string, 0 } -}; - -#endif - - ngx_module_t ngx_http_uwsgi_module; @@ -465,7 +451,7 @@ static ngx_command_t ngx_http_uwsgi_comm ngx_conf_set_bitmask_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_uwsgi_loc_conf_t, ssl_protocols), - &ngx_http_uwsgi_ssl_protocols }, + &ngx_ssl_protocol_masks }, { ngx_string("uwsgi_ssl_ciphers"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, diff -r 788c6187bdbd -r 99c2f52beae2 src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -31,26 +31,6 @@ static ngx_conf_enum_t ngx_mail_starttl }; - -static ngx_conf_bitmask_t ngx_mail_ssl_protocols[] = { - { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, - { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, - { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, - { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, - { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, - { ngx_null_string, 0 } -}; - - -static ngx_conf_enum_t ngx_mail_ssl_verify[] = { - { ngx_string("off"), NGX_SSL_VERIFY_OFF }, - { ngx_string("on"), NGX_SSL_VERIFY_REQUIRED }, - { ngx_string("optional"), NGX_SSL_VERIFY_OPTIONAL }, - { ngx_string("optional_no_ca"), NGX_SSL_VERIFY_OPTIONAL_NO_CA }, - { ngx_null_string, 0 } -}; - - static ngx_command_t ngx_mail_ssl_commands[] = { { ngx_string("ssl"), @@ -107,7 +87,7 @@ static ngx_command_t ngx_mail_ssl_comma ngx_conf_set_bitmask_slot, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, protocols), - &ngx_mail_ssl_protocols }, + &ngx_ssl_protocol_masks }, { ngx_string("ssl_ciphers"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, @@ -156,7 +136,7 @@ static ngx_command_t ngx_mail_ssl_comma ngx_conf_set_enum_slot, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, verify), - &ngx_mail_ssl_verify }, + &ngx_ssl_verify_options }, { ngx_string("ssl_verify_depth"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, diff -r 788c6187bdbd -r 99c2f52beae2 src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -96,16 +96,6 @@ static ngx_int_t ngx_stream_proxy_ssl_na static ngx_int_t ngx_stream_proxy_set_ssl(ngx_conf_t *cf, ngx_stream_proxy_srv_conf_t *pscf); - -static ngx_conf_bitmask_t ngx_stream_proxy_ssl_protocols[] = { - { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, - { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, - { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, - { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, - { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, - { ngx_null_string, 0 } -}; - #endif @@ -239,7 +229,7 @@ static ngx_command_t ngx_stream_proxy_c ngx_conf_set_bitmask_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_proxy_srv_conf_t, ssl_protocols), - &ngx_stream_proxy_ssl_protocols }, + &ngx_ssl_protocol_masks }, { ngx_string("proxy_ssl_ciphers"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, diff -r 788c6187bdbd -r 99c2f52beae2 src/stream/ngx_stream_ssl_module.c --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -30,16 +30,6 @@ static char *ngx_stream_ssl_session_cach void *conf); -static ngx_conf_bitmask_t ngx_stream_ssl_protocols[] = { - { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, - { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, - { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, - { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, - { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, - { ngx_null_string, 0 } -}; - - static ngx_command_t ngx_stream_ssl_commands[] = { { ngx_string("ssl_handshake_timeout"), @@ -89,7 +79,7 @@ static ngx_command_t ngx_stream_ssl_com ngx_conf_set_bitmask_slot, NGX_STREAM_SRV_CONF_OFFSET, offsetof(ngx_stream_ssl_conf_t, protocols), - &ngx_stream_ssl_protocols }, + &ngx_ssl_protocol_masks }, { ngx_string("ssl_ciphers"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, From piotrsikora at google.com Thu Aug 18 00:29:27 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 17 Aug 2016 17:29:27 -0700 Subject: [PATCH] Thread pools: create threads in detached state Message-ID: # HG changeset patch # User Piotr Sikora # Date 1471265524 25200 # Mon Aug 15 05:52:04 2016 -0700 # Node ID f5fa7a77bcf49091d4315b18f2bca098ca314b06 # Parent c131f20c9562387f94a268440594c288725d3ba8 Thread pools: create threads in detached state. This prevents resource leak, since those threads are never joined. Found with ThreadSanitizer. Signed-off-by: Piotr Sikora diff -r c131f20c9562 -r f5fa7a77bcf4 src/core/ngx_thread_pool.c --- a/src/core/ngx_thread_pool.c +++ b/src/core/ngx_thread_pool.c @@ -137,6 +137,13 @@ ngx_thread_pool_init(ngx_thread_pool_t * return NGX_ERROR; } + err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (err) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "pthread_attr_setdetachstate() failed"); + return NGX_ERROR; + } + #if 0 err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); if (err) { From piotrsikora at google.com Thu Aug 18 00:29:31 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 17 Aug 2016 17:29:31 -0700 Subject: [PATCH 1 of 2] Core: use ngx_trylock() where possible Message-ID: <2f2ec92c3af93c11e195.1471480171@piotrsikora.sfo.corp.google.com> # HG changeset patch # User Piotr Sikora # Date 1471265530 25200 # Mon Aug 15 05:52:10 2016 -0700 # Node ID 2f2ec92c3af93c11e195fb6d805df57518fede7c # Parent c131f20c9562387f94a268440594c288725d3ba8 Core: use ngx_trylock() where possible. It makes code much more readable. No binary changes. Signed-off-by: Piotr Sikora diff -r c131f20c9562 -r 2f2ec92c3af9 src/core/ngx_rwlock.c --- a/src/core/ngx_rwlock.c +++ b/src/core/ngx_rwlock.c @@ -23,7 +23,7 @@ ngx_rwlock_wlock(ngx_atomic_t *lock) for ( ;; ) { - if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) { + if (ngx_trylock(lock, NGX_RWLOCK_WLOCK)) { return; } @@ -35,9 +35,7 @@ ngx_rwlock_wlock(ngx_atomic_t *lock) ngx_cpu_pause(); } - if (*lock == 0 - && ngx_atomic_cmp_set(lock, 0, NGX_RWLOCK_WLOCK)) - { + if (ngx_trylock(lock, NGX_RWLOCK_WLOCK)) { return; } } diff -r c131f20c9562 -r 2f2ec92c3af9 src/core/ngx_shmtx.c --- a/src/core/ngx_shmtx.c +++ b/src/core/ngx_shmtx.c @@ -62,7 +62,7 @@ ngx_shmtx_destroy(ngx_shmtx_t *mtx) ngx_uint_t ngx_shmtx_trylock(ngx_shmtx_t *mtx) { - return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)); + return ngx_trylock(mtx->lock, ngx_pid); } @@ -75,7 +75,7 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx) for ( ;; ) { - if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) { + if (ngx_trylock(mtx->lock, ngx_pid)) { return; } @@ -87,9 +87,7 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx) ngx_cpu_pause(); } - if (*mtx->lock == 0 - && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) - { + if (ngx_trylock(mtx->lock, ngx_pid)) { return; } } @@ -100,7 +98,7 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx) if (mtx->semaphore) { (void) ngx_atomic_fetch_add(mtx->wait, 1); - if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) { + if (ngx_trylock(mtx->lock, ngx_pid)) { (void) ngx_atomic_fetch_add(mtx->wait, -1); return; } diff -r c131f20c9562 -r 2f2ec92c3af9 src/core/ngx_spinlock.c --- a/src/core/ngx_spinlock.c +++ b/src/core/ngx_spinlock.c @@ -19,7 +19,7 @@ ngx_spinlock(ngx_atomic_t *lock, ngx_ato for ( ;; ) { - if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) { + if (ngx_trylock(lock, value)) { return; } @@ -31,7 +31,7 @@ ngx_spinlock(ngx_atomic_t *lock, ngx_ato ngx_cpu_pause(); } - if (*lock == 0 && ngx_atomic_cmp_set(lock, 0, value)) { + if (ngx_trylock(lock, value)) { return; } } diff -r c131f20c9562 -r 2f2ec92c3af9 src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -84,7 +84,7 @@ ngx_time_update(void) ngx_time_t *tp; struct timeval tv; - if (!ngx_trylock(&ngx_time_lock)) { + if (!ngx_trylock(&ngx_time_lock, 1)) { return; } @@ -200,7 +200,7 @@ ngx_time_sigsafe_update(void) ngx_time_t *tp; struct timeval tv; - if (!ngx_trylock(&ngx_time_lock)) { + if (!ngx_trylock(&ngx_time_lock, 1)) { return; } diff -r c131f20c9562 -r 2f2ec92c3af9 src/os/unix/ngx_atomic.h --- a/src/os/unix/ngx_atomic.h +++ b/src/os/unix/ngx_atomic.h @@ -306,7 +306,9 @@ ngx_atomic_fetch_add(ngx_atomic_t *value void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin); -#define ngx_trylock(lock) (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1)) +#define ngx_trylock(lock, value) \ + (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, value)) + #define ngx_unlock(lock) *(lock) = 0 diff -r c131f20c9562 -r 2f2ec92c3af9 src/os/win32/ngx_atomic.h --- a/src/os/win32/ngx_atomic.h +++ b/src/os/win32/ngx_atomic.h @@ -62,7 +62,9 @@ typedef volatile ngx_atomic_uint_t ngx_ void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin); -#define ngx_trylock(lock) (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, 1)) +#define ngx_trylock(lock, value) \ + (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, value)) + #define ngx_unlock(lock) *(lock) = 0 From piotrsikora at google.com Thu Aug 18 00:29:32 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 17 Aug 2016 17:29:32 -0700 Subject: [PATCH 2 of 2] Core: add ngx_atomic_store() and ngx_atomic_load() In-Reply-To: <2f2ec92c3af93c11e195.1471480171@piotrsikora.sfo.corp.google.com> References: <2f2ec92c3af93c11e195.1471480171@piotrsikora.sfo.corp.google.com> Message-ID: <40765d8ee4dd29089b0e.1471480172@piotrsikora.sfo.corp.google.com> # HG changeset patch # User Piotr Sikora # Date 1471265532 25200 # Mon Aug 15 05:52:12 2016 -0700 # Node ID 40765d8ee4dd29089b0e60ed5b6099ac624e804e # Parent 2f2ec92c3af93c11e195fb6d805df57518fede7c Core: add ngx_atomic_store() and ngx_atomic_load(). Those functions must be used to prevent data races between threads operating concurrently on the same variables. No performance loss measured in microbenchmarks on x86_64. No binary changes when compiled without __atomic intrinsics. Found with ThreadSanitizer. Signed-off-by: Piotr Sikora diff -r 2f2ec92c3af9 -r 40765d8ee4dd auto/cc/conf --- a/auto/cc/conf +++ b/auto/cc/conf @@ -178,7 +178,7 @@ if [ "$NGX_PLATFORM" != win32 ]; then fi - ngx_feature="gcc builtin atomic operations" + ngx_feature="gcc builtin __sync operations" ngx_feature_name=NGX_HAVE_GCC_ATOMIC ngx_feature_run=yes ngx_feature_incs= @@ -195,6 +195,19 @@ if [ "$NGX_PLATFORM" != win32 ]; then . auto/feature + ngx_feature="gcc builtin __atomic operations" + ngx_feature_name=NGX_HAVE_GCC_ATOMIC_STORE_AND_LOAD + ngx_feature_run=yes + ngx_feature_incs= + ngx_feature_path= + ngx_feature_libs= + ngx_feature_test="long n = 0; + __atomic_store_n(&n, 1, __ATOMIC_RELEASE); + if (__atomic_load_n(&n, __ATOMIC_ACQUIRE) != 1) + return 1" + . auto/feature + + if [ "$NGX_CC_NAME" = "ccc" ]; then echo "checking for C99 variadic macros ... disabled" else diff -r 2f2ec92c3af9 -r 40765d8ee4dd src/core/ngx_rwlock.c --- a/src/core/ngx_rwlock.c +++ b/src/core/ngx_rwlock.c @@ -53,7 +53,7 @@ ngx_rwlock_rlock(ngx_atomic_t *lock) ngx_atomic_uint_t readers; for ( ;; ) { - readers = *lock; + readers = ngx_atomic_load(lock); if (readers != NGX_RWLOCK_WLOCK && ngx_atomic_cmp_set(lock, readers, readers + 1)) @@ -69,7 +69,7 @@ ngx_rwlock_rlock(ngx_atomic_t *lock) ngx_cpu_pause(); } - readers = *lock; + readers = ngx_atomic_load(lock); if (readers != NGX_RWLOCK_WLOCK && ngx_atomic_cmp_set(lock, readers, readers + 1)) @@ -89,10 +89,10 @@ ngx_rwlock_unlock(ngx_atomic_t *lock) { ngx_atomic_uint_t readers; - readers = *lock; + readers = ngx_atomic_load(lock); if (readers == NGX_RWLOCK_WLOCK) { - *lock = 0; + ngx_atomic_store(lock, 0); return; } @@ -102,7 +102,7 @@ ngx_rwlock_unlock(ngx_atomic_t *lock) return; } - readers = *lock; + readers = ngx_atomic_load(lock); } } diff -r 2f2ec92c3af9 -r 40765d8ee4dd src/core/ngx_shmtx.c --- a/src/core/ngx_shmtx.c +++ b/src/core/ngx_shmtx.c @@ -171,7 +171,7 @@ ngx_shmtx_wakeup(ngx_shmtx_t *mtx) for ( ;; ) { - wait = *mtx->wait; + wait = ngx_atomic_load(mtx->wait); if ((ngx_atomic_int_t) wait <= 0) { return; diff -r 2f2ec92c3af9 -r 40765d8ee4dd src/core/ngx_thread_pool.c --- a/src/core/ngx_thread_pool.c +++ b/src/core/ngx_thread_pool.c @@ -164,9 +164,9 @@ ngx_thread_pool_init(ngx_thread_pool_t * static void ngx_thread_pool_destroy(ngx_thread_pool_t *tp) { - ngx_uint_t n; - ngx_thread_task_t task; - volatile ngx_uint_t lock; + ngx_uint_t n; + ngx_atomic_t lock; + ngx_thread_task_t task; ngx_memzero(&task, sizeof(ngx_thread_task_t)); @@ -174,13 +174,13 @@ ngx_thread_pool_destroy(ngx_thread_pool_ task.ctx = (void *) &lock; for (n = 0; n < tp->threads; n++) { - lock = 1; + ngx_atomic_store(&lock, 1); if (ngx_thread_task_post(tp, &task) != NGX_OK) { return; } - while (lock) { + while (ngx_atomic_load(&lock) != 0) { ngx_sched_yield(); } @@ -196,9 +196,9 @@ ngx_thread_pool_destroy(ngx_thread_pool_ static void ngx_thread_pool_exit_handler(void *data, ngx_log_t *log) { - ngx_uint_t *lock = data; + ngx_atomic_uint_t *lock = data; - *lock = 0; + ngx_atomic_store(lock, 0); pthread_exit(0); } diff -r 2f2ec92c3af9 -r 40765d8ee4dd src/os/unix/ngx_atomic.h --- a/src/os/unix/ngx_atomic.h +++ b/src/os/unix/ngx_atomic.h @@ -304,12 +304,25 @@ ngx_atomic_fetch_add(ngx_atomic_t *value #endif +#if (NGX_HAVE_GCC_ATOMIC_STORE_AND_LOAD) + +#define ngx_atomic_store(x, value) __atomic_store_n(x, value, __ATOMIC_RELEASE) +#define ngx_atomic_load(x) __atomic_load_n(x, __ATOMIC_ACQUIRE) + +#else + +#define ngx_atomic_store(x, value) *(x) = value +#define ngx_atomic_load(x) *(x) + +#endif + + void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin); #define ngx_trylock(lock, value) \ - (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, value)) + (ngx_atomic_load(lock) == 0 && ngx_atomic_cmp_set(lock, 0, value)) -#define ngx_unlock(lock) *(lock) = 0 +#define ngx_unlock(lock) ngx_atomic_store(lock, 0) #endif /* _NGX_ATOMIC_H_INCLUDED_ */ diff -r 2f2ec92c3af9 -r 40765d8ee4dd src/os/win32/ngx_atomic.h --- a/src/os/win32/ngx_atomic.h +++ b/src/os/win32/ngx_atomic.h @@ -60,12 +60,16 @@ typedef volatile ngx_atomic_uint_t ngx_ #endif +#define ngx_atomic_store(x, value) *(x) = value +#define ngx_atomic_load(x) *(x) + + void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin); #define ngx_trylock(lock, value) \ - (*(lock) == 0 && ngx_atomic_cmp_set(lock, 0, value)) + (ngx_atomic_load(lock) == 0 && ngx_atomic_cmp_set(lock, 0, value)) -#define ngx_unlock(lock) *(lock) = 0 +#define ngx_unlock(lock) ngx_atomic_store(lock, 0) #endif /* _NGX_ATOMIC_H_INCLUDED_ */ From piotrsikora at google.com Thu Aug 18 00:29:40 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 17 Aug 2016 17:29:40 -0700 Subject: [PATCH] Events: improve ngx_notify() interface Message-ID: # HG changeset patch # User Piotr Sikora # Date 1471265536 25200 # Mon Aug 15 05:52:16 2016 -0700 # Node ID e4241e448bc94e6b598a2178d7378aef63741f3c # Parent c131f20c9562387f94a268440594c288725d3ba8 Events: improve ngx_notify() interface. Previous implementation had a race condition in which only the last of the notified handlers was called, i.e.: ngx_notify(ngx_ping_handler); ngx_notify(ngx_pong_handler); resulted in only ngx_pong_handler() being called. This wasn't an issue in standalone NGINX (because there is only one consumer of this interface), but it led to lost notifications when used with 3rd-party modules that were also using this interface. New implementation requires notification event to be initialized in order to register the handler: ngx_notify_init(&ngx_ping, ngx_ping_handler, cycle); ngx_notify_init(&ngx_pong, ngx_pong_handler, cycle); and notification is triggered on the event and not on a handler: ngx_notify(&ngx_ping); ngx_notify(&ngx_pong); Tested on Linux, FreeBSD, OS X and SmartOS. Found with ThreadSanitizer. Reported by Feng Li. Signed-off-by: Piotr Sikora diff -r c131f20c9562 -r e4241e448bc9 src/core/ngx_thread_pool.c --- a/src/core/ngx_thread_pool.c +++ b/src/core/ngx_thread_pool.c @@ -99,6 +99,7 @@ ngx_module_t ngx_thread_pool_module = { static ngx_str_t ngx_thread_pool_default = ngx_string("default"); static ngx_uint_t ngx_thread_pool_task_id; +static ngx_event_t ngx_thread_pool_notify; static ngx_atomic_t ngx_thread_pool_done_lock; static ngx_thread_pool_queue_t ngx_thread_pool_done; @@ -111,12 +112,6 @@ ngx_thread_pool_init(ngx_thread_pool_t * ngx_uint_t n; pthread_attr_t attr; - if (ngx_notify == NULL) { - ngx_log_error(NGX_LOG_ALERT, log, 0, - "the configured event method cannot be used with thread pools"); - return NGX_ERROR; - } - ngx_thread_pool_queue_init(&tp->queue); if (ngx_thread_mutex_create(&tp->mtx, log) != NGX_OK) { @@ -349,7 +344,7 @@ ngx_thread_pool_cycle(void *data) ngx_unlock(&ngx_thread_pool_done_lock); - (void) ngx_notify(ngx_thread_pool_handler); + (void) ngx_notify(&ngx_thread_pool_notify); } } @@ -588,10 +583,22 @@ ngx_thread_pool_init_worker(ngx_cycle_t tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_thread_pool_module); - if (tcf == NULL) { + if (tcf == NULL || tcf->pools.nelts == 0) { return NGX_OK; } + if (ngx_notify_init == NULL || ngx_notify == NULL) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "the configured event method cannot be used with thread pools"); + return NGX_ERROR; + } + + if (ngx_notify_init(&ngx_thread_pool_notify, ngx_thread_pool_handler, cycle) + != NGX_OK) + { + return NGX_ERROR; + } + ngx_thread_pool_queue_init(&ngx_thread_pool_done); tpp = tcf->pools.elts; @@ -622,7 +629,7 @@ ngx_thread_pool_exit_worker(ngx_cycle_t tcf = (ngx_thread_pool_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_thread_pool_module); - if (tcf == NULL) { + if (tcf == NULL || tcf->pools.nelts == 0) { return; } @@ -631,4 +638,8 @@ ngx_thread_pool_exit_worker(ngx_cycle_t for (i = 0; i < tcf->pools.nelts; i++) { ngx_thread_pool_destroy(tpp[i]); } + + if (ngx_notify_close != NULL) { + ngx_notify_close(&ngx_thread_pool_notify); + } } diff -r c131f20c9562 -r e4241e448bc9 src/event/modules/ngx_devpoll_module.c --- a/src/event/modules/ngx_devpoll_module.c +++ b/src/event/modules/ngx_devpoll_module.c @@ -90,7 +90,9 @@ ngx_event_module_t ngx_devpoll_module_c ngx_devpoll_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ + NULL, /* init a notify */ NULL, /* trigger a notify */ + NULL, /* close a notify */ ngx_devpoll_process_events, /* process the events */ ngx_devpoll_init, /* init the events */ ngx_devpoll_done, /* done the events */ diff -r c131f20c9562 -r e4241e448bc9 src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -103,8 +103,10 @@ typedef struct { static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer); #if (NGX_HAVE_EVENTFD) -static ngx_int_t ngx_epoll_notify_init(ngx_log_t *log); +static ngx_int_t ngx_epoll_notify_init(ngx_event_t *notify_event, + ngx_event_handler_pt handler, ngx_cycle_t *cycle); static void ngx_epoll_notify_handler(ngx_event_t *ev); +static void ngx_epoll_notify_close(ngx_event_t *notify_event); #endif #if (NGX_HAVE_EPOLLRDHUP) static void ngx_epoll_test_rdhup(ngx_cycle_t *cycle); @@ -118,7 +120,7 @@ static ngx_int_t ngx_epoll_add_connectio static ngx_int_t ngx_epoll_del_connection(ngx_connection_t *c, ngx_uint_t flags); #if (NGX_HAVE_EVENTFD) -static ngx_int_t ngx_epoll_notify(ngx_event_handler_pt handler); +static ngx_int_t ngx_epoll_notify(ngx_event_t *notify_event); #endif static ngx_int_t ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); @@ -134,12 +136,6 @@ static int ep = -1; static struct epoll_event *event_list; static ngx_uint_t nevents; -#if (NGX_HAVE_EVENTFD) -static int notify_fd = -1; -static ngx_event_t notify_event; -static ngx_connection_t notify_conn; -#endif - #if (NGX_HAVE_FILE_AIO) int ngx_eventfd = -1; @@ -189,9 +185,13 @@ ngx_event_module_t ngx_epoll_module_ctx ngx_epoll_add_connection, /* add an connection */ ngx_epoll_del_connection, /* delete an connection */ #if (NGX_HAVE_EVENTFD) + ngx_epoll_notify_init, /* init a notify */ ngx_epoll_notify, /* trigger a notify */ + ngx_epoll_notify_close, /* close a notify */ #else + NULL, /* init a notify */ NULL, /* trigger a notify */ + NULL, /* close a notify */ #endif ngx_epoll_process_events, /* process the events */ ngx_epoll_init, /* init the events */ @@ -335,12 +335,6 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_m return NGX_ERROR; } -#if (NGX_HAVE_EVENTFD) - if (ngx_epoll_notify_init(cycle->log) != NGX_OK) { - ngx_epoll_module_ctx.actions.notify = NULL; - } -#endif - #if (NGX_HAVE_FILE_AIO) ngx_epoll_aio_init(cycle, epcf); #endif @@ -383,9 +377,17 @@ ngx_epoll_init(ngx_cycle_t *cycle, ngx_m #if (NGX_HAVE_EVENTFD) static ngx_int_t -ngx_epoll_notify_init(ngx_log_t *log) +ngx_epoll_notify_init(ngx_event_t *notify_event, ngx_event_handler_pt handler, + ngx_cycle_t *cycle) { - struct epoll_event ee; + int notify_fd; + ngx_connection_t *notify_conn; + struct epoll_event ee; + + notify_conn = ngx_pcalloc(cycle->pool, sizeof(ngx_connection_t)); + if (notify_conn == NULL) { + return NGX_ERROR; + } #if (NGX_HAVE_SYS_EVENTFD_H) notify_fd = eventfd(0, 0); @@ -394,31 +396,35 @@ ngx_epoll_notify_init(ngx_log_t *log) #endif if (notify_fd == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "eventfd() failed"); + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "eventfd() failed"); return NGX_ERROR; } - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "notify eventfd: %d", notify_fd); - notify_event.handler = ngx_epoll_notify_handler; - notify_event.log = log; - notify_event.active = 1; + ngx_memzero(notify_event, sizeof(ngx_event_t)); - notify_conn.fd = notify_fd; - notify_conn.read = ¬ify_event; - notify_conn.log = log; + notify_event->data = notify_conn; + notify_event->handler = ngx_epoll_notify_handler; + notify_event->log = cycle->log; + notify_event->active = 1; + + notify_conn->data = handler; + notify_conn->fd = notify_fd; + notify_conn->read = notify_event; + notify_conn->log = cycle->log; ee.events = EPOLLIN|EPOLLET; - ee.data.ptr = ¬ify_conn; + ee.data.ptr = notify_conn; if (epoll_ctl(ep, EPOLL_CTL_ADD, notify_fd, &ee) == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "epoll_ctl(EPOLL_CTL_ADD, eventfd) failed"); if (close(notify_fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - "eventfd close() failed"); + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "close() eventfd %d failed", notify_fd); } return NGX_ERROR; @@ -431,31 +437,45 @@ ngx_epoll_notify_init(ngx_log_t *log) static void ngx_epoll_notify_handler(ngx_event_t *ev) { - ssize_t n; - uint64_t count; - ngx_err_t err; - ngx_event_handler_pt handler; + ngx_connection_t *c = ev->data; + + ssize_t n; + uint64_t count; + ngx_err_t err; + ngx_event_handler_pt handler; if (++ev->index == NGX_MAX_UINT32_VALUE) { ev->index = 0; - n = read(notify_fd, &count, sizeof(uint64_t)); + n = read(c->fd, &count, sizeof(uint64_t)); err = ngx_errno; ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0, - "read() eventfd %d: %z count:%uL", notify_fd, n, count); + "read() eventfd %d: %z count:%uL", c->fd, n, count); if ((size_t) n != sizeof(uint64_t)) { ngx_log_error(NGX_LOG_ALERT, ev->log, err, - "read() eventfd %d failed", notify_fd); + "read() eventfd %d failed", c->fd); } } - handler = ev->data; + handler = c->data; handler(ev); } + +static void +ngx_epoll_notify_close(ngx_event_t *notify_event) +{ + ngx_connection_t *c = notify_event->data; + + if (close(c->fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, notify_event->log, ngx_errno, + "close() eventfd %d failed", c->fd); + } +} + #endif @@ -536,17 +556,6 @@ ngx_epoll_done(ngx_cycle_t *cycle) ep = -1; -#if (NGX_HAVE_EVENTFD) - - if (close(notify_fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - "eventfd close() failed"); - } - - notify_fd = -1; - -#endif - #if (NGX_HAVE_FILE_AIO) if (ngx_eventfd != -1) { @@ -762,15 +771,14 @@ ngx_epoll_del_connection(ngx_connection_ #if (NGX_HAVE_EVENTFD) static ngx_int_t -ngx_epoll_notify(ngx_event_handler_pt handler) +ngx_epoll_notify(ngx_event_t *notify_event) { - static uint64_t inc = 1; + static uint64_t inc = 1; + ngx_connection_t *c = notify_event->data; - notify_event.data = handler; - - if ((size_t) write(notify_fd, &inc, sizeof(uint64_t)) != sizeof(uint64_t)) { - ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno, - "write() to eventfd %d failed", notify_fd); + if ((size_t) write(c->fd, &inc, sizeof(uint64_t)) != sizeof(uint64_t)) { + ngx_log_error(NGX_LOG_ALERT, notify_event->log, ngx_errno, + "write() to eventfd %d failed", c->fd); return NGX_ERROR; } diff -r c131f20c9562 -r e4241e448bc9 src/event/modules/ngx_eventport_module.c --- a/src/event/modules/ngx_eventport_module.c +++ b/src/event/modules/ngx_eventport_module.c @@ -140,7 +140,9 @@ static ngx_int_t ngx_eventport_add_event ngx_uint_t flags); static ngx_int_t ngx_eventport_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags); -static ngx_int_t ngx_eventport_notify(ngx_event_handler_pt handler); +static ngx_int_t ngx_eventport_notify_init(ngx_event_t *notify_event, + ngx_event_handler_pt handler, ngx_cycle_t *cycle); +static ngx_int_t ngx_eventport_notify(ngx_event_t *notify_event); static ngx_int_t ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); @@ -151,7 +153,6 @@ static int ep = -1; static port_event_t *event_list; static ngx_uint_t nevents; static timer_t event_timer = (timer_t) -1; -static ngx_event_t notify_event; static ngx_str_t eventport_name = ngx_string("eventport"); @@ -181,7 +182,9 @@ ngx_event_module_t ngx_eventport_module ngx_eventport_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ + ngx_eventport_notify_init, /* init a notify */ ngx_eventport_notify, /* trigger a notify */ + NULL, /* close a notify */ ngx_eventport_process_events, /* process the events */ ngx_eventport_init, /* init the events */ ngx_eventport_done, /* done the events */ @@ -223,9 +226,6 @@ ngx_eventport_init(ngx_cycle_t *cycle, n "port_create() failed"); return NGX_ERROR; } - - notify_event.active = 1; - notify_event.log = cycle->log; } if (nevents < epcf->events) { @@ -418,12 +418,24 @@ ngx_eventport_del_event(ngx_event_t *ev, static ngx_int_t -ngx_eventport_notify(ngx_event_handler_pt handler) +ngx_eventport_notify_init(ngx_event_t *notify_event, + ngx_event_handler_pt handler, ngx_cycle_t *cycle) { - notify_event.handler = handler; + ngx_memzero(notify_event, sizeof(ngx_event_t)); - if (port_send(ep, 0, ¬ify_event) != 0) { - ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno, + notify_event->handler = handler; + notify_event->active = 1; + notify_event->log = cycle->log; + + return NGX_OK; +} + + +static ngx_int_t +ngx_eventport_notify(ngx_event_t *notify_event) +{ + if (port_send(ep, 0, notify_event) != 0) { + ngx_log_error(NGX_LOG_ALERT, notify_event->log, ngx_errno, "port_send() failed"); return NGX_ERROR; } diff -r c131f20c9562 -r e4241e448bc9 src/event/modules/ngx_iocp_module.c --- a/src/event/modules/ngx_iocp_module.c +++ b/src/event/modules/ngx_iocp_module.c @@ -64,7 +64,9 @@ ngx_event_module_t ngx_iocp_module_ctx NULL, /* disable an event */ NULL, /* add an connection */ ngx_iocp_del_connection, /* delete an connection */ + NULL, /* init a notify */ NULL, /* trigger a notify */ + NULL, /* close a notify */ ngx_iocp_process_events, /* process the events */ ngx_iocp_init, /* init the events */ ngx_iocp_done /* done the events */ diff -r c131f20c9562 -r e4241e448bc9 src/event/modules/ngx_kqueue_module.c --- a/src/event/modules/ngx_kqueue_module.c +++ b/src/event/modules/ngx_kqueue_module.c @@ -18,7 +18,8 @@ typedef struct { static ngx_int_t ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer); #ifdef EVFILT_USER -static ngx_int_t ngx_kqueue_notify_init(ngx_log_t *log); +static ngx_int_t ngx_kqueue_notify_init(ngx_event_t *notify_event, + ngx_event_handler_pt handler, ngx_cycle_t *cycle); #endif static void ngx_kqueue_done(ngx_cycle_t *cycle); static ngx_int_t ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, @@ -28,7 +29,7 @@ static ngx_int_t ngx_kqueue_del_event(ng static ngx_int_t ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags); #ifdef EVFILT_USER -static ngx_int_t ngx_kqueue_notify(ngx_event_handler_pt handler); +static ngx_int_t ngx_kqueue_notify(ngx_event_t *notify_event); #endif static ngx_int_t ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); @@ -45,11 +46,6 @@ static struct kevent *change_list; static struct kevent *event_list; static ngx_uint_t max_changes, nchanges, nevents; -#ifdef EVFILT_USER -static ngx_event_t notify_event; -static struct kevent notify_kev; -#endif - static ngx_str_t kqueue_name = ngx_string("kqueue"); @@ -86,9 +82,13 @@ ngx_event_module_t ngx_kqueue_module_ct NULL, /* add an connection */ NULL, /* delete an connection */ #ifdef EVFILT_USER + ngx_kqueue_notify_init, /* init a notify */ ngx_kqueue_notify, /* trigger a notify */ + NULL, /* close a notify */ #else + NULL, /* init a notify */ NULL, /* trigger a notify */ + NULL, /* close a notify */ #endif ngx_kqueue_process_events, /* process the events */ ngx_kqueue_init, /* init the events */ @@ -132,12 +132,6 @@ ngx_kqueue_init(ngx_cycle_t *cycle, ngx_ "kqueue() failed"); return NGX_ERROR; } - -#ifdef EVFILT_USER - if (ngx_kqueue_notify_init(cycle->log) != NGX_OK) { - return NGX_ERROR; - } -#endif } if (max_changes < kcf->changes) { @@ -230,27 +224,39 @@ ngx_kqueue_init(ngx_cycle_t *cycle, ngx_ #ifdef EVFILT_USER static ngx_int_t -ngx_kqueue_notify_init(ngx_log_t *log) +ngx_kqueue_notify_init(ngx_event_t *notify_event, ngx_event_handler_pt handler, + ngx_cycle_t *cycle) { - notify_kev.ident = 0; - notify_kev.filter = EVFILT_USER; - notify_kev.data = 0; - notify_kev.flags = EV_ADD|EV_CLEAR; - notify_kev.fflags = 0; - notify_kev.udata = 0; + struct kevent *notify_kev; - if (kevent(ngx_kqueue, ¬ify_kev, 1, NULL, 0, NULL) == -1) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + notify_kev = ngx_pcalloc(cycle->pool, sizeof(struct kevent)); + if (notify_kev == NULL) { + return NGX_ERROR; + } + + notify_kev->ident = (uintptr_t) notify_event; + notify_kev->filter = EVFILT_USER; + notify_kev->data = 0; + notify_kev->flags = EV_ADD|EV_CLEAR; + notify_kev->fflags = 0; + notify_kev->udata = 0; + + if (kevent(ngx_kqueue, notify_kev, 1, NULL, 0, NULL) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "kevent(EVFILT_USER, EV_ADD) failed"); return NGX_ERROR; } - notify_event.active = 1; - notify_event.log = log; + ngx_memzero(notify_event, sizeof(ngx_event_t)); - notify_kev.flags = 0; - notify_kev.fflags = NOTE_TRIGGER; - notify_kev.udata = NGX_KQUEUE_UDATA_T ((uintptr_t) ¬ify_event); + notify_event->data = notify_kev; + notify_event->handler = handler; + notify_event->active = 1; + notify_event->log = cycle->log; + + notify_kev->flags = 0; + notify_kev->fflags = NOTE_TRIGGER; + notify_kev->udata = NGX_KQUEUE_UDATA_T ((uintptr_t) notify_event); return NGX_OK; } @@ -478,12 +484,12 @@ ngx_kqueue_set_event(ngx_event_t *ev, ng #ifdef EVFILT_USER static ngx_int_t -ngx_kqueue_notify(ngx_event_handler_pt handler) +ngx_kqueue_notify(ngx_event_t *notify_event) { - notify_event.handler = handler; + struct kevent *notify_kev = notify_event->data; - if (kevent(ngx_kqueue, ¬ify_kev, 1, NULL, 0, NULL) == -1) { - ngx_log_error(NGX_LOG_ALERT, notify_event.log, ngx_errno, + if (kevent(ngx_kqueue, notify_kev, 1, NULL, 0, NULL) == -1) { + ngx_log_error(NGX_LOG_ALERT, notify_event->log, ngx_errno, "kevent(EVFILT_USER, NOTE_TRIGGER) failed"); return NGX_ERROR; } diff -r c131f20c9562 -r e4241e448bc9 src/event/modules/ngx_poll_module.c --- a/src/event/modules/ngx_poll_module.c +++ b/src/event/modules/ngx_poll_module.c @@ -39,7 +39,9 @@ ngx_event_module_t ngx_poll_module_ctx ngx_poll_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ + NULL, /* init a notify */ NULL, /* trigger a notify */ + NULL, /* close a notify */ ngx_poll_process_events, /* process the events */ ngx_poll_init, /* init the events */ ngx_poll_done /* done the events */ diff -r c131f20c9562 -r e4241e448bc9 src/event/modules/ngx_select_module.c --- a/src/event/modules/ngx_select_module.c +++ b/src/event/modules/ngx_select_module.c @@ -47,7 +47,9 @@ ngx_event_module_t ngx_select_module_ct ngx_select_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ + NULL, /* init a notify */ NULL, /* trigger a notify */ + NULL, /* close a notify */ ngx_select_process_events, /* process the events */ ngx_select_init, /* init the events */ ngx_select_done /* done the events */ diff -r c131f20c9562 -r e4241e448bc9 src/event/modules/ngx_win32_select_module.c --- a/src/event/modules/ngx_win32_select_module.c +++ b/src/event/modules/ngx_win32_select_module.c @@ -48,7 +48,9 @@ ngx_event_module_t ngx_select_module_ct ngx_select_del_event, /* disable an event */ NULL, /* add an connection */ NULL, /* delete an connection */ + NULL, /* init a notify */ NULL, /* trigger a notify */ + NULL, /* close a notify */ ngx_select_process_events, /* process the events */ ngx_select_init, /* init the events */ ngx_select_done /* done the events */ diff -r c131f20c9562 -r e4241e448bc9 src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -170,7 +170,7 @@ ngx_event_module_t ngx_event_core_modul ngx_event_core_create_conf, /* create configuration */ ngx_event_core_init_conf, /* init configuration */ - { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } + { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; diff -r c131f20c9562 -r e4241e448bc9 src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -184,7 +184,10 @@ typedef struct { ngx_int_t (*add_conn)(ngx_connection_t *c); ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags); - ngx_int_t (*notify)(ngx_event_handler_pt handler); + ngx_int_t (*notify_init)(ngx_event_t *notify_event, + ngx_event_handler_pt handler, ngx_cycle_t *cycle); + ngx_int_t (*notify)(ngx_event_t *notify_event); + void (*notify_close)(ngx_event_t *notify_event); ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); @@ -416,7 +419,9 @@ extern ngx_uint_t ngx_use_epo #define ngx_add_conn ngx_event_actions.add_conn #define ngx_del_conn ngx_event_actions.del_conn +#define ngx_notify_init ngx_event_actions.notify_init #define ngx_notify ngx_event_actions.notify +#define ngx_notify_close ngx_event_actions.notify_close #define ngx_add_timer ngx_event_add_timer #define ngx_del_timer ngx_event_del_timer From mdounin at mdounin.ru Thu Aug 18 00:37:02 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 18 Aug 2016 03:37:02 +0300 Subject: [PATCH] SSL: fix order of checks during SSL certificate verification In-Reply-To: References: <20160804035352.GY57459@mdounin.ru> Message-ID: <20160818003702.GE24741@mdounin.ru> Hello! On Tue, Aug 09, 2016 at 12:51:38PM -0700, Piotr Sikora wrote: > Hey Maxim, > > > This behaviour is explicitly documented for years. The BUGS > > section outlines that the API is not intuitive and requires use of > > SSL_get_peer_certificate() in addition ot SSL_get_verify_result(). > > Exactly. > > > And this is what nginx does. I don't see compelling reasons to > > change the order of the calls here. > > No, it doesn't, which is the reason for this patch in the first > place... NGINX uses the result of SSL_get_verify_result() without > calling SSL_get_peer_certificate(), which is what the BUGS section > requires. Calling SSL_get_peer_certificate() is only needed if SSL_get_verify_result() returns X509_V_OK, to distinguish two of its different meanings: X509_V_OK The verification succeeded or no peer certificate was presented. And that's what nginx does. > Also, this breaks implementations (i.e. BoringSSL) that are a bit more > strict and don't use X509_V_OK as the initial value. Ok, this looks like the real reason for the patch. This looks like an API change in BoringSSL, and should be threated accordingly. Given the number of various API changes BoringSSL introduces here and there - we probably don't want to follow, at least till some version is actually released. > > This looks like a separate patch, or two patches. > > Fair enough. > > > Though I'm > > somewhat sceptical about the use of "upstream" and "client" in > > error messages introduced, this looks like a wrong approach for a > > generic SSL code. > > What you would prefer, then? > > 1. Returning error string back the the caller? > 2. Returning "rc" back to the caller and adding another function to > abstract X509_verify_cert_error_string()? > 3. Adding the caller string ("client" or "upstream") as the parameter > and writing error from within the function? I can't say I like either of the variants. (1) will require memory allocations, (2) looks hardly portable (what if another library will have different rc values? or will have more than one error string to print?), and (3) looks strange. May be something like "peer" in error messages instead would be a better solution, assuming context is already known from the c->log->action == "SSL handshaking to upstream". Alternatively, we can consider abstracting printing of verification results errors with something similar to ngx_ssl_error(). > > As well as magic values in the "verify" argument, > > Good call. > > > and the change of the ngx_ssl_check_host() semantics. > > You mean the introduction of error logs? If so, then it seems that > returning "rc" and adding another function to retrieve the error > string would be the best way to keep the behavior as close to the > existing one as possible. There are two changes in the ngx_ssl_check_host() function in the patch: - an API change which moves error printing to the function; - a semantics change which adds certificate verification check to the function. Both has problems. API changes tend to break 3rd party modules, and so it's better to avoid them unless really needed. The semantics change in question may not be adequate for various non-trivial cases when one want to check verification results but not host or vice versa. -- Maxim Dounin http://nginx.org/ From vbart at nginx.com Thu Aug 18 14:11:21 2016 From: vbart at nginx.com (Valentin Bartenev) Date: Thu, 18 Aug 2016 14:11:21 +0000 Subject: [nginx] Geo: fixed access to already freed memory. Message-ID: details: http://hg.nginx.org/nginx/rev/873d7053efb9 branches: changeset: 6655:873d7053efb9 user: Valentin Bartenev date: Thu Aug 18 17:11:03 2016 +0300 description: Geo: fixed access to already freed memory. Previously, in "ranges" mode when all added ranges were deleted, the ctx.high.low[i] was left pointing to a temporary array. diffstat: src/http/modules/ngx_http_geo_module.c | 7 ++++++- src/stream/ngx_stream_geo_module.c | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diffs (34 lines): diff -r c131f20c9562 -r 873d7053efb9 src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c Wed Aug 10 16:46:39 2016 +0300 +++ b/src/http/modules/ngx_http_geo_module.c Thu Aug 18 17:11:03 2016 +0300 @@ -469,7 +469,12 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c for (i = 0; i < 0x10000; i++) { a = (ngx_array_t *) ctx.high.low[i]; - if (a == NULL || a->nelts == 0) { + if (a == NULL) { + continue; + } + + if (a->nelts == 0) { + ctx.high.low[i] = NULL; continue; } diff -r c131f20c9562 -r 873d7053efb9 src/stream/ngx_stream_geo_module.c --- a/src/stream/ngx_stream_geo_module.c Wed Aug 10 16:46:39 2016 +0300 +++ b/src/stream/ngx_stream_geo_module.c Thu Aug 18 17:11:03 2016 +0300 @@ -436,7 +436,12 @@ ngx_stream_geo_block(ngx_conf_t *cf, ngx for (i = 0; i < 0x10000; i++) { a = (ngx_array_t *) ctx.high.low[i]; - if (a == NULL || a->nelts == 0) { + if (a == NULL) { + continue; + } + + if (a->nelts == 0) { + ctx.high.low[i] = NULL; continue; } From arut at nginx.com Thu Aug 18 14:15:28 2016 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 18 Aug 2016 14:15:28 +0000 Subject: [nginx] Fixed wrong type of the "line" field. Message-ID: details: http://hg.nginx.org/nginx/rev/a2f57dfa65a9 branches: changeset: 6656:a2f57dfa65a9 user: Roman Arutyunyan date: Thu Aug 18 17:13:07 2016 +0300 description: Fixed wrong type of the "line" field. The new type ngx_uint_t was supposed when formatting the line number. diffstat: src/mail/ngx_mail.h | 2 +- src/stream/ngx_stream.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diffs (24 lines): diff -r 873d7053efb9 -r a2f57dfa65a9 src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h Thu Aug 18 17:11:03 2016 +0300 +++ b/src/mail/ngx_mail.h Thu Aug 18 17:13:07 2016 +0300 @@ -117,7 +117,7 @@ typedef struct { ngx_str_t server_name; u_char *file_name; - ngx_int_t line; + ngx_uint_t line; ngx_resolver_t *resolver; ngx_log_t *error_log; diff -r 873d7053efb9 -r a2f57dfa65a9 src/stream/ngx_stream.h --- a/src/stream/ngx_stream.h Thu Aug 18 17:11:03 2016 +0300 +++ b/src/stream/ngx_stream.h Thu Aug 18 17:13:07 2016 +0300 @@ -136,7 +136,7 @@ typedef struct { ngx_stream_conf_ctx_t *ctx; u_char *file_name; - ngx_int_t line; + ngx_uint_t line; ngx_flag_t tcp_nodelay; From arut at nginx.com Thu Aug 18 14:15:30 2016 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 18 Aug 2016 14:15:30 +0000 Subject: [nginx] Ensure "listen" exists in a mail or stream server (ticket #1049). Message-ID: details: http://hg.nginx.org/nginx/rev/3d5202c71f94 branches: changeset: 6657:3d5202c71f94 user: Roman Arutyunyan date: Wed Aug 17 11:26:51 2016 +0300 description: Ensure "listen" exists in a mail or stream server (ticket #1049). diffstat: src/mail/ngx_mail.h | 2 ++ src/mail/ngx_mail_core_module.c | 9 +++++++++ src/stream/ngx_stream.h | 2 ++ src/stream/ngx_stream_core_module.c | 11 +++++++++++ 4 files changed, 24 insertions(+), 0 deletions(-) diffs (84 lines): diff -r a2f57dfa65a9 -r 3d5202c71f94 src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h Thu Aug 18 17:13:07 2016 +0300 +++ b/src/mail/ngx_mail.h Wed Aug 17 11:26:51 2016 +0300 @@ -124,6 +124,8 @@ typedef struct { /* server ctx */ ngx_mail_conf_ctx_t *ctx; + + ngx_uint_t listen; /* unsigned listen:1; */ } ngx_mail_core_srv_conf_t; diff -r a2f57dfa65a9 -r 3d5202c71f94 src/mail/ngx_mail_core_module.c --- a/src/mail/ngx_mail_core_module.c Thu Aug 18 17:13:07 2016 +0300 +++ b/src/mail/ngx_mail_core_module.c Wed Aug 17 11:26:51 2016 +0300 @@ -279,6 +279,13 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx *cf = pcf; + if (rv == NGX_CONF_OK && !cscf->listen) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"listen\" is defined for server in %s:%ui", + cscf->file_name, cscf->line); + return NGX_CONF_ERROR; + } + return rv; } @@ -295,6 +302,8 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx ngx_mail_module_t *module; ngx_mail_core_main_conf_t *cmcf; + cscf->listen = 1; + value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); diff -r a2f57dfa65a9 -r 3d5202c71f94 src/stream/ngx_stream.h --- a/src/stream/ngx_stream.h Thu Aug 18 17:13:07 2016 +0300 +++ b/src/stream/ngx_stream.h Wed Aug 17 11:26:51 2016 +0300 @@ -144,6 +144,8 @@ typedef struct { ngx_msec_t resolver_timeout; ngx_resolver_t *resolver; + + ngx_uint_t listen; /* unsigned listen:1; */ } ngx_stream_core_srv_conf_t; diff -r a2f57dfa65a9 -r 3d5202c71f94 src/stream/ngx_stream_core_module.c --- a/src/stream/ngx_stream_core_module.c Thu Aug 18 17:13:07 2016 +0300 +++ b/src/stream/ngx_stream_core_module.c Wed Aug 17 11:26:51 2016 +0300 @@ -325,6 +325,13 @@ ngx_stream_core_server(ngx_conf_t *cf, n *cf = pcf; + if (rv == NGX_CONF_OK && !cscf->listen) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"listen\" is defined for server in %s:%ui", + cscf->file_name, cscf->line); + return NGX_CONF_ERROR; + } + return rv; } @@ -332,12 +339,16 @@ ngx_stream_core_server(ngx_conf_t *cf, n static char * ngx_stream_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_stream_core_srv_conf_t *cscf = conf; + ngx_str_t *value; ngx_url_t u; ngx_uint_t i, backlog; ngx_stream_listen_t *ls, *als; ngx_stream_core_main_conf_t *cmcf; + cscf->listen = 1; + value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); From piotrsikora at google.com Fri Aug 19 01:12:46 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Thu, 18 Aug 2016 18:12:46 -0700 Subject: [PATCH] HTTP: add support for trailers in HTTP responses In-Reply-To: <20160804022412.GW57459@mdounin.ru> References: <20160721134430.GV57459@mdounin.ru> <20160801132154.GH57459@mdounin.ru> <20160804022412.GW57459@mdounin.ru> Message-ID: Hey Maxim, > By saying "most popular use case" you are talking about something > real-world you are aware of? Yes. Furthermore, I'm aware of a few systems using NGINX that use either ugly workarounds or are missing features exactly because NGINX doesn't support trailers. > And this probably an additional thing to consider when introducing > trailers: right now nginx strips all trailers. Changing this may > be a surprise for those who use trailers internally, if any. This can be easily mitigated with "proxy_pass_trailers on|off". > We've already talked about gRPC. Yes, and I'm not sure why you keep ignoring it. If it's because you assume that it has to be end-to-end HTTP/2 and as such trailers aren't the main blocker, then there are reverse proxies like grpc-gateway [1] (which, coincidentally, doesn't support trailers), that convert HTTP/1.1 requests to a "pure" gRPC requests and back... Lack of trailers in NGINX prevents people from writing custom upstream gRPC module, which could provide similar functionality in NGINX. However, if it's because "it's Google pushing it's own library", then it's neither good nor technical reason for rejecting trailers support. [1] https://github.com/grpc-ecosystem/grpc-gateway > Fetch API and Server Timing are > just specifications being developed which allow use of trailers, > not much different from HTTP/1.1 itself. Well, they wouldn't be adding it if it was so useless, would they? > On the other hand, here is a good discussion of trailers and their > security in this Fetch API ticket: > > https://github.com/whatwg/fetch/issues/34 Yes, and the consensus is that there are no new security implications, as long as you don't magically merge trailers with headers (which, as previously stated, I have no intention of doing). > And here is a linked HTTPbis ticket to reconsider "TE: trailers" > as it looks unneded: > > https://github.com/httpwg/http11bis/issues/18 > > This is somewhat in line with what I think about it, as previously > discussed in this thread. I can drop this requirement if you insist, but that's much less conservative approach than NGINX usually takes and I expect that some obscure HTTP clients will break because of lack of proper support for trailer-part in chunked encoding. > I'm still not convinced that trailers are needed. As previously > said, this HTTP feature was mostly unused for 17 years, and > this suggests something is wrong with the feature. So it may be a > good idea to postpone this at least till some real user will > appear. You have real users commenting in this thread, why do you keep ignoring them? Other people already expressed interest, commented on their internal implementations and/or said that they use workarounds because NGINX doesn't support trailers. What more do you need? > In either case, I do not think that added trailers should by > itself change transfer encoding used and remove Content-Length. Again, why this is an issue with trailers but it's not an issue with gzip? Best regards, Piotr Sikora From piotrsikora at google.com Fri Aug 19 02:46:29 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Thu, 18 Aug 2016 19:46:29 -0700 Subject: [PATCH] SSL: fix order of checks during SSL certificate verification In-Reply-To: <20160818003702.GE24741@mdounin.ru> References: <20160804035352.GY57459@mdounin.ru> <20160818003702.GE24741@mdounin.ru> Message-ID: Hey Maxim, > Calling SSL_get_peer_certificate() is only needed if > SSL_get_verify_result() returns X509_V_OK, to distinguish two of > its different meanings: > > X509_V_OK > The verification succeeded or no peer certificate was presented. > > And that's what nginx does. That's not what the documentation says, though... At this point, NGINX is just relying on a known bug, nothing else. > Ok, this looks like the real reason for the patch. This looks > like an API change in BoringSSL, and should be threated > accordingly. Nope, that's not the real reason... BoringSSL actually added a workaround for this [1], just to play nicely with NGINX and netty-tcnative, because virtually everything else is using OpenSSL API correctly, i.e. checking if peer sent the certificate before checking if that certificate passed verification. The real reason for this patch is that existing code is misusing OpenSSL API. [1] https://boringssl.googlesource.com/boringssl/+/37646838e9bb62a0d9d506b117193611c4c46012 > Given the number of various API changes BoringSSL introduces here > and there - we probably don't want to follow, at least till some > version is actually released. While this might have been true 2 years ago, nowadays BoringSSL tries to be a drop-in replacement for OpenSSL... and looking at the commit log for ngx_event_openssl.c, it seems that compatibility with new OpenSSL requires way more changes to NGINX than compatibility with BoringSSL. > I can't say I like either of the variants. (1) will require > memory allocations, Agreed. > (2) looks hardly portable (what if another > library will have different rc values? or will have more than one > error string to print?), Well, it's portable assuming that the library also converts the "rc" value back to the error string (like in the patchset I sent yesterday). > and (3) looks strange. Agreed. > May be something like "peer" in error messages instead would be a > better solution, assuming context is already known from the > c->log->action == "SSL handshaking to upstream". To be honest, I don't see why we need to lose "client" and "upstream" from the error log if those functions are called only for client and host verification. > Alternatively, > we can consider abstracting printing of verification results > errors with something similar to ngx_ssl_error(). That's acceptable, but I don't see any advantage over providing an alias for X509_verify_cert_error_string(). Best regards, Piotr Sikora From piotrsikora at google.com Fri Aug 19 04:26:27 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Thu, 18 Aug 2016 21:26:27 -0700 Subject: [PATCH] SSL: remove no longer needed workaround for BoringSSL Message-ID: <05a43cbd6e0d4e4e94be.1471580787@piotrsikora.sfo.corp.google.com> # HG changeset patch # User Piotr Sikora # Date 1471556988 25200 # Thu Aug 18 14:49:48 2016 -0700 # Node ID 05a43cbd6e0d4e4e94be2c48765e7d12b1faf0e4 # Parent 3d5202c71f94b155c0beefaf707f2f45a05634cf SSL: remove no longer needed workaround for BoringSSL. BoringSSL added a no-op stub for OPENSSL_config() on 2016-01-26. Requested by David Benjamin. Signed-off-by: Piotr Sikora diff -r 3d5202c71f94 -r 05a43cbd6e0d src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -118,9 +118,7 @@ ngx_ssl_init(ngx_log_t *log) #else -#ifndef OPENSSL_IS_BORINGSSL OPENSSL_config(NULL); -#endif SSL_library_init(); SSL_load_error_strings(); From vbart at nginx.com Fri Aug 19 11:06:53 2016 From: vbart at nginx.com (Valentin V. Bartenev) Date: Fri, 19 Aug 2016 14:06:53 +0300 Subject: [PATCH] HTTP: add support for trailers in HTTP responses In-Reply-To: References: <20160721134430.GV57459@mdounin.ru> <20160804022412.GW57459@mdounin.ru> Message-ID: <2008263.qLhO4KSZur@vbart-workstation> My two cents. If somebody wants nginx to support trailers then why not, as long as this feature is optional. I think nginx mustn't be used as "political lever" if one of the developers dislike the concept of some feature, don't want to see use-cases and thinks that the only purpose is to push some technology by well-known company. It's too naive to think that we can change something by denying some feature. The only result of such stubbornness is that our users will have to choice other alternatives to nginx or have to invent their own solutions. I strongly suggest moving the debate to more constructive ground, and instead of keep refusing think about how we can introduce trailers support in the most clever way. wbr, Valentin V. Bartenev From mdounin at mdounin.ru Sun Aug 21 14:02:11 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sun, 21 Aug 2016 17:02:11 +0300 Subject: [PATCH] SSL: fix order of checks during SSL certificate verification In-Reply-To: References: <20160804035352.GY57459@mdounin.ru> <20160818003702.GE24741@mdounin.ru> Message-ID: <20160821140211.GH24741@mdounin.ru> Hello! On Thu, Aug 18, 2016 at 07:46:29PM -0700, Piotr Sikora wrote: > Hey Maxim, > > > Calling SSL_get_peer_certificate() is only needed if > > SSL_get_verify_result() returns X509_V_OK, to distinguish two of > > its different meanings: > > > > X509_V_OK > > The verification succeeded or no peer certificate was presented. > > > > And that's what nginx does. > > That's not what the documentation says, though... The above quote is from the documentation. > At this point, NGINX is just relying on a known bug, nothing else. At this point nginx just uses the interface provided by the OpenSSL library, exactly as documented. The fact that the interface is flawed (and documented to be flawed to make sure people will use it properly) has nothing to do with nginx use of it. > > Ok, this looks like the real reason for the patch. This looks > > like an API change in BoringSSL, and should be threated > > accordingly. > > Nope, that's not the real reason... BoringSSL actually added a > workaround for this [1], just to play nicely with NGINX and > netty-tcnative, because virtually everything else is using OpenSSL API > correctly, i.e. checking if peer sent the certificate before checking > if that certificate passed verification. > > The real reason for this patch is that existing code is misusing OpenSSL API. > > [1] https://boringssl.googlesource.com/boringssl/+/37646838e9bb62a0d9d506b117193611c4c46012 So the change was inspired by an attempt to change the API in BoringSSL. As for "misusing", see above. [...] > > (2) looks hardly portable (what if another > > library will have different rc values? or will have more than one > > error string to print?), > > Well, it's portable assuming that the library also converts the "rc" > value back to the error string (like in the patchset I sent > yesterday). Your patches assume that there are no conflicts between nginx error codes (NGX_OK, NGX_DECLINED) and SSL_get_verify_result() error codes. While this is currently true, this is not something I would rely on, even assuming OpenSSL only. -- Maxim Dounin http://nginx.org/ From ru at nginx.com Mon Aug 22 10:18:15 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Mon, 22 Aug 2016 10:18:15 +0000 Subject: [nginx] Events: fixed setting of IP_BIND_ADDRESS_NO_PORT/SO_REUSEADDR. Message-ID: details: http://hg.nginx.org/nginx/rev/7fd6b93face8 branches: changeset: 6658:7fd6b93face8 user: Ruslan Ermilov date: Mon Aug 22 11:40:10 2016 +0300 description: Events: fixed setting of IP_BIND_ADDRESS_NO_PORT/SO_REUSEADDR. The IP_BIND_ADDRESS_NO_PORT option is set on upstream sockets if proxy_bind does not specify a port. The SO_REUSEADDR option is set on UDP upstream sockets if proxy_bind specifies a port. Due to checking of the wrong port, IP_BIND_ADDRESS_NO_PORT was never set, and SO_REUSEPORT was always set. diffstat: src/event/ngx_event_connect.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 3d5202c71f94 -r 7fd6b93face8 src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c Wed Aug 17 11:26:51 2016 +0300 +++ b/src/event/ngx_event_connect.c Mon Aug 22 11:40:10 2016 +0300 @@ -91,7 +91,7 @@ ngx_event_connect_peer(ngx_peer_connecti #endif #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT || NGX_LINUX) - port = ngx_inet_get_port(pc->sockaddr); + port = ngx_inet_get_port(pc->local->sockaddr); #endif #if (NGX_HAVE_IP_BIND_ADDRESS_NO_PORT) From mdounin at mdounin.ru Mon Aug 22 15:07:58 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 22 Aug 2016 15:07:58 +0000 Subject: [nginx] SSL: remove no longer needed workaround for BoringSSL. Message-ID: details: http://hg.nginx.org/nginx/rev/3d8be8fb0149 branches: changeset: 6659:3d8be8fb0149 user: Piotr Sikora date: Thu Aug 18 14:49:48 2016 -0700 description: SSL: remove no longer needed workaround for BoringSSL. BoringSSL added a no-op stub for OPENSSL_config() on 2016-01-26. Requested by David Benjamin. Signed-off-by: Piotr Sikora diffstat: src/event/ngx_event_openssl.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diffs (13 lines): diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -118,9 +118,7 @@ ngx_ssl_init(ngx_log_t *log) #else -#ifndef OPENSSL_IS_BORINGSSL OPENSSL_config(NULL); -#endif SSL_library_init(); SSL_load_error_strings(); From mdounin at mdounin.ru Mon Aug 22 15:08:21 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 22 Aug 2016 18:08:21 +0300 Subject: [PATCH] SSL: remove no longer needed workaround for BoringSSL In-Reply-To: <05a43cbd6e0d4e4e94be.1471580787@piotrsikora.sfo.corp.google.com> References: <05a43cbd6e0d4e4e94be.1471580787@piotrsikora.sfo.corp.google.com> Message-ID: <20160822150821.GL24741@mdounin.ru> Hello! On Thu, Aug 18, 2016 at 09:26:27PM -0700, Piotr Sikora wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1471556988 25200 > # Thu Aug 18 14:49:48 2016 -0700 > # Node ID 05a43cbd6e0d4e4e94be2c48765e7d12b1faf0e4 > # Parent 3d5202c71f94b155c0beefaf707f2f45a05634cf > SSL: remove no longer needed workaround for BoringSSL. > > BoringSSL added a no-op stub for OPENSSL_config() on 2016-01-26. > > Requested by David Benjamin. > > Signed-off-by: Piotr Sikora > > diff -r 3d5202c71f94 -r 05a43cbd6e0d src/event/ngx_event_openssl.c > --- a/src/event/ngx_event_openssl.c > +++ b/src/event/ngx_event_openssl.c > @@ -118,9 +118,7 @@ ngx_ssl_init(ngx_log_t *log) > > #else > > -#ifndef OPENSSL_IS_BORINGSSL > OPENSSL_config(NULL); > -#endif > > SSL_library_init(); > SSL_load_error_strings(); Committed, thanks. -- Maxim Dounin http://nginx.org/ From pluknet at nginx.com Mon Aug 22 15:54:36 2016 From: pluknet at nginx.com (Sergey Kandaurov) Date: Mon, 22 Aug 2016 15:54:36 +0000 Subject: [nginx] SSL: adopted session ticket handling for OpenSSL 1.1.0. Message-ID: details: http://hg.nginx.org/nginx/rev/3eb1a92a2f05 branches: changeset: 6660:3eb1a92a2f05 user: Sergey Kandaurov date: Mon Aug 22 18:53:21 2016 +0300 description: SSL: adopted session ticket handling for OpenSSL 1.1.0. Return 1 in the SSL_CTX_set_tlsext_ticket_key_cb() callback function to indicate that a new session ticket is created, as per documentation. Until 1.1.0, OpenSSL didn't make a distinction between non-negative return values. See https://git.openssl.org/?p=openssl.git;a=commitdiff;h=5c753de for details. diffstat: src/event/ngx_event_openssl.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 3d8be8fb0149 -r 3eb1a92a2f05 src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Thu Aug 18 14:49:48 2016 -0700 +++ b/src/event/ngx_event_openssl.c Mon Aug 22 18:53:21 2016 +0300 @@ -2986,7 +2986,7 @@ ngx_ssl_session_ticket_key_callback(ngx_ ngx_ssl_session_ticket_md(), NULL); ngx_memcpy(name, key[0].name, 16); - return 0; + return 1; } else { /* decrypt session ticket */ From cloud.gate at outlook.com Mon Aug 22 18:40:06 2016 From: cloud.gate at outlook.com (Cloud Gate) Date: Mon, 22 Aug 2016 18:40:06 +0000 Subject: True Dynamic Module Binary Plug-In Model ETA Message-ID: Hello nginx developers, I hope this is the appropriate forum for this question. In an nginx.com presentation from Sep 2015, Ruslan Ermilov indicated that work is being done on support for "true dynamic modules" i.e. a mechanism that would not require compilation against nginx source code, but rather allow API-based binary DLL/SO module plug-in support. Can you please provide an estimate on when this feature will be publicly available? Is there any way our company could facilitate this support (via commercial contract, implement our own "quick-n-dirty" version of this idea, etc)? It would be terrific if this feature was available in the near future, if possible! As commercial developers, our plug-in must target different nginx versions, different compiler options, we might have conflicting third-party libraries, etc. Most importantly, we may not be able to ship source code, so we must be the ones to compile the module and thus nginx. Even internally, there are many logistical problems with having our module team compile nginx (e.g. so we can run module unit and integration tests, etc), when in fact a different department entirely might "own" the official nginx server compilation, etc. For these and other reasons, a true, binary / API-based, standalone DLL/SO plug-in model would be a terrific benefit and save us many problems and complexities with trying to develop a commercial nginx plug-in. Any time frame or relevant information or additional thoughts you can provide on this topic would be greatly appreciated, Thanks! -- Cloud Gate -------------- next part -------------- An HTML attachment was scrubbed... URL: From gopal.raghavan at here.com Tue Aug 23 02:51:54 2016 From: gopal.raghavan at here.com (Raghavan, Gopal) Date: Tue, 23 Aug 2016 02:51:54 +0000 Subject: ngx_list_create in shm_zone In-Reply-To: References: Message-ID: <9DD12C20-7155-400E-99A2-07F696C6A93D@here.com> Is it possible to use ngx_list_create and ngx_list_init with share memory? List functions take ngx_pool_t, however shared memory zone provides ngx_slab_pool_t. If yes, could you please share an example. Thanks, -- Gopal -------------- next part -------------- An HTML attachment was scrubbed... URL: From maxim at nginx.com Tue Aug 23 07:50:59 2016 From: maxim at nginx.com (Maxim Konovalov) Date: Tue, 23 Aug 2016 10:50:59 +0300 Subject: True Dynamic Module Binary Plug-In Model ETA In-Reply-To: References: Message-ID: <245aaab6-c73b-0952-1bd3-847cf219e1b3@nginx.com> Hello, On 8/22/16 9:40 PM, Cloud Gate wrote: > Hello nginx developers, > > > I hope this is the appropriate forum for this question. In an > nginx.com presentation from Sep 2015, Ruslan Ermilov indicated that > work is being done on support for "true dynamic modules" i.e. a > mechanism that would not require compilation against nginx source > code, but rather allow API-based binary DLL/SO module plug-in > support. Can you please provide an estimate on when this feature > will be publicly available? Is there any way our company could > facilitate this support (via commercial contract, implement our own > "quick-n-dirty" version of this idea, etc)? It would be terrific if > this feature was available in the near future, if possible! > DSO support (aka phase 1 of the project) was added to nginx core early this year in nginx-1.9.11. Please visit the following links for more information: http://mailman.nginx.org/pipermail/nginx-announce/2016/000170.html http://nginx.org/r/load_module https://www.nginx.com/resources/wiki/extending/ Somewhere at this time we also started to ship a number of packages with nginx dynamic modules: http://nginx.org/en/linux_packages.html At this stage you still need nginx sources to compile dynamic modules though. While API-based DSO model is desired and it is in the long term roadmap it is far beyond the horizon of current planning to talk seriously about possible ETA. We also have a talk about nginx dynamic modules model, its current state and our nearest plans at the upcoming nginx.conf 2016 in Austin: https://www.nginx.com/nginxconf/schedule/ > As commercial developers, our plug-in must target different nginx > versions, different compiler options, we might have conflicting > third-party libraries, etc. Most importantly, we may not be able to > ship source code, so we must be the ones to compile the module and > thus nginx. Even internally, there are many logistical problems with > having our module team compile nginx (e.g. so we can run module unit > and integration tests, etc), when in fact a different department > entirely might "own" the official nginx server compilation, etc. For > these and other reasons, a true, binary / API-based, standalone > DLL/SO plug-in model would be a terrific benefit and save us many > problems and complexities with trying to develop a commercial nginx > plug-in. > > Any time frame or relevant information or additional thoughts you > can provide on this topic would be greatly appreciated, > I will ask our PM team to consider your request. Thanks, Maxim -- Maxim Konovalov Join us at nginx.conf, Sept. 7-9, Austin, TX: http://nginx.com/nginxconf From mdounin at mdounin.ru Tue Aug 23 11:11:11 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 23 Aug 2016 14:11:11 +0300 Subject: ngx_list_create in shm_zone In-Reply-To: <9DD12C20-7155-400E-99A2-07F696C6A93D@here.com> References: <9DD12C20-7155-400E-99A2-07F696C6A93D@here.com> Message-ID: <20160823111111.GP24741@mdounin.ru> Hello! On Tue, Aug 23, 2016 at 02:51:54AM +0000, Raghavan, Gopal wrote: > Is it possible to use ngx_list_create and ngx_list_init with share memory? > List functions take ngx_pool_t, however shared memory zone provides ngx_slab_pool_t. > If yes, could you please share an example. No, it's not possible. -- Maxim Dounin http://nginx.org/ From rudolfs.bundulis at gmail.com Tue Aug 23 11:15:17 2016 From: rudolfs.bundulis at gmail.com (=?UTF-8?Q?R=C5=ABdolfs_Bundulis?=) Date: Tue, 23 Aug 2016 14:15:17 +0300 Subject: Dynamic module and obtaining http core module configuration In-Reply-To: <20160817234458.GD24741@mdounin.ru> References: <20160817234458.GD24741@mdounin.ru> Message-ID: Thanks for the explanations. Yeah well seeing that IOCP does not work as well I'll most likely move to Unix. -------------- next part -------------- An HTML attachment was scrubbed... URL: From gopal.raghavan at here.com Tue Aug 23 12:41:06 2016 From: gopal.raghavan at here.com (Raghavan, Gopal) Date: Tue, 23 Aug 2016 12:41:06 +0000 Subject: ngx_list_create in shm_zone In-Reply-To: <20160823111111.GP24741@mdounin.ru> References: <9DD12C20-7155-400E-99A2-07F696C6A93D@here.com> <20160823111111.GP24741@mdounin.ru> Message-ID: <17253803-54A4-4F68-810A-D20521AE9250@here.com> I can store as ngx_rbtree_t. Any suggestion on how to store a struct with list of items, something like this in shared memory? typedef struct { ngx_rbtree_node_t node; ngx_uint_t id; ngx_list_t *items; // list of items. But ngx_list_t is not possible since it needs ngx_pool_t. Any alternatives? } ngx_http_metadata_shm_block_t; Thanks, -- Gopal On 8/23/16, 7:11 AM, "nginx-devel on behalf of Maxim Dounin" wrote: >Hello! > >On Tue, Aug 23, 2016 at 02:51:54AM +0000, Raghavan, Gopal wrote: > >> Is it possible to use ngx_list_create and ngx_list_init with share memory? >> List functions take ngx_pool_t, however shared memory zone provides ngx_slab_pool_t. >> If yes, could you please share an example. > >No, it's not possible. > >-- >Maxim Dounin >http://nginx.org/ > >_______________________________________________ >nginx-devel mailing list >nginx-devel at nginx.org >http://mailman.nginx.org/mailman/listinfo/nginx-devel From wandenberg at gmail.com Tue Aug 23 13:15:36 2016 From: wandenberg at gmail.com (Wandenberg Peixoto) Date: Tue, 23 Aug 2016 10:15:36 -0300 Subject: ngx_list_create in shm_zone In-Reply-To: <17253803-54A4-4F68-810A-D20521AE9250@here.com> References: <9DD12C20-7155-400E-99A2-07F696C6A93D@here.com> <20160823111111.GP24741@mdounin.ru> <17253803-54A4-4F68-810A-D20521AE9250@here.com> Message-ID: Use ngx_queue_t On Aug 23, 2016 09:41, "Raghavan, Gopal" wrote: > I can store as ngx_rbtree_t. > Any suggestion on how to store a struct with list of items, something like > this in shared memory? > > typedef struct { > ngx_rbtree_node_t node; > ngx_uint_t id; > ngx_list_t *items; // list of items. But > ngx_list_t is not possible since it needs ngx_pool_t. Any alternatives? > } ngx_http_metadata_shm_block_t; > > Thanks, > -- > Gopal > > On 8/23/16, 7:11 AM, "nginx-devel on behalf of Maxim Dounin" < > nginx-devel-bounces at nginx.org on behalf of mdounin at mdounin.ru> wrote: > > >Hello! > > > >On Tue, Aug 23, 2016 at 02:51:54AM +0000, Raghavan, Gopal wrote: > > > >> Is it possible to use ngx_list_create and ngx_list_init with share > memory? > >> List functions take ngx_pool_t, however shared memory zone provides > ngx_slab_pool_t. > >> If yes, could you please share an example. > > > >No, it's not possible. > > > >-- > >Maxim Dounin > >http://nginx.org/ > > > >_______________________________________________ > >nginx-devel mailing list > >nginx-devel at nginx.org > >http://mailman.nginx.org/mailman/listinfo/nginx-devel > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ru at nginx.com Tue Aug 23 14:00:23 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Tue, 23 Aug 2016 14:00:23 +0000 Subject: [nginx] Geo: fixed overflow when iterating over ranges. Message-ID: details: http://hg.nginx.org/nginx/rev/ec141a44641b branches: changeset: 6661:ec141a44641b user: Ruslan Ermilov date: Tue Aug 23 15:57:29 2016 +0300 description: Geo: fixed overflow when iterating over ranges. diffstat: src/http/modules/ngx_http_geo_module.c | 12 ++++++++++-- src/stream/ngx_stream_geo_module.c | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diffs (72 lines): diff -r 3eb1a92a2f05 -r ec141a44641b src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c Mon Aug 22 18:53:21 2016 +0300 +++ b/src/http/modules/ngx_http_geo_module.c Tue Aug 23 15:57:29 2016 +0300 @@ -946,7 +946,9 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n next: - continue; + if (h == 0xffff) { + break; + } } return NGX_CONF_OK; @@ -985,7 +987,7 @@ ngx_http_geo_delete_range(ngx_conf_t *cf if (a == NULL) { warn = 1; - continue; + goto next; } range = a->elts; @@ -1010,6 +1012,12 @@ ngx_http_geo_delete_range(ngx_conf_t *cf warn = 1; } + + next: + + if (h == 0xffff) { + break; + } } return warn; diff -r 3eb1a92a2f05 -r ec141a44641b src/stream/ngx_stream_geo_module.c --- a/src/stream/ngx_stream_geo_module.c Mon Aug 22 18:53:21 2016 +0300 +++ b/src/stream/ngx_stream_geo_module.c Tue Aug 23 15:57:29 2016 +0300 @@ -896,7 +896,9 @@ ngx_stream_geo_add_range(ngx_conf_t *cf, next: - continue; + if (h == 0xffff) { + break; + } } return NGX_CONF_OK; @@ -935,7 +937,7 @@ ngx_stream_geo_delete_range(ngx_conf_t * if (a == NULL) { warn = 1; - continue; + goto next; } range = a->elts; @@ -960,6 +962,12 @@ ngx_stream_geo_delete_range(ngx_conf_t * warn = 1; } + + next: + + if (h == 0xffff) { + break; + } } return warn; From ru at nginx.com Tue Aug 23 14:00:26 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Tue, 23 Aug 2016 14:00:26 +0000 Subject: [nginx] Geo: fixed removing a range in certain cases. Message-ID: details: http://hg.nginx.org/nginx/rev/1301a58b5dac branches: changeset: 6662:1301a58b5dac user: Ruslan Ermilov date: Tue Aug 23 15:59:06 2016 +0300 description: Geo: fixed removing a range in certain cases. If the range includes two or more /16 networks and does not start at the /16 boundary, the last subrange was not removed (see 91cff7f97a50 for details). diffstat: src/http/modules/ngx_http_geo_module.c | 2 +- src/stream/ngx_stream_geo_module.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diffs (24 lines): diff -r ec141a44641b -r 1301a58b5dac src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c Tue Aug 23 15:57:29 2016 +0300 +++ b/src/http/modules/ngx_http_geo_module.c Tue Aug 23 15:59:06 2016 +0300 @@ -966,7 +966,7 @@ ngx_http_geo_delete_range(ngx_conf_t *cf warn = 0; - for (n = start; n <= end; n += 0x10000) { + for (n = start; n <= end; n = (n + 0x10000) & 0xffff0000) { h = n >> 16; diff -r ec141a44641b -r 1301a58b5dac src/stream/ngx_stream_geo_module.c --- a/src/stream/ngx_stream_geo_module.c Tue Aug 23 15:57:29 2016 +0300 +++ b/src/stream/ngx_stream_geo_module.c Tue Aug 23 15:59:06 2016 +0300 @@ -916,7 +916,7 @@ ngx_stream_geo_delete_range(ngx_conf_t * warn = 0; - for (n = start; n <= end; n += 0x10000) { + for (n = start; n <= end; n = (n + 0x10000) & 0xffff0000) { h = n >> 16; From ru at nginx.com Tue Aug 23 14:00:29 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Tue, 23 Aug 2016 14:00:29 +0000 Subject: [nginx] Geo: fixed insertion of ranges specified in descending order. Message-ID: details: http://hg.nginx.org/nginx/rev/53198d9bf84f branches: changeset: 6663:53198d9bf84f user: Ruslan Ermilov date: Tue Aug 23 15:59:14 2016 +0300 description: Geo: fixed insertion of ranges specified in descending order. diffstat: src/http/modules/ngx_http_geo_module.c | 11 ++++++++--- src/stream/ngx_stream_geo_module.c | 11 ++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diffs (42 lines): diff -r 1301a58b5dac -r 53198d9bf84f src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c Tue Aug 23 15:59:06 2016 +0300 +++ b/src/http/modules/ngx_http_geo_module.c Tue Aug 23 15:59:14 2016 +0300 @@ -940,9 +940,14 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n return NGX_CONF_ERROR; } - range->start = (u_short) s; - range->end = (u_short) e; - range->value = ctx->value; + range = a->elts; + + ngx_memmove(&range[1], &range[0], + (a->nelts - 1) * sizeof(ngx_http_geo_range_t)); + + range[0].start = (u_short) s; + range[0].end = (u_short) e; + range[0].value = ctx->value; next: diff -r 1301a58b5dac -r 53198d9bf84f src/stream/ngx_stream_geo_module.c --- a/src/stream/ngx_stream_geo_module.c Tue Aug 23 15:59:06 2016 +0300 +++ b/src/stream/ngx_stream_geo_module.c Tue Aug 23 15:59:14 2016 +0300 @@ -890,9 +890,14 @@ ngx_stream_geo_add_range(ngx_conf_t *cf, return NGX_CONF_ERROR; } - range->start = (u_short) s; - range->end = (u_short) e; - range->value = ctx->value; + range = a->elts; + + ngx_memmove(&range[1], &range[0], + (a->nelts - 1) * sizeof(ngx_stream_geo_range_t)); + + range[0].start = (u_short) s; + range[0].end = (u_short) e; + range[0].value = ctx->value; next: From ru at nginx.com Tue Aug 23 14:00:31 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Tue, 23 Aug 2016 14:00:31 +0000 Subject: [nginx] Geo: fixed warnings when removing nonexistent ranges. Message-ID: details: http://hg.nginx.org/nginx/rev/0ee6f023ef92 branches: changeset: 6664:0ee6f023ef92 user: Ruslan Ermilov date: Tue Aug 23 15:59:42 2016 +0300 description: Geo: fixed warnings when removing nonexistent ranges. geo $geo { ranges; 10.0.0.0-10.0.0.255 test; delete 10.0.1.0-10.0.1.255; # should warn delete 10.0.0.0-10.0.0.255; delete 10.0.0.0-10.0.0.255; # should warn } diffstat: src/http/modules/ngx_http_geo_module.c | 10 +++------- src/stream/ngx_stream_geo_module.c | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diffs (56 lines): diff -r 53198d9bf84f -r 0ee6f023ef92 src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c Tue Aug 23 15:59:14 2016 +0300 +++ b/src/http/modules/ngx_http_geo_module.c Tue Aug 23 15:59:42 2016 +0300 @@ -990,7 +990,7 @@ ngx_http_geo_delete_range(ngx_conf_t *cf a = (ngx_array_t *) ctx->high.low[h]; - if (a == NULL) { + if (a == NULL || a->nelts == 0) { warn = 1; goto next; } @@ -1009,13 +1009,9 @@ ngx_http_geo_delete_range(ngx_conf_t *cf break; } - if (s != (ngx_uint_t) range[i].start - && e != (ngx_uint_t) range[i].end) - { - continue; + if (i == a->nelts - 1) { + warn = 1; } - - warn = 1; } next: diff -r 53198d9bf84f -r 0ee6f023ef92 src/stream/ngx_stream_geo_module.c --- a/src/stream/ngx_stream_geo_module.c Tue Aug 23 15:59:14 2016 +0300 +++ b/src/stream/ngx_stream_geo_module.c Tue Aug 23 15:59:42 2016 +0300 @@ -940,7 +940,7 @@ ngx_stream_geo_delete_range(ngx_conf_t * a = (ngx_array_t *) ctx->high.low[h]; - if (a == NULL) { + if (a == NULL || a->nelts == 0) { warn = 1; goto next; } @@ -959,13 +959,9 @@ ngx_stream_geo_delete_range(ngx_conf_t * break; } - if (s != (ngx_uint_t) range[i].start - && e != (ngx_uint_t) range[i].end) - { - continue; + if (i == a->nelts - 1) { + warn = 1; } - - warn = 1; } next: From mdounin at mdounin.ru Tue Aug 23 14:22:12 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 23 Aug 2016 17:22:12 +0300 Subject: [PATCH] HTTP: add support for trailers in HTTP responses In-Reply-To: References: <20160721134430.GV57459@mdounin.ru> <20160801132154.GH57459@mdounin.ru> <20160804022412.GW57459@mdounin.ru> Message-ID: <20160823142212.GS24741@mdounin.ru> Hello! On Thu, Aug 18, 2016 at 06:12:46PM -0700, Piotr Sikora wrote: > > By saying "most popular use case" you are talking about something > > real-world you are aware of? > > Yes. > > Furthermore, I'm aware of a few systems using NGINX that use either > ugly workarounds or are missing features exactly because NGINX doesn't > support trailers. Could you please describe one of the uses cases in details? That's what I'm asking all the time, and still didn't get even a single description of a real-world use case. > > And this probably an additional thing to consider when introducing > > trailers: right now nginx strips all trailers. Changing this may > > be a surprise for those who use trailers internally, if any. > > This can be easily mitigated with "proxy_pass_trailers on|off". Sure. This is just one item from the long list of various implications of trailers. > > We've already talked about gRPC. > > Yes, and I'm not sure why you keep ignoring it. > > If it's because you assume that it has to be end-to-end HTTP/2 and as > such trailers aren't the main blocker, then there are reverse proxies > like grpc-gateway [1] (which, coincidentally, doesn't support > trailers), that convert HTTP/1.1 requests to a "pure" gRPC requests > and back... Lack of trailers in NGINX prevents people from writing > custom upstream gRPC module, which could provide similar functionality > in NGINX. The last sentense here contradicts the first one. If grpc-gateway is fine without trailers support, I don't see how lack of trailers in nginx prevents one from providing similar functionality in nginx. > However, if it's because "it's Google pushing it's own library", then > it's neither good nor technical reason for rejecting trailers support. > > [1] https://github.com/grpc-ecosystem/grpc-gateway > > > Fetch API and Server Timing are > > just specifications being developed which allow use of trailers, > > not much different from HTTP/1.1 itself. > > Well, they wouldn't be adding it if it was so useless, would they? The same applies to HTTP/1.1. Yet trailers are (mostly?) unused for many years. Moreover, it is clearly understood now that merging trailer headers to headers as supposed by HTTP/1.1 is a security disaster. > > On the other hand, here is a good discussion of trailers and their > > security in this Fetch API ticket: > > > > https://github.com/whatwg/fetch/issues/34 > > Yes, and the consensus is that there are no new security implications, > as long as you don't magically merge trailers with headers (which, as > previously stated, I have no intention of doing). Merging trailers with headers can happen somewhere else as long as you pass trailers through. And it will be perfectly in line with HTTP/1.1 specs. > > And here is a linked HTTPbis ticket to reconsider "TE: trailers" > > as it looks unneded: > > > > https://github.com/httpwg/http11bis/issues/18 > > > > This is somewhat in line with what I think about it, as previously > > discussed in this thread. > > I can drop this requirement if you insist, but that's much less > conservative approach than NGINX usually takes and I expect that some > obscure HTTP clients will break because of lack of proper support for > trailer-part in chunked encoding. The only potentially bad thing that can happen without forcing chunked transfer encoding is that trailers configured won't be sent if Content-Length is know. If this is critical for a use case, the Content-Length can be explicitly removed with additional configuration. Additionally, this is not something expected to happen when proxying, as Content-Length won't be known anyway if there are trailers in the upstream response. On the other hand, forcing chunked transfer encoding based on "TE: trailers" looks all the way wrong: - it will change the behaviour of nginx for such clients, even if there are no other reasons to do so; - it won't change the behaviour for other HTTP/1.1 clients who actually support trailers but doesn't advertize it via "TE: trailers", and thus trailers will be lost in some cases anyway. > > I'm still not convinced that trailers are needed. As previously > > said, this HTTP feature was mostly unused for 17 years, and > > this suggests something is wrong with the feature. So it may be a > > good idea to postpone this at least till some real user will > > appear. > > You have real users commenting in this thread, why do you keep > ignoring them? Other people already expressed interest, commented on > their internal implementations and/or said that they use workarounds > because NGINX doesn't support trailers. > > What more do you need? I'm just asking for a description of at least one real-world use case for trailers, to better understand how they are expected to be used in real life. > > In either case, I do not think that added trailers should by > > itself change transfer encoding used and remove Content-Length. > > Again, why this is an issue with trailers but it's not an issue with gzip? Gzip is something you explicitly enable in the configuration to change the content of some responses. It changes the content, and this in turn results in chunked transfer encoding when using HTTP/1.1. In contrast, trailers is something exists only in case of chunked transfer encoding. Depending on the use case, it may make sense to either: 1. once trailers are configured, force chunked encoding and sent trailers (if it is possible to do so); or 2. once trailers are configured, sent them as long as chunked encoding is used. Obviously enough, second approach is more flexible. And, as long as there is a way to force chunked encoding by other means, allows to do exactly the same thing as the first one, plus some additional things. The first approach may be easier and more natural for some use cases. But as there are no real-world use cases described, there are no arguments to support this approach. -- Maxim Dounin http://nginx.org/ From mdounin at mdounin.ru Tue Aug 23 14:57:53 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 23 Aug 2016 17:57:53 +0300 Subject: [PATCH] HTTP: add support for trailers in HTTP responses In-Reply-To: <2008263.qLhO4KSZur@vbart-workstation> References: <20160721134430.GV57459@mdounin.ru> <20160804022412.GW57459@mdounin.ru> <2008263.qLhO4KSZur@vbart-workstation> Message-ID: <20160823145753.GT24741@mdounin.ru> Hello! On Fri, Aug 19, 2016 at 02:06:53PM +0300, Valentin V. Bartenev wrote: > If somebody wants nginx to support trailers then why not, > as long as this feature is optional. The problem is that every feature implies additional complexity and support costs. Moreover, in case of trailers - certainly additional security concerns. Just adding all possible features won't work, as you will end up with a huge and bloated piece of junk. And that's why I asking for real-world use cases to make sure features added are in fact needed and benefits from features added outwheigh support costs. In case of trailers, there is additional argument of trailers being [mostly] unused for almost twenty years since introduction in HTTP/1.1. You may also find interesting this comment in the thread previously linked here: https://github.com/whatwg/fetch/issues/34#issuecomment-122377633 -- Maxim Dounin http://nginx.org/ From guruper at gmail.com Tue Aug 23 16:01:23 2016 From: guruper at gmail.com (Gurumurthi K) Date: Tue, 23 Aug 2016 21:31:23 +0530 Subject: Fwd: Constant Bit Rate delivery from NginX during Reverse Proxy In-Reply-To: References: Message-ID: Hi Team, We are trying to integrate NginX Plus 1.9.12 as the Mid-Tier caching layer with reverse proxy configured for upstream Device (Persistent Store) for the Content Delivery Network (Video) which works with the Constant Bit Rate delivery for the Down streaming to STB We have enabled slice module and configured the slice of 5MB and try to run a test we observed the NginX is not able to downstream the data at the requested BitRate, For example assume Edge Device to STB ? NginX ? Persistent Store, while we try to request with 3.75Mbps bitrate between these devices we could see our Persistent Store is able to transfer at 3.75Mbps and transfer from NginX is between 1.25Mbps to 4Mbps based on the catchup, sometime we are observing Nginx is transmitting at few Kbps While analyzing the wireshark capture we noticed that even though there are enough receive window Nginx is unable to serve the data because that is currently been filled from the upstream server at the same bitrate, While analyzing we found that Nginx will transfer only when the slice is cached fully Please let us know what kind of configuration which we can make to ensure Nginx transfers (limit-at) the rate requested, Attached our configuration file Thanks, Guru P.S: please reroute to the appropriate alias if you are not intended recipient -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: nginx.conf Type: application/octet-stream Size: 4472 bytes Desc: not available URL: From mailforpps at gmail.com Tue Aug 23 16:33:01 2016 From: mailforpps at gmail.com (phani prasad) Date: Tue, 23 Aug 2016 22:03:01 +0530 Subject: how to completely disable buffering request body Message-ID: Hi all, for one of our products we have chosen nginx as our webserver and using fastCGI to talk to upstream(application) layer. We have a usecase where in the client sends huge payload typically in MB and nginx is quick enough reading all the data and buffering it . Whereas our upstream server is quite slower in consuming the data. This resulted in timeout on client side since the upstream cant respond with status code until unless it finish reading the complete payload. Additional information is, the request is chunked. To address this we have tried several options but nothing worked out so far. 1. we turned off fastcgi_request_buffering setting it to off. This would only allow nginx not to buffer request payload into a temp file before forwarding it to application/upstream. But it still use some buffer chains to write to upstream. 2. setting client_body_buffer_size . this would only check if request body size is larger than client_body_buffer_size, then it writes whole or part of body to file. How does this work in case of chunked request body? What is the max chunk size that nginx can allocate? What if upstream is slow in consuming the data and nginx still tries to writev chain of buffers to the pipe? How many max chain buffers nginx would maintain to buffer request body? If so is it configurable? What other options that we can try out? we want to completely disable request body buffering and would want to stream the data as it just arrives from client. and if upstream is busy , nginx should be able to tune itself in the sense it should wait reading further data from client until upstream is ready to be written. Any help is much appreciated as this is blocking one of our product certifications. Thanks Prasad. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Tue Aug 23 17:06:35 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 23 Aug 2016 20:06:35 +0300 Subject: how to completely disable buffering request body In-Reply-To: References: Message-ID: <20160823170635.GV24741@mdounin.ru> Hello! On Tue, Aug 23, 2016 at 10:03:01PM +0530, phani prasad wrote: > Hi all, > > for one of our products we have chosen nginx as our webserver and using > fastCGI to talk to upstream(application) layer. We have a usecase where in > the client sends huge payload typically in MB and nginx is quick enough > reading all the data and buffering it . Whereas our upstream server is > quite slower in consuming the data. This resulted in timeout on client > side since the upstream cant respond with status code until unless it > finish reading the complete payload. Additional information is, the request > is chunked. This mailing list is about nginx development. Your question doesn't look to be related to development and should be more appropriate for the nginx general discussion mailing list, see http://nginx.org/en/support.html. -- Maxim Dounin http://nginx.org/ From maxim at nginx.com Tue Aug 23 17:56:27 2016 From: maxim at nginx.com (Maxim Konovalov) Date: Tue, 23 Aug 2016 20:56:27 +0300 Subject: Constant Bit Rate delivery from NginX during Reverse Proxy In-Reply-To: References: Message-ID: <7fb36a99-c12a-6de1-89a1-8d00797c95f5@nginx.com> Hello, On 8/23/16 7:01 PM, Gurumurthi K wrote: > > Hi Team, > > We are trying to integrate NginX Plus 1.9.12 as the Mid-Tier caching [...] If you are nginx-plus user please feel free to open a support ticket by sending email to plus-support at nginx.com. -- Maxim Konovalov Join us at nginx.conf, Sept. 7-9, Austin, TX: http://nginx.com/nginxconf From mdounin at mdounin.ru Wed Aug 24 12:54:23 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 24 Aug 2016 12:54:23 +0000 Subject: [nginx] Contrib: unicode2nginx compatibility with recent Perl versions. Message-ID: details: http://hg.nginx.org/nginx/rev/8752257e883f branches: changeset: 6665:8752257e883f user: Maxim Dounin date: Wed Aug 24 15:53:17 2016 +0300 description: Contrib: unicode2nginx compatibility with recent Perl versions. In recent Perl versions unpack("C*") unpacks wide characters by default, likely since perl 5.10 (seen at least in perl 5.20). Replaced with unpack("U0C*") instead to unpack bytes. While here, improved style and updated my email. diffstat: contrib/unicode2nginx/unicode-to-nginx.pl | 7 +++++-- 1 files changed, 5 insertions(+), 2 deletions(-) diffs (24 lines): diff --git a/contrib/unicode2nginx/unicode-to-nginx.pl b/contrib/unicode2nginx/unicode-to-nginx.pl --- a/contrib/unicode2nginx/unicode-to-nginx.pl +++ b/contrib/unicode2nginx/unicode-to-nginx.pl @@ -10,7 +10,7 @@ # Needs perl 5.6 or later. -# Written by Maxim Dounin, mdounin at rambler-co.ru +# Written by Maxim Dounin, mdounin at mdounin.ru ############################################################################### @@ -33,7 +33,10 @@ while (<>) { # Produce UTF-8 sequence from character code; - my $un_utf8 = join('', map { sprintf("%02X", $_) } unpack("C*", pack("U", hex($un_code)))); + my $un_utf8 = join('', + map { sprintf("%02X", $_) } + unpack("U0C*", pack("U", hex($un_code))) + ); print " $cs_code $un_utf8 ; $un_name\n"; From pluknet at nginx.com Thu Aug 25 10:00:36 2016 From: pluknet at nginx.com (Sergey Kandaurov) Date: Thu, 25 Aug 2016 10:00:36 +0000 Subject: [nginx] Geo: fixed indentation. Message-ID: details: http://hg.nginx.org/nginx/rev/3f82c1e7e29e branches: changeset: 6666:3f82c1e7e29e user: Sergey Kandaurov date: Thu Aug 25 12:59:39 2016 +0300 description: Geo: fixed indentation. diffstat: src/http/modules/ngx_http_geo_module.c | 10 +++++----- 1 files changed, 5 insertions(+), 5 deletions(-) diffs (48 lines): diff -r 8752257e883f -r 3f82c1e7e29e src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c Wed Aug 24 15:53:17 2016 +0300 +++ b/src/http/modules/ngx_http_geo_module.c Thu Aug 25 12:59:39 2016 +0300 @@ -819,7 +819,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n range = a->elts; ngx_memmove(&range[i + 2], &range[i + 1], - (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t)); + (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t)); range[i + 1].start = (u_short) s; range[i + 1].end = (u_short) e; @@ -858,7 +858,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n range = a->elts; ngx_memmove(&range[i + 3], &range[i + 1], - (a->nelts - 3 - i) * sizeof(ngx_http_geo_range_t)); + (a->nelts - 3 - i) * sizeof(ngx_http_geo_range_t)); range[i + 2].start = (u_short) (e + 1); range[i + 2].end = range[i].end; @@ -886,7 +886,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n range = a->elts; ngx_memmove(&range[i + 1], &range[i], - (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t)); + (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t)); range[i + 1].start = (u_short) (e + 1); @@ -910,7 +910,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n range = a->elts; ngx_memmove(&range[i + 2], &range[i + 1], - (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t)); + (a->nelts - 2 - i) * sizeof(ngx_http_geo_range_t)); range[i + 1].start = (u_short) s; range[i + 1].end = (u_short) e; @@ -1002,7 +1002,7 @@ ngx_http_geo_delete_range(ngx_conf_t *cf && e == (ngx_uint_t) range[i].end) { ngx_memmove(&range[i], &range[i + 1], - (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t)); + (a->nelts - 1 - i) * sizeof(ngx_http_geo_range_t)); a->nelts--; From ru at nginx.com Fri Aug 26 10:44:01 2016 From: ru at nginx.com (Ruslan Ermilov) Date: Fri, 26 Aug 2016 10:44:01 +0000 Subject: [nginx] Thread pools: create threads in detached state. Message-ID: details: http://hg.nginx.org/nginx/rev/33d075b9097d branches: changeset: 6667:33d075b9097d user: Piotr Sikora date: Mon Aug 15 05:52:04 2016 -0700 description: Thread pools: create threads in detached state. This prevents theoretical resource leak, since those threads are never joined. Found with ThreadSanitizer. Signed-off-by: Piotr Sikora diffstat: src/core/ngx_thread_pool.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diffs (17 lines): diff -r 3f82c1e7e29e -r 33d075b9097d src/core/ngx_thread_pool.c --- a/src/core/ngx_thread_pool.c Thu Aug 25 12:59:39 2016 +0300 +++ b/src/core/ngx_thread_pool.c Mon Aug 15 05:52:04 2016 -0700 @@ -137,6 +137,13 @@ ngx_thread_pool_init(ngx_thread_pool_t * return NGX_ERROR; } + err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + if (err) { + ngx_log_error(NGX_LOG_ALERT, log, err, + "pthread_attr_setdetachstate() failed"); + return NGX_ERROR; + } + #if 0 err = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); if (err) { From vl at nginx.com Fri Aug 26 12:34:55 2016 From: vl at nginx.com (Vladimir Homutov) Date: Fri, 26 Aug 2016 12:34:55 +0000 Subject: [nginx] Stream: the $bytes_received variable. Message-ID: details: http://hg.nginx.org/nginx/rev/5e2821c2de46 branches: changeset: 6668:5e2821c2de46 user: Vladimir Homutov date: Fri Aug 26 15:33:02 2016 +0300 description: Stream: the $bytes_received variable. The variable keeps the number of bytes received from the client. diffstat: src/stream/ngx_stream_variables.c | 17 +++++++++++++---- 1 files changed, 13 insertions(+), 4 deletions(-) diffs (50 lines): diff -r 33d075b9097d -r 5e2821c2de46 src/stream/ngx_stream_variables.c --- a/src/stream/ngx_stream_variables.c Mon Aug 15 05:52:04 2016 -0700 +++ b/src/stream/ngx_stream_variables.c Fri Aug 26 15:33:02 2016 +0300 @@ -21,7 +21,7 @@ static ngx_int_t ngx_stream_variable_ser ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_server_port(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); -static ngx_int_t ngx_stream_variable_bytes_sent(ngx_stream_session_t *s, +static ngx_int_t ngx_stream_variable_bytes(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); @@ -57,9 +57,12 @@ static ngx_stream_variable_t ngx_stream { ngx_string("server_port"), NULL, ngx_stream_variable_server_port, 0, 0, 0 }, - { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes_sent, + { ngx_string("bytes_sent"), NULL, ngx_stream_variable_bytes, 0, 0, 0 }, + { ngx_string("bytes_received"), NULL, ngx_stream_variable_bytes, + 1, 0, 0 }, + { ngx_string("connection"), NULL, ngx_stream_variable_connection, 0, 0, 0 }, @@ -461,7 +464,7 @@ ngx_stream_variable_server_port(ngx_stre static ngx_int_t -ngx_stream_variable_bytes_sent(ngx_stream_session_t *s, +ngx_stream_variable_bytes(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) { u_char *p; @@ -471,7 +474,13 @@ ngx_stream_variable_bytes_sent(ngx_strea return NGX_ERROR; } - v->len = ngx_sprintf(p, "%O", s->connection->sent) - p; + if (data == 1) { + v->len = ngx_sprintf(p, "%O", s->received) - p; + + } else { + v->len = ngx_sprintf(p, "%O", s->connection->sent) - p; + } + v->valid = 1; v->no_cacheable = 0; v->not_found = 0; From vl at nginx.com Fri Aug 26 12:34:58 2016 From: vl at nginx.com (Vladimir Homutov) Date: Fri, 26 Aug 2016 12:34:58 +0000 Subject: [nginx] Stream: the $session_time variable. Message-ID: details: http://hg.nginx.org/nginx/rev/164a0824ce20 branches: changeset: 6669:164a0824ce20 user: Vladimir Homutov date: Fri Aug 26 15:33:04 2016 +0300 description: Stream: the $session_time variable. The variable keeps time spent on processing the stream session. diffstat: src/stream/ngx_stream.h | 2 ++ src/stream/ngx_stream_handler.c | 5 +++++ src/stream/ngx_stream_variables.c | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 0 deletions(-) diffs (92 lines): diff -r 5e2821c2de46 -r 164a0824ce20 src/stream/ngx_stream.h --- a/src/stream/ngx_stream.h Fri Aug 26 15:33:02 2016 +0300 +++ b/src/stream/ngx_stream.h Fri Aug 26 15:33:04 2016 +0300 @@ -155,6 +155,8 @@ struct ngx_stream_session_s { ngx_connection_t *connection; off_t received; + time_t start_sec; + ngx_msec_t start_msec; ngx_log_handler_pt log_handler; diff -r 5e2821c2de46 -r 164a0824ce20 src/stream/ngx_stream_handler.c --- a/src/stream/ngx_stream_handler.c Fri Aug 26 15:33:02 2016 +0300 +++ b/src/stream/ngx_stream_handler.c Fri Aug 26 15:33:04 2016 +0300 @@ -28,6 +28,7 @@ ngx_stream_init_connection(ngx_connectio size_t len; ngx_int_t rc; ngx_uint_t i; + ngx_time_t *tp; struct sockaddr *sa; ngx_stream_port_t *port; struct sockaddr_in *sin; @@ -158,6 +159,10 @@ ngx_stream_init_connection(ngx_connectio return; } + tp = ngx_timeofday(); + s->start_sec = tp->sec; + s->start_msec = tp->msec; + if (cmcf->limit_conn_handler) { rc = cmcf->limit_conn_handler(s); diff -r 5e2821c2de46 -r 164a0824ce20 src/stream/ngx_stream_variables.c --- a/src/stream/ngx_stream_variables.c Fri Aug 26 15:33:02 2016 +0300 +++ b/src/stream/ngx_stream_variables.c Fri Aug 26 15:33:04 2016 +0300 @@ -23,6 +23,8 @@ static ngx_int_t ngx_stream_variable_ser ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_bytes(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_session_time(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); @@ -63,6 +65,9 @@ static ngx_stream_variable_t ngx_stream { ngx_string("bytes_received"), NULL, ngx_stream_variable_bytes, 1, 0, 0 }, + { ngx_string("session_time"), NULL, ngx_stream_variable_session_time, + 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + { ngx_string("connection"), NULL, ngx_stream_variable_connection, 0, 0, 0 }, @@ -491,6 +496,35 @@ ngx_stream_variable_bytes(ngx_stream_ses static ngx_int_t +ngx_stream_variable_session_time(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + u_char *p; + ngx_time_t *tp; + ngx_msec_int_t ms; + + p = ngx_pnalloc(s->connection->pool, NGX_TIME_T_LEN + 4); + if (p == NULL) { + return NGX_ERROR; + } + + tp = ngx_timeofday(); + + ms = (ngx_msec_int_t) + ((tp->sec - s->start_sec) * 1000 + (tp->msec - s->start_msec)); + ms = ngx_max(ms, 0); + + v->len = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t ngx_stream_variable_connection(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) { From vl at nginx.com Fri Aug 26 12:35:00 2016 From: vl at nginx.com (Vladimir Homutov) Date: Fri, 26 Aug 2016 12:35:00 +0000 Subject: [nginx] Stream: the $protocol variable. Message-ID: details: http://hg.nginx.org/nginx/rev/c6372a40c2a7 branches: changeset: 6670:c6372a40c2a7 user: Vladimir Homutov date: Fri Aug 26 15:33:07 2016 +0300 description: Stream: the $protocol variable. The variable keeps protocol used by the client, "TCP" or "UDP". diffstat: src/stream/ngx_stream_variables.c | 19 +++++++++++++++++++ 1 files changed, 19 insertions(+), 0 deletions(-) diffs (43 lines): diff -r 164a0824ce20 -r c6372a40c2a7 src/stream/ngx_stream_variables.c --- a/src/stream/ngx_stream_variables.c Fri Aug 26 15:33:04 2016 +0300 +++ b/src/stream/ngx_stream_variables.c Fri Aug 26 15:33:07 2016 +0300 @@ -40,6 +40,8 @@ static ngx_int_t ngx_stream_variable_tim ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_time_local(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_protocol(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); static ngx_stream_variable_t ngx_stream_core_variables[] = { @@ -89,6 +91,9 @@ static ngx_stream_variable_t ngx_stream { ngx_string("time_local"), NULL, ngx_stream_variable_time_local, 0, NGX_STREAM_VAR_NOCACHEABLE, 0 }, + { ngx_string("protocol"), NULL, + ngx_stream_variable_protocol, 0, 0, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -665,6 +670,20 @@ ngx_stream_variable_time_local(ngx_strea } +static ngx_int_t +ngx_stream_variable_protocol(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->len = 3; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) (s->connection->type == SOCK_DGRAM ? "UDP" : "TCP"); + + return NGX_OK; +} + + void * ngx_stream_map_find(ngx_stream_session_t *s, ngx_stream_map_t *map, ngx_str_t *match) From crasyangel at 163.com Sat Aug 27 10:08:28 2016 From: crasyangel at 163.com (baidu) Date: Sat, 27 Aug 2016 18:08:28 +0800 Subject: [nginx] internal location keepalive_requests issue In-Reply-To: References: Message-ID: location /hls { error_page 404 = @hls; keepalive_requests 1000; } location @hls { # Serve HLS fragments types { application/vnd.apple.mpegurl m3u8; video/mp2t ts; } root /tmp; add_header Cache-Control no-cache; keepalive_requests 1000; } keepalive_requests must be large enough in this two location meanwhile if set keepalive_requests to 0 or 1 in /hls, keepalive_requests would not work in @hls if (r->keepalive) { if (clcf->keepalive_timeout == 0) { r->keepalive = 0; } else if (r->connection->requests >= clcf->keepalive_requests) { r->keepalive = 0; } else if (r->headers_in.msie6 && r->method == NGX_HTTP_POST && (clcf->keepalive_disable & NGX_HTTP_KEEPALIVE_DISABLE_MSIE6)) { /* * MSIE may wait for some time if an response for * a POST request was sent over a keepalive connection */ r->keepalive = 0; } else if (r->headers_in.safari && (clcf->keepalive_disable & NGX_HTTP_KEEPALIVE_DISABLE_SAFARI)) { /* * Safari may send a POST request to a closed keepalive * connection and may stall for some time, see * https://bugs.webkit.org/show_bug.cgi?id=5760 */ r->keepalive = 0; } } Note r->keepalive only effect that Connection filed in response header and set keepalive timer when finalize request. Why place this code block in ngx_http_update_location_config? Would be better place it where set keepalive timer? And sometimes nginx would send "Connection: keep-alive", but close connection in 1.10.1 version, and this would be nothing seriously So why is it the expected behaviour? -------------- next part -------------- An HTML attachment was scrubbed... URL: From hongzhidao at gmail.com Tue Aug 30 10:00:45 2016 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Tue, 30 Aug 2016 18:00:45 +0800 Subject: nginx dso version Message-ID: Hi What's the best way manage the version with dynamic module? For example: ngx_http_same_module.so (1) ngx_http_same_module.so (2) ... Thanks. B.R. -------------- next part -------------- An HTML attachment was scrubbed... URL: From hongzhidao at gmail.com Tue Aug 30 10:33:36 2016 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Tue, 30 Aug 2016 18:33:36 +0800 Subject: nginx dso coredump Message-ID: Hi, guys I found a coredump file generated on production. (gdb) print ngx_http_abc_module $7 = {ctx_index = 18446744073709551615, index = 18446744073709551615, name = 0x0, spare0 = 0, spare1 = 0, version = 1010001, signature = 0x3520
, ctx = 0x204800, commands = 0x204840, type = 1347703880, init_master = 0, init_module = 0, init_process = 0, init_thread = 0, exit_thread = 0, exit_process = 0, exit_master = 0, spare_hook0 = 0, spare_hook1 = 0, spare_hook2 = 0, spare_hook3 = 0, spare_hook4 = 0, spare_hook5 = 0, spare_hook6 = 0, spare_hook7 = 0} The ngx_http_'abc'_module is a simple module written by ourself. It runed well in the past time, and I just changed the following structure defined in the module. typedef struct { ngx_flag_t valid; ... ngx_uint_t member1; # added ngx_uint_t member2; # added ... } ngx_http_abc_ctx_t; nginx.conf load_module modules/....; load_module modules/ngx_http_abc_module_3.so; # This module is in the last postion, the other modules seems right. And there is tiny detail. I generate so file named 'ngx_http_abc_module.so', then I copy as ngx_http_abc_module_3.so And here are short codes about this module. static ngx_int_t ngx_http_abc_handler(ngx_http_request_t *r) { ... ngx_http_abc_ctx_t *ctx; ngx_http_abc_loc_conf_t *vlcf; vlcf = ngx_http_get_module_loc_conf(r, ngx_http_abc_module); if (vlcf->enable == 0) { return NGX_DECLINED; } ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_abc_ctx_t)); if (ctx == NULL) { return NGX_ERROR; } ngx_http_set_ctx(r, ctx, ngx_http_abc_module); ? } config ngx_addon_name="ngx_http_abc_module" ngx_module_type=HTTP ngx_module_name=ngx_http_abc_module ngx_module_incs="$ngx_addon_dir" ngx_module_srcs="$ngx_addon_dir/ngx_http_abc_module.c" . auto/module It's sad that I can't regenerate coredump file now. By the way, It's so convinient that use dso instead of upgrading static module. Thanks so much. B.R. -------------- next part -------------- An HTML attachment was scrubbed... URL: From hongzhidao at gmail.com Tue Aug 30 10:54:45 2016 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Tue, 30 Aug 2016 18:54:45 +0800 Subject: nginx dso coredump In-Reply-To: References: Message-ID: Plus: kill -USR2 pid; sleep(2); kill -QUIT oldpid; 2016-08-30 18:33 GMT+08:00 ??? : > Hi, guys > > I found a coredump file generated on production. > > > (gdb) print ngx_http_abc_module > $7 = {ctx_index = 18446744073709551615, index = 18446744073709551615, name > = 0x0, spare0 = 0, spare1 = 0, version = 1010001, signature = 0x3520 >
, > ctx = 0x204800, commands = 0x204840, type = 1347703880, init_master = 0, > init_module = 0, init_process = 0, init_thread = 0, exit_thread = 0, > exit_process = 0, > exit_master = 0, spare_hook0 = 0, spare_hook1 = 0, spare_hook2 = 0, > spare_hook3 = 0, spare_hook4 = 0, spare_hook5 = 0, spare_hook6 = 0, > spare_hook7 = 0} > > > The ngx_http_'abc'_module is a simple module written by ourself. > It runed well in the past time, and I just changed the following structure > defined in the module. > > typedef struct { > > ngx_flag_t valid; > > ... > > ngx_uint_t member1; # added > > ngx_uint_t member2; # added > > ... > > } ngx_http_abc_ctx_t; > > > nginx.conf > > load_module modules/....; > load_module modules/ngx_http_abc_module_3.so; # This module is in the > last postion, the other modules seems right. > > And there is tiny detail. I generate so file named > 'ngx_http_abc_module.so', then I copy as ngx_http_abc_module_3.so > > And here are short codes about this module. > > static ngx_int_t > > ngx_http_abc_handler(ngx_http_request_t *r) > > { > > ... > > ngx_http_abc_ctx_t *ctx; > > ngx_http_abc_loc_conf_t *vlcf; > > vlcf = ngx_http_get_module_loc_conf(r, ngx_http_abc_module); > > if (vlcf->enable == 0) { > > return NGX_DECLINED; > > } > > ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_abc_ctx_t)); > > if (ctx == NULL) { > > return NGX_ERROR; > > } > > ngx_http_set_ctx(r, ctx, ngx_http_abc_module); > > ? > > } > > > config > > ngx_addon_name="ngx_http_abc_module" > > ngx_module_type=HTTP > > ngx_module_name=ngx_http_abc_module > > ngx_module_incs="$ngx_addon_dir" > > ngx_module_srcs="$ngx_addon_dir/ngx_http_abc_module.c" > > . auto/module > > > It's sad that I can't regenerate coredump file now. > > By the way, It's so convinient that use dso instead of upgrading static > module. > > Thanks so much. > > > B.R. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Tue Aug 30 11:22:24 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 30 Aug 2016 14:22:24 +0300 Subject: nginx dso coredump In-Reply-To: References: Message-ID: <20160830112223.GI1855@mdounin.ru> Hello! On Tue, Aug 30, 2016 at 06:33:36PM +0800, ??? wrote: [...] > I found a coredump file generated on production. [...] > nginx.conf > > load_module modules/....; > load_module modules/ngx_http_abc_module_3.so; # This module is in the > last postion, the other modules seems right. > > And there is tiny detail. I generate so file named > 'ngx_http_abc_module.so', then I copy as ngx_http_abc_module_3.so Note that when writing module *.so files care should be taken to not modify contents of files currently loaded. E.g., "make install" in nginx will first move an old file (if any) to *.so.old, and then copy the new file. If you happened to modify an *.so file currently loaded, segmentation fault is expected. Just using "cp" without moving an old file first is known to cause segmentation faults as it modifies contents of existing *.so files. -- Maxim Dounin http://nginx.org/ From hongzhidao at gmail.com Tue Aug 30 12:46:42 2016 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Tue, 30 Aug 2016 20:46:42 +0800 Subject: nginx dso coredump In-Reply-To: <20160830112223.GI1855@mdounin.ru> References: <20160830112223.GI1855@mdounin.ru> Message-ID: Thanks a lot for your reply. First, we want to manage the module versions, such as ngx_http_abc_module_1.so, ngx_http_abc_module_2.so. Maybe you can share a better way. Second: "Note that when writing module *.so files care should be taken to not modify contents of files currently loaded" -- I get, but we didn't. The above problem I described is: load_module modules/ngx_http_abc_module_2.so; # it runs well before upgrading Then we upgrade module named ngx_http_abc_module_3.so [ make install: generate new file ngx_http_abc_module.so; cp ngx_http_abc_module.so ngx_http_abc_module_3.so] Then change config load_module modules/ngx_http_abc_module_3.so; Finally we upgrade nginx: -USR2 && sleep && -QUIT old B.R.~ 2016-08-30 19:22 GMT+08:00 Maxim Dounin : > Hello! > > On Tue, Aug 30, 2016 at 06:33:36PM +0800, ??? wrote: > > > [...] > > > I found a coredump file generated on production. > > [...] > > > nginx.conf > > > > load_module modules/....; > > load_module modules/ngx_http_abc_module_3.so; # This module is in the > > last postion, the other modules seems right. > > > > And there is tiny detail. I generate so file named > > 'ngx_http_abc_module.so', then I copy as ngx_http_abc_module_3.so > > Note that when writing module *.so files care should be taken to > not modify contents of files currently loaded. E.g., "make > install" in nginx will first move an old file (if any) to > *.so.old, and then copy the new file. > > If you happened to modify an *.so file currently loaded, > segmentation fault is expected. Just using "cp" without moving an > old file first is known to cause segmentation faults as it > modifies contents of existing *.so files. > > -- > Maxim Dounin > http://nginx.org/ > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Tue Aug 30 13:05:05 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 30 Aug 2016 16:05:05 +0300 Subject: nginx dso coredump In-Reply-To: References: <20160830112223.GI1855@mdounin.ru> Message-ID: <20160830130505.GM1855@mdounin.ru> Hello! On Tue, Aug 30, 2016 at 08:46:42PM +0800, ??? wrote: > Thanks a lot for your reply. > > First, we want to manage the module versions, such as > ngx_http_abc_module_1.so, ngx_http_abc_module_2.so. > Maybe you can share a better way. > > Second: > "Note that when writing module *.so files care should be taken to > not modify contents of files currently loaded" -- I get, but we didn't. > > > The above problem I described is: > > load_module modules/ngx_http_abc_module_2.so; # it runs well before > upgrading > > > Then we upgrade module named ngx_http_abc_module_3.so > [ make install: generate new file ngx_http_abc_module.so; cp > ngx_http_abc_module.so ngx_http_abc_module_3.so] > > Then change config > > load_module modules/ngx_http_abc_module_3.so; > > Finally we upgrade nginx: -USR2 && sleep && -QUIT old As long as you use upgrade via USR2 signal this process should be fine. Note though, that if you'll try to reload a configuration instead of upgrade, you'll likely get a segmentation fault as well, since there will be multiple conflicting symbols for your module loaded at the same time. Overral I would recommend you to avoid using such distinct *.so names as it looks very fragile. If you want to store module version somewhere, consider just adding a symbol with appropriate information to the module itself. -- Maxim Dounin http://nginx.org/ From hongzhidao at gmail.com Tue Aug 30 15:25:26 2016 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Tue, 30 Aug 2016 23:25:26 +0800 Subject: nginx dso coredump In-Reply-To: <20160830130505.GM1855@mdounin.ru> References: <20160830112223.GI1855@mdounin.ru> <20160830130505.GM1855@mdounin.ru> Message-ID: Hello. So is it not allowed that we reload a configuration after change load_module directive? But it seems probably happened that others guys reload nginx, since they don't know whether load_module changes. I mean we should upgrade after change so files, but it's easy to get a segmentation fault if some other guy run a reload command at that time. B.R. 2016-08-30 21:05 GMT+08:00 Maxim Dounin : > Hello! > > On Tue, Aug 30, 2016 at 08:46:42PM +0800, ??? wrote: > > > Thanks a lot for your reply. > > > > First, we want to manage the module versions, such as > > ngx_http_abc_module_1.so, ngx_http_abc_module_2.so. > > Maybe you can share a better way. > > > > Second: > > "Note that when writing module *.so files care should be taken to > > not modify contents of files currently loaded" -- I get, but we didn't. > > > > > > The above problem I described is: > > > > load_module modules/ngx_http_abc_module_2.so; # it runs well before > > upgrading > > > > > > Then we upgrade module named ngx_http_abc_module_3.so > > [ make install: generate new file ngx_http_abc_module.so; cp > > ngx_http_abc_module.so ngx_http_abc_module_3.so] > > > > Then change config > > > > load_module modules/ngx_http_abc_module_3.so; > > > > Finally we upgrade nginx: -USR2 && sleep && -QUIT old > > As long as you use upgrade via USR2 signal this process should be > fine. Note though, that if you'll try to reload a configuration > instead of upgrade, you'll likely get a segmentation fault as > well, since there will be multiple conflicting symbols for your > module loaded at the same time. > > Overral I would recommend you to avoid using such distinct *.so > names as it looks very fragile. > > If you want to store module version somewhere, consider just > adding a symbol with appropriate information to the module itself. > > -- > Maxim Dounin > http://nginx.org/ > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mdounin at mdounin.ru Tue Aug 30 16:14:12 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 30 Aug 2016 19:14:12 +0300 Subject: nginx dso coredump In-Reply-To: References: <20160830112223.GI1855@mdounin.ru> <20160830130505.GM1855@mdounin.ru> Message-ID: <20160830161412.GO1855@mdounin.ru> Hello! On Tue, Aug 30, 2016 at 11:25:26PM +0800, ??? wrote: > So is it not allowed that we reload a configuration after change > load_module directive? Reloading configuration is allowed. What is not allowed is loading incompatible modules with conflicting symbols defined, and, as far as I understand, this what essentially happens in your case. You configuration has ngx_http_abc_module_1.so loaded with the ngx_http_abc_module symbol defined. And you load ngx_http_abc_module_2.so which defines the ngx_http_abc_module to something different and incompatible. > But it seems probably happened that others guys reload nginx, since they > don't know > whether load_module changes. > > I mean we should upgrade after change so files, but it's easy to get a > segmentation fault > if some other guy run a reload command at that time. What happens is a direct result of your manual intervention to naming and thus introducing multiple conflicting modules. And I don't think nginx can do much to prevent this from happening, at least without limiting of what modules can do. Most simple solution is to avoid manually renaming modules. -- Maxim Dounin http://nginx.org/ From hongzhidao at gmail.com Tue Aug 30 17:19:14 2016 From: hongzhidao at gmail.com (=?UTF-8?B?5rSq5b+X6YGT?=) Date: Wed, 31 Aug 2016 01:19:14 +0800 Subject: nginx dso coredump In-Reply-To: <20160830161412.GO1855@mdounin.ru> References: <20160830112223.GI1855@mdounin.ru> <20160830130505.GM1855@mdounin.ru> <20160830161412.GO1855@mdounin.ru> Message-ID: Hi. It?s do really a funny experience. Now I use in the following way. [ngx_http_hello_module] 1. development: ngx_http_hello_module.c => ngx_http_hello_module.so 2. production mv modules/ngx_http_hello_module.so modules/ngx_http_hello_module.so.2 upload ngx_http_hello_module.so to modules directory, and keep the same name -- configuration -- load_module module/ngx_http_hello_module.so; # It always use the same name. I can use lsof to check the so file used by nginx.pid or nginx.pid.oldbin. Is it the right way? Thanks again. B.R.~ -------------- next part -------------- An HTML attachment was scrubbed... URL: From igor at sysoev.ru Wed Aug 31 12:54:31 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Wed, 31 Aug 2016 12:54:31 +0000 Subject: [njs] encodeURI() and encodeURIComponent() functions. Message-ID: details: http://hg.nginx.org/njs/rev/d63ecb57f164 branches: changeset: 160:d63ecb57f164 user: Igor Sysoev date: Tue Aug 30 12:02:31 2016 +0300 description: encodeURI() and encodeURIComponent() functions. diffstat: njs/njs_builtin.c | 16 +++-- njs/njs_generator.c | 2 + njs/njs_lexer_keyword.c | 2 + njs/njs_parser.c | 2 + njs/njs_parser.h | 2 + njs/njs_string.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++ njs/njs_string.h | 4 + njs/njs_vm.h | 20 +++--- njs/test/njs_unit_test.c | 12 ++++ 9 files changed, 178 insertions(+), 15 deletions(-) diffs (309 lines): diff -r 7cce82b6b40b -r d63ecb57f164 njs/njs_builtin.c --- a/njs/njs_builtin.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_builtin.c Tue Aug 30 12:02:31 2016 +0300 @@ -82,12 +82,14 @@ njs_builtin_objects_create(njs_vm_t *vm) }; static const njs_object_init_t *function_init[] = { - &njs_eval_function_init, - NULL, - NULL, - NULL, - NULL, - NULL, + &njs_eval_function_init, /* eval */ + NULL, /* toString */ + NULL, /* isNaN */ + NULL, /* isFinite */ + NULL, /* parseInt */ + NULL, /* parseFloat */ + NULL, /* encodeURI */ + NULL, /* encodeURIComponent */ }; static const njs_function_init_t native_functions[] = { @@ -99,6 +101,8 @@ njs_builtin_objects_create(njs_vm_t *vm) { njs_number_parse_int, { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_INTEGER_ARG } }, { njs_number_parse_float, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_string_encode_uri, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_string_encode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } }, }; static const njs_object_prop_t null_proto_property = { diff -r 7cce82b6b40b -r d63ecb57f164 njs/njs_generator.c --- a/njs/njs_generator.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_generator.c Tue Aug 30 12:02:31 2016 +0300 @@ -300,6 +300,8 @@ njs_generator(njs_vm_t *vm, njs_parser_t case NJS_TOKEN_IS_FINITE: case NJS_TOKEN_PARSE_INT: case NJS_TOKEN_PARSE_FLOAT: + case NJS_TOKEN_ENCODE_URI: + case NJS_TOKEN_ENCODE_URI_COMPONENT: return njs_generate_builtin_object(vm, parser, node); case NJS_TOKEN_FUNCTION: diff -r 7cce82b6b40b -r d63ecb57f164 njs/njs_lexer_keyword.c --- a/njs/njs_lexer_keyword.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_lexer_keyword.c Tue Aug 30 12:02:31 2016 +0300 @@ -93,6 +93,8 @@ static const njs_keyword_t njs_keywords { nxt_string("isFinite"), NJS_TOKEN_IS_FINITE, 0 }, { nxt_string("parseInt"), NJS_TOKEN_PARSE_INT, 0 }, { nxt_string("parseFloat"), NJS_TOKEN_PARSE_FLOAT, 0 }, + { nxt_string("encodeURI"), NJS_TOKEN_ENCODE_URI, 0 }, + { nxt_string("encodeURIComponent"), NJS_TOKEN_ENCODE_URI_COMPONENT, 0 }, /* Reserved words. */ diff -r 7cce82b6b40b -r d63ecb57f164 njs/njs_parser.c --- a/njs/njs_parser.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_parser.c Tue Aug 30 12:02:31 2016 +0300 @@ -1671,6 +1671,8 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa case NJS_TOKEN_IS_FINITE: case NJS_TOKEN_PARSE_INT: case NJS_TOKEN_PARSE_FLOAT: + case NJS_TOKEN_ENCODE_URI: + case NJS_TOKEN_ENCODE_URI_COMPONENT: return njs_parser_builtin_function(vm, parser, node); default: diff -r 7cce82b6b40b -r d63ecb57f164 njs/njs_parser.h --- a/njs/njs_parser.h Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_parser.h Tue Aug 30 12:02:31 2016 +0300 @@ -181,6 +181,8 @@ typedef enum { NJS_TOKEN_IS_FINITE, NJS_TOKEN_PARSE_INT, NJS_TOKEN_PARSE_FLOAT, + NJS_TOKEN_ENCODE_URI, + NJS_TOKEN_ENCODE_URI_COMPONENT, NJS_TOKEN_RESERVED, } njs_token_t; diff -r 7cce82b6b40b -r d63ecb57f164 njs/njs_string.c --- a/njs/njs_string.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_string.c Tue Aug 30 12:02:31 2016 +0300 @@ -45,6 +45,8 @@ static njs_ret_t njs_string_match_multip njs_regexp_pattern_t *pattern); static njs_ret_t njs_string_split_part_add(njs_vm_t *vm, njs_array_t *array, u_char *start, size_t size, nxt_uint_t utf8); +static njs_ret_t njs_string_encode(njs_vm_t *vm, njs_value_t *value, + const uint32_t *escape); njs_ret_t @@ -2105,6 +2107,137 @@ const njs_object_init_t njs_string_prot }; +/* + * encodeURI(string) + */ + +njs_ret_t +njs_string_encode_uri(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + static const uint32_t escape[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x50000025, /* 0101 0000 0000 0000 0000 0000 0010 0101 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x78000000, /* 0111 1000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ + + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + if (nargs > 1) { + return njs_string_encode(vm, &args[1], escape); + } + + vm->retval = njs_string_void; + + return NXT_OK; +} + + +/* + * encodeURIComponent(string) + */ + +njs_ret_t +njs_string_encode_uri_component(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + static const uint32_t escape[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0xfc00987d, /* 1111 1100 0000 0000 1001 1000 0111 1101 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x78000001, /* 0111 1000 0000 0000 0000 0000 0000 0001 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0xb8000001, /* 1011 1000 0000 0000 0000 0000 0000 0001 */ + + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + if (nargs > 1) { + return njs_string_encode(vm, &args[1], escape); + } + + vm->retval = njs_string_void; + + return NXT_OK; +} + + +static njs_ret_t +njs_string_encode(njs_vm_t *vm, njs_value_t *value, const uint32_t *escape) +{ + u_char byte, *src, *dst; + size_t n, size; + njs_string_prop_t string; + static const u_char hex[16] = "0123456789ABCDEF"; + + nxt_prefetch(escape); + + (void) njs_string_prop(&string, value); + + src = string.start; + n = 0; + + for (size = string.size; size != 0; size--) { + byte = *src++; + + if ((escape[byte >> 5] & ((uint32_t) 1 << (byte & 0x1f))) != 0) { + n += 2; + } + } + + if (n == 0) { + /* GC: retain src. */ + vm->retval = *value; + return NXT_OK; + } + + size = string.size + n; + + dst = njs_string_alloc(vm, &vm->retval, size, size); + if (nxt_slow_path(dst == NULL)) { + return NXT_ERROR; + } + + size = string.size; + src = string.start; + + do { + byte = *src++; + + if ((escape[byte >> 5] & ((uint32_t) 1 << (byte & 0x1f))) != 0) { + *dst++ = '%'; + *dst++ = hex[byte >> 4]; + *dst++ = hex[byte & 0xf]; + + } else { + *dst++ = byte; + } + + size--; + + } while (size != 0); + + return NXT_OK; +} + + static nxt_int_t njs_values_hash_test(nxt_lvlhsh_query_t *lhq, void *data) { diff -r 7cce82b6b40b -r d63ecb57f164 njs/njs_string.h --- a/njs/njs_string.h Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_string.h Tue Aug 30 12:02:31 2016 +0300 @@ -104,6 +104,10 @@ nxt_noinline uint32_t njs_string_index(n njs_ret_t njs_primitive_value_to_string(njs_vm_t *vm, njs_value_t *dst, const njs_value_t *src); double njs_string_to_number(njs_value_t *value, nxt_bool_t exact); +njs_ret_t njs_string_encode_uri(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_string_encode_uri_component(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); njs_index_t njs_value_index(njs_vm_t *vm, njs_parser_t *parser, const njs_value_t *src); diff -r 7cce82b6b40b -r d63ecb57f164 njs/njs_vm.h --- a/njs/njs_vm.h Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/njs_vm.h Tue Aug 30 12:02:31 2016 +0300 @@ -668,7 +668,7 @@ typedef enum { enum njs_prototypes_e { - NJS_PROTOTYPE_OBJECT = 0, + NJS_PROTOTYPE_OBJECT = 0, NJS_PROTOTYPE_ARRAY, NJS_PROTOTYPE_BOOLEAN, NJS_PROTOTYPE_NUMBER, @@ -698,19 +698,21 @@ enum njs_constructor_e { enum njs_object_e { - NJS_OBJECT_MATH = 0, + NJS_OBJECT_MATH = 0, #define NJS_OBJECT_MAX (NJS_OBJECT_MATH + 1) }; enum njs_function_e { - NJS_FUNCTION_EVAL = 0, - NJS_FUNCTION_TO_STRING = 1, - NJS_FUNCTION_IS_NAN = 2, - NJS_FUNCTION_IS_FINITE = 3, - NJS_FUNCTION_PARSE_INT = 4, - NJS_FUNCTION_PARSE_FLOAT = 5, -#define NJS_FUNCTION_MAX (NJS_FUNCTION_PARSE_FLOAT + 1) + NJS_FUNCTION_EVAL = 0, + NJS_FUNCTION_TO_STRING, + NJS_FUNCTION_IS_NAN, + NJS_FUNCTION_IS_FINITE, + NJS_FUNCTION_PARSE_INT, + NJS_FUNCTION_PARSE_FLOAT, + NJS_FUNCTION_STRING_ENCODE_URI, + NJS_FUNCTION_STRING_ENCODE_URI_COMPONENT, +#define NJS_FUNCTION_MAX (NJS_FUNCTION_STRING_ENCODE_URI_COMPONENT + 1) }; diff -r 7cce82b6b40b -r d63ecb57f164 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 16 19:13:41 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Aug 30 12:02:31 2016 +0300 @@ -3297,6 +3297,18 @@ static njs_unit_test_t njs_test[] = { nxt_string("'0123456789'.split('').reverse().join('')"), nxt_string("9876543210") }, + { nxt_string("encodeURI()"), + nxt_string("undefined")}, + + { nxt_string("encodeURI('012???')"), + nxt_string("012%D0%B0%D0%B1%D0%B2")}, + + { nxt_string("encodeURI('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"), + nxt_string("~%7D%7C%7B%60_%5E%5D%5C%5B@?%3E=%3C;:/.-,+*)('&%25$#%22!%20")}, + + { nxt_string("encodeURIComponent('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"), + nxt_string("~%7D%7C%7B%60_%5E%5D%5C%5B%40%3F%3E%3D%3C%3B%3A%2F.-%2C%2B*)('%26%25%24%23%22!%20")}, + /* Functions. */ { nxt_string("return"), From igor at sysoev.ru Wed Aug 31 12:54:33 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Wed, 31 Aug 2016 12:54:33 +0000 Subject: [njs] decodeURI() and decodeURIComponent() functions. Message-ID: details: http://hg.nginx.org/njs/rev/323f00dc9879 branches: changeset: 161:323f00dc9879 user: Igor Sysoev date: Tue Aug 30 12:05:46 2016 +0300 description: decodeURI() and decodeURIComponent() functions. diffstat: njs/njs_builtin.c | 4 + njs/njs_generator.c | 2 + njs/njs_lexer_keyword.c | 2 + njs/njs_parser.c | 2 + njs/njs_parser.h | 10 +- njs/njs_string.c | 206 +++++++++++++++++++++++++++++++++++++++++++++++ njs/njs_string.h | 4 + njs/njs_vm.c | 1 + njs/njs_vm.h | 5 +- njs/test/njs_unit_test.c | 33 +++++++ 10 files changed, 264 insertions(+), 5 deletions(-) diffs (403 lines): diff -r d63ecb57f164 -r 323f00dc9879 njs/njs_builtin.c --- a/njs/njs_builtin.c Tue Aug 30 12:02:31 2016 +0300 +++ b/njs/njs_builtin.c Tue Aug 30 12:05:46 2016 +0300 @@ -90,6 +90,8 @@ njs_builtin_objects_create(njs_vm_t *vm) NULL, /* parseFloat */ NULL, /* encodeURI */ NULL, /* encodeURIComponent */ + NULL, /* decodeURI */ + NULL, /* decodeURIComponent */ }; static const njs_function_init_t native_functions[] = { @@ -103,6 +105,8 @@ njs_builtin_objects_create(njs_vm_t *vm) { njs_number_parse_float, { NJS_SKIP_ARG, NJS_STRING_ARG } }, { njs_string_encode_uri, { NJS_SKIP_ARG, NJS_STRING_ARG } }, { njs_string_encode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_string_decode_uri, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_string_decode_uri_component, { NJS_SKIP_ARG, NJS_STRING_ARG } }, }; static const njs_object_prop_t null_proto_property = { diff -r d63ecb57f164 -r 323f00dc9879 njs/njs_generator.c --- a/njs/njs_generator.c Tue Aug 30 12:02:31 2016 +0300 +++ b/njs/njs_generator.c Tue Aug 30 12:05:46 2016 +0300 @@ -302,6 +302,8 @@ njs_generator(njs_vm_t *vm, njs_parser_t case NJS_TOKEN_PARSE_FLOAT: case NJS_TOKEN_ENCODE_URI: case NJS_TOKEN_ENCODE_URI_COMPONENT: + case NJS_TOKEN_DECODE_URI: + case NJS_TOKEN_DECODE_URI_COMPONENT: return njs_generate_builtin_object(vm, parser, node); case NJS_TOKEN_FUNCTION: diff -r d63ecb57f164 -r 323f00dc9879 njs/njs_lexer_keyword.c --- a/njs/njs_lexer_keyword.c Tue Aug 30 12:02:31 2016 +0300 +++ b/njs/njs_lexer_keyword.c Tue Aug 30 12:05:46 2016 +0300 @@ -95,6 +95,8 @@ static const njs_keyword_t njs_keywords { nxt_string("parseFloat"), NJS_TOKEN_PARSE_FLOAT, 0 }, { nxt_string("encodeURI"), NJS_TOKEN_ENCODE_URI, 0 }, { nxt_string("encodeURIComponent"), NJS_TOKEN_ENCODE_URI_COMPONENT, 0 }, + { nxt_string("decodeURI"), NJS_TOKEN_DECODE_URI, 0 }, + { nxt_string("decodeURIComponent"), NJS_TOKEN_DECODE_URI_COMPONENT, 0 }, /* Reserved words. */ diff -r d63ecb57f164 -r 323f00dc9879 njs/njs_parser.c --- a/njs/njs_parser.c Tue Aug 30 12:02:31 2016 +0300 +++ b/njs/njs_parser.c Tue Aug 30 12:05:46 2016 +0300 @@ -1673,6 +1673,8 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa case NJS_TOKEN_PARSE_FLOAT: case NJS_TOKEN_ENCODE_URI: case NJS_TOKEN_ENCODE_URI_COMPONENT: + case NJS_TOKEN_DECODE_URI: + case NJS_TOKEN_DECODE_URI_COMPONENT: return njs_parser_builtin_function(vm, parser, node); default: diff -r d63ecb57f164 -r 323f00dc9879 njs/njs_parser.h --- a/njs/njs_parser.h Tue Aug 30 12:02:31 2016 +0300 +++ b/njs/njs_parser.h Tue Aug 30 12:05:46 2016 +0300 @@ -183,14 +183,16 @@ typedef enum { NJS_TOKEN_PARSE_FLOAT, NJS_TOKEN_ENCODE_URI, NJS_TOKEN_ENCODE_URI_COMPONENT, + NJS_TOKEN_DECODE_URI, + NJS_TOKEN_DECODE_URI_COMPONENT, NJS_TOKEN_RESERVED, } njs_token_t; typedef struct { - njs_token_t token:8; - njs_token_t prev_token:8; + njs_token_t token:16; + njs_token_t prev_token:16; uint8_t property; /* 1 bit */ uint32_t key_hash; @@ -222,8 +224,8 @@ typedef enum { typedef struct njs_parser_node_s njs_parser_node_t; struct njs_parser_node_s { - njs_token_t token:8; - njs_variable_node_state_t state:8; /* 2 bits */ + njs_token_t token:16; + njs_variable_node_state_t state:2; /* 2 bits */ uint8_t ctor:1; /* 1 bit */ uint8_t temporary; /* 1 bit */ uint32_t token_line; diff -r d63ecb57f164 -r 323f00dc9879 njs/njs_string.c --- a/njs/njs_string.c Tue Aug 30 12:02:31 2016 +0300 +++ b/njs/njs_string.c Tue Aug 30 12:05:46 2016 +0300 @@ -47,6 +47,8 @@ static njs_ret_t njs_string_split_part_a u_char *start, size_t size, nxt_uint_t utf8); static njs_ret_t njs_string_encode(njs_vm_t *vm, njs_value_t *value, const uint32_t *escape); +static njs_ret_t njs_string_decode(njs_vm_t *vm, njs_value_t *value, + const uint32_t *reserve); njs_ret_t @@ -2238,6 +2240,210 @@ njs_string_encode(njs_vm_t *vm, njs_valu } +/* + * decodeURI(string) + */ + +njs_ret_t +njs_string_decode_uri(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + static const uint32_t reserve[] = { + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0xac009858, /* 1010 1100 0000 0000 1001 1000 0101 1000 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x00000001, /* 0000 0000 0000 0000 0000 0000 0000 0001 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + }; + + if (nargs > 1) { + return njs_string_decode(vm, &args[1], reserve); + } + + vm->retval = njs_string_void; + + return NXT_OK; +} + + +/* + * decodeURIComponent(string) + */ + +njs_ret_t +njs_string_decode_uri_component(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused) +{ + static const uint32_t reserve[] = { + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + }; + + if (nargs > 1) { + return njs_string_decode(vm, &args[1], reserve); + } + + vm->retval = njs_string_void; + + return NXT_OK; +} + + +static njs_ret_t +njs_string_decode(njs_vm_t *vm, njs_value_t *value, const uint32_t *reserve) +{ + int8_t d0, d1; + u_char byte, *start, *src, *dst; + size_t n, size; + ssize_t length; + nxt_bool_t utf8; + njs_string_prop_t string; + + static const int8_t hex[256] + nxt_aligned(32) = + { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + + nxt_prefetch(&hex['0']); + nxt_prefetch(reserve); + + (void) njs_string_prop(&string, value); + + src = string.start; + n = 0; + + for (size = string.size; size != 0; size--) { + byte = *src++; + + if (byte == '%') { + if (size < 3) { + goto uri_error; + } + + d0 = hex[*src++]; + if (d0 < 0) { + goto uri_error; + } + + d1 = hex[*src++]; + if (d1 < 0) { + goto uri_error; + } + + byte = (d0 << 4) + d1; + + if ((reserve[byte >> 5] & ((uint32_t) 1 << (byte & 0x1f))) == 0) { + n += 2; + } + } + } + + if (n == 0) { + /* GC: retain src. */ + vm->retval = *value; + return NXT_OK; + } + + n = string.size - n; + + start = njs_string_alloc(vm, &vm->retval, n, n); + if (nxt_slow_path(start == NULL)) { + return NXT_ERROR; + } + + utf8 = 0; + dst = start; + size = string.size; + src = string.start; + + do { + byte = *src++; + + if (byte == '%') { + d0 = hex[*src++]; + d1 = hex[*src++]; + byte = (d0 << 4) + d1; + + utf8 |= (byte >= 0x80); + + if ((reserve[byte >> 5] & ((uint32_t) 1 << (byte & 0x1f))) != 0) { + size -= 2; + *dst++ = '%'; + *dst++ = src[-2]; + byte = src[-1]; + } + } + + *dst++ = byte; + + size--; + + } while (size != 0); + + if (utf8) { + length = nxt_utf8_length(start, n); + + if (length < 0) { + length = 0; + } + + if (vm->retval.short_string.size != NJS_STRING_LONG) { + vm->retval.short_string.length = length; + + } else { + vm->retval.data.u.string->length = length; + } + } + + return NXT_OK; + +uri_error: + + vm->exception = &njs_exception_uri_error; + + return NXT_ERROR; +} + + static nxt_int_t njs_values_hash_test(nxt_lvlhsh_query_t *lhq, void *data) { diff -r d63ecb57f164 -r 323f00dc9879 njs/njs_string.h --- a/njs/njs_string.h Tue Aug 30 12:02:31 2016 +0300 +++ b/njs/njs_string.h Tue Aug 30 12:05:46 2016 +0300 @@ -108,6 +108,10 @@ njs_ret_t njs_string_encode_uri(njs_vm_t nxt_uint_t nargs, njs_index_t unused); njs_ret_t njs_string_encode_uri_component(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_string_decode_uri(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +njs_ret_t njs_string_decode_uri_component(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); njs_index_t njs_value_index(njs_vm_t *vm, njs_parser_t *parser, const njs_value_t *src); diff -r d63ecb57f164 -r 323f00dc9879 njs/njs_vm.c --- a/njs/njs_vm.c Tue Aug 30 12:02:31 2016 +0300 +++ b/njs/njs_vm.c Tue Aug 30 12:05:46 2016 +0300 @@ -141,6 +141,7 @@ const njs_value_t njs_exception_syntax_ const njs_value_t njs_exception_reference_error = njs_string("ReferenceError"); const njs_value_t njs_exception_type_error = njs_string("TypeError"); const njs_value_t njs_exception_range_error = njs_string("RangeError"); +const njs_value_t njs_exception_uri_error = njs_string("URIError"); const njs_value_t njs_exception_memory_error = njs_string("MemoryError"); const njs_value_t njs_exception_internal_error = njs_string("InternalError"); diff -r d63ecb57f164 -r 323f00dc9879 njs/njs_vm.h --- a/njs/njs_vm.h Tue Aug 30 12:02:31 2016 +0300 +++ b/njs/njs_vm.h Tue Aug 30 12:05:46 2016 +0300 @@ -712,7 +712,9 @@ enum njs_function_e { NJS_FUNCTION_PARSE_FLOAT, NJS_FUNCTION_STRING_ENCODE_URI, NJS_FUNCTION_STRING_ENCODE_URI_COMPONENT, -#define NJS_FUNCTION_MAX (NJS_FUNCTION_STRING_ENCODE_URI_COMPONENT + 1) + NJS_FUNCTION_STRING_DECODE_URI, + NJS_FUNCTION_STRING_DECODE_URI_COMPONENT, +#define NJS_FUNCTION_MAX (NJS_FUNCTION_STRING_DECODE_URI_COMPONENT + 1) }; @@ -1005,6 +1007,7 @@ extern const njs_value_t njs_exception_ extern const njs_value_t njs_exception_reference_error; extern const njs_value_t njs_exception_type_error; extern const njs_value_t njs_exception_range_error; +extern const njs_value_t njs_exception_uri_error; extern const njs_value_t njs_exception_memory_error; extern const njs_value_t njs_exception_internal_error; diff -r d63ecb57f164 -r 323f00dc9879 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 30 12:02:31 2016 +0300 +++ b/njs/test/njs_unit_test.c Tue Aug 30 12:05:46 2016 +0300 @@ -3309,6 +3309,39 @@ static njs_unit_test_t njs_test[] = { nxt_string("encodeURIComponent('~}|{`_^]\\\\[@?>=<;:/.-,+*)(\\\'&%$#\"! ')"), nxt_string("~%7D%7C%7B%60_%5E%5D%5C%5B%40%3F%3E%3D%3C%3B%3A%2F.-%2C%2B*)('%26%25%24%23%22!%20")}, + { nxt_string("decodeURI()"), + nxt_string("undefined")}, + + { nxt_string("decodeURI('%QQ')"), + nxt_string("URIError")}, + + { nxt_string("decodeURI('%')"), + nxt_string("URIError")}, + + { nxt_string("decodeURI('%0')"), + nxt_string("URIError")}, + + { nxt_string("decodeURI('%00')"), + nxt_string("\0")}, + + { nxt_string("decodeURI('%3012%D0%B0%D0%B1%D0%B2')"), + nxt_string("012???")}, + + { nxt_string("decodeURI('%7e%7d%7c%7b%60%5f%5e%5d%5c%5b%40%3f%3e%3d%3c%3b%3a%2f%2e%2c%2b%2a%29%28%27%26%25%24%23%22%21%20')"), + nxt_string("~}|{`_^]\\[%40%3f>%3d<%3b%3a%2f.%2c%2b*)('%26%%24%23\"! ")}, + + { nxt_string("decodeURIComponent('%7e%7d%7c%7b%60%5f%5e%5d%5c%5b%40%3f%3e%3d%3c%3b%3a%2f%2e%2c%2b%2a%29%28%27%26%25%24%23%22%21%20')"), + nxt_string("~}|{`_^]\\[@?>=<;:/.,+*)('&%$#\"! ")}, + + { nxt_string("decodeURI('%41%42%43').length"), + nxt_string("3")}, + + { nxt_string("decodeURI('%D0%B0%D0%B1%D0%B2').length"), + nxt_string("3")}, + + { nxt_string("decodeURI('%80%81%82').length"), + nxt_string("3")}, + /* Functions. */ { nxt_string("return"), From igor at sysoev.ru Wed Aug 31 12:54:35 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Wed, 31 Aug 2016 12:54:35 +0000 Subject: [njs] C language features have been enabled. Message-ID: details: http://hg.nginx.org/njs/rev/47f4830c3d22 branches: changeset: 162:47f4830c3d22 user: Igor Sysoev date: Tue Aug 30 12:11:24 2016 +0300 description: C language features have been enabled. diffstat: nxt/auto/clang | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 86 insertions(+), 0 deletions(-) diffs (93 lines): diff -r 323f00dc9879 -r 47f4830c3d22 nxt/auto/clang --- a/nxt/auto/clang Tue Aug 30 12:05:46 2016 +0300 +++ b/nxt/auto/clang Tue Aug 30 12:11:24 2016 +0300 @@ -162,3 +162,89 @@ cat << END >> $NXT_MAKEFILE_CONF NXT_CC = ${CC} NXT_CFLAGS = ${CFLAGS} ${NXT_CFLAGS} END + + +# C language features. + +nxt_feature="GCC __builtin_expect()" +nxt_feature_name=NXT_HAVE_BUILTIN_EXPECT +nxt_feature_run=no +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="int main(int argc, char *const *argv) { + if ((__typeof__(argc == 0)) + __builtin_expect((argc == 0), 0)) + return 0; + return 1; + }" +. ${NXT_AUTO}feature + + +nxt_feature="GCC __builtin_unreachable()" +nxt_feature_name=NXT_HAVE_BUILTIN_UNREACHABLE +nxt_feature_run=no +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="int main() { + __builtin_unreachable(); + }" +. ${NXT_AUTO}feature + + +nxt_feature="GCC __builtin_prefetch()" +nxt_feature_name=NXT_HAVE_BUILTIN_PREFETCH +nxt_feature_run=no +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="int main() { + __builtin_prefetch(0); + }" +. ${NXT_AUTO}feature + + +nxt_feature="GCC __attribute__ visibility" +nxt_feature_name=NXT_HAVE_GCC_ATTRIBUTE_VISIBILITY +nxt_feature_run= +nxt_feature_path= +nxt_feature_libs= +nxt_feature_test="int n __attribute__ ((visibility(\"default\"))); + + int main() { + return 1; + }" +. ${NXT_AUTO}feature + + +nxt_feature="GCC __attribute__ aligned" +nxt_feature_name=NXT_HAVE_GCC_ATTRIBUTE_ALIGNED +nxt_feature_run= +nxt_feature_path= +nxt_feature_libs= +nxt_feature_test="int n __attribute__ ((aligned(64))); + + int main() { + return 1; + }" +. ${NXT_AUTO}feature + + +nxt_feature="GCC __attribute__ malloc" +nxt_feature_name=NXT_HAVE_GCC_ATTRIBUTE_MALLOC +nxt_feature_run= +nxt_feature_path= +nxt_feature_libs= +nxt_feature_test="#include + + void *f(void) __attribute__ ((__malloc__)); + + void *f(void) { + return malloc(1); + } + + int main() { + if (f() != NULL) { + return 1; + } + return 0; + }" +. ${NXT_AUTO}feature From igor at sysoev.ru Wed Aug 31 12:54:36 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Wed, 31 Aug 2016 12:54:36 +0000 Subject: [njs] An invalid value of Date object has been fixed. Message-ID: details: http://hg.nginx.org/njs/rev/c0aa3ecd2e83 branches: changeset: 163:c0aa3ecd2e83 user: Igor Sysoev date: Wed Aug 31 15:53:13 2016 +0300 description: An invalid value of Date object has been fixed. diffstat: njs/njs_date.c | 10 ++++++---- njs/test/njs_unit_test.c | 3 +++ 2 files changed, 9 insertions(+), 4 deletions(-) diffs (47 lines): diff -r 47f4830c3d22 -r c0aa3ecd2e83 njs/njs_date.c --- a/njs/njs_date.c Tue Aug 30 12:11:24 2016 +0300 +++ b/njs/njs_date.c Wed Aug 31 15:53:13 2016 +0300 @@ -81,8 +81,8 @@ njs_ret_t njs_date_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - double num; - int64_t time, values[8]; + double num, time; + int64_t values[8]; nxt_uint_t i, n; njs_date_t *date; struct tm tm; @@ -110,8 +110,8 @@ njs_date_constructor(njs_vm_t *vm, njs_v num = args[i].data.u.number; if (njs_is_nan(num)) { - nargs = 0; - break; + time = num; + goto done; } values[i] = num; @@ -138,6 +138,8 @@ njs_date_constructor(njs_vm_t *vm, njs_v } } + done: + date = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_date_t)); if (nxt_slow_path(date == NULL)) { return NXT_ERROR; diff -r 47f4830c3d22 -r c0aa3ecd2e83 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Aug 30 12:11:24 2016 +0300 +++ b/njs/test/njs_unit_test.c Wed Aug 31 15:53:13 2016 +0300 @@ -4465,6 +4465,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var o = Object.create(null); '__proto__' in o"), nxt_string("false") }, + { nxt_string("var d = new Date(''); d +' '+ d.getTime()"), + nxt_string("Invalid Date NaN") }, + { nxt_string("var d = new Date(1308895200000); d.getTime()"), nxt_string("1308895200000") }, From jason at codeassassin.com Wed Aug 31 13:38:20 2016 From: jason at codeassassin.com (Jason Stangroome) Date: Wed, 31 Aug 2016 23:38:20 +1000 Subject: [PATCH] Added the $upstream_connection variable Message-ID: Hello, I am using nginx primarily as a proxy and I am looking to improve the visibility and control over keepalive connections to upstreams. I have several patches I would like to submit for your consideration but I am relatively unfamiliar with the code base so I've started simple and I appreciate your feedback. I must say the code base has been very approachable to work with. To begin I am adding support for an $upstream_connection variable for use with the log_format directive. This is essentially the same as the $connection variable but applies to upstream connections instead of downstream. The intent of this variable is to help understand which requests are being serviced by the same upstream keepalive connection and which are using different connections. I think I have followed the Contributing Changes page at nginx.org. I've honoured the existing code formatting and my `hg export` output follows my signature. I have also executed the tests from the nginx-tests repository in a Ubuntu Trusty environment but I did not have many nginx modules included in my build. Regards, Jason -- # HG changeset patch # User Jason Stangroome # Date 1472649436 0 # Wed Aug 31 13:17:16 2016 +0000 # Node ID f06c8a934e3f3ceac2ff393a391234e225cbfcf1 # Parent c6372a40c2a731d8816160bf8f55a7a50050c2ac Added the $upstream_connection variable Allows the connection identifier of the upstream connection used to service a proxied request to be logged in the access.log to understand which requests are using which upstream keepalive connections. diff -r c6372a40c2a7 -r f06c8a934e3f src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_upstream.c Wed Aug 31 13:17:16 2016 +0000 @@ -161,6 +161,9 @@ static ngx_int_t ngx_http_upstream_response_length_variable( ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_upstream_connection_variable( + ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); + static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy); static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -395,6 +398,10 @@ ngx_http_upstream_response_length_variable, 1, NGX_HTTP_VAR_NOCACHEABLE, 0 }, + { ngx_string("upstream_connection"), NULL, + ngx_http_upstream_connection_variable, 0, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + #if (NGX_HTTP_CACHE) { ngx_string("upstream_cache_status"), NULL, @@ -1804,6 +1811,7 @@ if (u->state->connect_time == (ngx_msec_t) -1) { u->state->connect_time = ngx_current_msec - u->state->response_time; + u->state->connection_number = c->number; } if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) { @@ -5291,6 +5299,67 @@ } +static ngx_int_t +ngx_http_upstream_connection_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_uint_t i; + ngx_http_upstream_state_t *state; + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + if (r->upstream_states == NULL || r->upstream_states->nelts == 0) { + v->not_found = 1; + return NGX_OK; + } + + len = r->upstream_states->nelts * (NGX_ATOMIC_T_LEN + 2); + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + + v->data = p; + + i = 0; + state = r->upstream_states->elts; + + for ( ;; ) { + + p = ngx_sprintf(p, "%uA", state[i].connection_number); + + if (++i == r->upstream_states->nelts) { + break; + } + + if (state[i].peer) { + *p++ = ','; + *p++ = ' '; + + } else { + *p++ = ' '; + *p++ = ':'; + *p++ = ' '; + + if (++i == r->upstream_states->nelts) { + break; + } + + continue; + } + } + + v->len = p - v->data; + + return NGX_OK; +} + + ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) diff -r c6372a40c2a7 -r f06c8a934e3f src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_upstream.h Wed Aug 31 13:17:16 2016 +0000 @@ -66,6 +66,8 @@ off_t bytes_received; ngx_str_t *peer; + + ngx_atomic_uint_t connection_number; } ngx_http_upstream_state_t; From igor at sysoev.ru Wed Aug 31 16:02:57 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Wed, 31 Aug 2016 16:02:57 +0000 Subject: [njs] A fix in decodeURI() and decodeURIComponent() functions. Message-ID: details: http://hg.nginx.org/njs/rev/76f16f0ef6c5 branches: changeset: 164:76f16f0ef6c5 user: Igor Sysoev date: Wed Aug 31 17:51:54 2016 +0300 description: A fix in decodeURI() and decodeURIComponent() functions. diffstat: njs/njs_string.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (11 lines): diff -r c0aa3ecd2e83 -r 76f16f0ef6c5 njs/njs_string.c --- a/njs/njs_string.c Wed Aug 31 15:53:13 2016 +0300 +++ b/njs/njs_string.c Wed Aug 31 17:51:54 2016 +0300 @@ -2372,6 +2372,7 @@ njs_string_decode(njs_vm_t *vm, njs_valu byte = (d0 << 4) + d1; if ((reserve[byte >> 5] & ((uint32_t) 1 << (byte & 0x1f))) == 0) { + size -= 2; n += 2; } } From igor at sysoev.ru Wed Aug 31 16:19:35 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Wed, 31 Aug 2016 16:19:35 +0000 Subject: [njs] A fix in decodeURI() function. Message-ID: details: http://hg.nginx.org/njs/rev/584114a51b51 branches: changeset: 165:584114a51b51 user: Igor Sysoev date: Wed Aug 31 19:18:47 2016 +0300 description: A fix in decodeURI() function. diffstat: njs/njs_string.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) diffs (23 lines): diff -r 76f16f0ef6c5 -r 584114a51b51 njs/njs_string.c --- a/njs/njs_string.c Wed Aug 31 17:51:54 2016 +0300 +++ b/njs/njs_string.c Wed Aug 31 19:18:47 2016 +0300 @@ -2355,7 +2355,10 @@ njs_string_decode(njs_vm_t *vm, njs_valu byte = *src++; if (byte == '%') { - if (size < 3) { + + size -= 2; + + if (size == 0) { goto uri_error; } @@ -2372,7 +2375,6 @@ njs_string_decode(njs_vm_t *vm, njs_valu byte = (d0 << 4) + d1; if ((reserve[byte >> 5] & ((uint32_t) 1 << (byte & 0x1f))) == 0) { - size -= 2; n += 2; } } From igor at sysoev.ru Wed Aug 31 16:28:32 2016 From: igor at sysoev.ru (Igor Sysoev) Date: Wed, 31 Aug 2016 16:28:32 +0000 Subject: [njs] A fix in decodeURI() and decodeURIComponent() functions. Message-ID: details: http://hg.nginx.org/njs/rev/715b147cbfe0 branches: changeset: 166:715b147cbfe0 user: Igor Sysoev date: Wed Aug 31 19:28:08 2016 +0300 description: A fix in decodeURI() and decodeURIComponent() functions. diffstat: njs/njs_string.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diffs (23 lines): diff -r 584114a51b51 -r 715b147cbfe0 njs/njs_string.c --- a/njs/njs_string.c Wed Aug 31 19:18:47 2016 +0300 +++ b/njs/njs_string.c Wed Aug 31 19:28:08 2016 +0300 @@ -2317,8 +2317,8 @@ njs_string_decode(njs_vm_t *vm, njs_valu { int8_t d0, d1; u_char byte, *start, *src, *dst; - size_t n, size; - ssize_t length; + size_t n; + ssize_t size, length; nxt_bool_t utf8; njs_string_prop_t string; @@ -2358,7 +2358,7 @@ njs_string_decode(njs_vm_t *vm, njs_valu size -= 2; - if (size == 0) { + if (size <= 0) { goto uri_error; } From mdounin at mdounin.ru Wed Aug 31 16:50:39 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 31 Aug 2016 19:50:39 +0300 Subject: nginx dso coredump In-Reply-To: References: <20160830112223.GI1855@mdounin.ru> <20160830130505.GM1855@mdounin.ru> <20160830161412.GO1855@mdounin.ru> Message-ID: <20160831165039.GP1855@mdounin.ru> Hello! On Wed, Aug 31, 2016 at 01:19:14AM +0800, ??? wrote: > Hi. > > It?s do really a funny experience. Now I use in the following way. > > [ngx_http_hello_module] > > > 1. development: > > ngx_http_hello_module.c => ngx_http_hello_module.so > > > 2. production > > mv modules/ngx_http_hello_module.so modules/ngx_http_hello_module.so.2 > > upload ngx_http_hello_module.so to modules directory, and keep the same > name > > -- configuration -- > > load_module module/ngx_http_hello_module.so; # It always use the same > name. > > I can use lsof to check the so file used by nginx.pid or nginx.pid.oldbin. > > > Is it the right way? Thanks again. This should be fine, yes. -- Maxim Dounin http://nginx.org/ From josh at smyte.com Wed Aug 31 16:50:27 2016 From: josh at smyte.com (Josh Yudaken) Date: Wed, 31 Aug 2016 09:50:27 -0700 Subject: Add --without-http-expect option Message-ID: # HG changeset patch # User Josh Yudaken # Date 1472606412 25200 # Tue Aug 30 18:20:12 2016 -0700 # Node ID f81a22addc7fe1ca7486e932470756f4d73a3bb2 # Parent c6372a40c2a731d8816160bf8f55a7a50050c2ac Add --without-http-expect option Some load balancers (specifically Google Cloud) do not support the expect header. This adds an option to compile nginx without support. diff -r c6372a40c2a7 -r f81a22addc7f auto/options --- a/auto/options Fri Aug 26 15:33:07 2016 +0300 +++ b/auto/options Tue Aug 30 18:20:12 2016 -0700 @@ -57,6 +57,7 @@ HTTP_CACHE=YES HTTP_CHARSET=YES +HTTP_EXPECT=YES HTTP_GZIP=YES HTTP_SSL=NO HTTP_V2=NO @@ -237,6 +238,7 @@ --with-http_slice_module) HTTP_SLICE=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; + --without-http_expect) HTTP_EXPECT=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; --without-http_ssi_module) HTTP_SSI=NO ;; --without-http_userid_module) HTTP_USERID=NO ;; diff -r c6372a40c2a7 -r f81a22addc7f src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_core_module.c Tue Aug 30 18:20:12 2016 -0700 @@ -961,7 +961,9 @@ "client intended to send too large body: %O bytes", r->headers_in.content_length_n); +#if (NGX_HTTP_EXPECT) r->expect_tested = 1; +#endif (void) ngx_http_discard_request_body(r); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE); return NGX_OK; @@ -2539,7 +2541,9 @@ sr->internal = 1; sr->discard_body = r->discard_body; +#if (NGX_HTTP_EXPECT) sr->expect_tested = 1; +#endif sr->main_filter_need_in_memory = r->main_filter_need_in_memory; sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; diff -r c6372a40c2a7 -r f81a22addc7f src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_request.c Tue Aug 30 18:20:12 2016 -0700 @@ -129,9 +129,11 @@ offsetof(ngx_http_headers_in_t, transfer_encoding), ngx_http_process_header_line }, +#if (NGX_HTTP_EXPECT) { ngx_string("Expect"), offsetof(ngx_http_headers_in_t, expect), ngx_http_process_unique_header_line }, +#endif { ngx_string("Upgrade"), offsetof(ngx_http_headers_in_t, upgrade), diff -r c6372a40c2a7 -r f81a22addc7f src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_request.h Tue Aug 30 18:20:12 2016 -0700 @@ -190,7 +190,9 @@ ngx_table_elt_t *if_range; ngx_table_elt_t *transfer_encoding; +#if (NGX_HTTP_EXPECT) ngx_table_elt_t *expect; +#endif ngx_table_elt_t *upgrade; #if (NGX_HTTP_GZIP) @@ -525,7 +527,9 @@ unsigned request_complete:1; unsigned request_output:1; unsigned header_sent:1; +#if (NGX_HTTP_EXPECT) unsigned expect_tested:1; +#endif unsigned root_tested:1; unsigned done:1; unsigned logged:1; diff -r c6372a40c2a7 -r f81a22addc7f src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_request_body.c Tue Aug 30 18:20:12 2016 -0700 @@ -16,7 +16,9 @@ static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b); +#if (NGX_HTTP_EXPECT) static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r); +#endif static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in); @@ -53,10 +55,12 @@ } #endif +#if (NGX_HTTP_EXPECT) if (ngx_http_test_expect(r) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } +#endif rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { @@ -525,9 +529,11 @@ } #endif +#if (NGX_HTTP_EXPECT) if (ngx_http_test_expect(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } +#endif rev = r->connection->read; @@ -797,6 +803,7 @@ } +#if (NGX_HTTP_EXPECT) static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r) { @@ -837,6 +844,7 @@ return NGX_ERROR; } +#endif static ngx_int_t diff -r c6372a40c2a7 -r f81a22addc7f src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_special_response.c Tue Aug 30 18:20:12 2016 -0700 @@ -428,7 +428,9 @@ } } +#if (NGX_HTTP_EXPECT) r->expect_tested = 1; +#endif if (ngx_http_discard_request_body(r) != NGX_OK) { r->keepalive = 0; @@ -551,9 +553,11 @@ overwrite = err_page->overwrite; +#if (NGX_HTTP_EXPECT) if (overwrite && overwrite != NGX_HTTP_OK) { r->expect_tested = 1; } +#endif if (overwrite >= 0) { r->err_status = overwrite; From josh at smyte.com Wed Aug 31 17:08:44 2016 From: josh at smyte.com (Josh Yudaken) Date: Wed, 31 Aug 2016 10:08:44 -0700 Subject: [PATCH] Add --without-http-expect option Message-ID: # HG changeset patch # User Josh Yudaken # Date 1472606412 25200 # Tue Aug 30 18:20:12 2016 -0700 # Node ID f81a22addc7fe1ca7486e932470756f4d73a3bb2 # Parent c6372a40c2a731d8816160bf8f55a7a50050c2ac Add --without-http-expect option Some load balancers (specifically Google Cloud) do not support the expect header. This adds an option to compile nginx without support. diff -r c6372a40c2a7 -r f81a22addc7f auto/options --- a/auto/options Fri Aug 26 15:33:07 2016 +0300 +++ b/auto/options Tue Aug 30 18:20:12 2016 -0700 @@ -57,6 +57,7 @@ HTTP_CACHE=YES HTTP_CHARSET=YES +HTTP_EXPECT=YES HTTP_GZIP=YES HTTP_SSL=NO HTTP_V2=NO @@ -237,6 +238,7 @@ --with-http_slice_module) HTTP_SLICE=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; + --without-http_expect) HTTP_EXPECT=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; --without-http_ssi_module) HTTP_SSI=NO ;; --without-http_userid_module) HTTP_USERID=NO ;; diff -r c6372a40c2a7 -r f81a22addc7f src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_core_module.c Tue Aug 30 18:20:12 2016 -0700 @@ -961,7 +961,9 @@ "client intended to send too large body: %O bytes", r->headers_in.content_length_n); +#if (NGX_HTTP_EXPECT) r->expect_tested = 1; +#endif (void) ngx_http_discard_request_body(r); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE); return NGX_OK; @@ -2539,7 +2541,9 @@ sr->internal = 1; sr->discard_body = r->discard_body; +#if (NGX_HTTP_EXPECT) sr->expect_tested = 1; +#endif sr->main_filter_need_in_memory = r->main_filter_need_in_memory; sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; diff -r c6372a40c2a7 -r f81a22addc7f src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_request.c Tue Aug 30 18:20:12 2016 -0700 @@ -129,9 +129,11 @@ offsetof(ngx_http_headers_in_t, transfer_encoding), ngx_http_process_header_line }, +#if (NGX_HTTP_EXPECT) { ngx_string("Expect"), offsetof(ngx_http_headers_in_t, expect), ngx_http_process_unique_header_line }, +#endif { ngx_string("Upgrade"), offsetof(ngx_http_headers_in_t, upgrade), diff -r c6372a40c2a7 -r f81a22addc7f src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_request.h Tue Aug 30 18:20:12 2016 -0700 @@ -190,7 +190,9 @@ ngx_table_elt_t *if_range; ngx_table_elt_t *transfer_encoding; +#if (NGX_HTTP_EXPECT) ngx_table_elt_t *expect; +#endif ngx_table_elt_t *upgrade; #if (NGX_HTTP_GZIP) @@ -525,7 +527,9 @@ unsigned request_complete:1; unsigned request_output:1; unsigned header_sent:1; +#if (NGX_HTTP_EXPECT) unsigned expect_tested:1; +#endif unsigned root_tested:1; unsigned done:1; unsigned logged:1; diff -r c6372a40c2a7 -r f81a22addc7f src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_request_body.c Tue Aug 30 18:20:12 2016 -0700 @@ -16,7 +16,9 @@ static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r); static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b); +#if (NGX_HTTP_EXPECT) static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r); +#endif static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in); @@ -53,10 +55,12 @@ } #endif +#if (NGX_HTTP_EXPECT) if (ngx_http_test_expect(r) != NGX_OK) { rc = NGX_HTTP_INTERNAL_SERVER_ERROR; goto done; } +#endif rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t)); if (rb == NULL) { @@ -525,9 +529,11 @@ } #endif +#if (NGX_HTTP_EXPECT) if (ngx_http_test_expect(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } +#endif rev = r->connection->read; @@ -797,6 +803,7 @@ } +#if (NGX_HTTP_EXPECT) static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r) { @@ -837,6 +844,7 @@ return NGX_ERROR; } +#endif static ngx_int_t diff -r c6372a40c2a7 -r f81a22addc7f src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c Fri Aug 26 15:33:07 2016 +0300 +++ b/src/http/ngx_http_special_response.c Tue Aug 30 18:20:12 2016 -0700 @@ -428,7 +428,9 @@ } } +#if (NGX_HTTP_EXPECT) r->expect_tested = 1; +#endif if (ngx_http_discard_request_body(r) != NGX_OK) { r->keepalive = 0; @@ -551,9 +553,11 @@ overwrite = err_page->overwrite; +#if (NGX_HTTP_EXPECT) if (overwrite && overwrite != NGX_HTTP_OK) { r->expect_tested = 1; } +#endif if (overwrite >= 0) { r->err_status = overwrite; From mdounin at mdounin.ru Wed Aug 31 17:38:46 2016 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 31 Aug 2016 20:38:46 +0300 Subject: [PATCH] Add --without-http-expect option In-Reply-To: References: Message-ID: <20160831173846.GR1855@mdounin.ru> Hello! On Wed, Aug 31, 2016 at 10:08:44AM -0700, Josh Yudaken wrote: > # HG changeset patch > # User Josh Yudaken > # Date 1472606412 25200 > # Tue Aug 30 18:20:12 2016 -0700 > # Node ID f81a22addc7fe1ca7486e932470756f4d73a3bb2 > # Parent c6372a40c2a731d8816160bf8f55a7a50050c2ac > Add --without-http-expect option > > Some load balancers (specifically Google Cloud) do not support the expect > header. This adds an option to compile nginx without support. It is not clear why you are trying to add this as compile-time option. The Expect header is defined by the HTTP standard, and compiling nginx without appropriate support looks clearly wrong. If Google Cloud fails to properly balance HTTP and needs special workarounds on nginx side, you may consider adding this as a run-time option instead, similar to the "chunked_transfer_encoding" directive, see http://nginx.org/r/chunked_transfer_encoding. Or, better yet, report the bug to Google. It should be more or less trivial for them to fix this by just removing the Expect header from forwarded requests. -- Maxim Dounin http://nginx.org/ From josh at smyte.com Wed Aug 31 17:52:43 2016 From: josh at smyte.com (Josh Yudaken) Date: Wed, 31 Aug 2016 10:52:43 -0700 Subject: [PATCH] Add --without-http-expect option In-Reply-To: <20160831173846.GR1855@mdounin.ru> References: <20160831173846.GR1855@mdounin.ru> Message-ID: Hi, I wasn't sure of any other examples of it breaking the HTTP standard, so figured a compile time option was safer. Unfortunately bugging Google any more than we already do probably won't get the problem solved, and the standard "100 Continue" behavior causes 502 errors for our end users. For reference here is the issue on the google side: https://code.google.com/p/google-compute-engine/issues/detail?id=298 If you still deem it useful I can update this to use an "expect_continue"? option instead. - josh On Wed, Aug 31, 2016 at 10:38 AM, Maxim Dounin wrote: > Hello! > > On Wed, Aug 31, 2016 at 10:08:44AM -0700, Josh Yudaken wrote: > >> # HG changeset patch >> # User Josh Yudaken >> # Date 1472606412 25200 >> # Tue Aug 30 18:20:12 2016 -0700 >> # Node ID f81a22addc7fe1ca7486e932470756f4d73a3bb2 >> # Parent c6372a40c2a731d8816160bf8f55a7a50050c2ac >> Add --without-http-expect option >> >> Some load balancers (specifically Google Cloud) do not support the expect >> header. This adds an option to compile nginx without support. > > It is not clear why you are trying to add this as compile-time > option. The Expect header is defined by the HTTP standard, and > compiling nginx without appropriate support looks clearly wrong. > > If Google Cloud fails to properly balance HTTP and needs special > workarounds on nginx side, you may consider adding this as a > run-time option instead, similar to the > "chunked_transfer_encoding" directive, see > http://nginx.org/r/chunked_transfer_encoding. > > Or, better yet, report the bug to Google. It should be more or > less trivial for them to fix this by just removing the Expect > header from forwarded requests. > > -- > Maxim Dounin > http://nginx.org/ > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel From piotrsikora at google.com Wed Aug 31 22:24:19 2016 From: piotrsikora at google.com (Piotr Sikora) Date: Wed, 31 Aug 2016 15:24:19 -0700 Subject: [PATCH] SSL: fix order of checks during SSL certificate verification In-Reply-To: <20160821140211.GH24741@mdounin.ru> References: <20160804035352.GY57459@mdounin.ru> <20160818003702.GE24741@mdounin.ru> <20160821140211.GH24741@mdounin.ru> Message-ID: Hey Maxim, > At this point nginx just uses the interface provided by the > OpenSSL library, exactly as documented. The fact that the > interface is flawed (and documented to be flawed to make sure > people will use it properly) has nothing to do with nginx use of > it. And yet, NGINX doesn't use it properly. > Your patches assume that there are no conflicts between nginx > error codes (NGX_OK, NGX_DECLINED) and SSL_get_verify_result() > error codes. While this is currently true, this is not something > I would rely on, even assuming OpenSSL only. You didn't like the previous approach, when logging was done in ngx_event_openssl.c (because of the use of "client" and "upstream"), and you don't like this approach, when logging is done outside of ngx_event_openssl.c (since the error code must be passed back to the caller), which is actually one of the solutions you suggested. Could you tell me what would be acceptable approach, then? For the record, I don't understand why using "client" in ngx_ssl_verify_client() and "upstream" in ngx_ssl_verify_host() is a problem in the first place. Best regards, Piotr Sikora