From arut at nginx.com Thu Nov 1 12:30:47 2018 From: arut at nginx.com (Roman Arutyunyan) Date: Thu, 1 Nov 2018 15:30:47 +0300 Subject: cache: move open to thread pool In-Reply-To: <20181004093226.GD62311@Romans-MacBook-Air.local> References: <20180808181653.GX56558@mdounin.ru> <20180810113946.GG56558@mdounin.ru> <20180903160903.GI56558@mdounin.ru> <20180913181023.GW56558@mdounin.ru> <20181004093226.GD62311@Romans-MacBook-Air.local> Message-ID: <20181101123047.GG86326@Romans-MacBook-Air.local> Hi, On Thu, Oct 04, 2018 at 12:32:26PM +0300, Roman Arutyunyan wrote: > Hi, > > On Thu, Sep 13, 2018 at 09:10:23PM +0300, Maxim Dounin wrote: > > Hello! > > > > On Tue, Sep 04, 2018 at 04:58:05PM -0700, Ka-Hing Cheung via nginx-devel wrote: > > > > > On Mon, Sep 3, 2018 at 9:09 AM, Maxim Dounin wrote: > > [..] > > Here's another approach to thread open. This time it's 4 patches: > > - #1 a small open file cache refactoring > - #2 thread open in open file cache > - #3 thread open in http static module > - #4 thread open in http file cache The next iteration of the work. Only 3 patches this time. -- Roman Arutyunyan -------------- next part -------------- # HG changeset patch # User Roman Arutyunyan # Date 1540900849 -10800 # Tue Oct 30 15:00:49 2018 +0300 # Node ID 77f8ae0aabcf7246875f3db53c4c3b3f9f0dc9cc # Parent 874d47ac871a4b62fbe0ff5d469a8ad7bc5a4160 Threaded open support in open file cache. diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -17,6 +17,7 @@ struct ngx_file_s { ngx_fd_t fd; ngx_str_t name; ngx_file_info_t info; + ngx_err_t err; off_t offset; off_t sys_offset; diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -22,6 +22,8 @@ static void ngx_open_file_cache_cleanup(void *data); +static ngx_int_t ngx_open_uncached_file(ngx_str_t *name, + ngx_open_file_info_t *of, ngx_pool_t *pool); #if (NGX_HAVE_OPENAT) static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log); @@ -147,54 +149,15 @@ ngx_open_cached_file(ngx_open_file_cache time_t now; uint32_t hash; ngx_int_t rc; - ngx_file_info_t fi; ngx_pool_cleanup_t *cln; ngx_cached_open_file_t *file; - ngx_pool_cleanup_file_t *clnf; ngx_open_file_cache_cleanup_t *ofcln; of->fd = NGX_INVALID_FILE; of->err = 0; if (cache == NULL) { - - if (of->test_only) { - - if (ngx_file_info_wrapper(name, of, &fi, pool->log) - == NGX_FILE_ERROR) - { - return NGX_ERROR; - } - - of->uniq = ngx_file_uniq(&fi); - of->mtime = ngx_file_mtime(&fi); - of->size = ngx_file_size(&fi); - of->fs_size = ngx_file_fs_size(&fi); - of->is_dir = ngx_is_dir(&fi); - of->is_file = ngx_is_file(&fi); - of->is_link = ngx_is_link(&fi); - of->is_exec = ngx_is_exec(&fi); - - return NGX_OK; - } - - cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); - if (cln == NULL) { - return NGX_ERROR; - } - - rc = ngx_open_and_stat_file(name, of, pool->log); - - if (rc == NGX_OK && !of->is_dir) { - cln->handler = ngx_pool_cleanup_file; - clnf = cln->data; - - clnf->fd = of->fd; - clnf->name = name->data; - clnf->log = pool->log; - } - - return rc; + return ngx_open_uncached_file(name, of, pool); } cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t)); @@ -486,6 +449,163 @@ failed: } +static ngx_int_t +ngx_open_uncached_file(ngx_str_t *name, ngx_open_file_info_t *of, + ngx_pool_t *pool) +{ + ngx_fd_t fd; + ngx_int_t mode, create, access; + ngx_file_info_t fi; + ngx_pool_cleanup_t *cln; + ngx_pool_cleanup_file_t *clnf; + + if (of->test_only || of->test_dir) { + + if (ngx_file_info_wrapper(name, of, &fi, pool->log) == NGX_FILE_ERROR) { + return NGX_ERROR; + } + + if (of->test_only || ngx_is_dir(&fi)) { + goto done; + } + } + + if (!of->log) { + + /* + * Use non-blocking open() not to hang on FIFO files, etc. + * This flag has no effect on a regular files. + */ + + mode = NGX_FILE_RDONLY|NGX_FILE_NONBLOCK; + create = NGX_FILE_OPEN; + access = 0; + + } else { + mode = NGX_FILE_APPEND; + create = NGX_FILE_CREATE_OR_OPEN; + access = NGX_FILE_DEFAULT_ACCESS; + } + +#if (NGX_THREADS) + + if (of->thread_handler + && of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) + { + ngx_int_t rc; + ngx_file_t file; + + ngx_memzero(&file, sizeof(ngx_file_t)); + + file.log = pool->log; + file.fd = NGX_INVALID_FILE; + file.thread_handler = of->thread_handler; + file.thread_ctx = of->thread_ctx; + file.thread_task = of->thread_task; + + rc = ngx_thread_open(&file, name->data, mode, create, access, pool); + + if (rc == NGX_AGAIN) { + of->thread_task = file.thread_task; + return NGX_AGAIN; + } + + if (rc != NGX_OK) { + of->err = file.err; + of->failed = ngx_open_file_n; + return NGX_ERROR; + } + + fd = file.fd; + + } else { + fd = ngx_open_file_wrapper(name, of, mode, create, access, pool->log); + if (fd == NGX_INVALID_FILE) { + return NGX_ERROR; + } + } + +#else + fd = ngx_open_file_wrapper(name, of, mode, create, access, pool->log); + if (fd == NGX_INVALID_FILE) { + return NGX_ERROR; + } +#endif + + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, pool->log, ngx_errno, + ngx_fd_info_n " \"%V\" failed", name); + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, + ngx_close_file_n " \"%V\" failed", name); + } + + return NGX_ERROR; + } + + if (ngx_is_dir(&fi)) { + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, + ngx_close_file_n " \"%V\" failed", name); + } + + } else { + of->fd = fd; + + if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) { + if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, + ngx_read_ahead_n " \"%V\" failed", name); + } + } + + if (of->directio <= ngx_file_size(&fi)) { + if (ngx_directio_on(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, + ngx_directio_on_n " \"%V\" failed", name); + + } else { + of->is_directio = 1; + } + } + } + +done: + + of->uniq = ngx_file_uniq(&fi); + of->mtime = ngx_file_mtime(&fi); + of->size = ngx_file_size(&fi); + of->fs_size = ngx_file_fs_size(&fi); + of->is_dir = ngx_is_dir(&fi); + of->is_file = ngx_is_file(&fi); + of->is_link = ngx_is_link(&fi); + of->is_exec = ngx_is_exec(&fi); + + if (of->fd != NGX_INVALID_FILE) { + cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t)); + + if (cln == NULL) { + if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", name->data); + } + + return NGX_ERROR; + } + + cln->handler = ngx_pool_cleanup_file; + clnf = cln->data; + + clnf->fd = of->fd; + clnf->name = name->data; + clnf->log = pool->log; + } + + return NGX_OK; +} + + #if (NGX_HAVE_OPENAT) static ngx_fd_t diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -32,6 +32,13 @@ typedef struct { ngx_uint_t min_uses; +#if (NGX_THREADS || NGX_COMPAT) + ngx_int_t (*thread_handler)(ngx_thread_task_t *task, + ngx_file_t *file); + void *thread_ctx; + ngx_thread_task_t *thread_task; +#endif + #if (NGX_HAVE_OPENAT) size_t disable_symlinks_from; unsigned disable_symlinks:2; diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -11,6 +11,7 @@ #if (NGX_THREADS) #include +static void ngx_thread_open_handler(void *data, ngx_log_t *log); static void ngx_thread_read_handler(void *data, ngx_log_t *log); static void ngx_thread_write_chain_to_file_handler(void *data, ngx_log_t *log); #endif @@ -77,20 +78,112 @@ ngx_read_file(ngx_file_t *file, u_char * #if (NGX_THREADS) +typedef enum { + NGX_THREAD_FILE_OPEN = 1, + NGX_THREAD_FILE_READ, + NGX_THREAD_FILE_WRITE +} ngx_thread_file_op_e; + + typedef struct { ngx_fd_t fd; - ngx_uint_t write; /* unsigned write:1; */ + u_char *name; + ngx_uint_t op; /* ngx_thread_file_op_e */ u_char *buf; size_t size; ngx_chain_t *chain; off_t offset; + ngx_int_t mode; + ngx_int_t create; + ngx_int_t access; + size_t nbytes; ngx_err_t err; } ngx_thread_file_ctx_t; +ngx_int_t +ngx_thread_open(ngx_file_t *file, u_char *name, ngx_int_t mode, + ngx_int_t create, ngx_int_t access, ngx_pool_t *pool) +{ + ngx_thread_task_t *task; + ngx_thread_file_ctx_t *ctx; + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0, + "thread open: \"%s\"", name); + + task = file->thread_task; + + if (task == NULL) { + task = ngx_thread_task_alloc(pool, sizeof(ngx_thread_file_ctx_t)); + if (task == NULL) { + return NGX_ERROR; + } + + file->thread_task = task; + } + + ctx = task->ctx; + + if (task->event.complete) { + task->event.complete = 0; + + if (ctx->op != NGX_THREAD_FILE_OPEN) { + ngx_log_error(NGX_LOG_ALERT, file->log, 0, + "invalid thread operation, open expected"); + return NGX_ERROR; + } + + if (ctx->err) { + file->err = ctx->err; + return NGX_ERROR; + } + + file->fd = ctx->fd; + + return NGX_OK; + } + + task->handler = ngx_thread_open_handler; + + ctx->op = NGX_THREAD_FILE_OPEN; + + ctx->name = name; + ctx->mode = mode; + ctx->create = create; + ctx->access = access; + + if (file->thread_handler(task, file) != NGX_OK) { + return NGX_ERROR; + } + + return NGX_AGAIN; +} + + +static void +ngx_thread_open_handler(void *data, ngx_log_t *log) +{ + ngx_thread_file_ctx_t *ctx = data; + + ngx_fd_t fd; + + ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, "thread open handler"); + + fd = ngx_open_file(ctx->name, ctx->mode, ctx->create, ctx->access); + + if (fd == NGX_INVALID_FILE) { + ctx->err = ngx_errno; + + } else { + ctx->fd = fd; + ctx->err = 0; + } +} + + ssize_t ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool) @@ -118,9 +211,9 @@ ngx_thread_read(ngx_file_t *file, u_char if (task->event.complete) { task->event.complete = 0; - if (ctx->write) { + if (ctx->op != NGX_THREAD_FILE_READ) { ngx_log_error(NGX_LOG_ALERT, file->log, 0, - "invalid thread call, read instead of write"); + "invalid thread operation, read expected"); return NGX_ERROR; } @@ -135,7 +228,7 @@ ngx_thread_read(ngx_file_t *file, u_char task->handler = ngx_thread_read_handler; - ctx->write = 0; + ctx->op = NGX_THREAD_FILE_READ; ctx->fd = file->fd; ctx->buf = buf; @@ -501,9 +594,9 @@ ngx_thread_write_chain_to_file(ngx_file_ if (task->event.complete) { task->event.complete = 0; - if (!ctx->write) { + if (ctx->op != NGX_THREAD_FILE_WRITE) { ngx_log_error(NGX_LOG_ALERT, file->log, 0, - "invalid thread call, write instead of read"); + "invalid thread operation, write expected"); return NGX_ERROR; } @@ -519,7 +612,7 @@ ngx_thread_write_chain_to_file(ngx_file_ task->handler = ngx_thread_write_chain_to_file_handler; - ctx->write = 1; + ctx->op = NGX_THREAD_FILE_WRITE; ctx->fd = file->fd; ctx->chain = cl; diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -385,6 +385,8 @@ extern ngx_uint_t ngx_file_aio; #endif #if (NGX_THREADS) +ngx_int_t ngx_thread_open(ngx_file_t *file, u_char *name, + ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_pool_t *pool); ssize_t ngx_thread_read(ngx_file_t *file, u_char *buf, size_t size, off_t offset, ngx_pool_t *pool); ssize_t ngx_thread_write_chain_to_file(ngx_file_t *file, ngx_chain_t *cl, -------------- next part -------------- # HG changeset patch # User Roman Arutyunyan # Date 1540901639 -10800 # Tue Oct 30 15:13:59 2018 +0300 # Node ID 96b4ea1133b0d69de39401fe5cc5b5f28e8d81f9 # Parent 77f8ae0aabcf7246875f3db53c4c3b3f9f0dc9cc Static: threaded open support. diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -11,7 +11,14 @@ static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_static_send(ngx_http_request_t *r); static ngx_int_t ngx_http_static_init(ngx_conf_t *cf); +#if (NGX_THREADS) +static void ngx_http_static_write_event_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_static_thread_handler(ngx_thread_task_t *task, + ngx_file_t *file); +static void ngx_http_static_thread_event_handler(ngx_event_t *ev); +#endif static ngx_http_module_t ngx_http_static_module_ctx = { @@ -48,15 +55,9 @@ ngx_module_t ngx_http_static_module = { static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r) { - u_char *last, *location; - size_t root, len; - ngx_str_t path; + size_t root; + u_char *last; ngx_int_t rc; - ngx_uint_t level; - ngx_log_t *log; - ngx_buf_t *b; - ngx_chain_t out; - ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { @@ -67,42 +68,81 @@ ngx_http_static_handler(ngx_http_request return NGX_DECLINED; } - log = r->connection->log; - /* * ngx_http_map_uri_to_path() allocates memory for terminating '\0' * so we do not need to reserve memory for '/' for possible redirect */ - last = ngx_http_map_uri_to_path(r, &path, &root, 0); + last = ngx_http_map_uri_to_path(r, &r->open_file_name, &root, 0); if (last == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - path.len = last - path.data; + r->open_file_name.len = last - r->open_file_name.data; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, - "http filename: \"%s\"", path.data); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http filename: \"%s\"", r->open_file_name.data); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + ngx_memzero(&r->open_file_info, sizeof(ngx_open_file_info_t)); - of.read_ahead = clcf->read_ahead; - of.directio = clcf->directio; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.errors = clcf->open_file_cache_errors; - of.events = clcf->open_file_cache_events; +#if (NGX_THREADS) + if (clcf->aio == NGX_HTTP_AIO_THREADS && clcf->aio_open) { + r->open_file_info.thread_handler = ngx_http_static_thread_handler; + r->open_file_info.thread_ctx = r; + } +#endif - if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + if (ngx_http_set_open_file(r, clcf, &r->open_file_name, &r->open_file_info) + != NGX_OK) + { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) - != NGX_OK) - { - switch (of.err) { + rc = ngx_http_static_send(r); + +#if (NGX_THREADS) + if (rc == NGX_DONE) { + r->main->count++; + r->write_event_handler = ngx_http_static_write_event_handler; + } +#endif + + return rc; +} + + +static ngx_int_t +ngx_http_static_send(ngx_http_request_t *r) +{ + u_char *location, *last; + size_t len; + ngx_log_t *log; + ngx_int_t rc; + ngx_uint_t level; + ngx_buf_t *b; + ngx_chain_t out; + ngx_http_core_loc_conf_t *clcf; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http static send: \"%s\"", r->open_file_name.data); + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + log = r->connection->log; + + rc = ngx_open_cached_file(clcf->open_file_cache, &r->open_file_name, + &r->open_file_info, r->pool); + +#if (NGX_THREADS) + if (rc == NGX_AGAIN) { + return NGX_DONE; + } +#endif + + if (rc != NGX_OK) { + switch (r->open_file_info.err) { case 0: return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -133,8 +173,9 @@ ngx_http_static_handler(ngx_http_request } if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) { - ngx_log_error(level, log, of.err, - "%s \"%s\" failed", of.failed, path.data); + ngx_log_error(level, log, r->open_file_info.err, + "%s \"%s\" failed", r->open_file_info.failed, + r->open_file_name.data); } return rc; @@ -142,9 +183,10 @@ ngx_http_static_handler(ngx_http_request r->root_tested = !r->error_page; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", + r->open_file_info.fd); - if (of.is_dir) { + if (r->open_file_info.is_dir) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); @@ -158,9 +200,9 @@ ngx_http_static_handler(ngx_http_request len = r->uri.len + 1; if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) { - location = path.data + clcf->root.len; + location = r->open_file_name.data + clcf->root.len; - *last = '/'; + r->open_file_name.data[r->open_file_name.len] = '/'; } else { if (r->args.len) { @@ -193,9 +235,9 @@ ngx_http_static_handler(ngx_http_request #if !(NGX_WIN32) /* the not regular files are probably Unix specific */ - if (!of.is_file) { + if (!r->open_file_info.is_file) { ngx_log_error(NGX_LOG_CRIT, log, 0, - "\"%s\" is not a regular file", path.data); + "\"%s\" is not a regular file", r->open_file_name.data); return NGX_HTTP_NOT_FOUND; } @@ -215,8 +257,8 @@ ngx_http_static_handler(ngx_http_request log->action = "sending response to client"; r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = of.size; - r->headers_out.last_modified_time = of.mtime; + r->headers_out.content_length_n = r->open_file_info.size; + r->headers_out.last_modified_time = r->open_file_info.mtime; if (ngx_http_set_etag(r) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -226,7 +268,7 @@ ngx_http_static_handler(ngx_http_request return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (r != r->main && of.size == 0) { + if (r != r->main && r->open_file_info.size == 0) { return ngx_http_send_header(r); } @@ -251,16 +293,16 @@ ngx_http_static_handler(ngx_http_request } b->file_pos = 0; - b->file_last = of.size; + b->file_last = r->open_file_info.size; b->in_file = b->file_last ? 1: 0; b->last_buf = (r == r->main) ? 1: 0; b->last_in_chain = 1; - b->file->fd = of.fd; - b->file->name = path; + b->file->fd = r->open_file_info.fd; + b->file->name = r->open_file_name; b->file->log = log; - b->file->directio = of.is_directio; + b->file->directio = r->open_file_info.is_directio; out.buf = b; out.next = NULL; @@ -269,6 +311,90 @@ ngx_http_static_handler(ngx_http_request } +#if (NGX_THREADS) + +static void +ngx_http_static_write_event_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + + rc = ngx_http_static_send(r); + + if (rc != NGX_DONE) { + ngx_http_finalize_request(r, rc); + } +} + + +static ngx_int_t +ngx_http_static_thread_handler(ngx_thread_task_t *task, ngx_file_t *file) +{ + ngx_str_t name; + ngx_thread_pool_t *tp; + ngx_http_request_t *r; + ngx_http_core_loc_conf_t *clcf; + + r = file->thread_ctx; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + tp = clcf->thread_pool; + + if (tp == NULL) { + if (ngx_http_complex_value(r, clcf->thread_pool_value, &name) + != NGX_OK) + { + return NGX_ERROR; + } + + tp = ngx_thread_pool_get((ngx_cycle_t *) ngx_cycle, &name); + + if (tp == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "thread pool \"%V\" not found", &name); + return NGX_ERROR; + } + } + + task->event.data = r; + task->event.handler = ngx_http_static_thread_event_handler; + + if (ngx_thread_task_post(tp, task) != NGX_OK) { + return NGX_ERROR; + } + + r->main->blocked++; + r->aio = 1; + + return NGX_OK; +} + + +static void +ngx_http_static_thread_event_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + ngx_http_request_t *r; + + r = ev->data; + c = r->connection; + + ngx_http_set_log_request(c->log, r); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http static thread: \"%V?%V\"", &r->uri, &r->args); + + r->main->blocked--; + r->aio = 0; + + r->write_event_handler(r); + + ngx_http_run_posted_requests(c); +} + +#endif + + static ngx_int_t ngx_http_static_init(ngx_conf_t *cf) { diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -420,6 +420,13 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, aio_write), NULL }, + { ngx_string("aio_open"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, aio_open), + NULL }, + { ngx_string("read_ahead"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -2559,6 +2566,21 @@ ngx_http_cleanup_add(ngx_http_request_t ngx_int_t +ngx_http_set_open_file(ngx_http_request_t *r, + ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of) +{ + of->read_ahead = clcf->read_ahead; + of->directio = clcf->directio; + of->valid = clcf->open_file_cache_valid; + of->min_uses = clcf->open_file_cache_min_uses; + of->errors = clcf->open_file_cache_errors; + of->events = clcf->open_file_cache_events; + + return ngx_http_set_disable_symlinks(r, clcf, path, of); +} + + +ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of) { @@ -3380,6 +3402,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t clcf->subrequest_output_buffer_size = NGX_CONF_UNSET_SIZE; clcf->aio = NGX_CONF_UNSET; clcf->aio_write = NGX_CONF_UNSET; + clcf->aio_open = NGX_CONF_UNSET; #if (NGX_THREADS) clcf->thread_pool = NGX_CONF_UNSET_PTR; clcf->thread_pool_value = NGX_CONF_UNSET_PTR; @@ -3605,6 +3628,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t (size_t) ngx_pagesize); ngx_conf_merge_value(conf->aio, prev->aio, NGX_HTTP_AIO_OFF); ngx_conf_merge_value(conf->aio_write, prev->aio_write, 0); + ngx_conf_merge_value(conf->aio_open, prev->aio_open, 0); #if (NGX_THREADS) ngx_conf_merge_ptr_value(conf->thread_pool, prev->thread_pool, NULL); ngx_conf_merge_ptr_value(conf->thread_pool_value, prev->thread_pool_value, diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -382,6 +382,7 @@ struct ngx_http_core_loc_conf_s { ngx_flag_t sendfile; /* sendfile */ ngx_flag_t aio; /* aio */ ngx_flag_t aio_write; /* aio_write */ + ngx_flag_t aio_open; /* aio_open */ ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ @@ -522,6 +523,8 @@ ngx_int_t ngx_http_request_body_save_fil ngx_chain_t *chain); +ngx_int_t ngx_http_set_open_file(ngx_http_request_t *r, + ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of); ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -427,6 +427,9 @@ struct ngx_http_request_s { ngx_http_variable_value_t *variables; + ngx_str_t open_file_name; + ngx_open_file_info_t open_file_info; + #if (NGX_PCRE) ngx_uint_t ncaptures; int *captures; -------------- next part -------------- # HG changeset patch # User Roman Arutyunyan # Date 1540901629 -10800 # Tue Oct 30 15:13:49 2018 +0300 # Node ID 6e92d53dfeecf8e1635b31411843771fe0e85953 # Parent 96b4ea1133b0d69de39401fe5cc5b5f28e8d81f9 Cache: threaded open support. diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -18,6 +18,8 @@ static void ngx_http_file_cache_lock_wai ngx_http_cache_t *c); static ngx_int_t ngx_http_file_cache_read(ngx_http_request_t *r, ngx_http_cache_t *c); +static ngx_int_t ngx_http_file_cache_aio_open(ngx_http_request_t *r, + ngx_http_cache_t *c); static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c); #if (NGX_HAVE_FILE_AIO) @@ -264,13 +266,11 @@ ngx_http_file_cache_create_key(ngx_http_ ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r) { - ngx_int_t rc, rv; - ngx_uint_t test; - ngx_http_cache_t *c; - ngx_pool_cleanup_t *cln; - ngx_open_file_info_t of; - ngx_http_file_cache_t *cache; - ngx_http_core_loc_conf_t *clcf; + ngx_int_t rc; + ngx_uint_t test; + ngx_http_cache_t *c; + ngx_pool_cleanup_t *cln; + ngx_http_file_cache_t *cache; c = r->cache; @@ -315,7 +315,6 @@ ngx_http_file_cache_open(ngx_http_reques c->temp_file = 1; test = c->exists ? 1 : 0; - rv = NGX_DECLINED; } else { /* rc == NGX_DECLINED */ @@ -327,11 +326,10 @@ ngx_http_file_cache_open(ngx_http_reques return NGX_HTTP_CACHE_SCARCE; } - rv = NGX_HTTP_CACHE_SCARCE; + c->temp_file = 0; } else { c->temp_file = 1; - rv = NGX_DECLINED; } } @@ -340,62 +338,10 @@ ngx_http_file_cache_open(ngx_http_reques } if (!test) { - goto done; - } - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); - - of.uniq = c->uniq; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.events = clcf->open_file_cache_events; - of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; - of.read_ahead = clcf->read_ahead; - - if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool) - != NGX_OK) - { - switch (of.err) { - - case 0: - return NGX_ERROR; - - case NGX_ENOENT: - case NGX_ENOTDIR: - goto done; - - default: - ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - ngx_open_file_n " \"%s\" failed", c->file.name.data); - return NGX_ERROR; - } - } - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http file cache fd: %d", of.fd); - - c->file.fd = of.fd; - c->file.log = r->connection->log; - c->uniq = of.uniq; - c->length = of.size; - c->fs_size = (of.fs_size + cache->bsize - 1) / cache->bsize; - - c->buf = ngx_create_temp_buf(r->pool, c->body_start); - if (c->buf == NULL) { - return NGX_ERROR; - } - - return ngx_http_file_cache_read(r, c); - -done: - - if (rv == NGX_DECLINED) { return ngx_http_file_cache_lock(r, c); } - return rv; + return ngx_http_file_cache_read(r, c); } @@ -405,6 +351,10 @@ ngx_http_file_cache_lock(ngx_http_reques ngx_msec_t now, timer; ngx_http_file_cache_t *cache; + if (!c->temp_file) { + return NGX_HTTP_CACHE_SCARCE; + } + if (!c->lock) { return NGX_DECLINED; } @@ -534,6 +484,12 @@ ngx_http_file_cache_read(ngx_http_reques ngx_http_file_cache_t *cache; ngx_http_file_cache_header_t *h; + rc = ngx_http_file_cache_aio_open(r, c); + + if (rc != NGX_OK) { + return rc; + } + n = ngx_http_file_cache_aio_read(r, c); if (n < 0) { @@ -663,6 +619,89 @@ ngx_http_file_cache_read(ngx_http_reques } +static ngx_int_t +ngx_http_file_cache_aio_open(ngx_http_request_t *r, ngx_http_cache_t *c) +{ + ngx_int_t rc; + ngx_http_file_cache_t *cache; + ngx_http_core_loc_conf_t *clcf; + + if (c->file.fd != NGX_INVALID_FILE) { + return NGX_OK; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (!c->reading) { + ngx_memzero(&r->open_file_info, sizeof(ngx_open_file_info_t)); + + r->open_file_info.uniq = c->uniq; + r->open_file_info.valid = clcf->open_file_cache_valid; + r->open_file_info.min_uses = clcf->open_file_cache_min_uses; + r->open_file_info.events = clcf->open_file_cache_events; + r->open_file_info.directio = NGX_OPEN_FILE_DIRECTIO_OFF; + r->open_file_info.read_ahead = clcf->read_ahead; + +#if (NGX_THREADS) + if (clcf->aio == NGX_HTTP_AIO_THREADS && clcf->aio_open) { + r->open_file_info.thread_task = c->thread_task; + r->open_file_info.thread_handler = ngx_http_cache_thread_handler; + r->open_file_info.thread_ctx = r; + } +#endif + } + + rc = ngx_open_cached_file(clcf->open_file_cache, &c->file.name, + &r->open_file_info, r->pool); + +#if (NGX_THREADS) + + if (rc == NGX_AGAIN) { + c->reading = 1; + return NGX_AGAIN; + } + + c->reading = 0; + +#endif + + if (rc != NGX_OK) { + switch (r->open_file_info.err) { + + case NGX_OK: + return NGX_ERROR; + + case NGX_ENOENT: + case NGX_ENOTDIR: + return ngx_http_file_cache_lock(r, c); + + default: + ngx_log_error(NGX_LOG_CRIT, r->connection->log, + r->open_file_info.err, + ngx_open_file_n " \"%s\" failed", c->file.name.data); + return NGX_ERROR; + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http file cache fd: %d", r->open_file_info.fd); + + cache = c->file_cache; + c->file.fd = r->open_file_info.fd; + c->file.log = r->connection->log; + c->uniq = r->open_file_info.uniq; + c->length = r->open_file_info.size; + c->fs_size = (r->open_file_info.fs_size + cache->bsize - 1) / cache->bsize; + + c->buf = ngx_create_temp_buf(r->pool, c->body_start); + if (c->buf == NULL) { + return NGX_ERROR; + } + + return NGX_OK; +} + + static ssize_t ngx_http_file_cache_aio_read(ngx_http_request_t *r, ngx_http_cache_t *c) { @@ -1229,6 +1268,7 @@ ngx_http_file_cache_reopen(ngx_http_requ ngx_shmtx_unlock(&cache->shpool->mutex); c->secondary = 1; + c->file.fd = NGX_INVALID_FILE; c->file.name.len = 0; c->body_start = c->buf->end - c->buf->start; From maxim at nginx.com Thu Nov 1 16:08:10 2018 From: maxim at nginx.com (Maxim Konovalov) Date: Thu, 1 Nov 2018 19:08:10 +0300 Subject: cache: move open to thread pool In-Reply-To: <20181101123047.GG86326@Romans-MacBook-Air.local> References: <20180808181653.GX56558@mdounin.ru> <20180810113946.GG56558@mdounin.ru> <20180903160903.GI56558@mdounin.ru> <20180913181023.GW56558@mdounin.ru> <20181004093226.GD62311@Romans-MacBook-Air.local> <20181101123047.GG86326@Romans-MacBook-Air.local> Message-ID: <67879f0c-03e9-8e39-72c2-7edfaaedb603@nginx.com> On 01/11/2018 15:30, Roman Arutyunyan wrote: > Hi, > > On Thu, Oct 04, 2018 at 12:32:26PM +0300, Roman Arutyunyan wrote: >> Hi, >> >> On Thu, Sep 13, 2018 at 09:10:23PM +0300, Maxim Dounin wrote: >>> Hello! >>> >>> On Tue, Sep 04, 2018 at 04:58:05PM -0700, Ka-Hing Cheung via nginx-devel wrote: >>> >>>> On Mon, Sep 3, 2018 at 9:09 AM, Maxim Dounin wrote: >> [..] >> >> Here's another approach to thread open. This time it's 4 patches: >> >> - #1 a small open file cache refactoring >> - #2 thread open in open file cache >> - #3 thread open in http static module >> - #4 thread open in http file cache > The next iteration of the work. > Only 3 patches this time. Testing and feedbacks are welcome. -- Maxim Konovalov From hidinginthebbc at gmail.com Sat Nov 3 09:00:02 2018 From: hidinginthebbc at gmail.com (Thomas Peterson) Date: Sat, 03 Nov 2018 09:00:02 +0000 Subject: [PATCH] Proxy: Adding proxy_cache_key emedded variable Message-ID: <41a499230eb674b1b3ec.1541235602@dhcp-9c60.meeting.ietf.org> # HG changeset patch # User Thomas Peterson # Date 1541231609 0 # Sat Nov 03 07:53:29 2018 +0000 # Node ID 41a499230eb674b1b3ec7cfd093f3a074f9a0d09 # Parent bddacdaaec9ef174504899f1528155f84bf60e59 Proxy: Adding proxy_cache_key emedded variable This value being able to be set as part of response headers allows for greater debugging of caching, and to permit analytics on cache-key distribution. diff -r bddacdaaec9e -r 41a499230eb6 src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c Wed Oct 31 16:49:40 2018 +0300 +++ b/src/http/modules/ngx_http_proxy_module.c Sat Nov 03 07:53:29 2018 +0000 @@ -154,6 +154,8 @@ ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_proxy_internal_chunked_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_proxy_cache_key_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix); static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, @@ -824,6 +826,11 @@ { ngx_string("proxy_add_x_forwarded_for"), NULL, ngx_http_proxy_add_x_forwarded_for_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, +#if (NGX_HTTP_CACHE) + { ngx_string("proxy_cache_key"), NULL, + ngx_http_proxy_cache_key_variable, 0, NGX_HTTP_VAR_NOHASH, 0 }, +#endif + #if 0 { ngx_string("proxy_add_via"), NULL, NULL, 0, NGX_HTTP_VAR_NOHASH, 0 }, #endif @@ -2499,6 +2506,52 @@ return NGX_OK; } +static ngx_int_t +ngx_http_proxy_cache_key_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + size_t len; + ngx_str_t *key; + ngx_uint_t i; + ngx_http_cache_t *c; + ngx_http_upstream_t *u; + + u = r->upstream; + if(!u->cacheable) { + v->not_found = 1; + return NGX_ERROR; + } + + c = r->cache; + len = 0; + key = c->keys.elts; + for (i = 0; i < c->keys.nelts; i++) { + len += key[i].len; + } + + if(len == 0) { + return NGX_ERROR; + } + + p = ngx_pnalloc(r->pool, len); + if (p == NULL) { + return NGX_ERROR; + } + v->data = p; + + i = 0; + for (i = 0; i < c->keys.nelts; i++) { + p = ngx_cpymem(p, key[i].data, key[i].len); + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->len = len; + + return NGX_OK; +} static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, From mdounin at mdounin.ru Tue Nov 6 15:23:38 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:38 +0000 Subject: [nginx] Mp4: fixed reading 64-bit atoms. Message-ID: details: http://hg.nginx.org/nginx/rev/e5069816039b branches: changeset: 7376:e5069816039b user: Roman Arutyunyan date: Tue Nov 06 16:29:18 2018 +0300 description: Mp4: fixed reading 64-bit atoms. Previously there was no validation for the size of a 64-bit atom in an mp4 file. This could lead to a CPU hog when the size is 0, or various other problems due to integer underflow when calculating atom data size, including segmentation fault or worker process memory disclosure. diffstat: src/http/modules/ngx_http_mp4_module.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diffs (17 lines): diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -942,6 +942,13 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file atom_size = ngx_mp4_get_64value(atom_header + 8); atom_header_size = sizeof(ngx_mp4_atom_header64_t); + if (atom_size < sizeof(ngx_mp4_atom_header64_t)) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 atom is too small:%uL", + mp4->file.name.data, atom_size); + return NGX_ERROR; + } + } else { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 atom is too small:%uL", From mdounin at mdounin.ru Tue Nov 6 15:23:39 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:39 +0000 Subject: [nginx] HTTP/2: flood detection. Message-ID: details: http://hg.nginx.org/nginx/rev/d4448892a294 branches: changeset: 7377:d4448892a294 user: Ruslan Ermilov date: Tue Nov 06 16:29:35 2018 +0300 description: HTTP/2: flood detection. Fixed uncontrolled memory growth in case peer is flooding us with some frames (e.g., SETTINGS and PING) and doesn't read data. Fix is to limit the number of allocated control frames. diffstat: src/http/v2/ngx_http_v2.c | 12 +++++++++++- src/http/v2/ngx_http_v2.h | 1 + 2 files changed, 12 insertions(+), 1 deletions(-) diffs (47 lines): diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -662,6 +662,7 @@ ngx_http_v2_handle_connection(ngx_http_v h2c->pool = NULL; h2c->free_frames = NULL; + h2c->frames = 0; h2c->free_fake_connections = NULL; #if (NGX_HTTP_SSL) @@ -2895,7 +2896,7 @@ ngx_http_v2_get_frame(ngx_http_v2_connec frame->blocked = 0; - } else { + } else if (h2c->frames < 10000) { pool = h2c->pool ? h2c->pool : h2c->connection->pool; frame = ngx_pcalloc(pool, sizeof(ngx_http_v2_out_frame_t)); @@ -2919,6 +2920,15 @@ ngx_http_v2_get_frame(ngx_http_v2_connec frame->last = frame->first; frame->handler = ngx_http_v2_frame_handler; + + h2c->frames++; + + } else { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "http2 flood detected"); + + h2c->connection->error = 1; + return NULL; } #if (NGX_DEBUG) diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -120,6 +120,7 @@ struct ngx_http_v2_connection_s { ngx_http_connection_t *http_connection; ngx_uint_t processing; + ngx_uint_t frames; ngx_uint_t pushing; ngx_uint_t concurrent_pushes; From mdounin at mdounin.ru Tue Nov 6 15:23:41 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:41 +0000 Subject: [nginx] HTTP/2: limit the number of idle state switches. Message-ID: details: http://hg.nginx.org/nginx/rev/e7f19d268c72 branches: changeset: 7378:e7f19d268c72 user: Ruslan Ermilov date: Tue Nov 06 16:29:49 2018 +0300 description: HTTP/2: limit the number of idle state switches. An attack that continuously switches HTTP/2 connection between idle and active states can result in excessive CPU usage. This is because when a connection switches to the idle state, all of its memory pool caches are freed. This change limits the maximum allowed number of idle state switches to 10 * http2_max_requests (i.e., 10000 by default). This limits possible CPU usage in one connection, and also imposes a limit on the maximum lifetime of a connection. Initially reported by Gal Goldshtein from F5 Networks. diffstat: src/http/v2/ngx_http_v2.c | 13 ++++++++++--- src/http/v2/ngx_http_v2.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diffs (37 lines): diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -4511,12 +4511,19 @@ ngx_http_v2_idle_handler(ngx_event_t *re #endif + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + if (h2c->idle++ > 10 * h2scf->max_requests) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "http2 flood detected"); + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); + return; + } + c->destroyed = 0; ngx_reusable_connection(c, 0); - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); - h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); if (h2c->pool == NULL) { ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -121,6 +121,7 @@ struct ngx_http_v2_connection_s { ngx_uint_t processing; ngx_uint_t frames; + ngx_uint_t idle; ngx_uint_t pushing; ngx_uint_t concurrent_pushes; From mdounin at mdounin.ru Tue Nov 6 15:23:43 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:43 +0000 Subject: [nginx] gRPC: limited allocations due to ping and settings frames. Message-ID: details: http://hg.nginx.org/nginx/rev/57463f4e2fcd branches: changeset: 7379:57463f4e2fcd user: Maxim Dounin date: Tue Nov 06 16:29:59 2018 +0300 description: gRPC: limited allocations due to ping and settings frames. diffstat: src/http/modules/ngx_http_grpc_module.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diffs (39 lines): diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -78,6 +78,9 @@ typedef struct { ngx_uint_t id; + ngx_uint_t pings; + ngx_uint_t settings; + ssize_t send_window; size_t recv_window; @@ -3584,6 +3587,12 @@ ngx_http_grpc_parse_settings(ngx_http_re ctx->rest); return NGX_ERROR; } + + if (ctx->free == NULL && ctx->settings++ > 1000) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent too many settings frames"); + return NGX_ERROR; + } } for (p = b->pos; p < last; p++) { @@ -3736,6 +3745,12 @@ ngx_http_grpc_parse_ping(ngx_http_reques "upstream sent ping frame with ack flag"); return NGX_ERROR; } + + if (ctx->free == NULL && ctx->pings++ > 1000) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent too many ping frames"); + return NGX_ERROR; + } } for (p = b->pos; p < last; p++) { From mdounin at mdounin.ru Tue Nov 6 15:23:44 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:44 +0000 Subject: [nginx] nginx-1.15.6-RELEASE Message-ID: details: http://hg.nginx.org/nginx/rev/2351853ce686 branches: changeset: 7380:2351853ce686 user: Maxim Dounin date: Tue Nov 06 16:32:08 2018 +0300 description: nginx-1.15.6-RELEASE diffstat: docs/xml/nginx/changes.xml | 64 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 64 insertions(+), 0 deletions(-) diffs (74 lines): diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,70 @@ + + + + +??? ????????????? HTTP/2 ?????? ??? ??????? +?????????? ??????????? ?????? (CVE-2018-16843) +? ???????? ?????????? (CVE-2018-16844). + + +when using HTTP/2 a client might cause +excessive memory consumption (CVE-2018-16843) +and CPU usage (CVE-2018-16844). + + + + + +??? ????????? ?????????? ?????????? mp4-????? ??????? ngx_http_mp4_module +?????????? ?????? ???????? ???????? ????? ???? ?????????? ??????? +(CVE-2018-16845). + + +processing of a specially crafted mp4 file with the ngx_http_mp4_module +might result in worker process memory disclosure +(CVE-2018-16845). + + + + + +????????? proxy_socket_keepalive, fastcgi_socket_keepalive, +grpc_socket_keepalive, memcached_socket_keepalive, +scgi_socket_keepalive ? uwsgi_socket_keepalive. + + +the "proxy_socket_keepalive", "fastcgi_socket_keepalive", +"grpc_socket_keepalive", "memcached_socket_keepalive", +"scgi_socket_keepalive", and "uwsgi_socket_keepalive" directives. + + + + + +???? nginx ??? ?????? ? OpenSSL 1.1.0, ? ????????????? ? OpenSSL 1.1.1, +???????? TLS 1.3 ?????? ??? ????????. + + +if nginx was built with OpenSSL 1.1.0 and used with OpenSSL 1.1.1, +the TLS 1.3 protocol was always enabled. + + + + + +??? ?????? ? gRPC-????????? ????? ????????????? ??????? ?????????? ??????. + + +working with gRPC backends might result in excessive memory consumption. + + + + + + From mdounin at mdounin.ru Tue Nov 6 15:23:46 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:46 +0000 Subject: [nginx] release-1.15.6 tag Message-ID: details: http://hg.nginx.org/nginx/rev/a2506436986a branches: changeset: 7381:a2506436986a user: Maxim Dounin date: Tue Nov 06 16:32:09 2018 +0300 description: release-1.15.6 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -431,3 +431,4 @@ b234199c7ed8a156a6bb98f7ff58302c857c954f 28b3e17ca7eba1e6a0891afde0e4bc5bcc99c861 release-1.15.3 49d49835653857daa418e68d6cbfed4958c78fca release-1.15.4 f062e43d74fc2578bb100a9e82a953efa1eb9e4e release-1.15.5 +2351853ce6867b6166823bdf94333c0a76633c0a release-1.15.6 From mdounin at mdounin.ru Tue Nov 6 15:23:48 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:48 +0000 Subject: [nginx] Version bump. Message-ID: details: http://hg.nginx.org/nginx/rev/945234478ff8 branches: stable-1.14 changeset: 7382:945234478ff8 user: Maxim Dounin date: Tue Nov 06 16:33:16 2018 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1014000 -#define NGINX_VERSION "1.14.0" +#define nginx_version 1014001 +#define NGINX_VERSION "1.14.1" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From mdounin at mdounin.ru Tue Nov 6 15:23:49 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:49 +0000 Subject: [nginx] Updated OpenSSL used for win32 builds. Message-ID: details: http://hg.nginx.org/nginx/rev/3ef5d7403989 branches: stable-1.14 changeset: 7383:3ef5d7403989 user: Maxim Dounin date: Tue Aug 28 15:05:41 2018 +0300 description: Updated OpenSSL used for win32 builds. diffstat: misc/GNUmakefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/misc/GNUmakefile b/misc/GNUmakefile --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -6,7 +6,7 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-1.0.2o +OPENSSL = openssl-1.0.2p ZLIB = zlib-1.2.11 PCRE = pcre-8.42 From mdounin at mdounin.ru Tue Nov 6 15:23:51 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:51 +0000 Subject: [nginx] Mp4: fixed reading 64-bit atoms. Message-ID: details: http://hg.nginx.org/nginx/rev/fdc19a3289c1 branches: stable-1.14 changeset: 7384:fdc19a3289c1 user: Roman Arutyunyan date: Tue Nov 06 16:29:18 2018 +0300 description: Mp4: fixed reading 64-bit atoms. Previously there was no validation for the size of a 64-bit atom in an mp4 file. This could lead to a CPU hog when the size is 0, or various other problems due to integer underflow when calculating atom data size, including segmentation fault or worker process memory disclosure. diffstat: src/http/modules/ngx_http_mp4_module.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diffs (17 lines): diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -942,6 +942,13 @@ ngx_http_mp4_read_atom(ngx_http_mp4_file atom_size = ngx_mp4_get_64value(atom_header + 8); atom_header_size = sizeof(ngx_mp4_atom_header64_t); + if (atom_size < sizeof(ngx_mp4_atom_header64_t)) { + ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, + "\"%s\" mp4 atom is too small:%uL", + mp4->file.name.data, atom_size); + return NGX_ERROR; + } + } else { ngx_log_error(NGX_LOG_ERR, mp4->file.log, 0, "\"%s\" mp4 atom is too small:%uL", From mdounin at mdounin.ru Tue Nov 6 15:23:52 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:52 +0000 Subject: [nginx] HTTP/2: flood detection. Message-ID: details: http://hg.nginx.org/nginx/rev/1c6b6163c039 branches: stable-1.14 changeset: 7385:1c6b6163c039 user: Ruslan Ermilov date: Tue Nov 06 16:29:35 2018 +0300 description: HTTP/2: flood detection. Fixed uncontrolled memory growth in case peer is flooding us with some frames (e.g., SETTINGS and PING) and doesn't read data. Fix is to limit the number of allocated control frames. diffstat: src/http/v2/ngx_http_v2.c | 12 +++++++++++- src/http/v2/ngx_http_v2.h | 1 + 2 files changed, 12 insertions(+), 1 deletions(-) diffs (47 lines): diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -664,6 +664,7 @@ ngx_http_v2_handle_connection(ngx_http_v h2c->pool = NULL; h2c->free_frames = NULL; + h2c->frames = 0; h2c->free_fake_connections = NULL; #if (NGX_HTTP_SSL) @@ -2895,7 +2896,7 @@ ngx_http_v2_get_frame(ngx_http_v2_connec frame->blocked = 0; - } else { + } else if (h2c->frames < 10000) { pool = h2c->pool ? h2c->pool : h2c->connection->pool; frame = ngx_pcalloc(pool, sizeof(ngx_http_v2_out_frame_t)); @@ -2919,6 +2920,15 @@ ngx_http_v2_get_frame(ngx_http_v2_connec frame->last = frame->first; frame->handler = ngx_http_v2_frame_handler; + + h2c->frames++; + + } else { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "http2 flood detected"); + + h2c->connection->error = 1; + return NULL; } #if (NGX_DEBUG) diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -120,6 +120,7 @@ struct ngx_http_v2_connection_s { ngx_http_connection_t *http_connection; ngx_uint_t processing; + ngx_uint_t frames; ngx_uint_t pushing; ngx_uint_t concurrent_pushes; From mdounin at mdounin.ru Tue Nov 6 15:23:54 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:54 +0000 Subject: [nginx] HTTP/2: limit the number of idle state switches. Message-ID: details: http://hg.nginx.org/nginx/rev/9200b41db765 branches: stable-1.14 changeset: 7386:9200b41db765 user: Ruslan Ermilov date: Tue Nov 06 16:29:49 2018 +0300 description: HTTP/2: limit the number of idle state switches. An attack that continuously switches HTTP/2 connection between idle and active states can result in excessive CPU usage. This is because when a connection switches to the idle state, all of its memory pool caches are freed. This change limits the maximum allowed number of idle state switches to 10 * http2_max_requests (i.e., 10000 by default). This limits possible CPU usage in one connection, and also imposes a limit on the maximum lifetime of a connection. Initially reported by Gal Goldshtein from F5 Networks. diffstat: src/http/v2/ngx_http_v2.c | 13 ++++++++++--- src/http/v2/ngx_http_v2.h | 1 + 2 files changed, 11 insertions(+), 3 deletions(-) diffs (37 lines): diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -4481,12 +4481,19 @@ ngx_http_v2_idle_handler(ngx_event_t *re #endif + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); + + if (h2c->idle++ > 10 * h2scf->max_requests) { + ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, + "http2 flood detected"); + ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_NO_ERROR); + return; + } + c->destroyed = 0; ngx_reusable_connection(c, 0); - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); - h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log); if (h2c->pool == NULL) { ngx_http_v2_finalize_connection(h2c, NGX_HTTP_V2_INTERNAL_ERROR); diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -121,6 +121,7 @@ struct ngx_http_v2_connection_s { ngx_uint_t processing; ngx_uint_t frames; + ngx_uint_t idle; ngx_uint_t pushing; ngx_uint_t concurrent_pushes; From mdounin at mdounin.ru Tue Nov 6 15:23:56 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:56 +0000 Subject: [nginx] gRPC: limited allocations due to ping and settings frames. Message-ID: details: http://hg.nginx.org/nginx/rev/6afba58cd5a3 branches: stable-1.14 changeset: 7387:6afba58cd5a3 user: Maxim Dounin date: Tue Nov 06 16:29:59 2018 +0300 description: gRPC: limited allocations due to ping and settings frames. diffstat: src/http/modules/ngx_http_grpc_module.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diffs (39 lines): diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c +++ b/src/http/modules/ngx_http_grpc_module.c @@ -78,6 +78,9 @@ typedef struct { ngx_uint_t id; + ngx_uint_t pings; + ngx_uint_t settings; + ssize_t send_window; size_t recv_window; @@ -3531,6 +3534,12 @@ ngx_http_grpc_parse_settings(ngx_http_re ctx->rest); return NGX_ERROR; } + + if (ctx->free == NULL && ctx->settings++ > 1000) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent too many settings frames"); + return NGX_ERROR; + } } for (p = b->pos; p < last; p++) { @@ -3683,6 +3692,12 @@ ngx_http_grpc_parse_ping(ngx_http_reques "upstream sent ping frame with ack flag"); return NGX_ERROR; } + + if (ctx->free == NULL && ctx->pings++ > 1000) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "upstream sent too many ping frames"); + return NGX_ERROR; + } } for (p = b->pos; p < last; p++) { From mdounin at mdounin.ru Tue Nov 6 15:23:57 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:57 +0000 Subject: [nginx] nginx-1.14.1-RELEASE Message-ID: details: http://hg.nginx.org/nginx/rev/fe8e8322d9c1 branches: stable-1.14 changeset: 7388:fe8e8322d9c1 user: Maxim Dounin date: Tue Nov 06 16:52:46 2018 +0300 description: nginx-1.14.1-RELEASE diffstat: docs/xml/nginx/changes.xml | 40 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 40 insertions(+), 0 deletions(-) diffs (50 lines): diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,46 @@ + + + + +??? ????????????? HTTP/2 ?????? ??? ??????? +?????????? ??????????? ?????? (CVE-2018-16843) +? ???????? ?????????? (CVE-2018-16844). + + +when using HTTP/2 a client might cause +excessive memory consumption (CVE-2018-16843) +and CPU usage (CVE-2018-16844). + + + + + +??? ????????? ?????????? ?????????? mp4-????? ??????? ngx_http_mp4_module +?????????? ?????? ???????? ???????? ????? ???? ?????????? ??????? +(CVE-2018-16845). + + +processing of a specially crafted mp4 file with the ngx_http_mp4_module +might result in worker process memory disclosure +(CVE-2018-16845). + + + + + +??? ?????? ? gRPC-????????? ????? ????????????? ??????? ?????????? ??????. + + +working with gRPC backends might result in excessive memory consumption. + + + + + + From mdounin at mdounin.ru Tue Nov 6 15:23:59 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 06 Nov 2018 15:23:59 +0000 Subject: [nginx] release-1.14.1 tag Message-ID: details: http://hg.nginx.org/nginx/rev/ac466b907fa9 branches: stable-1.14 changeset: 7389:ac466b907fa9 user: Maxim Dounin date: Tue Nov 06 16:52:46 2018 +0300 description: release-1.14.1 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -426,3 +426,4 @@ 31c929e16910c38492581ef474e72fa67c28f124 64179f242cb55fc206bca59de9bfdc4cf5ebcec7 release-1.13.11 051e5fa03b92b8a564f6b12debd483d267391e82 release-1.13.12 588054867fef65d3dc38df1ffefcade02a88f140 release-1.14.0 +fe8e8322d9c13597f06b80f2015124446f0a900c release-1.14.1 From xeioex at nginx.com Tue Nov 6 17:58:13 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 06 Nov 2018 17:58:13 +0000 Subject: [njs] Improved wording for "not a function" exception. Message-ID: details: http://hg.nginx.org/njs/rev/1df0fea011d1 branches: changeset: 637:1df0fea011d1 user: Dmitry Volyntsev date: Tue Nov 06 20:30:49 2018 +0300 description: Improved wording for "not a function" exception. diffstat: njs/njs_vm.c | 7 ++++++- njs/test/njs_unit_test.c | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diffs (44 lines): diff -r a3a0d5850b1a -r 1df0fea011d1 njs/njs_vm.c --- a/njs/njs_vm.c Wed Oct 31 16:06:06 2018 +0300 +++ b/njs/njs_vm.c Tue Nov 06 20:30:49 2018 +0300 @@ -1847,9 +1847,14 @@ njs_function_frame_create(njs_vm_t *vm, return njs_function_native_frame(vm, function, this, NULL, nargs, 0, ctor); } + + njs_type_error(vm, "%s is not a constructor", + njs_type_string(value->type)); + + return NXT_ERROR; } - njs_type_error(vm, "object is not callable"); + njs_type_error(vm, "%s is not a function", njs_type_string(value->type)); return NXT_ERROR; } diff -r a3a0d5850b1a -r 1df0fea011d1 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Oct 31 16:06:06 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Nov 06 20:30:49 2018 +0300 @@ -5184,7 +5184,7 @@ static njs_unit_test_t njs_test[] = nxt_string("OKundefined") }, { nxt_string("var a = 1; a()"), - nxt_string("TypeError: object is not callable") }, + nxt_string("TypeError: number is not a function") }, { nxt_string("var o = {a:1}; o.a()"), nxt_string("TypeError: 'a' is not a function") }, @@ -5672,10 +5672,10 @@ static njs_unit_test_t njs_test[] = nxt_string("object") }, { nxt_string("new decodeURI('%00')"), - nxt_string("TypeError: object is not callable")}, + nxt_string("TypeError: function is not a constructor")}, { nxt_string("new ''.toString"), - nxt_string("TypeError: object is not callable")}, + nxt_string("TypeError: function is not a constructor")}, { nxt_string("function F() { return Number }" "var o = new (F())(5);" From xeioex at nginx.com Tue Nov 6 17:58:13 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 06 Nov 2018 17:58:13 +0000 Subject: [njs] Using more approprite name for undefined value in exceptions. Message-ID: details: http://hg.nginx.org/njs/rev/5766e459c203 branches: changeset: 638:5766e459c203 user: Dmitry Volyntsev date: Tue Nov 06 20:57:52 2018 +0300 description: Using more approprite name for undefined value in exceptions. diffstat: njs/njs_vm.c | 2 +- njs/test/njs_interactive_test.c | 2 +- njs/test/njs_unit_test.c | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diffs (98 lines): diff -r 1df0fea011d1 -r 5766e459c203 njs/njs_vm.c --- a/njs/njs_vm.c Tue Nov 06 20:30:49 2018 +0300 +++ b/njs/njs_vm.c Tue Nov 06 20:57:52 2018 +0300 @@ -2207,7 +2207,7 @@ njs_type_string(njs_value_type_t type) return "null"; case NJS_VOID: - return "void"; + return "undefined"; case NJS_BOOLEAN: return "boolean"; diff -r 1df0fea011d1 -r 5766e459c203 njs/test/njs_interactive_test.c --- a/njs/test/njs_interactive_test.c Tue Nov 06 20:30:49 2018 +0300 +++ b/njs/test/njs_interactive_test.c Tue Nov 06 20:57:52 2018 +0300 @@ -140,7 +140,7 @@ static njs_interactive_test_t njs_test[ { nxt_string("function f(o) {return Object.keys(o)}" ENTER "f()" ENTER), - nxt_string("TypeError: cannot convert void to object\n" + nxt_string("TypeError: cannot convert undefined to object\n" " at Object.keys (native)\n" " at f (:1)\n" " at main (native)\n") }, diff -r 1df0fea011d1 -r 5766e459c203 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Nov 06 20:30:49 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Nov 06 20:57:52 2018 +0300 @@ -3071,7 +3071,7 @@ static njs_unit_test_t njs_test[] = nxt_string("") }, { nxt_string("Array.prototype.slice.call(undefined)"), - nxt_string("TypeError: cannot convert void to object") }, + nxt_string("TypeError: cannot convert undefined to object") }, { nxt_string("Array.prototype.slice.call(1)"), nxt_string("") }, @@ -5528,10 +5528,10 @@ static njs_unit_test_t njs_test[] = nxt_string("1552553") }, { nxt_string("[].join.call()"), - nxt_string("TypeError: cannot convert void to object") }, + nxt_string("TypeError: cannot convert undefined to object") }, { nxt_string("[].slice.call()"), - nxt_string("TypeError: cannot convert void to object") }, + nxt_string("TypeError: cannot convert undefined to object") }, { nxt_string("function f(a) {} ; var a = f; var b = f; a === b"), nxt_string("true") }, @@ -7071,7 +7071,7 @@ static njs_unit_test_t njs_test[] = nxt_string("false") }, { nxt_string("Object.create()"), - nxt_string("TypeError: prototype may only be an object or null: void") }, + nxt_string("TypeError: prototype may only be an object or null: undefined") }, { nxt_string("Object.create(1)"), nxt_string("TypeError: prototype may only be an object or null: number") }, @@ -7093,7 +7093,7 @@ static njs_unit_test_t njs_test[] = nxt_string("b") }, { nxt_string("Object.keys()"), - nxt_string("TypeError: cannot convert void argument to object") }, + nxt_string("TypeError: cannot convert undefined argument to object") }, { nxt_string("Object.keys('a')"), nxt_string("TypeError: cannot convert string argument to object") }, @@ -7214,7 +7214,7 @@ static njs_unit_test_t njs_test[] = nxt_string("2") }, { nxt_string("var o = {}; Object.defineProperty()"), - nxt_string("TypeError: cannot convert void argument to object") }, + nxt_string("TypeError: cannot convert undefined argument to object") }, { nxt_string("var o = {}; Object.defineProperty(o)"), nxt_string("TypeError: descriptor is not an object") }, @@ -7430,10 +7430,10 @@ static njs_unit_test_t njs_test[] = nxt_string("1,1,-1") }, { nxt_string("Object.getOwnPropertyDescriptor()"), - nxt_string("TypeError: cannot convert void argument to object") }, + nxt_string("TypeError: cannot convert undefined argument to object") }, { nxt_string("Object.getOwnPropertyDescriptor(undefined)"), - nxt_string("TypeError: cannot convert void argument to object") }, + nxt_string("TypeError: cannot convert undefined argument to object") }, { nxt_string("var o = {}; o[void 0] = 'a'; Object.getOwnPropertyDescriptor(o).value"), nxt_string("a") }, @@ -8092,7 +8092,7 @@ static njs_unit_test_t njs_test[] = nxt_string("Invalid Date") }, { nxt_string("[0].map(new Date().getDate)"), - nxt_string("TypeError: cannot convert void to date") }, + nxt_string("TypeError: cannot convert undefined to date") }, { nxt_string("new Date(eval)"), nxt_string("Invalid Date") }, From xeioex at nginx.com Tue Nov 6 17:58:14 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 06 Nov 2018 17:58:14 +0000 Subject: [njs] Initializing closure values of a function. Message-ID: details: http://hg.nginx.org/njs/rev/0372810c0d98 branches: changeset: 639:0372810c0d98 user: Dmitry Volyntsev date: Tue Nov 06 20:57:53 2018 +0300 description: Initializing closure values of a function. This fixes #55 issue on Github. diffstat: njs/njs_function.c | 10 +++++----- njs/njs_function.h | 1 + njs/njs_generator.c | 4 +++- njs/test/njs_unit_test.c | 40 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 6 deletions(-) diffs (110 lines): diff -r 5766e459c203 -r 0372810c0d98 njs/njs_function.c --- a/njs/njs_function.c Tue Nov 06 20:57:52 2018 +0300 +++ b/njs/njs_function.c Tue Nov 06 20:57:53 2018 +0300 @@ -399,7 +399,7 @@ njs_function_call(njs_vm_t *vm, njs_inde njs_ret_t ret; nxt_uint_t n, nesting; njs_frame_t *frame; - njs_value_t *value; + njs_value_t *dst, *src; njs_closure_t *closure, **closures; njs_function_t *function; njs_function_lambda_t *lambda; @@ -459,14 +459,14 @@ njs_function_call(njs_vm_t *vm, njs_inde return NXT_ERROR; } - /* TODO: copy initialzed values. */ - size -= sizeof(njs_value_t); closure->u.count = 0; - value = closure->values; + dst = closure->values; + + src = lambda->closure_scope; do { - *value++ = njs_value_void; + *dst++ = *src++; size -= sizeof(njs_value_t); } while (size != 0); } diff -r 5766e459c203 -r 0372810c0d98 njs/njs_function.h --- a/njs/njs_function.h Tue Nov 06 20:57:52 2018 +0300 +++ b/njs/njs_function.h Tue Nov 06 20:57:53 2018 +0300 @@ -34,6 +34,7 @@ struct njs_function_lambda_s { /* Initial values of local scope. */ njs_value_t *local_scope; + njs_value_t *closure_scope; union { u_char *start; diff -r 5766e459c203 -r 0372810c0d98 njs/njs_generator.c --- a/njs/njs_generator.c Tue Nov 06 20:57:52 2018 +0300 +++ b/njs/njs_generator.c Tue Nov 06 20:57:53 2018 +0300 @@ -2047,11 +2047,13 @@ njs_generate_function_scope(njs_vm_t *vm if (closure != NULL) { lambda->block_closures = 1; + lambda->closure_scope = closure->start; size = (1 + closure->items) * sizeof(njs_value_t); } + lambda->closure_size = size; + lambda->nesting = node->scope->nesting; - lambda->closure_size = size; lambda->arguments_object = parser->arguments_object; lambda->local_size = parser->scope_size; diff -r 5766e459c203 -r 0372810c0d98 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Nov 06 20:57:52 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Nov 06 20:57:53 2018 +0300 @@ -5287,6 +5287,46 @@ static njs_unit_test_t njs_test[] = { nxt_string("function f() { var a = f2(); }"), nxt_string("ReferenceError: \"f2\" is not defined in 1") }, + { nxt_string("(function(){ function f() {return f}; return f()})()"), + nxt_string("[object Function]") }, + + { nxt_string("var a = ''; " + "function f(list) {" + " function add(v) {a+=v};" + " list.forEach(function(v) {add(v)});" + "};" + "f(['a', 'b', 'c']); a"), + nxt_string("abc") }, + + { nxt_string("var l = [];" + "var f = function() { " + " function f2() { l.push(f); l.push(f2); }; " + " l.push(f); l.push(f2); " + " f2(); " + "}; " + "f(); " + "l.every(function(v) {return typeof v == 'function'})"), + nxt_string("true") }, + + { nxt_string("var l = [];" + "function baz() {" + " function foo(v) {" + " function bar() { foo(0); }" + " l.push(v);" + " if (v === 1) { bar(); }" + " }" + " foo(1);" + "}; baz(); l"), + nxt_string("1,0") }, + + { nxt_string("var gen = (function(){ " + " var s = 0; " + " return { inc: function() {s++}, " + " s: function() {return s} };});" + "var o1 = gen(); var o2 = gen();" + "[o1.s(),o2.s(),o1.inc(),o1.s(),o2.s(),o2.inc(),o1.s(),o2.s()]"), + nxt_string("0,0,,1,0,,1,1") }, + /* Recursive fibonacci. */ { nxt_string("function fibo(n) {" From mdounin at mdounin.ru Tue Nov 6 19:15:24 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 6 Nov 2018 22:15:24 +0300 Subject: [PATCH] Proxy: Adding proxy_cache_key emedded variable In-Reply-To: <41a499230eb674b1b3ec.1541235602@dhcp-9c60.meeting.ietf.org> References: <41a499230eb674b1b3ec.1541235602@dhcp-9c60.meeting.ietf.org> Message-ID: <20181106191524.GA56558@mdounin.ru> Hello! On Sat, Nov 03, 2018 at 09:00:02AM +0000, Thomas Peterson wrote: > # HG changeset patch > # User Thomas Peterson > # Date 1541231609 0 > # Sat Nov 03 07:53:29 2018 +0000 > # Node ID 41a499230eb674b1b3ec7cfd093f3a074f9a0d09 > # Parent bddacdaaec9ef174504899f1528155f84bf60e59 > Proxy: Adding proxy_cache_key emedded variable > > This value being able to be set as part of response headers allows for greater > debugging of caching, and to permit analytics on cache-key distribution. What's the expected difference with using the same value as in the proxy_cache_key directive? Also, shouldn't this be $upstream_cache_key instead, to ensure that a single variable can be used for all protocol-specific modules? [...] -- Maxim Dounin http://mdounin.ru/ From hidinginthebbc at gmail.com Wed Nov 7 07:04:38 2018 From: hidinginthebbc at gmail.com (Thomas Peterson) Date: Wed, 07 Nov 2018 07:04:38 +0000 Subject: [PATCH] Proxy: Adding proxy_cache_key emedded variable In-Reply-To: <20181106191524.GA56558@mdounin.ru> References: <41a499230eb674b1b3ec.1541235602@dhcp-9c60.meeting.ietf.org> <20181106191524.GA56558@mdounin.ru> Message-ID: <30DE41DD-18C5-4870-96C5-E5E08AD078F3@gmail.com> To answer your first point around the proxy_cache_key directive, this is to cover for the scenario where a requesting client (or further upstream client) does not have access to the server's proxy_cache_key directive and in a response wants to confirm what actual key was used, not just what the configuration declares. For my own particular deployment this is not a header I would expose to the public, but between tiers in my load balancer hierarchy and when troubleshooting cache performance. As for renaming the variable, I'm more than happy to do so if you feel that's more appropriate. I chose its current name as the change is part of the proxy codebase, not of upstream. Regards ?On 06/11/2018, 19:15, "nginx-devel on behalf of Maxim Dounin" wrote: Hello! On Sat, Nov 03, 2018 at 09:00:02AM +0000, Thomas Peterson wrote: > # HG changeset patch > # User Thomas Peterson > # Date 1541231609 0 > # Sat Nov 03 07:53:29 2018 +0000 > # Node ID 41a499230eb674b1b3ec7cfd093f3a074f9a0d09 > # Parent bddacdaaec9ef174504899f1528155f84bf60e59 > Proxy: Adding proxy_cache_key emedded variable > > This value being able to be set as part of response headers allows for greater > debugging of caching, and to permit analytics on cache-key distribution. What's the expected difference with using the same value as in the proxy_cache_key directive? Also, shouldn't this be $upstream_cache_key instead, to ensure that a single variable can be used for all protocol-specific modules? [...] -- Maxim Dounin http://mdounin.ru/ _______________________________________________ nginx-devel mailing list nginx-devel at nginx.org http://mailman.nginx.org/mailman/listinfo/nginx-devel From xeioex at nginx.com Wed Nov 7 15:41:48 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 07 Nov 2018 15:41:48 +0000 Subject: [njs] Fixed accumulative flag in CLI file mode. Message-ID: details: http://hg.nginx.org/njs/rev/f174a6ad9c3c branches: changeset: 640:f174a6ad9c3c user: Dmitry Volyntsev date: Wed Nov 07 18:41:25 2018 +0300 description: Fixed accumulative flag in CLI file mode. diffstat: njs/njs_shell.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 0372810c0d98 -r f174a6ad9c3c njs/njs_shell.c --- a/njs/njs_shell.c Tue Nov 06 20:57:53 2018 +0300 +++ b/njs/njs_shell.c Wed Nov 07 18:41:25 2018 +0300 @@ -145,7 +145,7 @@ main(int argc, char **argv) nxt_memzero(&vm_options, sizeof(njs_vm_opt_t)); - vm_options.accumulative = 1; + vm_options.accumulative = opts.interactive; vm_options.backtrace = 1; vm_options.sandbox = opts.sandbox; From xeioex at nginx.com Wed Nov 7 15:41:48 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 07 Nov 2018 15:41:48 +0000 Subject: [njs] Added njs_vm_retval_dump(). Message-ID: details: http://hg.nginx.org/njs/rev/f5ba2d1d3752 branches: changeset: 641:f5ba2d1d3752 user: Dmitry Volyntsev date: Wed Nov 07 18:41:28 2018 +0300 description: Added njs_vm_retval_dump(). diffstat: njs/njs.c | 18 ++++++++++++++++-- njs/njs.h | 10 ++++++---- njs/njs_shell.c | 2 +- 3 files changed, 23 insertions(+), 7 deletions(-) diffs (74 lines): diff -r f174a6ad9c3c -r f5ba2d1d3752 njs/njs.c --- a/njs/njs.c Wed Nov 07 18:41:25 2018 +0300 +++ b/njs/njs.c Wed Nov 07 18:41:28 2018 +0300 @@ -671,7 +671,8 @@ njs_vm_memory_error(njs_vm_t *vm) } -njs_ret_t njs_vm_retval_to_ext_string(njs_vm_t *vm, nxt_str_t *retval) +njs_ret_t +njs_vm_retval_to_ext_string(njs_vm_t *vm, nxt_str_t *dst) { if (vm->top_frame == NULL) { /* An exception was thrown during compilation. */ @@ -679,7 +680,20 @@ njs_ret_t njs_vm_retval_to_ext_string(nj njs_vm_init(vm); } - return njs_vm_value_to_ext_string(vm, retval, &vm->retval, 1); + return njs_vm_value_to_ext_string(vm, dst, &vm->retval, 1); +} + + +njs_ret_t +njs_vm_retval_dump(njs_vm_t *vm, nxt_str_t *dst, nxt_uint_t indent) +{ + if (vm->top_frame == NULL) { + /* An exception was thrown during compilation. */ + + njs_vm_init(vm); + } + + return njs_vm_value_dump(vm, dst, &vm->retval, 1); } diff -r f174a6ad9c3c -r f5ba2d1d3752 njs/njs.h --- a/njs/njs.h Wed Nov 07 18:41:25 2018 +0300 +++ b/njs/njs.h Wed Nov 07 18:41:28 2018 +0300 @@ -200,8 +200,12 @@ NXT_EXPORT nxt_int_t njs_value_string_co NXT_EXPORT njs_ret_t njs_vm_value_to_ext_string(njs_vm_t *vm, nxt_str_t *dst, const njs_value_t *src, nxt_uint_t handle_exception); -NXT_EXPORT njs_ret_t njs_vm_retval_to_ext_string(njs_vm_t *vm, - nxt_str_t *retval); +NXT_EXPORT njs_ret_t njs_vm_retval_to_ext_string(njs_vm_t *vm, nxt_str_t *dst); + +NXT_EXPORT njs_ret_t njs_vm_value_dump(njs_vm_t *vm, nxt_str_t *dst, + const njs_value_t *value, nxt_uint_t indent); +NXT_EXPORT njs_ret_t njs_vm_retval_dump(njs_vm_t *vm, nxt_str_t *dst, + nxt_uint_t indent); NXT_EXPORT void njs_vm_memory_error(njs_vm_t *vm); @@ -226,8 +230,6 @@ NXT_EXPORT nxt_int_t njs_value_is_string NXT_EXPORT nxt_int_t njs_value_is_object(const njs_value_t *value); NXT_EXPORT nxt_int_t njs_value_is_function(const njs_value_t *value); -NXT_EXPORT njs_ret_t njs_vm_value_dump(njs_vm_t *vm, nxt_str_t *retval, - const njs_value_t *value, nxt_uint_t indent); NXT_EXPORT njs_ret_t njs_vm_object_alloc(njs_vm_t *vm, njs_value_t *retval, ...); NXT_EXPORT njs_value_t *njs_vm_object_prop(njs_vm_t *vm, diff -r f174a6ad9c3c -r f5ba2d1d3752 njs/njs_shell.c --- a/njs/njs_shell.c Wed Nov 07 18:41:25 2018 +0300 +++ b/njs/njs_shell.c Wed Nov 07 18:41:28 2018 +0300 @@ -452,7 +452,7 @@ njs_process_script(njs_vm_t *vm, njs_opt ret = njs_vm_run(vm); } - if (njs_vm_value_dump(vm, out, njs_vm_retval(vm), 1) != NXT_OK) { + if (njs_vm_retval_dump(vm, out, 1) != NXT_OK) { *out = nxt_string_value("failed to get retval from VM"); return NXT_ERROR; } From xeioex at nginx.com Wed Nov 7 15:41:48 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 07 Nov 2018 15:41:48 +0000 Subject: [njs] njs_vm_run() is simplified. Message-ID: details: http://hg.nginx.org/njs/rev/6ebf35347eee branches: changeset: 642:6ebf35347eee user: Dmitry Volyntsev date: Wed Nov 07 18:41:29 2018 +0300 description: njs_vm_run() is simplified. diffstat: njs/njs.c | 59 +++++++++++++++++--------------------------------------- njs/njs.h | 1 + njs/njs_shell.c | 1 + 3 files changed, 20 insertions(+), 41 deletions(-) diffs (131 lines): diff -r f5ba2d1d3752 -r 6ebf35347eee njs/njs.c --- a/njs/njs.c Wed Nov 07 18:41:28 2018 +0300 +++ b/njs/njs.c Wed Nov 07 18:41:29 2018 +0300 @@ -183,8 +183,6 @@ njs_vm_create(njs_vm_opt_t *options) if (nxt_slow_path(ret != NXT_OK)) { return NULL; } - - vm->retval = njs_value_void; } } @@ -283,6 +281,13 @@ njs_vm_compile(njs_vm_t *vm, u_char **st vm->scope_size = parser->scope_size; vm->variables_hash = parser->scope->variables; + if (vm->options.init) { + ret = njs_vm_init(vm); + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + } + return NJS_OK; fail: @@ -360,8 +365,6 @@ njs_vm_clone(njs_vm_t *vm, njs_external_ goto fail; } - nvm->retval = njs_value_void; - return nvm; } @@ -436,6 +439,10 @@ njs_vm_init(njs_vm_t *vm) vm->trace.handler = njs_parser_trace_handler; vm->trace.data = vm; + if (njs_is_null(&vm->retval)) { + vm->retval = njs_value_void; + } + return NXT_OK; } @@ -558,12 +565,9 @@ njs_vm_post_event(njs_vm_t *vm, njs_vm_e nxt_int_t njs_vm_run(njs_vm_t *vm) { - nxt_str_t s; nxt_int_t ret; - nxt_thread_log_debug("RUN:"); - - if (vm->backtrace != NULL) { + if (nxt_slow_path(vm->backtrace != NULL)) { nxt_array_reset(vm->backtrace); } @@ -573,42 +577,15 @@ njs_vm_run(njs_vm_t *vm) ret = njs_vm_handle_events(vm); } - if (nxt_slow_path(ret == NXT_AGAIN)) { - nxt_thread_log_debug("VM: AGAIN"); - return ret; - } + switch (ret) { + case NJS_STOP: + return NJS_OK; - if (nxt_slow_path(ret != NJS_STOP)) { - nxt_thread_log_debug("VM: ERROR"); + case NXT_AGAIN: + case NXT_ERROR: + default: return ret; } - - if (vm->retval.type == NJS_NUMBER) { - nxt_thread_log_debug("VM: %f", vm->retval.data.u.number); - - } else if (vm->retval.type == NJS_BOOLEAN) { - nxt_thread_log_debug("VM: boolean: %d", vm->retval.data.truth); - - } else if (vm->retval.type == NJS_STRING) { - - if (njs_vm_value_to_ext_string(vm, &s, &vm->retval, 0) == NJS_OK) { - nxt_thread_log_debug("VM: '%V'", &s); - } - - } else if (vm->retval.type == NJS_FUNCTION) { - nxt_thread_log_debug("VM: function"); - - } else if (vm->retval.type == NJS_NULL) { - nxt_thread_log_debug("VM: null"); - - } else if (vm->retval.type == NJS_VOID) { - nxt_thread_log_debug("VM: void"); - - } else { - nxt_thread_log_debug("VM: unknown: %d", vm->retval.type); - } - - return NJS_OK; } diff -r f5ba2d1d3752 -r 6ebf35347eee njs/njs.h --- a/njs/njs.h Wed Nov 07 18:41:28 2018 +0300 +++ b/njs/njs.h Wed Nov 07 18:41:29 2018 +0300 @@ -143,6 +143,7 @@ typedef struct { njs_vm_ops_t *ops; uint8_t trailer; /* 1 bit */ + uint8_t init; /* 1 bit */ uint8_t accumulative; /* 1 bit */ uint8_t backtrace; /* 1 bit */ uint8_t sandbox; /* 1 bit */ diff -r f5ba2d1d3752 -r 6ebf35347eee njs/njs_shell.c --- a/njs/njs_shell.c Wed Nov 07 18:41:28 2018 +0300 +++ b/njs/njs_shell.c Wed Nov 07 18:41:29 2018 +0300 @@ -145,6 +145,7 @@ main(int argc, char **argv) nxt_memzero(&vm_options, sizeof(njs_vm_opt_t)); + vm_options.init = !opts.interactive; vm_options.accumulative = opts.interactive; vm_options.backtrace = 1; vm_options.sandbox = opts.sandbox; From mdounin at mdounin.ru Wed Nov 7 15:45:08 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 7 Nov 2018 18:45:08 +0300 Subject: [PATCH] Proxy: Adding proxy_cache_key emedded variable In-Reply-To: <30DE41DD-18C5-4870-96C5-E5E08AD078F3@gmail.com> References: <41a499230eb674b1b3ec.1541235602@dhcp-9c60.meeting.ietf.org> <20181106191524.GA56558@mdounin.ru> <30DE41DD-18C5-4870-96C5-E5E08AD078F3@gmail.com> Message-ID: <20181107154508.GF56558@mdounin.ru> Hello! On Wed, Nov 07, 2018 at 07:04:38AM +0000, Thomas Peterson wrote: > To answer your first point around the proxy_cache_key directive, > this is to cover for the scenario where a requesting client (or > further upstream client) does not have access to the server's > proxy_cache_key directive and in a response wants to confirm > what actual key was used, not just what the configuration > declares. For my own particular deployment this is not a header > I would expose to the public, but between tiers in my load > balancer hierarchy and when troubleshooting cache performance. The point is that there shouldn't much difference between using something like proxy_cache_key $scheme$proxy_host$uri$is_args$args; add_header X-Cache-Key $proxy_cache_key; and using proxy_cache_key $scheme$proxy_host$uri$is_args$args; add_header X-Cache-Key $scheme$proxy_host$uri$is_args$args; instead - that is, using the same value directly. Or you may even do something like set $cache_key $scheme$proxy_host$uri$is_args$args; proxy_cache_key $cache_key; add_header X-Cache-Key $cache_key; so they key used will be guaranteed to match one in the variable, also providing an easy access. While "wants to confirm what actual key was used, not just what the configuration declares" might be the reason, it looks more like a development and/or debugging task. Could you please clarify why the above methods does not work in your case, and how often the actual key used was different from one declared in the configuration in your practice? > As for renaming the variable, I'm more than happy to do so if > you feel that's more appropriate. I chose its current name as > the change is part of the proxy codebase, not of upstream. The point is that this shouldn't be in the proxy codebase. -- Maxim Dounin http://mdounin.ru/ From vbart at nginx.com Thu Nov 8 13:46:07 2018 From: vbart at nginx.com (Valentin Bartenev) Date: Thu, 08 Nov 2018 13:46:07 +0000 Subject: [njs] Fixed misplaced njs_internal_error(). Message-ID: details: http://hg.nginx.org/njs/rev/c5a3ac902bc2 branches: changeset: 643:c5a3ac902bc2 user: Valentin Bartenev date: Thu Nov 08 16:45:54 2018 +0300 description: Fixed misplaced njs_internal_error(). diffstat: njs/njs_variable.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diffs (16 lines): diff -r 6ebf35347eee -r c5a3ac902bc2 njs/njs_variable.c --- a/njs/njs_variable.c Wed Nov 07 18:41:29 2018 +0300 +++ b/njs/njs_variable.c Thu Nov 08 16:45:54 2018 +0300 @@ -83,10 +83,11 @@ njs_builtin_add(njs_vm_t *vm, njs_parser ret = nxt_lvlhsh_insert(&scope->variables, &lhq); if (nxt_fast_path(ret == NXT_OK)) { - njs_internal_error(vm, "lvlhsh insert failed"); return var; } + njs_internal_error(vm, "lvlhsh insert failed"); + nxt_mem_cache_free(vm->mem_cache_pool, var->name.start); nxt_mem_cache_free(vm->mem_cache_pool, var); From maxim at nginx.com Thu Nov 8 14:19:19 2018 From: maxim at nginx.com (Maxim Konovalov) Date: Thu, 8 Nov 2018 17:19:19 +0300 Subject: cache: move open to thread pool In-Reply-To: References: <20180808181653.GX56558@mdounin.ru> <20180810113946.GG56558@mdounin.ru> <20180903160903.GI56558@mdounin.ru> Message-ID: Hi Ka-Hing, would you mind to test Roman's most recent patches that add "aio_open" directive? http://mailman.nginx.org/pipermail/nginx-devel/2018-November/011538.html We are looking for overall performance and stability metrics and feedback. Much appreciated, Maxim -- Maxim Konovalov From vbart at nginx.com Fri Nov 9 15:06:01 2018 From: vbart at nginx.com (Valentin Bartenev) Date: Fri, 09 Nov 2018 15:06:01 +0000 Subject: [njs] Fixed equality operator with "null" value as right operand. Message-ID: details: http://hg.nginx.org/njs/rev/abec5f8d55a1 branches: changeset: 644:abec5f8d55a1 user: Valentin Bartenev date: Fri Nov 09 18:05:39 2018 +0300 description: Fixed equality operator with "null" value as right operand. diffstat: njs/njs_vm.c | 9 +++++++-- njs/test/njs_unit_test.c | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diffs (33 lines): diff -r c5a3ac902bc2 -r abec5f8d55a1 njs/njs_vm.c --- a/njs/njs_vm.c Thu Nov 08 16:45:54 2018 +0300 +++ b/njs/njs_vm.c Fri Nov 09 18:05:39 2018 +0300 @@ -1519,9 +1519,14 @@ njs_vmcode_not_equal(njs_vm_t *vm, njs_v static nxt_noinline njs_ret_t njs_values_equal(njs_vm_t *vm, const njs_value_t *val1, const njs_value_t *val2) { + nxt_bool_t nv1, nv2; + + nv1 = njs_is_null_or_void(val1); + nv2 = njs_is_null_or_void(val2); + /* Void and null are equal and not comparable with anything else. */ - if (njs_is_null_or_void(val1)) { - return (njs_is_null_or_void(val2)); + if (nv1 || nv2) { + return (nv1 && nv2); } if (njs_is_numeric(val1) && njs_is_numeric(val2)) { diff -r c5a3ac902bc2 -r abec5f8d55a1 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 08 16:45:54 2018 +0300 +++ b/njs/test/njs_unit_test.c Fri Nov 09 18:05:39 2018 +0300 @@ -1025,6 +1025,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("null == false"), nxt_string("false") }, + { nxt_string("0 == null"), + nxt_string("false") }, + { nxt_string("!null"), nxt_string("true") }, From vbart at nginx.com Fri Nov 9 15:20:34 2018 From: vbart at nginx.com (Valentin Bartenev) Date: Fri, 09 Nov 2018 15:20:34 +0000 Subject: [njs] Fixed equality operator when both operands are objects. Message-ID: details: http://hg.nginx.org/njs/rev/025b22bf8c49 branches: changeset: 645:025b22bf8c49 user: Valentin Bartenev date: Thu Nov 08 20:32:45 2018 +0300 description: Fixed equality operator when both operands are objects. diffstat: njs/njs_vm.c | 4 ++++ njs/test/njs_unit_test.c | 6 ++++++ 2 files changed, 10 insertions(+), 0 deletions(-) diffs (30 lines): diff -r abec5f8d55a1 -r 025b22bf8c49 njs/njs_vm.c --- a/njs/njs_vm.c Fri Nov 09 18:05:39 2018 +0300 +++ b/njs/njs_vm.c Thu Nov 08 20:32:45 2018 +0300 @@ -1543,6 +1543,10 @@ njs_values_equal(njs_vm_t *vm, const njs return (val1->data.u.object == val2->data.u.object); } + if (njs_is_object(val1) && njs_is_object(val2)) { + return 0; + } + return njs_trap(vm, NJS_TRAP_NUMBERS); } diff -r abec5f8d55a1 -r 025b22bf8c49 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Fri Nov 09 18:05:39 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Nov 08 20:32:45 2018 +0300 @@ -1136,6 +1136,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("({}) == false"), nxt_string("false") }, + { nxt_string("new Number(1) == new String('1')"), + nxt_string("false") }, + + { nxt_string("var a = Object; a == Object"), + nxt_string("true") }, + { nxt_string("var a = { valueOf: function() { return 5 } }; a == 5"), nxt_string("true") }, From vbart at nginx.com Fri Nov 9 16:23:45 2018 From: vbart at nginx.com (Valentin Bartenev) Date: Fri, 09 Nov 2018 16:23:45 +0000 Subject: [njs] Fixed equality operator with object and string. Message-ID: details: http://hg.nginx.org/njs/rev/7d06ada396d7 branches: changeset: 646:7d06ada396d7 user: Valentin Bartenev date: Fri Nov 09 18:22:01 2018 +0300 description: Fixed equality operator with object and string. diffstat: njs/njs_vm.c | 25 ++++++++++++++++++++++--- njs/test/njs_unit_test.c | 19 +++++++++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diffs (81 lines): diff -r 025b22bf8c49 -r 7d06ada396d7 njs/njs_vm.c --- a/njs/njs_vm.c Thu Nov 08 20:32:45 2018 +0300 +++ b/njs/njs_vm.c Fri Nov 09 18:22:01 2018 +0300 @@ -1519,7 +1519,8 @@ njs_vmcode_not_equal(njs_vm_t *vm, njs_v static nxt_noinline njs_ret_t njs_values_equal(njs_vm_t *vm, const njs_value_t *val1, const njs_value_t *val2) { - nxt_bool_t nv1, nv2; + nxt_bool_t nv1, nv2; + const njs_value_t *hv, *lv; nv1 = njs_is_null_or_void(val1); nv2 = njs_is_null_or_void(val2); @@ -1543,11 +1544,29 @@ njs_values_equal(njs_vm_t *vm, const njs return (val1->data.u.object == val2->data.u.object); } - if (njs_is_object(val1) && njs_is_object(val2)) { + /* Sort values as: numeric < string < objects. */ + + if (val1->type > val2->type) { + hv = val1; + lv = val2; + + } else { + hv = val2; + lv = val1; + } + + /* If "lv" is an object then "hv" can only be another object. */ + if (njs_is_object(lv)) { return 0; } - return njs_trap(vm, NJS_TRAP_NUMBERS); + /* If "hv" is a string then "lv" can only be a numeric. */ + if (njs_is_string(hv)) { + return (lv->data.u.number == njs_string_to_number(hv, 0)); + } + + /* "hv" is an object and "lv" is either a string or a numeric. */ + return njs_trap(vm, NJS_TRAP_COMPARISON); } diff -r 025b22bf8c49 -r 7d06ada396d7 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 08 20:32:45 2018 +0300 +++ b/njs/test/njs_unit_test.c Fri Nov 09 18:22:01 2018 +0300 @@ -1142,6 +1142,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = Object; a == Object"), nxt_string("true") }, + { nxt_string("'1' == new Number(1)"), + nxt_string("true") }, + + { nxt_string("new String('abc') == 'abc'"), + nxt_string("true") }, + + { nxt_string("false == new String('0')"), + nxt_string("true") }, + { nxt_string("var a = { valueOf: function() { return 5 } }; a == 5"), nxt_string("true") }, @@ -1151,6 +1160,16 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = { valueOf: function() { return '5' } }; a == '5'"), nxt_string("true") }, + { nxt_string("var a = { valueOf: function() { return 5 } }; a == '5'"), + nxt_string("true") }, + + { nxt_string("var a = { toString: function() { return true } }; '1' == a"), + nxt_string("true") }, + + { nxt_string("var a = { valueOf: function() { return 'b' }," + " toString: function() { return 'a' } }; a == 'a'"), + nxt_string("false") }, + /* Comparisions. */ { nxt_string("1 < 2"), From hidinginthebbc at gmail.com Fri Nov 9 08:00:59 2018 From: hidinginthebbc at gmail.com (Thomas Peterson) Date: Fri, 9 Nov 2018 08:00:59 +0000 Subject: [PATCH] Proxy: Adding proxy_cache_key emedded variable In-Reply-To: <20181107154508.GF56558@mdounin.ru> References: <41a499230eb674b1b3ec.1541235602@dhcp-9c60.meeting.ietf.org> <20181106191524.GA56558@mdounin.ru> <30DE41DD-18C5-4870-96C5-E5E08AD078F3@gmail.com> <20181107154508.GF56558@mdounin.ru> Message-ID: <2284bf7d-13a2-dd73-27b0-44df55443545@gmail.com> Thanks for your response, I didn't consider using a configuration variable. However upon investigating my patch in greater detail, I have noticed a difference in behaviour. Consider the following configuration: ? proxy_cache_key??? $scheme$proxy_host$request_uri; ? set $var_cache_key $scheme$proxy_host$request_uri; ? add_header Proxy-Cache-Key $proxy_cache_key; ? add_header Var-Cache-Key?? $var_cache_key; I am expecting both of these headers to contain the same value - however in running this in the nginx test harness does not show this, it shows the $proxy_host value being empty when interpolated into $var_cache_key. Attached is the test which should fail against my patch. I'd appreciate it if you could tell me where I am going wrong. Regards On 07/11/2018 15:45, Maxim Dounin wrote: > Hello! > > On Wed, Nov 07, 2018 at 07:04:38AM +0000, Thomas Peterson wrote: > >> To answer your first point around the proxy_cache_key directive, >> this is to cover for the scenario where a requesting client (or >> further upstream client) does not have access to the server's >> proxy_cache_key directive and in a response wants to confirm >> what actual key was used, not just what the configuration >> declares. For my own particular deployment this is not a header >> I would expose to the public, but between tiers in my load >> balancer hierarchy and when troubleshooting cache performance. > The point is that there shouldn't much difference between using > something like > > proxy_cache_key $scheme$proxy_host$uri$is_args$args; > add_header X-Cache-Key $proxy_cache_key; > > and using > > proxy_cache_key $scheme$proxy_host$uri$is_args$args; > add_header X-Cache-Key $scheme$proxy_host$uri$is_args$args; > > instead - that is, using the same value directly. Or you may > even do something like > > set $cache_key $scheme$proxy_host$uri$is_args$args; > proxy_cache_key $cache_key; > add_header X-Cache-Key $cache_key; > > so they key used will be guaranteed to match one in the variable, > also providing an easy access. > > While "wants to confirm what actual key was used, not just what > the configuration declares" might be the reason, it looks more > like a development and/or debugging task. > > Could you please clarify why the above methods does not work in > your case, and how often the actual key used was different from > one declared in the configuration in your practice? > >> As for renaming the variable, I'm more than happy to do so if >> you feel that's more appropriate. I chose its current name as >> the change is part of the proxy codebase, not of upstream. > The point is that this shouldn't be in the proxy codebase. > -------------- next part -------------- A non-text attachment was scrubbed... Name: proxy_cache_key_variable.t Type: application/x-troff Size: 2783 bytes Desc: not available URL: From wy7980 at gmail.com Sat Nov 10 12:16:35 2018 From: wy7980 at gmail.com (wy7980) Date: Sat, 10 Nov 2018 20:16:35 +0800 Subject: fix bug of fmt overflow Message-ID: # HG changeset patch # User wy7980 # Date 1541824641 -28800 # Sat Nov 10 12:37:21 2018 +0800 # Node ID e93ac0fd29c1f49e7dd49ff5e1efd58c009d359a # Parent a2506436986ae9cf941fd9477aa77e28f501e11d fix bug of fmt overflow diff -r a2506436986a -r e93ac0fd29c1 src/core/ngx_string.c --- a/src/core/ngx_string.c Tue Nov 06 16:32:09 2018 +0300 +++ b/src/core/ngx_string.c Sat Nov 10 12:37:21 2018 +0800 @@ -172,8 +172,9 @@ ngx_uint_t width, sign, hex, max_width, frac_width, scale, n; ngx_str_t *v; ngx_variable_value_t *vv; - - while (*fmt && buf < last) { + char *fmt_last = (char *)fmt + strlen(fmt); + + while (*fmt && buf < last && fmt < fmt_last) { /* * "buf < last" means that we could copy at least one character: -------------- next part -------------- An HTML attachment was scrubbed... URL: From vbart at nginx.com Sat Nov 10 12:29:41 2018 From: vbart at nginx.com (Valentin V. Bartenev) Date: Sat, 10 Nov 2018 15:29:41 +0300 Subject: fix bug of fmt overflow In-Reply-To: References: Message-ID: <5548245.hASaZNxDgi@vbart-laptop> On Saturday, 10 November 2018 15:16:35 MSK wy7980 wrote: > # HG changeset patch > # User wy7980 > # Date 1541824641 -28800 > # Sat Nov 10 12:37:21 2018 +0800 > # Node ID e93ac0fd29c1f49e7dd49ff5e1efd58c009d359a > # Parent a2506436986ae9cf941fd9477aa77e28f501e11d > > fix bug of fmt overflow > > diff -r a2506436986a -r e93ac0fd29c1 src/core/ngx_string.c > --- a/src/core/ngx_string.c Tue Nov 06 16:32:09 2018 +0300 > +++ b/src/core/ngx_string.c Sat Nov 10 12:37:21 2018 +0800 > @@ -172,8 +172,9 @@ > ngx_uint_t width, sign, hex, max_width, frac_width, scale, > n; > ngx_str_t *v; > ngx_variable_value_t *vv; > - > - while (*fmt && buf < last) { > + char *fmt_last = (char *)fmt + strlen(fmt); > + > + while (*fmt && buf < last && fmt < fmt_last) { > > /* > * "buf < last" means that we could copy at least one character: > Could you clarify what bug you are trying to fix? There should be no overflows unless you specified an incorrect format string. wbr, Valentin V. Bartenev From wy7980 at gmail.com Sat Nov 10 13:18:25 2018 From: wy7980 at gmail.com (wy7980) Date: Sat, 10 Nov 2018 21:18:25 +0800 Subject: fix bug of fmt overflow In-Reply-To: <5548245.hASaZNxDgi@vbart-laptop> References: <5548245.hASaZNxDgi@vbart-laptop> Message-ID: Yes, I just mean the incorrect format string of fmt, it can be dangerous. Valentin V. Bartenev ?2018?11?10??? ??8:29??? > On Saturday, 10 November 2018 15:16:35 MSK wy7980 wrote: > > # HG changeset patch > > # User wy7980 > > # Date 1541824641 -28800 > > # Sat Nov 10 12:37:21 2018 +0800 > > # Node ID e93ac0fd29c1f49e7dd49ff5e1efd58c009d359a > > # Parent a2506436986ae9cf941fd9477aa77e28f501e11d > > > > fix bug of fmt overflow > > > > diff -r a2506436986a -r e93ac0fd29c1 src/core/ngx_string.c > > --- a/src/core/ngx_string.c Tue Nov 06 16:32:09 2018 +0300 > > +++ b/src/core/ngx_string.c Sat Nov 10 12:37:21 2018 +0800 > > @@ -172,8 +172,9 @@ > > ngx_uint_t width, sign, hex, max_width, frac_width, > scale, > > n; > > ngx_str_t *v; > > ngx_variable_value_t *vv; > > - > > - while (*fmt && buf < last) { > > + char *fmt_last = (char *)fmt + strlen(fmt); > > + > > + while (*fmt && buf < last && fmt < fmt_last) { > > > > /* > > * "buf < last" means that we could copy at least one character: > > > > > Could you clarify what bug you are trying to fix? > There should be no overflows unless you specified an incorrect format > string. > > wbr, Valentin V. Bartenev > > > > _______________________________________________ > 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 vbart at nginx.com Sat Nov 10 15:10:17 2018 From: vbart at nginx.com (Valentin V. Bartenev) Date: Sat, 10 Nov 2018 18:10:17 +0300 Subject: fix bug of fmt overflow In-Reply-To: References: <5548245.hASaZNxDgi@vbart-laptop> Message-ID: <2338167.mgNxyRjs8k@vbart-laptop> On Saturday, 10 November 2018 16:18:25 MSK wy7980 wrote: > Yes, I just mean the incorrect format string of fmt, it can be dangerous. [..] If the format string is incorrect, e.g. if it isn't terminated with a null character or have incorrect specifiers, or the number of them is bigger than the number of supplied arguments then it's dangerous anyway (with or without your patch). So, please don't supply incorrect format string in your code. wbr, Valentin V. Bartenev From vbart at nginx.com Mon Nov 12 14:23:04 2018 From: vbart at nginx.com (Valentin Bartenev) Date: Mon, 12 Nov 2018 14:23:04 +0000 Subject: [njs] RegExp: fixed a case when lastIndex is greater than string size. Message-ID: details: http://hg.nginx.org/njs/rev/f1da98bdd82f branches: changeset: 647:f1da98bdd82f user: Valentin Bartenev date: Mon Nov 12 17:22:14 2018 +0300 description: RegExp: fixed a case when lastIndex is greater than string size. Previously, it resulted in: "InternalError: pcre_exec() failed: -32" due to negative string size caused by subtraction of last_index. diffstat: njs/njs_regexp.c | 62 ++++++++++++++++++++++++----------------------- njs/test/njs_unit_test.c | 3 ++ 2 files changed, 35 insertions(+), 30 deletions(-) diffs (91 lines): diff -r 7d06ada396d7 -r f1da98bdd82f njs/njs_regexp.c --- a/njs/njs_regexp.c Fri Nov 09 18:22:01 2018 +0300 +++ b/njs/njs_regexp.c Mon Nov 12 17:22:14 2018 +0300 @@ -644,42 +644,44 @@ njs_regexp_prototype_exec(njs_vm_t *vm, (void) njs_string_prop(&string, value); - utf8 = NJS_STRING_BYTE; - type = NJS_REGEXP_BYTE; - - if (string.length != 0) { - utf8 = NJS_STRING_ASCII; - type = NJS_REGEXP_UTF8; - - if (string.length != string.size) { - utf8 = NJS_STRING_UTF8; - } - } + if (string.size >= regexp->last_index) { + utf8 = NJS_STRING_BYTE; + type = NJS_REGEXP_BYTE; - pattern = regexp->pattern; - - if (nxt_regex_is_valid(&pattern->regex[type])) { - string.start += regexp->last_index; - string.size -= regexp->last_index; + if (string.length != 0) { + utf8 = NJS_STRING_ASCII; + type = NJS_REGEXP_UTF8; - match_data = nxt_regex_match_data(&pattern->regex[type], - vm->regex_context); - if (nxt_slow_path(match_data == NULL)) { - njs_memory_error(vm); - return NXT_ERROR; + if (string.length != string.size) { + utf8 = NJS_STRING_UTF8; + } } - ret = njs_regexp_match(vm, &pattern->regex[type], string.start, - string.size, match_data); - if (ret >= 0) { - return njs_regexp_exec_result(vm, regexp, utf8, string.start, - match_data); - } + pattern = regexp->pattern; + + if (nxt_regex_is_valid(&pattern->regex[type])) { + string.start += regexp->last_index; + string.size -= regexp->last_index; + + match_data = nxt_regex_match_data(&pattern->regex[type], + vm->regex_context); + if (nxt_slow_path(match_data == NULL)) { + njs_memory_error(vm); + return NXT_ERROR; + } - if (nxt_slow_path(ret != NXT_REGEX_NOMATCH)) { - nxt_regex_match_data_free(match_data, vm->regex_context); + ret = njs_regexp_match(vm, &pattern->regex[type], string.start, + string.size, match_data); + if (ret >= 0) { + return njs_regexp_exec_result(vm, regexp, utf8, string.start, + match_data); + } - return NXT_ERROR; + if (nxt_slow_path(ret != NXT_REGEX_NOMATCH)) { + nxt_regex_match_data_free(match_data, vm->regex_context); + + return NXT_ERROR; + } } } diff -r 7d06ada396d7 -r f1da98bdd82f njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Fri Nov 09 18:22:01 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Nov 12 17:22:14 2018 +0300 @@ -5973,6 +5973,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = /^$/.exec(''); a.length +' '+ a"), nxt_string("1 ") }, + { nxt_string("var r = /3/g; r.exec('123') +' '+ r.exec('3')"), + nxt_string("3 null") }, + { nxt_string("var r = /??/ig;" "var a = r.exec('???');" "r.lastIndex +' '+ a +' '+ " From xeioex at nginx.com Mon Nov 12 15:38:17 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 12 Nov 2018 15:38:17 +0000 Subject: [njs] Allowing variables and functions to be redeclared. Message-ID: details: http://hg.nginx.org/njs/rev/46364c618468 branches: changeset: 648:46364c618468 user: Dmitry Volyntsev date: Mon Nov 12 18:27:05 2018 +0300 description: Allowing variables and functions to be redeclared. diffstat: njs/njs_function.c | 2 +- njs/njs_function.h | 6 ++---- njs/njs_generator.c | 9 +++++++-- njs/njs_parser.c | 6 +++--- njs/njs_variable.c | 17 +++++++---------- njs/test/njs_unit_test.c | 33 ++++++++++++++++++++++++++++----- 6 files changed, 48 insertions(+), 25 deletions(-) diffs (173 lines): diff -r f1da98bdd82f -r 46364c618468 njs/njs_function.c --- a/njs/njs_function.c Mon Nov 12 17:22:14 2018 +0300 +++ b/njs/njs_function.c Mon Nov 12 18:27:05 2018 +0300 @@ -412,7 +412,7 @@ njs_function_call(njs_vm_t *vm, njs_inde frame->return_address = vm->current + advance; lambda = function->u.lambda; - vm->current = lambda->u.start; + vm->current = lambda->start; #if (NXT_DEBUG) vm->scopes[NJS_SCOPE_CALLEE_ARGUMENTS] = NULL; diff -r f1da98bdd82f -r 46364c618468 njs/njs_function.h --- a/njs/njs_function.h Mon Nov 12 17:22:14 2018 +0300 +++ b/njs/njs_function.h Mon Nov 12 18:27:05 2018 +0300 @@ -36,10 +36,8 @@ struct njs_function_lambda_s { njs_value_t *local_scope; njs_value_t *closure_scope; - union { - u_char *start; - njs_parser_t *parser; - } u; + u_char *start; + njs_parser_t *parser; }; diff -r f1da98bdd82f -r 46364c618468 njs/njs_generator.c --- a/njs/njs_generator.c Mon Nov 12 17:22:14 2018 +0300 +++ b/njs/njs_generator.c Mon Nov 12 18:27:05 2018 +0300 @@ -2007,6 +2007,11 @@ njs_generate_function_declaration(njs_vm return NXT_ERROR; } + if (!njs_is_function(&var->value)) { + /* A variable was declared with the same name. */ + return NXT_OK; + } + lambda = var->value.data.u.function->u.lambda; ret = njs_generate_function_scope(vm, lambda, node); @@ -2032,7 +2037,7 @@ njs_generate_function_scope(njs_vm_t *vm nxt_array_t *closure; njs_parser_t *parser; - parser = lambda->u.parser; + parser = lambda->parser; node = node->right; parser->code_size += node->scope->argument_closures @@ -2058,7 +2063,7 @@ njs_generate_function_scope(njs_vm_t *vm lambda->local_size = parser->scope_size; lambda->local_scope = parser->local_scope; - lambda->u.start = parser->code_start; + lambda->start = parser->code_start; } return ret; diff -r f1da98bdd82f -r 46364c618468 njs/njs_parser.c --- a/njs/njs_parser.c Mon Nov 12 17:22:14 2018 +0300 +++ b/njs/njs_parser.c Mon Nov 12 18:27:05 2018 +0300 @@ -496,7 +496,7 @@ njs_parser_function_declaration(njs_vm_t return NJS_TOKEN_ERROR; } - function->u.lambda->u.parser = parser; + function->u.lambda->parser = parser; token = njs_parser_function_lambda(vm, function->u.lambda, token); @@ -578,7 +578,7 @@ njs_parser_function_expression(njs_vm_t } node->u.value.data.u.lambda = lambda; - lambda->u.parser = parser; + lambda->parser = parser; token = njs_parser_function_lambda(vm, lambda, token); @@ -619,7 +619,7 @@ njs_parser_function_lambda(njs_vm_t *vm, njs_variable_t *arg; njs_parser_node_t *node, *body, *last; - parser = lambda->u.parser; + parser = lambda->parser; ret = njs_parser_scope_begin(vm, parser, NJS_SCOPE_FUNCTION); if (nxt_slow_path(ret != NXT_OK)) { diff -r f1da98bdd82f -r 46364c618468 njs/njs_variable.c --- a/njs/njs_variable.c Mon Nov 12 17:22:14 2018 +0300 +++ b/njs/njs_variable.c Mon Nov 12 18:27:05 2018 +0300 @@ -119,12 +119,17 @@ njs_variable_add(njs_vm_t *vm, njs_parse } } + if (nxt_lvlhsh_find(&scope->variables, &lhq) == NXT_OK) { + var = lhq.value; + return var; + } + var = njs_variable_alloc(vm, &lhq.key, type); if (nxt_slow_path(var == NULL)) { return var; } - lhq.replace = vm->options.accumulative; + lhq.replace = 0; lhq.value = var; lhq.pool = vm->mem_cache_pool; @@ -137,15 +142,7 @@ njs_variable_add(njs_vm_t *vm, njs_parse nxt_mem_cache_free(vm->mem_cache_pool, var->name.start); nxt_mem_cache_free(vm->mem_cache_pool, var); - if (ret == NXT_ERROR) { - return NULL; - } - - /* ret == NXT_DECLINED. */ - - njs_parser_syntax_error(vm, parser, "Identifier \"%.*s\" " - "has already been declared", - (int) lhq.key.length, lhq.key.start); + njs_type_error(vm, "lvlhsh insert failed"); return NULL; } diff -r f1da98bdd82f -r 46364c618468 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Nov 12 17:22:14 2018 +0300 +++ b/njs/test/njs_unit_test.c Mon Nov 12 18:27:05 2018 +0300 @@ -75,11 +75,34 @@ static njs_unit_test_t njs_test[] = { nxt_string("if(1)if(0){0?0:0}else\nvar a\nelse\nvar b"), nxt_string("undefined") }, - { nxt_string("function f(){} function f(){}"), - nxt_string("SyntaxError: Identifier \"f\" has already been declared in 1") }, - - { nxt_string("var f = 1; function f() {}"), - nxt_string("SyntaxError: Identifier \"f\" has already been declared in 1") }, + { nxt_string("var a = 1; var a; a"), + nxt_string("1") }, + + { nxt_string("(function (x) {if (x) { var a = 3; return a} else { var a = 4; return a}})(1)"), + nxt_string("3") }, + + { nxt_string("(function (x) {if (x) { var a = 3; return a} else { var a = 4; return a}})(0)"), + nxt_string("4") }, + + { nxt_string("function f(){return 2}; var f; f()"), + nxt_string("2") }, + + { nxt_string("function f(){return 2}; var f = 1; f()"), + nxt_string("TypeError: number is not a function") }, + + { nxt_string("function f(){return 1}; function f(){return 2}; f()"), + nxt_string("2") }, + + { nxt_string("var f = 1; function f() {}; f"), + nxt_string("1") }, + +#if 0 /* TODO */ + { nxt_string("var a; Object.getOwnPropertyDescriptor(this, 'a').value"), + nxt_string("undefined") }, + + { nxt_string("this.a = 1; a"), + nxt_string("1") }, +#endif { nxt_string("f() = 1"), nxt_string("ReferenceError: Invalid left-hand side in assignment in 1") }, From pluknet at nginx.com Mon Nov 12 17:21:31 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Mon, 12 Nov 2018 17:21:31 +0000 Subject: [njs] Fixed building by SunC 5.15. Message-ID: details: http://hg.nginx.org/njs/rev/81d029f4139c branches: changeset: 649:81d029f4139c user: Sergey Kandaurov date: Mon Nov 12 20:08:36 2018 +0300 description: Fixed building by SunC 5.15. diffstat: njs/njs_shell.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 46364c618468 -r 81d029f4139c njs/njs_shell.c --- a/njs/njs_shell.c Mon Nov 12 18:27:05 2018 +0300 +++ b/njs/njs_shell.c Mon Nov 12 20:08:36 2018 +0300 @@ -227,7 +227,7 @@ njs_externals_init(njs_vm_t *vm) njs_value_t *value; const njs_extern_t *proto; - static const nxt_str_t name = nxt_string_value("console"); + static const nxt_str_t name = nxt_string("console"); proto = njs_vm_external_prototype(vm, &njs_externals[0]); if (proto == NULL) { From pluknet at nginx.com Tue Nov 13 11:17:29 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Tue, 13 Nov 2018 11:17:29 +0000 Subject: [njs] Fixed unit tests for SunC. Message-ID: details: http://hg.nginx.org/njs/rev/19a9743c00c8 branches: changeset: 650:19a9743c00c8 user: Sergey Kandaurov date: Tue Nov 13 14:16:54 2018 +0300 description: Fixed unit tests for SunC. diffstat: njs/test/njs_unit_test.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diffs (14 lines): diff -r 81d029f4139c -r 19a9743c00c8 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Mon Nov 12 20:08:36 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Nov 13 14:16:54 2018 +0300 @@ -9071,8 +9071,10 @@ static njs_unit_test_t njs_test[] = { nxt_string("Math.sinh(-Infinity)"), nxt_string("-Infinity") }, +#ifndef __SUNPRO_C /* Sun C 5.15: round error */ { nxt_string("Math.sinh(1) - (Math.E - 1/Math.E)/2"), nxt_string("0") }, +#endif { nxt_string("Math.sqrt()"), nxt_string("NaN") }, From vl at nginx.com Tue Nov 13 13:41:20 2018 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 13 Nov 2018 13:41:20 +0000 Subject: [nginx] Version bump. Message-ID: details: http://hg.nginx.org/nginx/rev/2e7c4c3b0644 branches: changeset: 7390:2e7c4c3b0644 user: Vladimir Homutov date: Tue Nov 13 14:42:47 2018 +0300 description: Version bump. diffstat: src/core/nginx.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diffs (14 lines): diff -r a2506436986a -r 2e7c4c3b0644 src/core/nginx.h --- a/src/core/nginx.h Tue Nov 06 16:32:09 2018 +0300 +++ b/src/core/nginx.h Tue Nov 13 14:42:47 2018 +0300 @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1015006 -#define NGINX_VERSION "1.15.6" +#define nginx_version 1015007 +#define NGINX_VERSION "1.15.7" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD From vl at nginx.com Tue Nov 13 13:41:22 2018 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 13 Nov 2018 13:41:22 +0000 Subject: [nginx] Stream: fixed possible use of a freed connection. Message-ID: details: http://hg.nginx.org/nginx/rev/27559d4a5151 branches: changeset: 7391:27559d4a5151 user: Vladimir Homutov date: Wed Nov 07 13:22:14 2018 +0300 description: Stream: fixed possible use of a freed connection. The session handler may result in session termination, thus a connection pool (from which c->udp was allocated) may be destroyed. diffstat: src/event/ngx_event_udp.c | 7 ++++++- 1 files changed, 6 insertions(+), 1 deletions(-) diffs (24 lines): diff -r 2e7c4c3b0644 -r 27559d4a5151 src/event/ngx_event_udp.c --- a/src/event/ngx_event_udp.c Tue Nov 13 14:42:47 2018 +0300 +++ b/src/event/ngx_event_udp.c Wed Nov 07 13:22:14 2018 +0300 @@ -261,7 +261,10 @@ ngx_event_recvmsg(ngx_event_t *ev) rev->handler(rev); - c->udp->buffer = NULL; + if (c->udp) { + c->udp->buffer = NULL; + } + rev->ready = 0; goto next; @@ -561,6 +564,8 @@ ngx_delete_udp_connection(void *data) ngx_connection_t *c = data; ngx_rbtree_delete(&c->listening->rbtree, &c->udp->node); + + c->udp = NULL; } From vl at nginx.com Tue Nov 13 13:41:23 2018 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 13 Nov 2018 13:41:23 +0000 Subject: [nginx] Stream: session completion check code moved to a separate function. Message-ID: details: http://hg.nginx.org/nginx/rev/04ff25798002 branches: changeset: 7392:04ff25798002 user: Vladimir Homutov date: Mon Nov 12 12:05:03 2018 +0300 description: Stream: session completion check code moved to a separate function. The code refactored to simplify the ngx_stream_proxy_process() function and facilitate adding new session termination conditions. diffstat: src/stream/ngx_stream_proxy_module.c | 114 +++++++++++++++++++++++----------- 1 files changed, 76 insertions(+), 38 deletions(-) diffs (138 lines): diff -r 27559d4a5151 -r 04ff25798002 src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Wed Nov 07 13:22:14 2018 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Mon Nov 12 12:05:03 2018 +0300 @@ -73,6 +73,8 @@ static void ngx_stream_proxy_connect_han static ngx_int_t ngx_stream_proxy_test_connect(ngx_connection_t *c); static void ngx_stream_proxy_process(ngx_stream_session_t *s, ngx_uint_t from_upstream, ngx_uint_t do_write); +static ngx_int_t ngx_stream_proxy_test_finalize(ngx_stream_session_t *s, + ngx_uint_t from_upstream); static void ngx_stream_proxy_next_upstream(ngx_stream_session_t *s); static void ngx_stream_proxy_finalize(ngx_stream_session_t *s, ngx_uint_t rc); static u_char *ngx_stream_proxy_log_error(ngx_log_t *log, u_char *buf, @@ -1646,44 +1648,7 @@ ngx_stream_proxy_process(ngx_stream_sess c->log->action = "proxying connection"; - if (c->type == SOCK_DGRAM - && pscf->responses != NGX_MAX_INT32_VALUE - && u->responses >= pscf->responses * u->requests - && !src->buffered && dst && !dst->buffered) - { - handler = c->log->handler; - c->log->handler = NULL; - - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "udp done" - ", packets from/to client:%ui/%ui" - ", bytes from/to client:%O/%O" - ", bytes from/to upstream:%O/%O", - u->requests, u->responses, - s->received, c->sent, u->received, pc ? pc->sent : 0); - - c->log->handler = handler; - - ngx_stream_proxy_finalize(s, NGX_STREAM_OK); - return; - } - - if (c->type == SOCK_STREAM - && src->read->eof && dst && (dst->read->eof || !dst->buffered)) - { - handler = c->log->handler; - c->log->handler = NULL; - - ngx_log_error(NGX_LOG_INFO, c->log, 0, - "%s disconnected" - ", bytes from/to client:%O/%O" - ", bytes from/to upstream:%O/%O", - from_upstream ? "upstream" : "client", - s->received, c->sent, u->received, pc ? pc->sent : 0); - - c->log->handler = handler; - - ngx_stream_proxy_finalize(s, NGX_STREAM_OK); + if (ngx_stream_proxy_test_finalize(s, from_upstream) == NGX_OK) { return; } @@ -1710,6 +1675,79 @@ ngx_stream_proxy_process(ngx_stream_sess } +static ngx_int_t +ngx_stream_proxy_test_finalize(ngx_stream_session_t *s, + ngx_uint_t from_upstream) +{ + ngx_connection_t *c, *pc; + ngx_log_handler_pt handler; + ngx_stream_upstream_t *u; + ngx_stream_proxy_srv_conf_t *pscf; + + pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module); + + c = s->connection; + u = s->upstream; + pc = u->connected ? u->peer.connection : NULL; + + if (c->type == SOCK_DGRAM) { + + if (pscf->responses == NGX_MAX_INT32_VALUE + || u->responses < pscf->responses * u->requests) + { + return NGX_DECLINED; + } + + if (pc == NULL || c->buffered || pc->buffered) { + return NGX_DECLINED; + } + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "udp done" + ", packets from/to client:%ui/%ui" + ", bytes from/to client:%O/%O" + ", bytes from/to upstream:%O/%O", + u->requests, u->responses, + s->received, c->sent, u->received, pc ? pc->sent : 0); + + c->log->handler = handler; + + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); + + return NGX_OK; + } + + /* c->type == SOCK_STREAM */ + + if (pc == NULL + || (!c->read->eof && !pc->read->eof) + || (!c->read->eof && c->buffered) + || (!pc->read->eof && pc->buffered)) + { + return NGX_DECLINED; + } + + handler = c->log->handler; + c->log->handler = NULL; + + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "%s disconnected" + ", bytes from/to client:%O/%O" + ", bytes from/to upstream:%O/%O", + from_upstream ? "upstream" : "client", + s->received, c->sent, u->received, pc ? pc->sent : 0); + + c->log->handler = handler; + + ngx_stream_proxy_finalize(s, NGX_STREAM_OK); + + return NGX_OK; +} + + static void ngx_stream_proxy_next_upstream(ngx_stream_session_t *s) { From vl at nginx.com Tue Nov 13 13:41:25 2018 From: vl at nginx.com (Vladimir Homutov) Date: Tue, 13 Nov 2018 13:41:25 +0000 Subject: [nginx] Stream: proxy_requests directive. Message-ID: details: http://hg.nginx.org/nginx/rev/4698cede59ff branches: changeset: 7393:4698cede59ff user: Vladimir Homutov date: Mon Nov 12 16:29:30 2018 +0300 description: Stream: proxy_requests directive. The directive allows to drop binding between a client and existing UDP stream session after receiving a specified number of packets. First packet from the same client address and port will start a new session. Old session continues to exist and will terminate at moment defined by configuration: either after receiving the expected number of responses, or after timeout, as specified by the "proxy_responses" and/or "proxy_timeout" directives. By default, proxy_requests is zero (disabled). diffstat: src/event/ngx_event.h | 1 + src/event/ngx_event_udp.c | 15 +++++++++++++-- src/stream/ngx_stream_proxy_module.c | 27 +++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 4 deletions(-) diffs (127 lines): diff -r 04ff25798002 -r 4698cede59ff src/event/ngx_event.h --- a/src/event/ngx_event.h Mon Nov 12 12:05:03 2018 +0300 +++ b/src/event/ngx_event.h Mon Nov 12 16:29:30 2018 +0300 @@ -509,6 +509,7 @@ void ngx_event_recvmsg(ngx_event_t *ev); void ngx_udp_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); #endif +void ngx_delete_udp_connection(void *data); ngx_int_t ngx_trylock_accept_mutex(ngx_cycle_t *cycle); ngx_int_t ngx_enable_accept_events(ngx_cycle_t *cycle); u_char *ngx_accept_log_error(ngx_log_t *log, u_char *buf, size_t len); diff -r 04ff25798002 -r 4698cede59ff src/event/ngx_event_udp.c --- a/src/event/ngx_event_udp.c Mon Nov 12 12:05:03 2018 +0300 +++ b/src/event/ngx_event_udp.c Mon Nov 12 16:29:30 2018 +0300 @@ -23,7 +23,6 @@ static void ngx_close_accepted_udp_conne static ssize_t ngx_udp_shared_recv(ngx_connection_t *c, u_char *buf, size_t size); static ngx_int_t ngx_insert_udp_connection(ngx_connection_t *c); -static void ngx_delete_udp_connection(void *data); static ngx_connection_t *ngx_lookup_udp_connection(ngx_listening_t *ls, struct sockaddr *sockaddr, socklen_t socklen, struct sockaddr *local_sockaddr, socklen_t local_socklen); @@ -558,11 +557,15 @@ ngx_insert_udp_connection(ngx_connection } -static void +void ngx_delete_udp_connection(void *data) { ngx_connection_t *c = data; + if (c->udp == NULL) { + return; + } + ngx_rbtree_delete(&c->listening->rbtree, &c->udp->node); c->udp = NULL; @@ -643,4 +646,12 @@ ngx_lookup_udp_connection(ngx_listening_ return NULL; } +#else + +void +ngx_delete_udp_connection(void *data) +{ + return; +} + #endif diff -r 04ff25798002 -r 4698cede59ff src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Mon Nov 12 12:05:03 2018 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Mon Nov 12 16:29:30 2018 +0300 @@ -26,6 +26,7 @@ typedef struct { size_t buffer_size; size_t upload_rate; size_t download_rate; + ngx_uint_t requests; ngx_uint_t responses; ngx_uint_t next_upstream_tries; ngx_flag_t next_upstream; @@ -195,6 +196,13 @@ static ngx_command_t ngx_stream_proxy_c offsetof(ngx_stream_proxy_srv_conf_t, download_rate), NULL }, + { ngx_string("proxy_requests"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, requests), + NULL }, + { ngx_string("proxy_responses"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, @@ -1341,11 +1349,14 @@ ngx_stream_proxy_process_connection(ngx_ } else { if (s->connection->type == SOCK_DGRAM) { - if (pscf->responses == NGX_MAX_INT32_VALUE) { + + if (pscf->responses == NGX_MAX_INT32_VALUE + || (u->responses >= pscf->responses * u->requests)) + { /* * successfully terminate timed out UDP session - * with unspecified number of responses + * if expected number of responses was received */ handler = c->log->handler; @@ -1692,6 +1703,14 @@ ngx_stream_proxy_test_finalize(ngx_strea if (c->type == SOCK_DGRAM) { + if (pscf->requests && u->requests < pscf->requests) { + return NGX_DECLINED; + } + + if (pscf->requests) { + ngx_delete_udp_connection(c); + } + if (pscf->responses == NGX_MAX_INT32_VALUE || u->responses < pscf->responses * u->requests) { @@ -1943,6 +1962,7 @@ ngx_stream_proxy_create_srv_conf(ngx_con conf->buffer_size = NGX_CONF_UNSET_SIZE; conf->upload_rate = NGX_CONF_UNSET_SIZE; conf->download_rate = NGX_CONF_UNSET_SIZE; + conf->requests = NGX_CONF_UNSET_UINT; conf->responses = NGX_CONF_UNSET_UINT; conf->next_upstream_tries = NGX_CONF_UNSET_UINT; conf->next_upstream = NGX_CONF_UNSET; @@ -1987,6 +2007,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf ngx_conf_merge_size_value(conf->download_rate, prev->download_rate, 0); + ngx_conf_merge_uint_value(conf->requests, + prev->requests, 0); + ngx_conf_merge_uint_value(conf->responses, prev->responses, NGX_MAX_INT32_VALUE); From pluknet at nginx.com Tue Nov 13 16:13:32 2018 From: pluknet at nginx.com (Sergey Kandaurov) Date: Tue, 13 Nov 2018 16:13:32 +0000 Subject: [njs] Tolerate epsilon difference in the previous unit test change. Message-ID: details: http://hg.nginx.org/njs/rev/52e540f16740 branches: changeset: 651:52e540f16740 user: Sergey Kandaurov date: Tue Nov 13 15:25:00 2018 +0300 description: Tolerate epsilon difference in the previous unit test change. diffstat: njs/test/njs_unit_test.c | 11 +++++++---- 1 files changed, 7 insertions(+), 4 deletions(-) diffs (21 lines): diff -r 19a9743c00c8 -r 52e540f16740 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Nov 13 14:16:54 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Nov 13 15:25:00 2018 +0300 @@ -9071,10 +9071,13 @@ static njs_unit_test_t njs_test[] = { nxt_string("Math.sinh(-Infinity)"), nxt_string("-Infinity") }, -#ifndef __SUNPRO_C /* Sun C 5.15: round error */ - { nxt_string("Math.sinh(1) - (Math.E - 1/Math.E)/2"), - nxt_string("0") }, -#endif + /* + * The difference is Number.EPSILON on Solaris + * and zero on other platforms. + */ + { nxt_string("Math.abs(Math.sinh(1) - (Math.E - 1/Math.E)/2)" + " <= Number.EPSILON"), + nxt_string("true") }, { nxt_string("Math.sqrt()"), nxt_string("NaN") }, From mdounin at mdounin.ru Tue Nov 13 19:11:10 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 13 Nov 2018 22:11:10 +0300 Subject: [PATCH] Proxy: Adding proxy_cache_key emedded variable In-Reply-To: <2284bf7d-13a2-dd73-27b0-44df55443545@gmail.com> References: <41a499230eb674b1b3ec.1541235602@dhcp-9c60.meeting.ietf.org> <20181106191524.GA56558@mdounin.ru> <30DE41DD-18C5-4870-96C5-E5E08AD078F3@gmail.com> <20181107154508.GF56558@mdounin.ru> <2284bf7d-13a2-dd73-27b0-44df55443545@gmail.com> Message-ID: <20181113191109.GR99070@mdounin.ru> Hello! On Fri, Nov 09, 2018 at 08:00:59AM +0000, Thomas Peterson wrote: > Thanks for your response, I didn't consider using a configuration > variable. However upon investigating my patch in greater detail, I have > noticed a difference in behaviour. Consider the following configuration: > > ? proxy_cache_key??? $scheme$proxy_host$request_uri; > ? set $var_cache_key $scheme$proxy_host$request_uri; > > ? add_header Proxy-Cache-Key $proxy_cache_key; > ? add_header Var-Cache-Key?? $var_cache_key; > > I am expecting both of these headers to contain the same value - however > in running this in the nginx test harness does not show this, it shows > the $proxy_host value being empty when interpolated into $var_cache_key. > Attached is the test which should fail against my patch. > > I'd appreciate it if you could tell me where I am going wrong. The problem is that the $proxy_host variable is only available when proxy starts working. Before this, it is empty, and hence "set", which is executed during rewrite phase, will use an empty value. Sorry for the broken example. If you want to use the $proxy_host variable, the solution would be to use map instead (http://nginx.org/r/map). That is, something like this: map $scheme $cache_key { default $scheme$proxy_host$request_uri; } proxy_cache_key $cache_key; add_header X-Cache-Key $cache_key; The map is evaluated (and cached) once proxy_cache_key is resolved, so there will be no problem like the one with set. -- Maxim Dounin http://mdounin.ru/ From hidinginthebbc at gmail.com Wed Nov 14 10:04:51 2018 From: hidinginthebbc at gmail.com (Thomas Peterson) Date: Wed, 14 Nov 2018 10:04:51 +0000 Subject: [PATCH] Proxy: Adding proxy_cache_key emedded variable In-Reply-To: <20181113191109.GR99070@mdounin.ru> References: <41a499230eb674b1b3ec.1541235602@dhcp-9c60.meeting.ietf.org> <20181106191524.GA56558@mdounin.ru> <30DE41DD-18C5-4870-96C5-E5E08AD078F3@gmail.com> <20181107154508.GF56558@mdounin.ru> <2284bf7d-13a2-dd73-27b0-44df55443545@gmail.com> <20181113191109.GR99070@mdounin.ru> Message-ID: Thank you for the clarification. If the map example you gave me should cover when upstream modules are being used, I don't think my patch will be required anymore. Regards On 13/11/2018 19:11, Maxim Dounin wrote: > Hello! > > On Fri, Nov 09, 2018 at 08:00:59AM +0000, Thomas Peterson wrote: > >> Thanks for your response, I didn't consider using a configuration >> variable. However upon investigating my patch in greater detail, I have >> noticed a difference in behaviour. Consider the following configuration: >> >> ? proxy_cache_key??? $scheme$proxy_host$request_uri; >> ? set $var_cache_key $scheme$proxy_host$request_uri; >> >> ? add_header Proxy-Cache-Key $proxy_cache_key; >> ? add_header Var-Cache-Key?? $var_cache_key; >> >> I am expecting both of these headers to contain the same value - however >> in running this in the nginx test harness does not show this, it shows >> the $proxy_host value being empty when interpolated into $var_cache_key. >> Attached is the test which should fail against my patch. >> >> I'd appreciate it if you could tell me where I am going wrong. > The problem is that the $proxy_host variable is only available when > proxy starts working. Before this, it is empty, and hence "set", > which is executed during rewrite phase, will use an empty value. > Sorry for the broken example. > > If you want to use the $proxy_host variable, the solution would be > to use map instead (http://nginx.org/r/map). That is, something > like this: > > map $scheme $cache_key { > default $scheme$proxy_host$request_uri; > } > > proxy_cache_key $cache_key; > add_header X-Cache-Key $cache_key; > > The map is evaluated (and cached) once proxy_cache_key is > resolved, so there will be no problem like the one with set. > From ramprasad.tamilselvan at quantil.com Thu Nov 15 01:24:52 2018 From: ramprasad.tamilselvan at quantil.com (Ramprasad Tamilselvan) Date: Wed, 14 Nov 2018 17:24:52 -0800 Subject: [PATCH] New directive to configure TLSv1.3 ciphers Message-ID: <83b05772dbd657b31df1.1542245092@CDN1276.local> # HG changeset patch # User Ramprasad Tamilselvan # Date 1542241466 28800 # Wed Nov 14 16:24:26 2018 -0800 # Node ID 83b05772dbd657b31df16d712a64c908c371f0d9 # Parent 4698cede59ffa438bcae1fd6c5d8fec4d69b2c92 New directive to configure TLSv1.3 ciphers. In openssl 1.1.1, a new API is introduced to configure ciphers for TLSv1.3. A new directive ssl_ciphersuites will call the new API to configure the ciphers for TLSv1.3. diff -r 4698cede59ff -r 83b05772dbd6 src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c Mon Nov 12 16:29:30 2018 +0300 +++ b/src/event/ngx_event_openssl.c Wed Nov 14 16:24:26 2018 -0800 @@ -660,8 +660,20 @@ ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, - ngx_uint_t prefer_server_ciphers) + ngx_str_t *ciphersuites, ngx_uint_t prefer_server_ciphers) { + +#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) + /* set cipher as "" so that SSL_CTX_set_cipher_list can detect + * any invalid ciphers */ + if (SSL_CTX_set_ciphersuites(ssl->ctx, (char *) "") == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_ciphersuites(\"%V\") failed", + ciphersuites); + return NGX_ERROR; + } +#endif + if (SSL_CTX_set_cipher_list(ssl->ctx, (char *) ciphers->data) == 0) { ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, "SSL_CTX_set_cipher_list(\"%V\") failed", @@ -669,6 +681,16 @@ return NGX_ERROR; } +#if (OPENSSL_VERSION_NUMBER >= 0x10101000L) + /* set ciphers for TLSv1.3 */ + if (SSL_CTX_set_ciphersuites(ssl->ctx, (char *) ciphersuites->data) == 0) { + ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0, + "SSL_CTX_set_ciphersuites(\"%V\") failed", + ciphersuites); + return NGX_ERROR; + } +#endif + if (prefer_server_ciphers) { SSL_CTX_set_options(ssl->ctx, SSL_OP_CIPHER_SERVER_PREFERENCE); } diff -r 4698cede59ff -r 83b05772dbd6 src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h Mon Nov 12 16:29:30 2018 +0300 +++ b/src/event/ngx_event_openssl.h Wed Nov 14 16:24:26 2018 -0800 @@ -165,7 +165,7 @@ ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_str_t *key, ngx_array_t *passwords); ngx_int_t ngx_ssl_ciphers(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *ciphers, - ngx_uint_t prefer_server_ciphers); + ngx_str_t *ciphersuites, ngx_uint_t prefer_server_ciphers); ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert, ngx_int_t depth); ngx_int_t ngx_ssl_trusted_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, diff -r 4698cede59ff -r 83b05772dbd6 src/http/modules/ngx_http_grpc_module.c --- a/src/http/modules/ngx_http_grpc_module.c Mon Nov 12 16:29:30 2018 +0300 +++ b/src/http/modules/ngx_http_grpc_module.c Wed Nov 14 16:24:26 2018 -0800 @@ -9,6 +9,9 @@ #include #include +#define NGX_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384" \ + ":TLS_CHACHA20_POLY1305_SHA256" \ + ":TLS_AES_128_GCM_SHA256" typedef struct { ngx_array_t *flushes; @@ -31,6 +34,7 @@ ngx_uint_t ssl; ngx_uint_t ssl_protocols; ngx_str_t ssl_ciphers; + ngx_str_t ssl_ciphersuites; ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; @@ -365,6 +369,13 @@ offsetof(ngx_http_grpc_loc_conf_t, ssl_ciphers), NULL }, + { ngx_string("grpc_ssl_ciphersuites"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_grpc_loc_conf_t, ssl_ciphersuites), + NULL }, + { ngx_string("grpc_ssl_name"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_set_complex_value_slot, @@ -4165,6 +4176,7 @@ * conf->ssl = 0; * conf->ssl_protocols = 0; * conf->ssl_ciphers = { 0, NULL }; + * conf->ssl_ciphersuites = { 0, NULL }; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; * conf->ssl_certificate = { 0, NULL }; @@ -4280,6 +4292,9 @@ ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); + ngx_conf_merge_str_value(conf->ssl_ciphersuites, prev->ssl_ciphersuites, + NGX_DEFAULT_CIPHERSUITES); + if (conf->upstream.ssl_name == NULL) { conf->upstream.ssl_name = prev->upstream.ssl_name; } @@ -4673,7 +4688,8 @@ } } - if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, 0) + if (ngx_ssl_ciphers(cf, glcf->upstream.ssl, &glcf->ssl_ciphers, + &glcf->ssl_ciphersuites, 0) != NGX_OK) { return NGX_ERROR; diff -r 4698cede59ff -r 83b05772dbd6 src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c Mon Nov 12 16:29:30 2018 +0300 +++ b/src/http/modules/ngx_http_proxy_module.c Wed Nov 14 16:24:26 2018 -0800 @@ -9,6 +9,9 @@ #include #include +#define NGX_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384" \ + ":TLS_CHACHA20_POLY1305_SHA256" \ + ":TLS_AES_128_GCM_SHA256" typedef struct { ngx_array_t caches; /* ngx_http_file_cache_t * */ @@ -94,6 +97,7 @@ ngx_uint_t ssl; ngx_uint_t ssl_protocols; ngx_str_t ssl_ciphers; + ngx_str_t ssl_ciphersuites; ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; @@ -659,6 +663,13 @@ offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphers), NULL }, + { ngx_string("proxy_ssl_ciphersuites"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, ssl_ciphersuites), + NULL }, + { ngx_string("proxy_ssl_name"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_set_complex_value_slot, @@ -2825,6 +2836,7 @@ * conf->ssl = 0; * conf->ssl_protocols = 0; * conf->ssl_ciphers = { 0, NULL }; + * conf->ssl_ciphersuites = { 0, NULL }; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; * conf->ssl_certificate = { 0, NULL }; @@ -3208,6 +3220,9 @@ ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); + ngx_conf_merge_str_value(conf->ssl_ciphersuites, prev->ssl_ciphersuites, + NGX_DEFAULT_CIPHERSUITES); + if (conf->upstream.ssl_name == NULL) { conf->upstream.ssl_name = prev->upstream.ssl_name; } @@ -4293,7 +4308,8 @@ } } - if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, 0) + if (ngx_ssl_ciphers(cf, plcf->upstream.ssl, &plcf->ssl_ciphers, + &plcf->ssl_ciphersuites, 0) != NGX_OK) { return NGX_ERROR; diff -r 4698cede59ff -r 83b05772dbd6 src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c Mon Nov 12 16:29:30 2018 +0300 +++ b/src/http/modules/ngx_http_ssl_module.c Wed Nov 14 16:24:26 2018 -0800 @@ -16,6 +16,9 @@ #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" #define NGX_DEFAULT_ECDH_CURVE "auto" +#define NGX_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384" \ + ":TLS_CHACHA20_POLY1305_SHA256" \ + ":TLS_AES_128_GCM_SHA256" #define NGX_HTTP_NPN_ADVERTISE "\x08http/1.1" @@ -133,6 +136,13 @@ NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, ciphers), NULL }, + + { ngx_string("ssl_ciphersuites"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_SRV_CONF_OFFSET, + offsetof(ngx_http_ssl_srv_conf_t, ciphersuites), + NULL }, { ngx_string("ssl_buffer_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, @@ -556,6 +566,7 @@ * sscf->trusted_certificate = { 0, NULL }; * sscf->crl = { 0, NULL }; * sscf->ciphers = { 0, NULL }; + * sscf->ciphersuites = { 0, NULL }; * sscf->shm_zone = NULL; * sscf->stapling_file = { 0, NULL }; * sscf->stapling_responder = { 0, NULL }; @@ -637,6 +648,9 @@ ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); + ngx_conf_merge_str_value(conf->ciphersuites, prev->ciphersuites, + NGX_DEFAULT_CIPHERSUITES); + ngx_conf_merge_value(conf->stapling, prev->stapling, 0); ngx_conf_merge_value(conf->stapling_verify, prev->stapling_verify, 0); ngx_conf_merge_str_value(conf->stapling_file, prev->stapling_file, ""); @@ -734,7 +748,7 @@ return NGX_CONF_ERROR; } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, &conf->ciphersuites, conf->prefer_server_ciphers) != NGX_OK) { diff -r 4698cede59ff -r 83b05772dbd6 src/http/modules/ngx_http_ssl_module.h --- a/src/http/modules/ngx_http_ssl_module.h Mon Nov 12 16:29:30 2018 +0300 +++ b/src/http/modules/ngx_http_ssl_module.h Wed Nov 14 16:24:26 2018 -0800 @@ -44,6 +44,8 @@ ngx_str_t ciphers; + ngx_str_t ciphersuites; + ngx_array_t *passwords; ngx_shm_zone_t *shm_zone; diff -r 4698cede59ff -r 83b05772dbd6 src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c Mon Nov 12 16:29:30 2018 +0300 +++ b/src/http/modules/ngx_http_uwsgi_module.c Wed Nov 14 16:24:26 2018 -0800 @@ -11,6 +11,9 @@ #include #include +#define NGX_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384" \ + ":TLS_CHACHA20_POLY1305_SHA256" \ + ":TLS_AES_128_GCM_SHA256" typedef struct { ngx_array_t caches; /* ngx_http_file_cache_t * */ @@ -51,6 +54,7 @@ ngx_uint_t ssl; ngx_uint_t ssl_protocols; ngx_str_t ssl_ciphers; + ngx_str_t ssl_ciphersuites; ngx_uint_t ssl_verify_depth; ngx_str_t ssl_trusted_certificate; ngx_str_t ssl_crl; @@ -497,6 +501,13 @@ offsetof(ngx_http_uwsgi_loc_conf_t, ssl_ciphers), NULL }, + { ngx_string("uwsgi_ssl_ciphersuites"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, ssl_ciphersuites), + NULL }, + { ngx_string("uwsgi_ssl_name"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_set_complex_value_slot, @@ -1773,6 +1784,9 @@ ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); + ngx_conf_merge_str_value(conf->ssl_ciphersuites, prev->ssl_ciphersuites, + NGX_DEFAULT_CIPHERSUITES); + if (conf->upstream.ssl_name == NULL) { conf->upstream.ssl_name = prev->upstream.ssl_name; } @@ -2382,7 +2396,8 @@ } } - if (ngx_ssl_ciphers(cf, uwcf->upstream.ssl, &uwcf->ssl_ciphers, 0) + if (ngx_ssl_ciphers(cf, uwcf->upstream.ssl, &uwcf->ssl_ciphers, + &uwcf->ssl_ciphersuites, 0) != NGX_OK) { return NGX_ERROR; diff -r 4698cede59ff -r 83b05772dbd6 src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c Mon Nov 12 16:29:30 2018 +0300 +++ b/src/mail/ngx_mail_ssl_module.c Wed Nov 14 16:24:26 2018 -0800 @@ -11,6 +11,9 @@ #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" +#define NGX_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384" \ + ":TLS_CHACHA20_POLY1305_SHA256" \ + ":TLS_AES_128_GCM_SHA256" #define NGX_DEFAULT_ECDH_CURVE "auto" @@ -126,6 +129,13 @@ offsetof(ngx_mail_ssl_conf_t, ciphers), NULL }, + { ngx_string("ssl_ciphersuites"), + NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_MAIL_SRV_CONF_OFFSET, + offsetof(ngx_mail_ssl_conf_t, ciphersuites), + NULL }, + { ngx_string("ssl_prefer_server_ciphers"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -251,6 +261,7 @@ * scf->trusted_certificate = { 0, NULL }; * scf->crl = { 0, NULL }; * scf->ciphers = { 0, NULL }; + * scf->ciphersuites = { 0, NULL }; * scf->shm_zone = NULL; */ @@ -316,6 +327,9 @@ ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); + ngx_conf_merge_str_value(conf->ciphersuites, prev->ciphersuites, + NGX_DEFAULT_CIPHERSUITES); + conf->ssl.log = cf->log; @@ -412,7 +426,7 @@ } } - if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, + if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, &conf->ciphersuites, conf->prefer_server_ciphers) != NGX_OK) { diff -r 4698cede59ff -r 83b05772dbd6 src/mail/ngx_mail_ssl_module.h --- a/src/mail/ngx_mail_ssl_module.h Mon Nov 12 16:29:30 2018 +0300 +++ b/src/mail/ngx_mail_ssl_module.h Wed Nov 14 16:24:26 2018 -0800 @@ -47,6 +47,8 @@ ngx_str_t ciphers; + ngx_str_t ciphersuites; + ngx_array_t *passwords; ngx_shm_zone_t *shm_zone; diff -r 4698cede59ff -r 83b05772dbd6 src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Mon Nov 12 16:29:30 2018 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Wed Nov 14 16:24:26 2018 -0800 @@ -9,6 +9,9 @@ #include #include +#define NGX_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384" \ + ":TLS_CHACHA20_POLY1305_SHA256" \ + ":TLS_AES_128_GCM_SHA256" typedef struct { ngx_addr_t *addr; @@ -39,6 +42,7 @@ ngx_flag_t ssl_session_reuse; ngx_uint_t ssl_protocols; ngx_str_t ssl_ciphers; + ngx_str_t ssl_ciphersuites; ngx_stream_complex_value_t *ssl_name; ngx_flag_t ssl_server_name; @@ -268,6 +272,13 @@ offsetof(ngx_stream_proxy_srv_conf_t, ssl_ciphers), NULL }, + { ngx_string("proxy_ssl_ciphersuites"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_proxy_srv_conf_t, ssl_ciphersuites), + NULL }, + { ngx_string("proxy_ssl_name"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_stream_set_complex_value_slot, @@ -1945,6 +1956,7 @@ * * conf->ssl_protocols = 0; * conf->ssl_ciphers = { 0, NULL }; + * conf->ssl_ciphersuites = { 0, NULL }; * conf->ssl_name = NULL; * conf->ssl_trusted_certificate = { 0, NULL }; * conf->ssl_crl = { 0, NULL }; @@ -2038,6 +2050,9 @@ ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT"); + ngx_conf_merge_str_value(conf->ssl_ciphersuites, prev->ssl_ciphersuites, + NGX_DEFAULT_CIPHERSUITES); + if (conf->ssl_name == NULL) { conf->ssl_name = prev->ssl_name; } @@ -2115,7 +2130,9 @@ } } - if (ngx_ssl_ciphers(cf, pscf->ssl, &pscf->ssl_ciphers, 0) != NGX_OK) { + if (ngx_ssl_ciphers(cf, pscf->ssl, &pscf->ssl_ciphers, + &pscf->ssl_ciphersuites, 0) + != NGX_OK) { return NGX_ERROR; } diff -r 4698cede59ff -r 83b05772dbd6 src/stream/ngx_stream_ssl_module.c --- a/src/stream/ngx_stream_ssl_module.c Mon Nov 12 16:29:30 2018 +0300 +++ b/src/stream/ngx_stream_ssl_module.c Wed Nov 14 16:24:26 2018 -0800 @@ -15,6 +15,9 @@ #define NGX_DEFAULT_CIPHERS "HIGH:!aNULL:!MD5" +#define NGX_DEFAULT_CIPHERSUITES "TLS_AES_256_GCM_SHA384" \ + ":TLS_CHACHA20_POLY1305_SHA256" \ + ":TLS_AES_128_GCM_SHA256" #define NGX_DEFAULT_ECDH_CURVE "auto" @@ -117,6 +120,13 @@ offsetof(ngx_stream_ssl_conf_t, ciphers), NULL }, + { ngx_string("ssl_ciphersuites"), + NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_STREAM_SRV_CONF_OFFSET, + offsetof(ngx_stream_ssl_conf_t, ciphersuites), + NULL }, + { ngx_string("ssl_verify_client"), NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_enum_slot, @@ -511,6 +521,7 @@ * scf->trusted_certificate = { 0, NULL }; * scf->crl = { 0, NULL }; * scf->ciphers = { 0, NULL }; + * scf->ciphersuites = { 0, NULL }; * scf->shm_zone = NULL; */ @@ -573,6 +584,9 @@ ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFAULT_CIPHERS); + ngx_conf_merge_str_value(conf->ciphersuites, prev->ciphersuites, + NGX_DEFAULT_CIPHERSUITES); + conf->ssl.log = cf->log; @@ -627,7 +641,7 @@ } if (ngx_ssl_ciphers(cf, &conf->ssl, &conf->ciphers, - conf->prefer_server_ciphers) + &conf->ciphersuites, conf->prefer_server_ciphers) != NGX_OK) { return NGX_CONF_ERROR; diff -r 4698cede59ff -r 83b05772dbd6 src/stream/ngx_stream_ssl_module.h --- a/src/stream/ngx_stream_ssl_module.h Mon Nov 12 16:29:30 2018 +0300 +++ b/src/stream/ngx_stream_ssl_module.h Wed Nov 14 16:24:26 2018 -0800 @@ -42,6 +42,8 @@ ngx_str_t ciphers; + ngx_str_t ciphersuites; + ngx_array_t *passwords; ngx_shm_zone_t *shm_zone; From vbart at nginx.com Thu Nov 15 11:57:21 2018 From: vbart at nginx.com (Valentin Bartenev) Date: Thu, 15 Nov 2018 11:57:21 +0000 Subject: [njs] Fixed lvlhsh test on 64-bit big-endian systems. Message-ID: details: http://hg.nginx.org/njs/rev/7f0f7d149709 branches: changeset: 652:7f0f7d149709 user: Valentin Bartenev date: Thu Nov 15 12:45:02 2018 +0300 description: Fixed lvlhsh test on 64-bit big-endian systems. The nxt_murmur_hash2() generated 4-byte hash that was stored in uintptr_t, which was 8 bytes long on 64-bit systems. At each iteration, it took the previous key and hashed it again. The problem was that it took only the first 4 bytes of the key, and these 4 bytes were always zero on 64-bit big-endian system. That resulted in equal keys at each iteration. The bug was discovered on IBM/S390x. diffstat: nxt/test/lvlhsh_unit_test.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r 52e540f16740 -r 7f0f7d149709 nxt/test/lvlhsh_unit_test.c --- a/nxt/test/lvlhsh_unit_test.c Tue Nov 13 15:25:00 2018 +0300 +++ b/nxt/test/lvlhsh_unit_test.c Thu Nov 15 12:45:02 2018 +0300 @@ -196,7 +196,7 @@ static const nxt_mem_proto_t mem_cache_ static nxt_int_t lvlhsh_unit_test(nxt_uint_t n) { - uintptr_t key; + uint32_t key; nxt_uint_t i; nxt_lvlhsh_t lh; nxt_lvlhsh_each_t lhe; From ru at nginx.com Thu Nov 15 14:19:57 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Thu, 15 Nov 2018 14:19:57 +0000 Subject: [nginx] Core: free shared memory on cycle initialization failure. Message-ID: details: http://hg.nginx.org/nginx/rev/650574a44505 branches: changeset: 7394:650574a44505 user: Ruslan Ermilov date: Thu Nov 15 15:28:54 2018 +0300 description: Core: free shared memory on cycle initialization failure. diffstat: src/core/ngx_cycle.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 64 insertions(+), 0 deletions(-) diffs (81 lines): diff -r 4698cede59ff -r 650574a44505 src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c Mon Nov 12 16:29:30 2018 +0300 +++ b/src/core/ngx_cycle.c Thu Nov 15 15:28:54 2018 +0300 @@ -843,6 +843,69 @@ failed: } } + /* free the newly created shared memory */ + + part = &cycle->shared_memory.part; + shm_zone = part->elts; + + for (i = 0; /* void */ ; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + part = part->next; + shm_zone = part->elts; + i = 0; + } + + if (shm_zone[i].shm.addr == NULL) { + continue; + } + + opart = &old_cycle->shared_memory.part; + oshm_zone = opart->elts; + + for (n = 0; /* void */ ; n++) { + + if (n >= opart->nelts) { + if (opart->next == NULL) { + break; + } + opart = opart->next; + oshm_zone = opart->elts; + n = 0; + } + + if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) { + continue; + } + + if (ngx_strncmp(shm_zone[i].shm.name.data, + oshm_zone[n].shm.name.data, + shm_zone[i].shm.name.len) + != 0) + { + continue; + } + + if (shm_zone[i].tag == oshm_zone[n].tag + && shm_zone[i].shm.size == oshm_zone[n].shm.size + && !shm_zone[i].noreuse) + { + goto old_shm_zone_found; + } + + break; + } + + ngx_shm_free(&shm_zone[i].shm); + + old_shm_zone_found: + + continue; + } + if (ngx_test_config) { ngx_destroy_cycle_pools(&conf); return NULL; @@ -1274,6 +1337,7 @@ ngx_shared_memory_add(ngx_conf_t *cf, ng shm_zone->data = NULL; shm_zone->shm.log = cf->cycle->log; + shm_zone->shm.addr = NULL; shm_zone->shm.size = size; shm_zone->shm.name = *name; shm_zone->shm.exists = 0; From mdounin at mdounin.ru Thu Nov 15 14:53:53 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 15 Nov 2018 17:53:53 +0300 Subject: [PATCH] New directive to configure TLSv1.3 ciphers In-Reply-To: <83b05772dbd657b31df1.1542245092@CDN1276.local> References: <83b05772dbd657b31df1.1542245092@CDN1276.local> Message-ID: <20181115145353.GA99070@mdounin.ru> Hello! On Wed, Nov 14, 2018 at 05:24:52PM -0800, Ramprasad Tamilselvan wrote: > # HG changeset patch > # User Ramprasad Tamilselvan > # Date 1542241466 28800 > # Wed Nov 14 16:24:26 2018 -0800 > # Node ID 83b05772dbd657b31df16d712a64c908c371f0d9 > # Parent 4698cede59ffa438bcae1fd6c5d8fec4d69b2c92 > New directive to configure TLSv1.3 ciphers. > > In openssl 1.1.1, a new API is introduced to configure ciphers > for TLSv1.3. A new directive ssl_ciphersuites will call the new > API to configure the ciphers for TLSv1.3. Thank you for your patch. I do object introducing a new directive for this, see this ticket for details: https://trac.nginx.org/nginx/ticket/1529 -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Thu Nov 15 17:32:02 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 15 Nov 2018 17:32:02 +0000 Subject: [njs] console.time() and console.timeEnd() methods. Message-ID: details: http://hg.nginx.org/njs/rev/46632012ac03 branches: changeset: 653:46632012ac03 user: Artem S. Povalyukhin date: Wed Nov 14 18:14:49 2018 +0300 description: console.time() and console.timeEnd() methods. This fixes #62 issue on Github. diffstat: njs/njs_shell.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ njs/test/njs_expect_test.exp | 18 ++++++++- 2 files changed, 103 insertions(+), 1 deletions(-) diffs (156 lines): diff -r 7f0f7d149709 -r 46632012ac03 njs/njs_shell.c --- a/njs/njs_shell.c Thu Nov 15 12:45:02 2018 +0300 +++ b/njs/njs_shell.c Wed Nov 14 18:14:49 2018 +0300 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,10 @@ static njs_ret_t njs_ext_console_dump(nj nxt_uint_t nargs, njs_index_t unused); static njs_ret_t njs_ext_console_help(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); +static njs_ret_t njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); static njs_external_t njs_ext_console[] = { @@ -102,6 +107,30 @@ static njs_external_t njs_ext_console[] NULL, njs_ext_console_help, 0 }, + + { nxt_string("time"), + NJS_EXTERN_METHOD, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + njs_ext_console_time, + 0 }, + + { nxt_string("timeEnd"), + NJS_EXTERN_METHOD, + NULL, + 0, + NULL, + NULL, + NULL, + NULL, + NULL, + njs_ext_console_time_end, + 0 }, }; static njs_external_t njs_externals[] = { @@ -123,6 +152,9 @@ static njs_external_t njs_externals[] = static njs_completion_t njs_completion; +static struct timeval njs_console_time; + + int main(int argc, char **argv) { @@ -727,3 +759,57 @@ njs_ext_console_help(njs_vm_t *vm, njs_v return NJS_OK; } + + +static njs_ret_t +njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + if (!njs_value_is_void(njs_arg(args, nargs, 1))) { + njs_vm_error(vm, "labels not implemented"); + return NJS_ERROR; + } + + vm->retval = njs_value_void; + + gettimeofday(&njs_console_time, NULL); + + return NJS_OK; +} + + +static njs_ret_t +njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + int64_t us, ms; + struct timeval tv; + + gettimeofday(&tv, NULL); + + if (!njs_value_is_void(njs_arg(args, nargs, 1))) { + njs_vm_error(vm, "labels not implemented"); + return NJS_ERROR; + } + + if (nxt_fast_path(njs_console_time.tv_sec || njs_console_time.tv_usec)) { + + us = ((int64_t) tv.tv_sec - njs_console_time.tv_sec) * 1000000 + + ((int64_t) tv.tv_usec - njs_console_time.tv_usec); + + ms = us / 1000; + us = us % 1000; + + printf("default: %" PRIu64 ".%03" PRIu64 "ms\n", ms, us); + + njs_console_time.tv_sec = 0; + njs_console_time.tv_usec = 0; + + } else { + printf("Timer \"default\" doesn?t exist.\n"); + } + + vm->retval = njs_value_void; + + return NJS_OK; +} diff -r 7f0f7d149709 -r 46632012ac03 njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Thu Nov 15 12:45:02 2018 +0300 +++ b/njs/test/njs_expect_test.exp Wed Nov 14 18:14:49 2018 +0300 @@ -80,7 +80,7 @@ njs_test { # Global completions, multiple partial match njs_test { {"cons\t\t" - "console*console.help*console.log*const"} + "console*console.help*console.time*const"} } njs_test { @@ -190,6 +190,22 @@ njs_test { "console.help()\r\nVM built-in objects:"} } +# console.time* functions +njs_test { + {"console.time()\r\n" + "console.time()\r\nundefined\r\n>> "} + {"console.time(undefined)\r\n" + "console.time(undefined)\r\nundefined\r\n>> "} + {"console.timeEnd()\r\n" + "console.timeEnd()\r\ndefault: *.*ms\r\nundefined\r\n>> "} + {"console.time('a')\r\n" + "console.time('a')\r\nError: labels not implemented"} + {"console.timeEnd('a')\r\n" + "console.timeEnd('a')\r\nError: labels not implemented"} + {"console.timeEnd()\r\n" + "console.timeEnd()\r\nTimer \"default\" doesn?t exist."} +} + njs_test { {"console.ll()\r\n" "console.ll()\r\nTypeError: 'll' is not a function"} From xeioex at nginx.com Thu Nov 15 17:32:02 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 15 Nov 2018 17:32:02 +0000 Subject: [njs] Fixed global objects. Message-ID: details: http://hg.nginx.org/njs/rev/e11011d45499 branches: changeset: 655:e11011d45499 user: Dmitry Volyntsev date: Thu Nov 15 20:31:35 2018 +0300 description: Fixed global objects. 1) Making it extensible. 2) Adding default properties according to ES5.1:15.1.1. diffstat: njs/njs_builtin.c | 27 +++++++++++++++++++++++++-- njs/test/njs_unit_test.c | 30 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) diffs (91 lines): diff -r 2711e84ede6a -r e11011d45499 njs/njs_builtin.c --- a/njs/njs_builtin.c Wed Apr 04 17:38:10 2018 +0300 +++ b/njs/njs_builtin.c Thu Nov 15 20:31:35 2018 +0300 @@ -276,6 +276,7 @@ njs_builtin_objects_create(njs_vm_t *vm) } object->shared = 1; + object->extensible = 1; object++; } @@ -1118,8 +1119,30 @@ const njs_object_init_t njs_njs_object_ }; +static const njs_object_prop_t njs_global_this_object_properties[] = +{ + { + .type = NJS_PROPERTY, + .name = njs_string("NaN"), + .value = njs_value(NJS_NUMBER, 0, NAN), + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("Infinity"), + .value = njs_value(NJS_NUMBER, 0, INFINITY), + }, + + { + .type = NJS_PROPERTY, + .name = njs_string("undefined"), + .value = njs_value(NJS_VOID, 0, NAN), + }, +}; + + const njs_object_init_t njs_global_this_init = { nxt_string("this"), - NULL, - 0 + njs_global_this_object_properties, + nxt_nitems(njs_global_this_object_properties) }; diff -r 2711e84ede6a -r e11011d45499 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Apr 04 17:38:10 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Nov 15 20:31:35 2018 +0300 @@ -6488,6 +6488,33 @@ static njs_unit_test_t njs_test[] = { nxt_string("this"), nxt_string("[object Object]") }, + { nxt_string("this.a = 1; this.a"), + nxt_string("1") }, + + { nxt_string("this.undefined = 42"), + nxt_string("TypeError: Cannot assign to read-only property 'undefined' of object") }, + + { nxt_string("this.Infinity = 42"), + nxt_string("TypeError: Cannot assign to read-only property 'Infinity' of object") }, + + { nxt_string("this.NaN = 42"), + nxt_string("TypeError: Cannot assign to read-only property 'NaN' of object") }, + + { nxt_string("typeof this.undefined"), + nxt_string("undefined") }, + + { nxt_string("typeof this.Infinity"), + nxt_string("number") }, + + { nxt_string("this.Infinity + 1"), + nxt_string("Infinity") }, + + { nxt_string("typeof this.NaN"), + nxt_string("number") }, + + { nxt_string("this.NaN + 1"), + nxt_string("NaN") }, + { nxt_string("njs"), nxt_string("[object Object]") }, @@ -9177,6 +9204,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("Math"), nxt_string("[object Object]") }, + { nxt_string("Math.x = function (x) {return 2*x;}; Math.x(3)"), + nxt_string("6") }, + { nxt_string("isNaN"), nxt_string("[object Function]") }, From xeioex at nginx.com Thu Nov 15 17:32:02 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 15 Nov 2018 17:32:02 +0000 Subject: [njs] Improved handling of builtin objects. Message-ID: details: http://hg.nginx.org/njs/rev/2711e84ede6a branches: changeset: 654:2711e84ede6a user: Dmitry Volyntsev date: Wed Apr 04 17:38:10 2018 +0300 description: Improved handling of builtin objects. The handling of njs_object_init_t arrays is unified across njs_builtin.c functions. diffstat: njs/njs_builtin.c | 939 +++++++++++++++++++-------------------- njs/njs_crypto.c | 12 + njs/njs_fs.c | 6 + njs/njs_module.c | 16 - njs/njs_module.h | 1 - njs/njs_shell.c | 19 +- njs/njs_vm.h | 7 - njs/test/njs_expect_test.exp | 5 + njs/test/njs_interactive_test.c | 5 + 9 files changed, 499 insertions(+), 511 deletions(-) diffs (truncated from 1323 to 1000 lines): diff -r 46632012ac03 -r 2711e84ede6a njs/njs_builtin.c --- a/njs/njs_builtin.c Wed Nov 14 18:14:49 2018 +0300 +++ b/njs/njs_builtin.c Wed Apr 04 17:38:10 2018 +0300 @@ -1,6 +1,7 @@ /* * Copyright (C) Igor Sysoev + * Copyright (C) Dmitry Volyntsev * Copyright (C) NGINX, Inc. */ @@ -23,25 +24,30 @@ typedef struct { } njs_function_init_t; -static nxt_int_t njs_builtin_completions(njs_vm_t *vm, size_t *size, - nxt_str_t *completions); +static njs_ret_t njs_prototype_function(njs_vm_t *vm, njs_value_t *args, + nxt_uint_t nargs, njs_index_t unused); static nxt_array_t *njs_vm_expression_completions(njs_vm_t *vm, nxt_str_t *expression); static nxt_array_t *njs_object_completions(njs_vm_t *vm, njs_object_t *object); + const njs_object_init_t njs_njs_object_init; +const njs_object_init_t njs_global_this_init; + const njs_object_init_t *njs_object_init[] = { - NULL, /* global this */ + &njs_global_this_init, /* global this */ &njs_njs_object_init, /* global njs object */ &njs_math_object_init, /* Math */ &njs_json_object_init, /* JSON */ + NULL }; const njs_object_init_t *njs_module_init[] = { &njs_fs_object_init, /* fs */ - &njs_crypto_object_init /* crypto */ + &njs_crypto_object_init, /* crypto */ + NULL }; @@ -64,6 +70,7 @@ const njs_object_init_t *njs_prototype_ &njs_syntax_error_prototype_init, &njs_type_error_prototype_init, &njs_uri_error_prototype_init, + NULL }; @@ -87,6 +94,7 @@ const njs_object_init_t *njs_construc &njs_type_error_constructor_init, &njs_uri_error_constructor_init, &njs_memory_error_constructor_init, + NULL }; @@ -103,7 +111,8 @@ const njs_object_init_t *njs_function &njs_decode_uri_component_function_init, &njs_require_function_init, &njs_set_timeout_function_init, - &njs_clear_timeout_function_init + &njs_clear_timeout_function_init, + NULL }; @@ -143,102 +152,95 @@ const njs_object_prop_t njs_arguments_o }; -static njs_ret_t -njs_prototype_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, - njs_index_t unused) -{ - vm->retval = njs_value_void; +const njs_function_init_t njs_native_constructors[] = { + /* SunC does not allow empty array initialization. */ + { njs_object_constructor, { 0 } }, + { njs_array_constructor, { 0 } }, + { njs_boolean_constructor, { 0 } }, + { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, + { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_function_constructor, { 0 } }, + { njs_regexp_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } }, + { njs_date_constructor, { 0 } }, + { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, + NJS_STRING_ARG } }, + { njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_internal_error_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_range_error_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_reference_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_syntax_error_constructor, + { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_type_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_uri_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, + { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, +}; + +const njs_object_prototype_t njs_prototype_values[] = { + /* + * GCC 4 complains about uninitialized .shared field, + * if the .type field is initialized as .object.type. + */ + { .object = { .type = NJS_OBJECT } }, + { .object = { .type = NJS_ARRAY } }, - return NXT_OK; -} + /* + * The .object.type field must be initialzed after the .value field, + * otherwise SunC 5.9 treats the .value as .object.value or so. + */ + { .object_value = { .value = njs_value(NJS_BOOLEAN, 0, 0.0), + .object = { .type = NJS_OBJECT_BOOLEAN } } }, + + { .object_value = { .value = njs_value(NJS_NUMBER, 0, 0.0), + .object = { .type = NJS_OBJECT_NUMBER } } }, + + { .object_value = { .value = njs_string(""), + .object = { .type = NJS_OBJECT_STRING } } }, + + { .function = { .native = 1, + .args_offset = 1, + .u.native = njs_prototype_function, + .object = { .type = NJS_FUNCTION } } }, + + { .object = { .type = NJS_REGEXP } }, + + { .date = { .time = NAN, + .object = { .type = NJS_DATE } } }, + + { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), + .object = { .type = NJS_OBJECT } } }, + + { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), + .object = { .type = NJS_OBJECT } } }, + + { .object = { .type = NJS_OBJECT_ERROR } }, + { .object = { .type = NJS_OBJECT_EVAL_ERROR } }, + { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, + { .object = { .type = NJS_OBJECT_RANGE_ERROR } }, + { .object = { .type = NJS_OBJECT_REF_ERROR } }, + { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, + { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, + { .object = { .type = NJS_OBJECT_URI_ERROR } }, + { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, +}; + nxt_int_t njs_builtin_objects_create(njs_vm_t *vm) { - nxt_int_t ret; - nxt_uint_t i; - njs_module_t *module; - njs_object_t *objects; - njs_function_t *functions, *constructors; - nxt_lvlhsh_query_t lhq; - njs_object_prototype_t *prototypes; - - static const njs_object_prototype_t prototype_values[] = { - /* - * GCC 4 complains about uninitialized .shared field, - * if the .type field is initialized as .object.type. - */ - { .object = { .type = NJS_OBJECT } }, - { .object = { .type = NJS_ARRAY } }, - - /* - * The .object.type field must be initialzed after the .value field, - * otherwise SunC 5.9 treats the .value as .object.value or so. - */ - { .object_value = { .value = njs_value(NJS_BOOLEAN, 0, 0.0), - .object = { .type = NJS_OBJECT_BOOLEAN } } }, - - { .object_value = { .value = njs_value(NJS_NUMBER, 0, 0.0), - .object = { .type = NJS_OBJECT_NUMBER } } }, - - { .object_value = { .value = njs_string(""), - .object = { .type = NJS_OBJECT_STRING } } }, - - { .function = { .native = 1, - .args_offset = 1, - .u.native = njs_prototype_function, - .object = { .type = NJS_FUNCTION } } }, - - { .object = { .type = NJS_REGEXP } }, - - { .date = { .time = NAN, - .object = { .type = NJS_DATE } } }, - - { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), - .object = { .type = NJS_OBJECT } } }, - - { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), - .object = { .type = NJS_OBJECT } } }, - - { .object = { .type = NJS_OBJECT_ERROR } }, - { .object = { .type = NJS_OBJECT_EVAL_ERROR } }, - { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, - { .object = { .type = NJS_OBJECT_RANGE_ERROR } }, - { .object = { .type = NJS_OBJECT_REF_ERROR } }, - { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, - { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, - { .object = { .type = NJS_OBJECT_URI_ERROR } }, - { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, - }; - - static const njs_function_init_t native_constructors[] = { - /* SunC does not allow empty array initialization. */ - { njs_object_constructor, { 0 } }, - { njs_array_constructor, { 0 } }, - { njs_boolean_constructor, { 0 } }, - { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, - { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_function_constructor, { 0 } }, - { njs_regexp_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } }, - { njs_date_constructor, { 0 } }, - { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, - NJS_STRING_ARG } }, - { njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_internal_error_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_range_error_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_reference_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_syntax_error_constructor, - { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_type_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_uri_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, - }; + nxt_int_t ret; + njs_module_t *module; + njs_object_t *object; + njs_function_t *func; + nxt_lvlhsh_query_t lhq; + njs_object_prototype_t *prototype; + const njs_object_init_t *obj, **p; + const njs_function_init_t *f; static const njs_object_prop_t function_prototype_property = { .type = NJS_PROPERTY_HANDLER, @@ -246,6 +248,8 @@ njs_builtin_objects_create(njs_vm_t *vm) .value = njs_prop_handler(njs_function_prototype_create), }; + static const nxt_str_t sandbox_key = nxt_string("sandbox"); + ret = njs_object_hash_create(vm, &vm->shared->function_prototype_hash, &function_prototype_property, 1); if (nxt_slow_path(ret != NXT_OK)) { @@ -259,48 +263,57 @@ njs_builtin_objects_create(njs_vm_t *vm) return NXT_ERROR; } - objects = vm->shared->objects; + object = vm->shared->objects; + + for (p = njs_object_init; *p != NULL; p++) { + obj = *p; - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { - if (njs_object_init[i] != NULL) { - ret = njs_object_hash_create(vm, &objects[i].shared_hash, - njs_object_init[i]->properties, - njs_object_init[i]->items); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } + ret = njs_object_hash_create(vm, &object->shared_hash, + obj->properties, obj->items); + + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; } - objects[i].shared = 1; + object->shared = 1; + + object++; } lhq.replace = 0; - lhq.proto = &njs_modules_hash_proto; lhq.pool = vm->mem_cache_pool; - for (i = NJS_MODULE_FS; i < NJS_MODULE_MAX; i++) { - if (vm->options.sandbox && !njs_sandbox_module(i)) { - continue; - } + for (p = njs_module_init; *p != NULL; p++) { + obj = *p; module = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_module_t)); if (nxt_slow_path(module == NULL)) { return NJS_ERROR; } - module->name = njs_module_init[i]->name; - ret = njs_object_hash_create(vm, &module->object.shared_hash, - njs_module_init[i]->properties, - njs_module_init[i]->items); + obj->properties, obj->items); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } + if (vm->options.sandbox) { + lhq.key = sandbox_key; + lhq.key_hash = nxt_djb_hash(sandbox_key.start, sandbox_key.length); + lhq.proto = &njs_object_hash_proto; + + ret = nxt_lvlhsh_find(&module->object.shared_hash, &lhq); + if (nxt_fast_path(ret != NXT_OK)) { + continue; + } + } + + module->name = obj->name; module->object.shared = 1; lhq.key = module->name; lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); + lhq.proto = &njs_modules_hash_proto; lhq.value = module; ret = nxt_lvlhsh_insert(&vm->modules_hash, &lhq); @@ -309,73 +322,88 @@ njs_builtin_objects_create(njs_vm_t *vm) } } - functions = vm->shared->functions; + f = njs_native_functions; + func = vm->shared->functions; - for (i = NJS_FUNCTION_EVAL; i < NJS_FUNCTION_MAX; i++) { - if (njs_function_init[i]->items != 0) { - ret = njs_object_hash_create(vm, &functions[i].object.shared_hash, - njs_function_init[i]->properties, - njs_function_init[i]->items); - if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; - } + for (p = njs_function_init; *p != NULL; p++) { + obj = *p; + + ret = njs_object_hash_create(vm, &func->object.shared_hash, + obj->properties, obj->items); + if (nxt_slow_path(ret != NXT_OK)) { + return NXT_ERROR; } - functions[i].object.shared = 1; - functions[i].object.extensible = 1; - functions[i].native = 1; - functions[i].args_offset = 1; - functions[i].u.native = njs_native_functions[i].native; - functions[i].args_types[0] = njs_native_functions[i].args_types[0]; - functions[i].args_types[1] = njs_native_functions[i].args_types[1]; - functions[i].args_types[2] = njs_native_functions[i].args_types[2]; - functions[i].args_types[3] = njs_native_functions[i].args_types[3]; - functions[i].args_types[4] = njs_native_functions[i].args_types[4]; + func->object.shared = 1; + func->object.extensible = 1; + func->native = 1; + func->args_offset = 1; + + func->u.native = f->native; + memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); + + f++; + func++; } - prototypes = vm->shared->prototypes; + prototype = vm->shared->prototypes; + memcpy(prototype, njs_prototype_values, sizeof(njs_prototype_values)); - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { - prototypes[i] = prototype_values[i]; + for (p = njs_prototype_init; *p != NULL; p++) { + obj = *p; - ret = njs_object_hash_create(vm, &prototypes[i].object.shared_hash, - njs_prototype_init[i]->properties, - njs_prototype_init[i]->items); + ret = njs_object_hash_create(vm, &prototype->object.shared_hash, + obj->properties, obj->items); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } + + prototype++; } - prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = + vm->shared->prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = vm->shared->empty_regexp_pattern; - constructors = vm->shared->constructors; + f = njs_native_constructors; + func = vm->shared->constructors; + + for (p = njs_constructor_init; *p != NULL; p++) { + obj = *p; - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { - constructors[i].object.shared = 0; - constructors[i].object.extensible = 1; - constructors[i].native = 1; - constructors[i].ctor = 1; - constructors[i].args_offset = 1; - constructors[i].u.native = native_constructors[i].native; - constructors[i].args_types[0] = native_constructors[i].args_types[0]; - constructors[i].args_types[1] = native_constructors[i].args_types[1]; - constructors[i].args_types[2] = native_constructors[i].args_types[2]; - constructors[i].args_types[3] = native_constructors[i].args_types[3]; - constructors[i].args_types[4] = native_constructors[i].args_types[4]; + func->object.shared = 0; + func->object.extensible = 1; + func->native = 1; + func->ctor = 1; + func->args_offset = 1; - ret = njs_object_hash_create(vm, &constructors[i].object.shared_hash, - njs_constructor_init[i]->properties, - njs_constructor_init[i]->items); + func->u.native = f->native; + + memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); + + ret = njs_object_hash_create(vm, &func->object.shared_hash, + obj->properties, obj->items); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } + + f++; + func++; } return NXT_OK; } +static njs_ret_t +njs_prototype_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, + njs_index_t unused) +{ + vm->retval = njs_value_void; + + return NXT_OK; +} + + /* * Object(), * Object.__proto__ -> Function_Prototype, @@ -493,53 +521,15 @@ njs_builtin_objects_clone(njs_vm_t *vm) } -nxt_array_t * -njs_vm_completions(njs_vm_t *vm, nxt_str_t *expression) +static size_t +njs_builtin_completions_size(njs_vm_t *vm) { - size_t size; - nxt_array_t *completions; - - if (expression == NULL) { - if (njs_builtin_completions(vm, &size, NULL) != NXT_OK) { - return NULL; - } - - completions = nxt_array_create(size, sizeof(nxt_str_t), - &njs_array_mem_proto, - vm->mem_cache_pool); - - if (nxt_slow_path(completions == NULL)) { - return NULL; - } - - if (njs_builtin_completions(vm, &size, completions->start) != NXT_OK) { - return NULL; - } - - completions->items = size; - - return completions; - } - - return njs_vm_expression_completions(vm, expression); -} - - -static nxt_int_t -njs_builtin_completions(njs_vm_t *vm, size_t *size, nxt_str_t *completions) -{ - char *compl; - size_t n, len; - nxt_str_t string; - nxt_uint_t i, k; - njs_object_t *objects; - njs_keyword_t *keyword; - njs_function_t *constructors; - njs_object_prop_t *prop; - nxt_lvlhsh_each_t lhe, lhe_prop; - njs_extern_value_t *ev; - const njs_extern_t *ext_proto, *ext_prop; - njs_object_prototype_t *prototypes; + nxt_uint_t n; + njs_keyword_t *keyword; + nxt_lvlhsh_each_t lhe, lhe_prop; + njs_extern_value_t *ev; + const njs_extern_t *ext_proto, *ext_prop; + const njs_object_init_t **p; n = 0; @@ -552,123 +542,147 @@ njs_builtin_completions(njs_vm_t *vm, si break; } - if (completions != NULL) { - completions[n++] = keyword->name; + n++; + } + + for (p = njs_object_init; *p != NULL; p++) { + n += (*p)->items; + } + + for (p = njs_prototype_init; *p != NULL; p++) { + n += (*p)->items; + } + + for (p = njs_constructor_init; *p != NULL; p++) { + n += (*p)->items; + } + + nxt_lvlhsh_each_init(&lhe, &njs_extern_value_hash_proto); - } else { + for ( ;; ) { + ev = nxt_lvlhsh_each(&vm->externals_hash, &lhe); + + if (ev == NULL) { + break; + } + + ext_proto = ev->value.external.proto; + + nxt_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto); + + n++; + + for ( ;; ) { + ext_prop = nxt_lvlhsh_each(&ext_proto->hash, &lhe_prop); + + if (ext_prop == NULL) { + break; + } + n++; } } - objects = vm->shared->objects; + return n; +} + - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { - if (njs_object_init[i] == NULL) { - continue; +static nxt_array_t * +njs_builtin_completions(njs_vm_t *vm, nxt_array_t *array) +{ + char *compl; + size_t n, len; + nxt_str_t string, *completions; + nxt_uint_t i, k; + njs_keyword_t *keyword; + nxt_lvlhsh_each_t lhe, lhe_prop; + njs_extern_value_t *ev; + const njs_extern_t *ext_proto, *ext_prop; + const njs_object_prop_t *prop; + const njs_object_init_t *obj, **p; + + n = 0; + completions = array->start; + + nxt_lvlhsh_each_init(&lhe, &njs_keyword_hash_proto); + + for ( ;; ) { + keyword = nxt_lvlhsh_each(&vm->shared->keywords_hash, &lhe); + + if (keyword == NULL) { + break; } - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + completions[n++] = keyword->name; + } + + for (p = njs_object_init; *p != NULL; p++) { + obj = *p; - for ( ;; ) { - prop = nxt_lvlhsh_each(&objects[i].shared_hash, &lhe); + for (i = 0; i < obj->items; i++) { + prop = &obj->properties[i]; + njs_string_get(&prop->name, &string); + len = obj->name.length + string.length + 2; - if (prop == NULL) { - break; + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (compl == NULL) { + return NULL; } - if (completions != NULL) { - njs_string_get(&prop->name, &string); - len = njs_object_init[i]->name.length + string.length + 2; + snprintf(compl, len, "%s.%s", obj->name.start, string.start); + + completions[n].length = len; + completions[n++].start = (u_char *) compl; + } + } + + for (p = njs_prototype_init; *p != NULL; p++) { + obj = *p; + + for (i = 0; i < obj->items; i++) { + prop = &obj->properties[i]; + njs_string_get(&prop->name, &string); + len = string.length + 2; - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (compl == NULL) { - return NXT_ERROR; + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (compl == NULL) { + return NULL; + } + + snprintf(compl, len, ".%s", string.start); + + for (k = 0; k < n; k++) { + if (strncmp((char *) completions[k].start, compl, len) + == 0) + { + break; } + } - snprintf(compl, len, "%s.%s", njs_object_init[i]->name.start, - string.start); - + if (k == n) { completions[n].length = len; completions[n++].start = (u_char *) compl; - - } else { - n++; } } } - prototypes = vm->shared->prototypes; - - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + for (p = njs_constructor_init; *p != NULL; p++) { + obj = *p; - for ( ;; ) { - prop = nxt_lvlhsh_each(&prototypes[i].object.shared_hash, &lhe); + for (i = 0; i < obj->items; i++) { + prop = &obj->properties[i]; + njs_string_get(&prop->name, &string); + len = obj->name.length + string.length + 2; - if (prop == NULL) { - break; + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (compl == NULL) { + return NULL; } - if (completions != NULL) { - njs_string_get(&prop->name, &string); - len = string.length + 2; - - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (compl == NULL) { - return NXT_ERROR; - } - - snprintf(compl, len, ".%s", string.start); - - for (k = 0; k < n; k++) { - if (strncmp((char *) completions[k].start, compl, len) - == 0) - { - break; - } - } - - if (k == n) { - completions[n].length = len; - completions[n++].start = (u_char *) compl; - } - - } else { - n++; - } - } - } + snprintf(compl, len, "%s.%s", obj->name.start, string.start); - constructors = vm->shared->constructors; - - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - - for ( ;; ) { - prop = nxt_lvlhsh_each(&constructors[i].object.shared_hash, &lhe); - - if (prop == NULL) { - break; - } - - if (completions != NULL) { - njs_string_get(&prop->name, &string); - len = njs_constructor_init[i]->name.length + string.length + 2; - - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (compl == NULL) { - return NXT_ERROR; - } - - snprintf(compl, len, "%s.%s", - njs_constructor_init[i]->name.start, string.start); - - completions[n].length = len; - completions[n++].start = (u_char *) compl; - - } else { - n++; - } + completions[n].length = len; + completions[n++].start = (u_char *) compl; } } @@ -685,21 +699,16 @@ njs_builtin_completions(njs_vm_t *vm, si nxt_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto); - if (completions != NULL) { - len = ev->name.length + 1; - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (compl == NULL) { - return NXT_ERROR; - } + len = ev->name.length + 1; + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (compl == NULL) { + return NULL; + } - snprintf(compl, len, "%.*s", (int) ev->name.length, ev->name.start); + snprintf(compl, len, "%.*s", (int) ev->name.length, ev->name.start); - completions[n].length = len; - completions[n++].start = (u_char *) compl; - - } else { - n++; - } + completions[n].length = len; + completions[n++].start = (u_char *) compl; for ( ;; ) { ext_prop = nxt_lvlhsh_each(&ext_proto->hash, &lhe_prop); @@ -708,31 +717,48 @@ njs_builtin_completions(njs_vm_t *vm, si break; } - if (completions != NULL) { - len = ev->name.length + ev->name.length + 2; - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (compl == NULL) { - return NXT_ERROR; - } + len = ev->name.length + ev->name.length + 2; + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); + if (compl == NULL) { + return NULL; + } - snprintf(compl, len, "%.*s.%.*s", (int) ev->name.length, - ev->name.start, (int) ext_prop->name.length, - ext_prop->name.start); + snprintf(compl, len, "%.*s.%.*s", (int) ev->name.length, + ev->name.start, (int) ext_prop->name.length, + ext_prop->name.start); - completions[n].length = len; - completions[n++].start = (u_char *) compl; - - } else { - n++; - } + completions[n].length = len; + completions[n++].start = (u_char *) compl; } } - if (size) { - *size = n; + array->items = n; + + return array; +} + + +nxt_array_t * +njs_vm_completions(njs_vm_t *vm, nxt_str_t *expression) +{ + size_t size; + nxt_array_t *completions; + + if (expression == NULL) { + size = njs_builtin_completions_size(vm); + + completions = nxt_array_create(size, sizeof(nxt_str_t), + &njs_array_mem_proto, + vm->mem_cache_pool); + + if (nxt_slow_path(completions == NULL)) { + return NULL; + } + + return njs_builtin_completions(vm, completions); } - return NXT_OK; + return njs_vm_expression_completions(vm, expression); } @@ -911,185 +937,135 @@ njs_object_completions(njs_vm_t *vm, njs } -nxt_int_t -njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, - nxt_str_t *name) +static nxt_int_t +njs_builtin_match(const njs_object_init_t **objects, njs_function_t *function, + const njs_object_prop_t **prop, const njs_object_init_t **object) { - char *buf; - size_t len; - nxt_str_t string; - nxt_uint_t i; - njs_module_t *module; - njs_object_t *objects; - njs_function_t *constructors; - njs_object_prop_t *prop; - nxt_lvlhsh_each_t lhe, lhe_prop; - njs_object_prototype_t *prototypes; + nxt_uint_t i; + const njs_object_init_t *o, **p; + const njs_object_prop_t *pr; - objects = vm->shared->objects; - - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { - if (njs_object_init[i] == NULL) { - continue; - } - - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + for (p = objects; *p != NULL; p++) { + o = *p; - for ( ;; ) { - prop = nxt_lvlhsh_each(&objects[i].shared_hash, &lhe); + for (i = 0; i < o->items; i++) { + pr = &o->properties[i]; - if (prop == NULL) { - break; - } - - if (!njs_is_function(&prop->value)) { + if (pr->type != NJS_METHOD) { continue; } - if (function == prop->value.data.u.function) { - njs_string_get(&prop->name, &string); - len = njs_object_init[i]->name.length + string.length - + sizeof("."); - - buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (buf == NULL) { - return NXT_ERROR; - } - - snprintf(buf, len, "%s.%s", njs_object_init[i]->name.start, - string.start); - - name->length = len; - name->start = (u_char *) buf; - - return NXT_OK; - } - } - } - - prototypes = vm->shared->prototypes; - - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - - for ( ;; ) { - prop = nxt_lvlhsh_each(&prototypes[i].object.shared_hash, &lhe); - - if (prop == NULL) { - break; - } - - if (!njs_is_function(&prop->value)) { + if (function != pr->value.data.u.function) { continue; } - if (function == prop->value.data.u.function) { - njs_string_get(&prop->name, &string); - len = njs_prototype_init[i]->name.length + string.length - + sizeof(".prototype."); - - buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); - if (buf == NULL) { - return NXT_ERROR; - } - - snprintf(buf, len, "%s.prototype.%s", - njs_prototype_init[i]->name.start, string.start); - - name->length = len; - name->start = (u_char *) buf; - - return NXT_OK; - } - } - } - - constructors = vm->shared->constructors; - - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - - for ( ;; ) { - prop = nxt_lvlhsh_each(&constructors[i].object.shared_hash, &lhe); - - if (prop == NULL) { - break; - } - - if (!njs_is_function(&prop->value)) { - continue; - } - - if (function == prop->value.data.u.function) { - njs_string_get(&prop->name, &string); From xeioex at nginx.com Thu Nov 15 17:32:03 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 15 Nov 2018 17:32:03 +0000 Subject: [njs] Fixed local scope this. Message-ID: details: http://hg.nginx.org/njs/rev/93ef4b20c674 branches: changeset: 656:93ef4b20c674 user: Dmitry Volyntsev date: Thu Nov 15 20:31:35 2018 +0300 description: Fixed local scope this. diffstat: njs/njs_parser.c | 23 +++++++++++++++++------ njs/test/njs_unit_test.c | 17 +++++++++++++++++ 2 files changed, 34 insertions(+), 6 deletions(-) diffs (74 lines): diff -r e11011d45499 -r 93ef4b20c674 njs/njs_parser.c --- a/njs/njs_parser.c Thu Nov 15 20:31:35 2018 +0300 +++ b/njs/njs_parser.c Thu Nov 15 20:31:35 2018 +0300 @@ -1806,10 +1806,11 @@ njs_parser_token(njs_parser_t *parser) njs_token_t njs_parser_terminal(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { - double num; - njs_ret_t ret; - njs_value_t *ext; - njs_parser_node_t *node; + double num; + njs_ret_t ret; + njs_value_t *ext; + njs_parser_node_t *node; + njs_parser_scope_t *scope; if (token == NJS_TOKEN_OPEN_PARENTHESIS) { @@ -1980,8 +1981,18 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa case NJS_TOKEN_THIS: nxt_thread_log_debug("JS: this"); - if (parser->scope->type != NJS_SCOPE_GLOBAL) { - node->index = NJS_INDEX_THIS; + scope = parser->scope; + + while (scope->type != NJS_SCOPE_GLOBAL) { + if (scope->type == NJS_SCOPE_FUNCTION) { + node->index = NJS_INDEX_THIS; + break; + } + + scope = scope->parent; + } + + if (node->index == NJS_INDEX_THIS) { break; } diff -r e11011d45499 -r 93ef4b20c674 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 15 20:31:35 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Nov 15 20:31:35 2018 +0300 @@ -6485,6 +6485,8 @@ static njs_unit_test_t njs_test[] = { nxt_string("/./ instanceof Object"), nxt_string("true") }, + /* global this. */ + { nxt_string("this"), nxt_string("[object Object]") }, @@ -6515,6 +6517,21 @@ static njs_unit_test_t njs_test[] = { nxt_string("this.NaN + 1"), nxt_string("NaN") }, + { nxt_string("if (1) {new this}"), + nxt_string("TypeError: object is not a function") }, + + { nxt_string("if (1) {this()}"), + nxt_string("TypeError: object is not a function") }, + + { nxt_string("var ex; try {new this} catch (e) {ex = e}; ex"), + nxt_string("TypeError: object is not a function") }, + + { nxt_string("var ex; try {({}) instanceof this} catch (e) {ex = e}; ex"), + nxt_string("TypeError: right argument is not a function") }, + + { nxt_string("Function.call(this, 'var x / = 1;')"), + nxt_string("InternalError: Not implemented") }, + { nxt_string("njs"), nxt_string("[object Object]") }, From xeioex at nginx.com Thu Nov 15 17:32:03 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 15 Nov 2018 17:32:03 +0000 Subject: [njs] Extended Object.defineProperty() spec conformance. Message-ID: details: http://hg.nginx.org/njs/rev/5f0090c02589 branches: changeset: 657:5f0090c02589 user: Dmitry Volyntsev date: Thu Nov 15 20:31:35 2018 +0300 description: Extended Object.defineProperty() spec conformance. 1) non-primitive property names. 2) support of array index properties. 3) support of special properties with NJS_PROPERTY_HANDLER, like length. diffstat: njs/njs_object.c | 128 ++++++++++++++++++++++++++++++++-------------- njs/test/njs_unit_test.c | 43 +++++++++++++++ 2 files changed, 131 insertions(+), 40 deletions(-) diffs (278 lines): diff -r 93ef4b20c674 -r 5f0090c02589 njs/njs_object.c --- a/njs/njs_object.c Thu Nov 15 20:31:35 2018 +0300 +++ b/njs/njs_object.c Thu Nov 15 20:31:35 2018 +0300 @@ -24,7 +24,7 @@ static njs_ret_t njs_external_property_d njs_value_t *setval, njs_value_t *retval); static njs_ret_t njs_object_query_prop_handler(njs_property_query_t *pq, njs_object_t *object); -static njs_ret_t njs_define_property(njs_vm_t *vm, njs_object_t *object, +static njs_ret_t njs_define_property(njs_vm_t *vm, njs_value_t *object, const njs_value_t *name, const njs_object_t *descriptor); @@ -967,17 +967,18 @@ static njs_ret_t njs_object_define_property(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - nxt_int_t ret; - const njs_value_t *value, *name, *descriptor; - - value = njs_arg(args, nargs, 1); - - if (!njs_is_object(value)) { + nxt_int_t ret; + njs_value_t *value; + const njs_value_t *name, *descriptor; + + if (!njs_is_object(njs_arg(args, nargs, 1))) { njs_type_error(vm, "cannot convert %s argument to object", - njs_type_string(value->type)); + njs_type_string(njs_arg(args, nargs, 1)->type)); return NXT_ERROR; } + value = &args[1]; + if (!value->data.u.object->extensible) { njs_type_error(vm, "object is not extensible"); return NXT_ERROR; @@ -985,16 +986,14 @@ njs_object_define_property(njs_vm_t *vm, descriptor = njs_arg(args, nargs, 3); - if (!njs_is_object(descriptor)){ + if (!njs_is_object(descriptor)) { njs_type_error(vm, "descriptor is not an object"); return NXT_ERROR; } name = njs_arg(args, nargs, 2); - ret = njs_define_property(vm, value->data.u.object, name, - descriptor->data.u.object); - + ret = njs_define_property(vm, value, name, descriptor->data.u.object); if (nxt_slow_path(ret != NXT_OK)) { return NXT_ERROR; } @@ -1010,13 +1009,13 @@ njs_object_define_properties(njs_vm_t *v njs_index_t unused) { nxt_int_t ret; + njs_value_t *value; nxt_lvlhsh_t *hash; - njs_object_t *object; nxt_lvlhsh_each_t lhe; njs_object_prop_t *prop; - const njs_value_t *value, *descriptor; - - value = njs_arg(args, nargs, 1); + const njs_value_t *descriptor; + + value = &args[1]; if (!njs_is_object(value)) { njs_type_error(vm, "cannot convert %s argument to object", @@ -1039,7 +1038,6 @@ njs_object_define_properties(njs_vm_t *v nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - object = value->data.u.object; hash = &descriptor->data.u.object->hash; for ( ;; ) { @@ -1050,7 +1048,7 @@ njs_object_define_properties(njs_vm_t *v } if (prop->enumerable && njs_is_object(&prop->value)) { - ret = njs_define_property(vm, object, &prop->name, + ret = njs_define_property(vm, value, &prop->name, prop->value.data.u.object); if (nxt_slow_path(ret != NXT_OK)) { @@ -1121,22 +1119,29 @@ njs_descriptor_prop(njs_vm_t *vm, const /* * ES5.1, 8.12.9: [[DefineOwnProperty]] - * Only data descriptors are suppored. + * Limited support of special descriptors like length and array index + * (values can be set, but without property flags support). */ static njs_ret_t -njs_define_property(njs_vm_t *vm, njs_object_t *object, const njs_value_t *name, +njs_define_property(njs_vm_t *vm, njs_value_t *object, const njs_value_t *name, const njs_object_t *descriptor) { - nxt_int_t ret; - nxt_bool_t unset; - njs_object_prop_t *desc, *current; - nxt_lvlhsh_query_t lhq; - - njs_string_get(name, &lhq.key); - lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); - lhq.proto = &njs_object_hash_proto; - - ret = nxt_lvlhsh_find(&object->hash, &lhq); + nxt_int_t ret; + nxt_bool_t unset; + njs_object_prop_t *desc, *current; + njs_property_query_t pq; + + njs_string_get(name, &pq.lhq.key); + pq.lhq.key_hash = nxt_djb_hash(pq.lhq.key.start, pq.lhq.key.length); + pq.lhq.proto = &njs_object_hash_proto; + + njs_property_query_init(&pq, NJS_PROPERTY_QUERY_SET, 0); + + ret = njs_property_query(vm, &pq, object, name); + + if (ret != NXT_OK && ret != NXT_DECLINED) { + return ret; + } unset = (ret == NXT_OK); desc = njs_descriptor_prop(vm, name, descriptor, unset); @@ -1145,14 +1150,24 @@ njs_define_property(njs_vm_t *vm, njs_ob } if (nxt_fast_path(ret == NXT_DECLINED)) { - lhq.value = desc; - lhq.replace = 0; - lhq.pool = vm->mem_cache_pool; - - ret = nxt_lvlhsh_insert(&object->hash, &lhq); - if (nxt_slow_path(ret != NXT_OK)) { - njs_internal_error(vm, "lvlhsh insert failed"); - return NXT_ERROR; + if (nxt_slow_path(pq.lhq.value != NULL)) { + current = pq.lhq.value; + + if (nxt_slow_path(current->type == NJS_WHITEOUT)) { + /* Previously deleted property. */ + *current = *desc; + } + + } else { + pq.lhq.value = desc; + pq.lhq.replace = 0; + pq.lhq.pool = vm->mem_cache_pool; + + ret = nxt_lvlhsh_insert(&object->data.u.object->hash, &pq.lhq); + if (nxt_slow_path(ret != NXT_OK)) { + njs_internal_error(vm, "lvlhsh insert failed"); + return NXT_ERROR; + } } return NXT_OK; @@ -1160,7 +1175,40 @@ njs_define_property(njs_vm_t *vm, njs_ob /* Updating existing prop. */ - current = lhq.value; + current = pq.lhq.value; + + switch (current->type) { + case NJS_PROPERTY: + break; + + case NJS_PROPERTY_REF: + if (njs_is_valid(&desc->value)) { + *current->value.data.u.value = desc->value; + } else { + *current->value.data.u.value = njs_value_void; + } + + return NXT_OK; + + case NJS_PROPERTY_HANDLER: + if (current->writable && njs_is_valid(&desc->value)) { + ret = current->value.data.u.prop_handler(vm, object, &desc->value, + &vm->retval); + + if (nxt_slow_path(ret != NXT_OK)) { + return ret; + } + } + + return NXT_OK; + + default: + njs_internal_error(vm, "unexpected property type '%s' " + "while defining property", + njs_prop_type_string(current->type)); + + return NXT_ERROR; + } if (!current->configurable) { if (desc->configurable == NJS_ATTRIBUTE_TRUE) { @@ -1208,7 +1256,7 @@ njs_define_property(njs_vm_t *vm, njs_ob exception: njs_type_error(vm, "Cannot redefine property: '%.*s'", - (int) lhq.key.length, lhq.key.start); + (int) pq.lhq.key.length, pq.lhq.key.start); return NXT_ERROR; } diff -r 93ef4b20c674 -r 5f0090c02589 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 15 20:31:35 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Nov 15 20:31:35 2018 +0300 @@ -2933,6 +2933,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("[].length = 2**32 - 1"), nxt_string("MemoryError") }, + { nxt_string("Object.defineProperty([], 'length',{value: 2**32 - 1})"), + nxt_string("MemoryError") }, + { nxt_string("[].length = 2**32"), nxt_string("RangeError: Invalid array length") }, @@ -7369,6 +7372,46 @@ static njs_unit_test_t njs_test[] = "Object.keys(o)"), nxt_string("b") }, + { nxt_string("var o = {a:1}; delete o.a;" + "Object.defineProperty(o, 'a', { value: 1 }); o.a"), + nxt_string("1") }, + + { nxt_string("var o = {a:1}; delete o.a;" + "Object.defineProperty(o, 'a', { value: 1 }); o.a = 2; o.a"), + nxt_string("TypeError: Cannot assign to read-only property 'a' of object") }, + + { nxt_string("var o = {a:1}; delete o.a;" + "Object.defineProperty(o, 'a', { value: 1, writable:1 }); o.a = 2; o.a"), + nxt_string("2") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, new String('a'), { value: 1}); o.a"), + nxt_string("1") }, + + { nxt_string("var o = {};" + "Object.defineProperty(o, {toString:function(){return 'a'}}, { value: 1}); o.a"), + nxt_string("1") }, + + { nxt_string("var a = [1, 2];" + "Object.defineProperty(a, '1', {value: 5}); a[1]"), + nxt_string("5") }, + + { nxt_string("var a = [1, 2];" + "Object.defineProperty(a, '3', {}); njs.dump(a)"), + nxt_string("[1,2,,undefined]") }, + + { nxt_string("var a = [1, 2];" + "Object.defineProperty(a, 'length', {}); a"), + nxt_string("1,2") }, + + { nxt_string("var a = [1, 2];" + "Object.defineProperty(a, 'length', {value: 1}); a"), + nxt_string("1") }, + + { nxt_string("var a = [1, 2];" + "Object.defineProperty(a, 'length', {value: 5}); a"), + nxt_string("1,2,,,") }, + { nxt_string("var o = Object.defineProperties({a:1}, {}); o.a"), nxt_string("1") }, From xeioex at nginx.com Thu Nov 15 17:32:03 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 15 Nov 2018 17:32:03 +0000 Subject: [njs] Handling non-object values in Object.keys(). Message-ID: details: http://hg.nginx.org/njs/rev/76e139b439ad branches: changeset: 658:76e139b439ad user: Dmitry Volyntsev date: Thu Nov 15 20:31:35 2018 +0300 description: Handling non-object values in Object.keys(). This fixes #54 issue on Github. diffstat: njs/njs_object.c | 133 +++++++++++++++++++++++++++++++--------------- njs/njs_object.h | 2 +- njs/test/njs_unit_test.c | 21 ++++++- 3 files changed, 108 insertions(+), 48 deletions(-) diffs (226 lines): diff -r 5f0090c02589 -r 76e139b439ad njs/njs_object.c --- a/njs/njs_object.c Thu Nov 15 20:31:35 2018 +0300 +++ b/njs/njs_object.c Thu Nov 15 20:31:35 2018 +0300 @@ -865,7 +865,7 @@ njs_object_keys(njs_vm_t *vm, njs_value_ value = njs_arg(args, nargs, 1); - if (!njs_is_object(value)) { + if (njs_is_null_or_void(value)) { njs_type_error(vm, "cannot convert %s argument to object", njs_type_string(value->type)); @@ -874,7 +874,6 @@ njs_object_keys(njs_vm_t *vm, njs_value_ keys = njs_object_keys_array(vm, value); if (keys == NULL) { - njs_memory_error(vm); return NXT_ERROR; } @@ -887,43 +886,69 @@ njs_object_keys(njs_vm_t *vm, njs_value_ njs_array_t * -njs_object_keys_array(njs_vm_t *vm, const njs_value_t *object) +njs_object_keys_array(njs_vm_t *vm, const njs_value_t *value) { - uint32_t i, n, keys_length, array_length; - njs_value_t *value; + uint32_t i, n, length, keys_length; + njs_value_t *string; njs_array_t *keys, *array; nxt_lvlhsh_t *hash; njs_object_prop_t *prop; + njs_string_prop_t string_prop; nxt_lvlhsh_each_t lhe; array = NULL; + length = 0; keys_length = 0; - array_length = 0; - - if (njs_is_array(object)) { - array = object->data.u.array; - array_length = array->length; - - for (i = 0; i < array_length; i++) { + + switch (value->type) { + case NJS_ARRAY: + array = value->data.u.array; + length = array->length; + + for (i = 0; i < length; i++) { if (njs_is_valid(&array->start[i])) { keys_length++; } } + + break; + + case NJS_STRING: + case NJS_OBJECT_STRING: + if (value->type == NJS_OBJECT_STRING) { + string = &value->data.u.object_value->value; + + } else { + string = (njs_value_t *) value; + } + + length = njs_string_prop(&string_prop, string); + keys_length += length; + break; + + default: + break; } - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - - hash = &object->data.u.object->hash; - - for ( ;; ) { - prop = nxt_lvlhsh_each(hash, &lhe); - - if (prop == NULL) { - break; - } - - if (prop->type != NJS_WHITEOUT && prop->enumerable) { - keys_length++; + if (nxt_fast_path(njs_is_object(value))) { + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + hash = &value->data.u.object->hash; + + } else { + hash = NULL; + } + + if (nxt_fast_path(hash != NULL)) { + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; + } + + if (prop->type != NJS_WHITEOUT && prop->enumerable) { + keys_length++; + } } } @@ -934,28 +959,48 @@ njs_object_keys_array(njs_vm_t *vm, cons n = 0; - for (i = 0; i < array_length; i++) { - if (njs_is_valid(&array->start[i])) { - value = &keys->start[n++]; - /* - * The maximum array index is 4294967294, so - * it can be stored as a short string inside value. - */ - njs_uint32_to_string(value, i); + switch (value->type) { + case NJS_ARRAY: + for (i = 0; i < length; i++) { + if (njs_is_valid(&array->start[i])) { + njs_uint32_to_string(&keys->start[n++], i); + } } + + break; + + case NJS_STRING: + case NJS_OBJECT_STRING: + if (value->type == NJS_OBJECT_STRING) { + string = &value->data.u.object_value->value; + + } else { + string = (njs_value_t *) value; + } + + for (i = 0; i < length; i++) { + njs_uint32_to_string(&keys->start[n++], i); + } + + break; + + default: + break; } - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); - - for ( ;; ) { - prop = nxt_lvlhsh_each(hash, &lhe); - - if (prop == NULL) { - break; - } - - if (prop->type != NJS_WHITEOUT && prop->enumerable) { - njs_string_copy(&keys->start[n++], &prop->name); + if (nxt_fast_path(hash != NULL)) { + nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); + + for ( ;; ) { + prop = nxt_lvlhsh_each(hash, &lhe); + + if (prop == NULL) { + break; + } + + if (prop->type != NJS_WHITEOUT && prop->enumerable) { + njs_string_copy(&keys->start[n++], &prop->name); + } } } diff -r 5f0090c02589 -r 76e139b439ad njs/njs_object.h --- a/njs/njs_object.h Thu Nov 15 20:31:35 2018 +0300 +++ b/njs/njs_object.h Thu Nov 15 20:31:35 2018 +0300 @@ -79,7 +79,7 @@ njs_object_t *njs_object_alloc(njs_vm_t njs_object_t *njs_object_value_copy(njs_vm_t *vm, njs_value_t *value); njs_object_t *njs_object_value_alloc(njs_vm_t *vm, const njs_value_t *value, nxt_uint_t type); -njs_array_t *njs_object_keys_array(njs_vm_t *vm, const njs_value_t *object); +njs_array_t *njs_object_keys_array(njs_vm_t *vm, const njs_value_t *value); njs_ret_t njs_value_property(njs_vm_t *vm, njs_value_t *value, const njs_value_t *property, njs_value_t *retval); njs_object_prop_t *njs_object_property(njs_vm_t *vm, const njs_object_t *obj, diff -r 5f0090c02589 -r 76e139b439ad njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 15 20:31:35 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Nov 15 20:31:35 2018 +0300 @@ -7236,11 +7236,26 @@ static njs_unit_test_t njs_test[] = { nxt_string("Object.keys()"), nxt_string("TypeError: cannot convert undefined argument to object") }, - { nxt_string("Object.keys('a')"), - nxt_string("TypeError: cannot convert string argument to object") }, + { nxt_string("Object.keys('??Z')"), + nxt_string("0,1,2") }, + + { nxt_string("Object.keys(new String('??Z'))"), + nxt_string("0,1,2") }, + + { nxt_string("var s = new String('??Z'); s.a = 1; Object.keys(s)"), + nxt_string("0,1,2,a") }, + + { nxt_string("var r = new RegExp('?bc'); r.a = 1; Object.keys(r)"), + nxt_string("a") }, + + { nxt_string("Object.keys(Object.create(new String('abc')))"), + nxt_string("") }, { nxt_string("Object.keys(1)"), - nxt_string("TypeError: cannot convert number argument to object") }, + nxt_string("") }, + + { nxt_string("Object.keys(true)"), + nxt_string("") }, { nxt_string("var o = {}; Object.defineProperty(o, 'a', {}); o.a"), nxt_string("undefined") }, From mdounin at mdounin.ru Thu Nov 15 18:31:34 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 15 Nov 2018 18:31:34 +0000 Subject: [nginx] Core: ngx_explicit_memzero(). Message-ID: details: http://hg.nginx.org/nginx/rev/9ca82f273967 branches: changeset: 7395:9ca82f273967 user: Maxim Dounin date: Thu Nov 15 21:28:02 2018 +0300 description: Core: ngx_explicit_memzero(). diffstat: src/core/ngx_string.c | 8 ++++++++ src/core/ngx_string.h | 2 ++ src/event/ngx_event_openssl.c | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) diffs (51 lines): diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -2013,6 +2013,14 @@ ngx_sort(void *base, size_t n, size_t si } +void +ngx_explicit_memzero(void *buf, size_t n) +{ + ngx_memzero(buf, n); + ngx_memory_barrier(); +} + + #if (NGX_MEMCPY_LIMIT) void * diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -88,6 +88,8 @@ ngx_strlchr(u_char *p, u_char *last, u_c #define ngx_memzero(buf, n) (void) memset(buf, 0, n) #define ngx_memset(buf, c, n) (void) memset(buf, c, n) +void ngx_explicit_memzero(void *buf, size_t n); + #if (NGX_MEMCPY_LIMIT) 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 @@ -1051,7 +1051,7 @@ cleanup: ngx_close_file_n " \"%s\" failed", file->data); } - ngx_memzero(buf, NGX_SSL_PASSWORD_BUFFER_SIZE); + ngx_explicit_memzero(buf, NGX_SSL_PASSWORD_BUFFER_SIZE); return passwords; } @@ -1068,7 +1068,7 @@ ngx_ssl_passwords_cleanup(void *data) pwd = passwords->elts; for (i = 0; i < passwords->nelts; i++) { - ngx_memzero(pwd[i].data, pwd[i].len); + ngx_explicit_memzero(pwd[i].data, pwd[i].len); } } From ramprasad.tamilselvan at quantil.com Thu Nov 15 18:55:27 2018 From: ramprasad.tamilselvan at quantil.com (Ramprasad Tamilselvan) Date: Thu, 15 Nov 2018 10:55:27 -0800 Subject: [PATCH] New directive to configure TLSv1.3 ciphers In-Reply-To: References: Message-ID: Thanks for the clarification. In this case, I think the patch is not required. Regards, Ramprasad > On Nov 15, 2018, at 9:32 AM, nginx-devel-request at nginx.org wrote: > > Send nginx-devel mailing list submissions to > nginx-devel at nginx.org > > To subscribe or unsubscribe via the World Wide Web, visit > http://mailman.nginx.org/mailman/listinfo/nginx-devel > or, via email, send a message with subject or body 'help' to > nginx-devel-request at nginx.org > > You can reach the person managing the list at > nginx-devel-owner at nginx.org > > When replying, please edit your Subject line so it is more specific > than "Re: Contents of nginx-devel digest..." > > > Today's Topics: > > 1. [nginx] Core: free shared memory on cycle initialization > failure. (Ruslan Ermilov) > 2. Re: [PATCH] New directive to configure TLSv1.3 ciphers > (Maxim Dounin) > 3. [njs] console.time() and console.timeEnd() methods. > (Dmitry Volyntsev) > 4. [njs] Fixed global objects. (Dmitry Volyntsev) > 5. [njs] Improved handling of builtin objects. (Dmitry Volyntsev) > > > ---------------------------------------------------------------------- > > Message: 1 > Date: Thu, 15 Nov 2018 14:19:57 +0000 > From: Ruslan Ermilov > To: nginx-devel at nginx.org > Subject: [nginx] Core: free shared memory on cycle initialization > failure. > Message-ID: > > Content-Type: text/plain; charset="us-ascii" > > details: http://hg.nginx.org/nginx/rev/650574a44505 > branches: > changeset: 7394:650574a44505 > user: Ruslan Ermilov > date: Thu Nov 15 15:28:54 2018 +0300 > description: > Core: free shared memory on cycle initialization failure. > > diffstat: > > src/core/ngx_cycle.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 files changed, 64 insertions(+), 0 deletions(-) > > diffs (81 lines): > > diff -r 4698cede59ff -r 650574a44505 src/core/ngx_cycle.c > --- a/src/core/ngx_cycle.c Mon Nov 12 16:29:30 2018 +0300 > +++ b/src/core/ngx_cycle.c Thu Nov 15 15:28:54 2018 +0300 > @@ -843,6 +843,69 @@ failed: > } > } > > + /* free the newly created shared memory */ > + > + part = &cycle->shared_memory.part; > + shm_zone = part->elts; > + > + for (i = 0; /* void */ ; i++) { > + > + if (i >= part->nelts) { > + if (part->next == NULL) { > + break; > + } > + part = part->next; > + shm_zone = part->elts; > + i = 0; > + } > + > + if (shm_zone[i].shm.addr == NULL) { > + continue; > + } > + > + opart = &old_cycle->shared_memory.part; > + oshm_zone = opart->elts; > + > + for (n = 0; /* void */ ; n++) { > + > + if (n >= opart->nelts) { > + if (opart->next == NULL) { > + break; > + } > + opart = opart->next; > + oshm_zone = opart->elts; > + n = 0; > + } > + > + if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) { > + continue; > + } > + > + if (ngx_strncmp(shm_zone[i].shm.name.data, > + oshm_zone[n].shm.name.data, > + shm_zone[i].shm.name.len) > + != 0) > + { > + continue; > + } > + > + if (shm_zone[i].tag == oshm_zone[n].tag > + && shm_zone[i].shm.size == oshm_zone[n].shm.size > + && !shm_zone[i].noreuse) > + { > + goto old_shm_zone_found; > + } > + > + break; > + } > + > + ngx_shm_free(&shm_zone[i].shm); > + > + old_shm_zone_found: > + > + continue; > + } > + > if (ngx_test_config) { > ngx_destroy_cycle_pools(&conf); > return NULL; > @@ -1274,6 +1337,7 @@ ngx_shared_memory_add(ngx_conf_t *cf, ng > > shm_zone->data = NULL; > shm_zone->shm.log = cf->cycle->log; > + shm_zone->shm.addr = NULL; > shm_zone->shm.size = size; > shm_zone->shm.name = *name; > shm_zone->shm.exists = 0; > > > ------------------------------ > > Message: 2 > Date: Thu, 15 Nov 2018 17:53:53 +0300 > From: Maxim Dounin > To: nginx-devel at nginx.org > Subject: Re: [PATCH] New directive to configure TLSv1.3 ciphers > Message-ID: <20181115145353.GA99070 at mdounin.ru> > Content-Type: text/plain; charset=us-ascii > > Hello! > > On Wed, Nov 14, 2018 at 05:24:52PM -0800, Ramprasad Tamilselvan wrote: > >> # HG changeset patch >> # User Ramprasad Tamilselvan >> # Date 1542241466 28800 >> # Wed Nov 14 16:24:26 2018 -0800 >> # Node ID 83b05772dbd657b31df16d712a64c908c371f0d9 >> # Parent 4698cede59ffa438bcae1fd6c5d8fec4d69b2c92 >> New directive to configure TLSv1.3 ciphers. >> >> In openssl 1.1.1, a new API is introduced to configure ciphers >> for TLSv1.3. A new directive ssl_ciphersuites will call the new >> API to configure the ciphers for TLSv1.3. > > Thank you for your patch. > > I do object introducing a new directive for this, see this ticket > for details: > > https://trac.nginx.org/nginx/ticket/1529 > > -- > Maxim Dounin > http://mdounin.ru/ > > > ------------------------------ > > Message: 3 > Date: Thu, 15 Nov 2018 17:32:02 +0000 > From: Dmitry Volyntsev > To: nginx-devel at nginx.org > Subject: [njs] console.time() and console.timeEnd() methods. > Message-ID: > > Content-Type: text/plain; charset="utf-8" > > details: http://hg.nginx.org/njs/rev/46632012ac03 > branches: > changeset: 653:46632012ac03 > user: Artem S. Povalyukhin > date: Wed Nov 14 18:14:49 2018 +0300 > description: > console.time() and console.timeEnd() methods. > > This fixes #62 issue on Github. > > diffstat: > > njs/njs_shell.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ > njs/test/njs_expect_test.exp | 18 ++++++++- > 2 files changed, 103 insertions(+), 1 deletions(-) > > diffs (156 lines): > > diff -r 7f0f7d149709 -r 46632012ac03 njs/njs_shell.c > --- a/njs/njs_shell.c Thu Nov 15 12:45:02 2018 +0300 > +++ b/njs/njs_shell.c Wed Nov 14 18:14:49 2018 +0300 > @@ -14,6 +14,7 @@ > #include > #include > #include > +#include > #include > > #include > @@ -63,6 +64,10 @@ static njs_ret_t njs_ext_console_dump(nj > nxt_uint_t nargs, njs_index_t unused); > static njs_ret_t njs_ext_console_help(njs_vm_t *vm, njs_value_t *args, > nxt_uint_t nargs, njs_index_t unused); > +static njs_ret_t njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, > + nxt_uint_t nargs, njs_index_t unused); > +static njs_ret_t njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, > + nxt_uint_t nargs, njs_index_t unused); > > > static njs_external_t njs_ext_console[] = { > @@ -102,6 +107,30 @@ static njs_external_t njs_ext_console[] > NULL, > njs_ext_console_help, > 0 }, > + > + { nxt_string("time"), > + NJS_EXTERN_METHOD, > + NULL, > + 0, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + njs_ext_console_time, > + 0 }, > + > + { nxt_string("timeEnd"), > + NJS_EXTERN_METHOD, > + NULL, > + 0, > + NULL, > + NULL, > + NULL, > + NULL, > + NULL, > + njs_ext_console_time_end, > + 0 }, > }; > > static njs_external_t njs_externals[] = { > @@ -123,6 +152,9 @@ static njs_external_t njs_externals[] = > static njs_completion_t njs_completion; > > > +static struct timeval njs_console_time; > + > + > int > main(int argc, char **argv) > { > @@ -727,3 +759,57 @@ njs_ext_console_help(njs_vm_t *vm, njs_v > > return NJS_OK; > } > + > + > +static njs_ret_t > +njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, > + njs_index_t unused) > +{ > + if (!njs_value_is_void(njs_arg(args, nargs, 1))) { > + njs_vm_error(vm, "labels not implemented"); > + return NJS_ERROR; > + } > + > + vm->retval = njs_value_void; > + > + gettimeofday(&njs_console_time, NULL); > + > + return NJS_OK; > +} > + > + > +static njs_ret_t > +njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, > + njs_index_t unused) > +{ > + int64_t us, ms; > + struct timeval tv; > + > + gettimeofday(&tv, NULL); > + > + if (!njs_value_is_void(njs_arg(args, nargs, 1))) { > + njs_vm_error(vm, "labels not implemented"); > + return NJS_ERROR; > + } > + > + if (nxt_fast_path(njs_console_time.tv_sec || njs_console_time.tv_usec)) { > + > + us = ((int64_t) tv.tv_sec - njs_console_time.tv_sec) * 1000000 > + + ((int64_t) tv.tv_usec - njs_console_time.tv_usec); > + > + ms = us / 1000; > + us = us % 1000; > + > + printf("default: %" PRIu64 ".%03" PRIu64 "ms\n", ms, us); > + > + njs_console_time.tv_sec = 0; > + njs_console_time.tv_usec = 0; > + > + } else { > + printf("Timer \"default\" doesn?t exist.\n"); > + } > + > + vm->retval = njs_value_void; > + > + return NJS_OK; > +} > diff -r 7f0f7d149709 -r 46632012ac03 njs/test/njs_expect_test.exp > --- a/njs/test/njs_expect_test.exp Thu Nov 15 12:45:02 2018 +0300 > +++ b/njs/test/njs_expect_test.exp Wed Nov 14 18:14:49 2018 +0300 > @@ -80,7 +80,7 @@ njs_test { > # Global completions, multiple partial match > njs_test { > {"cons\t\t" > - "console*console.help*console.log*const"} > + "console*console.help*console.time*const"} > } > > njs_test { > @@ -190,6 +190,22 @@ njs_test { > "console.help()\r\nVM built-in objects:"} > } > > +# console.time* functions > +njs_test { > + {"console.time()\r\n" > + "console.time()\r\nundefined\r\n>> "} > + {"console.time(undefined)\r\n" > + "console.time(undefined)\r\nundefined\r\n>> "} > + {"console.timeEnd()\r\n" > + "console.timeEnd()\r\ndefault: *.*ms\r\nundefined\r\n>> "} > + {"console.time('a')\r\n" > + "console.time('a')\r\nError: labels not implemented"} > + {"console.timeEnd('a')\r\n" > + "console.timeEnd('a')\r\nError: labels not implemented"} > + {"console.timeEnd()\r\n" > + "console.timeEnd()\r\nTimer \"default\" doesn?t exist."} > +} > + > njs_test { > {"console.ll()\r\n" > "console.ll()\r\nTypeError: 'll' is not a function"} > > ------------------------------ > > Message: 4 > Date: Thu, 15 Nov 2018 17:32:02 +0000 > From: Dmitry Volyntsev > To: nginx-devel at nginx.org > Subject: [njs] Fixed global objects. > Message-ID: > > Content-Type: text/plain; charset="us-ascii" > > details: http://hg.nginx.org/njs/rev/e11011d45499 > branches: > changeset: 655:e11011d45499 > user: Dmitry Volyntsev > date: Thu Nov 15 20:31:35 2018 +0300 > description: > Fixed global objects. > > 1) Making it extensible. > 2) Adding default properties according to ES5.1:15.1.1. > > diffstat: > > njs/njs_builtin.c | 27 +++++++++++++++++++++++++-- > njs/test/njs_unit_test.c | 30 ++++++++++++++++++++++++++++++ > 2 files changed, 55 insertions(+), 2 deletions(-) > > diffs (91 lines): > > diff -r 2711e84ede6a -r e11011d45499 njs/njs_builtin.c > --- a/njs/njs_builtin.c Wed Apr 04 17:38:10 2018 +0300 > +++ b/njs/njs_builtin.c Thu Nov 15 20:31:35 2018 +0300 > @@ -276,6 +276,7 @@ njs_builtin_objects_create(njs_vm_t *vm) > } > > object->shared = 1; > + object->extensible = 1; > > object++; > } > @@ -1118,8 +1119,30 @@ const njs_object_init_t njs_njs_object_ > }; > > > +static const njs_object_prop_t njs_global_this_object_properties[] = > +{ > + { > + .type = NJS_PROPERTY, > + .name = njs_string("NaN"), > + .value = njs_value(NJS_NUMBER, 0, NAN), > + }, > + > + { > + .type = NJS_PROPERTY, > + .name = njs_string("Infinity"), > + .value = njs_value(NJS_NUMBER, 0, INFINITY), > + }, > + > + { > + .type = NJS_PROPERTY, > + .name = njs_string("undefined"), > + .value = njs_value(NJS_VOID, 0, NAN), > + }, > +}; > + > + > const njs_object_init_t njs_global_this_init = { > nxt_string("this"), > - NULL, > - 0 > + njs_global_this_object_properties, > + nxt_nitems(njs_global_this_object_properties) > }; > diff -r 2711e84ede6a -r e11011d45499 njs/test/njs_unit_test.c > --- a/njs/test/njs_unit_test.c Wed Apr 04 17:38:10 2018 +0300 > +++ b/njs/test/njs_unit_test.c Thu Nov 15 20:31:35 2018 +0300 > @@ -6488,6 +6488,33 @@ static njs_unit_test_t njs_test[] = > { nxt_string("this"), > nxt_string("[object Object]") }, > > + { nxt_string("this.a = 1; this.a"), > + nxt_string("1") }, > + > + { nxt_string("this.undefined = 42"), > + nxt_string("TypeError: Cannot assign to read-only property 'undefined' of object") }, > + > + { nxt_string("this.Infinity = 42"), > + nxt_string("TypeError: Cannot assign to read-only property 'Infinity' of object") }, > + > + { nxt_string("this.NaN = 42"), > + nxt_string("TypeError: Cannot assign to read-only property 'NaN' of object") }, > + > + { nxt_string("typeof this.undefined"), > + nxt_string("undefined") }, > + > + { nxt_string("typeof this.Infinity"), > + nxt_string("number") }, > + > + { nxt_string("this.Infinity + 1"), > + nxt_string("Infinity") }, > + > + { nxt_string("typeof this.NaN"), > + nxt_string("number") }, > + > + { nxt_string("this.NaN + 1"), > + nxt_string("NaN") }, > + > { nxt_string("njs"), > nxt_string("[object Object]") }, > > @@ -9177,6 +9204,9 @@ static njs_unit_test_t njs_test[] = > { nxt_string("Math"), > nxt_string("[object Object]") }, > > + { nxt_string("Math.x = function (x) {return 2*x;}; Math.x(3)"), > + nxt_string("6") }, > + > { nxt_string("isNaN"), > nxt_string("[object Function]") }, > > > > ------------------------------ > > Message: 5 > Date: Thu, 15 Nov 2018 17:32:02 +0000 > From: Dmitry Volyntsev > To: nginx-devel at nginx.org > Subject: [njs] Improved handling of builtin objects. > Message-ID: > > Content-Type: text/plain; charset="us-ascii" > > details: http://hg.nginx.org/njs/rev/2711e84ede6a > branches: > changeset: 654:2711e84ede6a > user: Dmitry Volyntsev > date: Wed Apr 04 17:38:10 2018 +0300 > description: > Improved handling of builtin objects. > > The handling of njs_object_init_t arrays is unified across > njs_builtin.c functions. > > diffstat: > > njs/njs_builtin.c | 939 +++++++++++++++++++-------------------- > njs/njs_crypto.c | 12 + > njs/njs_fs.c | 6 + > njs/njs_module.c | 16 - > njs/njs_module.h | 1 - > njs/njs_shell.c | 19 +- > njs/njs_vm.h | 7 - > njs/test/njs_expect_test.exp | 5 + > njs/test/njs_interactive_test.c | 5 + > 9 files changed, 499 insertions(+), 511 deletions(-) > > diffs (truncated from 1323 to 1000 lines): > > diff -r 46632012ac03 -r 2711e84ede6a njs/njs_builtin.c > --- a/njs/njs_builtin.c Wed Nov 14 18:14:49 2018 +0300 > +++ b/njs/njs_builtin.c Wed Apr 04 17:38:10 2018 +0300 > @@ -1,6 +1,7 @@ > > /* > * Copyright (C) Igor Sysoev > + * Copyright (C) Dmitry Volyntsev > * Copyright (C) NGINX, Inc. > */ > > @@ -23,25 +24,30 @@ typedef struct { > } njs_function_init_t; > > > -static nxt_int_t njs_builtin_completions(njs_vm_t *vm, size_t *size, > - nxt_str_t *completions); > +static njs_ret_t njs_prototype_function(njs_vm_t *vm, njs_value_t *args, > + nxt_uint_t nargs, njs_index_t unused); > static nxt_array_t *njs_vm_expression_completions(njs_vm_t *vm, > nxt_str_t *expression); > static nxt_array_t *njs_object_completions(njs_vm_t *vm, njs_object_t *object); > > + > const njs_object_init_t njs_njs_object_init; > +const njs_object_init_t njs_global_this_init; > + > > const njs_object_init_t *njs_object_init[] = { > - NULL, /* global this */ > + &njs_global_this_init, /* global this */ > &njs_njs_object_init, /* global njs object */ > &njs_math_object_init, /* Math */ > &njs_json_object_init, /* JSON */ > + NULL > }; > > > const njs_object_init_t *njs_module_init[] = { > &njs_fs_object_init, /* fs */ > - &njs_crypto_object_init /* crypto */ > + &njs_crypto_object_init, /* crypto */ > + NULL > }; > > > @@ -64,6 +70,7 @@ const njs_object_init_t *njs_prototype_ > &njs_syntax_error_prototype_init, > &njs_type_error_prototype_init, > &njs_uri_error_prototype_init, > + NULL > }; > > > @@ -87,6 +94,7 @@ const njs_object_init_t *njs_construc > &njs_type_error_constructor_init, > &njs_uri_error_constructor_init, > &njs_memory_error_constructor_init, > + NULL > }; > > > @@ -103,7 +111,8 @@ const njs_object_init_t *njs_function > &njs_decode_uri_component_function_init, > &njs_require_function_init, > &njs_set_timeout_function_init, > - &njs_clear_timeout_function_init > + &njs_clear_timeout_function_init, > + NULL > }; > > > @@ -143,102 +152,95 @@ const njs_object_prop_t njs_arguments_o > }; > > > -static njs_ret_t > -njs_prototype_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, > - njs_index_t unused) > -{ > - vm->retval = njs_value_void; > +const njs_function_init_t njs_native_constructors[] = { > + /* SunC does not allow empty array initialization. */ > + { njs_object_constructor, { 0 } }, > + { njs_array_constructor, { 0 } }, > + { njs_boolean_constructor, { 0 } }, > + { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, > + { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > + { njs_function_constructor, { 0 } }, > + { njs_regexp_constructor, > + { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } }, > + { njs_date_constructor, { 0 } }, > + { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > + { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, > + NJS_STRING_ARG } }, > + { njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > + { njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > + { njs_internal_error_constructor, > + { NJS_SKIP_ARG, NJS_STRING_ARG } }, > + { njs_range_error_constructor, > + { NJS_SKIP_ARG, NJS_STRING_ARG } }, > + { njs_reference_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > + { njs_syntax_error_constructor, > + { NJS_SKIP_ARG, NJS_STRING_ARG } }, > + { njs_type_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > + { njs_uri_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > + { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > +}; > + > +const njs_object_prototype_t njs_prototype_values[] = { > + /* > + * GCC 4 complains about uninitialized .shared field, > + * if the .type field is initialized as .object.type. > + */ > + { .object = { .type = NJS_OBJECT } }, > + { .object = { .type = NJS_ARRAY } }, > > - return NXT_OK; > -} > + /* > + * The .object.type field must be initialzed after the .value field, > + * otherwise SunC 5.9 treats the .value as .object.value or so. > + */ > + { .object_value = { .value = njs_value(NJS_BOOLEAN, 0, 0.0), > + .object = { .type = NJS_OBJECT_BOOLEAN } } }, > + > + { .object_value = { .value = njs_value(NJS_NUMBER, 0, 0.0), > + .object = { .type = NJS_OBJECT_NUMBER } } }, > + > + { .object_value = { .value = njs_string(""), > + .object = { .type = NJS_OBJECT_STRING } } }, > + > + { .function = { .native = 1, > + .args_offset = 1, > + .u.native = njs_prototype_function, > + .object = { .type = NJS_FUNCTION } } }, > + > + { .object = { .type = NJS_REGEXP } }, > + > + { .date = { .time = NAN, > + .object = { .type = NJS_DATE } } }, > + > + { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), > + .object = { .type = NJS_OBJECT } } }, > + > + { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), > + .object = { .type = NJS_OBJECT } } }, > + > + { .object = { .type = NJS_OBJECT_ERROR } }, > + { .object = { .type = NJS_OBJECT_EVAL_ERROR } }, > + { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, > + { .object = { .type = NJS_OBJECT_RANGE_ERROR } }, > + { .object = { .type = NJS_OBJECT_REF_ERROR } }, > + { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, > + { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, > + { .object = { .type = NJS_OBJECT_URI_ERROR } }, > + { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, > +}; > + > > > nxt_int_t > njs_builtin_objects_create(njs_vm_t *vm) > { > - nxt_int_t ret; > - nxt_uint_t i; > - njs_module_t *module; > - njs_object_t *objects; > - njs_function_t *functions, *constructors; > - nxt_lvlhsh_query_t lhq; > - njs_object_prototype_t *prototypes; > - > - static const njs_object_prototype_t prototype_values[] = { > - /* > - * GCC 4 complains about uninitialized .shared field, > - * if the .type field is initialized as .object.type. > - */ > - { .object = { .type = NJS_OBJECT } }, > - { .object = { .type = NJS_ARRAY } }, > - > - /* > - * The .object.type field must be initialzed after the .value field, > - * otherwise SunC 5.9 treats the .value as .object.value or so. > - */ > - { .object_value = { .value = njs_value(NJS_BOOLEAN, 0, 0.0), > - .object = { .type = NJS_OBJECT_BOOLEAN } } }, > - > - { .object_value = { .value = njs_value(NJS_NUMBER, 0, 0.0), > - .object = { .type = NJS_OBJECT_NUMBER } } }, > - > - { .object_value = { .value = njs_string(""), > - .object = { .type = NJS_OBJECT_STRING } } }, > - > - { .function = { .native = 1, > - .args_offset = 1, > - .u.native = njs_prototype_function, > - .object = { .type = NJS_FUNCTION } } }, > - > - { .object = { .type = NJS_REGEXP } }, > - > - { .date = { .time = NAN, > - .object = { .type = NJS_DATE } } }, > - > - { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), > - .object = { .type = NJS_OBJECT } } }, > - > - { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), > - .object = { .type = NJS_OBJECT } } }, > - > - { .object = { .type = NJS_OBJECT_ERROR } }, > - { .object = { .type = NJS_OBJECT_EVAL_ERROR } }, > - { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, > - { .object = { .type = NJS_OBJECT_RANGE_ERROR } }, > - { .object = { .type = NJS_OBJECT_REF_ERROR } }, > - { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, > - { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, > - { .object = { .type = NJS_OBJECT_URI_ERROR } }, > - { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, > - }; > - > - static const njs_function_init_t native_constructors[] = { > - /* SunC does not allow empty array initialization. */ > - { njs_object_constructor, { 0 } }, > - { njs_array_constructor, { 0 } }, > - { njs_boolean_constructor, { 0 } }, > - { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, > - { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - { njs_function_constructor, { 0 } }, > - { njs_regexp_constructor, > - { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } }, > - { njs_date_constructor, { 0 } }, > - { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, > - NJS_STRING_ARG } }, > - { njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - { njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - { njs_internal_error_constructor, > - { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - { njs_range_error_constructor, > - { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - { njs_reference_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - { njs_syntax_error_constructor, > - { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - { njs_type_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - { njs_uri_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, > - }; > + nxt_int_t ret; > + njs_module_t *module; > + njs_object_t *object; > + njs_function_t *func; > + nxt_lvlhsh_query_t lhq; > + njs_object_prototype_t *prototype; > + const njs_object_init_t *obj, **p; > + const njs_function_init_t *f; > > static const njs_object_prop_t function_prototype_property = { > .type = NJS_PROPERTY_HANDLER, > @@ -246,6 +248,8 @@ njs_builtin_objects_create(njs_vm_t *vm) > .value = njs_prop_handler(njs_function_prototype_create), > }; > > + static const nxt_str_t sandbox_key = nxt_string("sandbox"); > + > ret = njs_object_hash_create(vm, &vm->shared->function_prototype_hash, > &function_prototype_property, 1); > if (nxt_slow_path(ret != NXT_OK)) { > @@ -259,48 +263,57 @@ njs_builtin_objects_create(njs_vm_t *vm) > return NXT_ERROR; > } > > - objects = vm->shared->objects; > + object = vm->shared->objects; > + > + for (p = njs_object_init; *p != NULL; p++) { > + obj = *p; > > - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { > - if (njs_object_init[i] != NULL) { > - ret = njs_object_hash_create(vm, &objects[i].shared_hash, > - njs_object_init[i]->properties, > - njs_object_init[i]->items); > - if (nxt_slow_path(ret != NXT_OK)) { > - return NXT_ERROR; > - } > + ret = njs_object_hash_create(vm, &object->shared_hash, > + obj->properties, obj->items); > + > + if (nxt_slow_path(ret != NXT_OK)) { > + return NXT_ERROR; > } > > - objects[i].shared = 1; > + object->shared = 1; > + > + object++; > } > > lhq.replace = 0; > - lhq.proto = &njs_modules_hash_proto; > lhq.pool = vm->mem_cache_pool; > > - for (i = NJS_MODULE_FS; i < NJS_MODULE_MAX; i++) { > - if (vm->options.sandbox && !njs_sandbox_module(i)) { > - continue; > - } > + for (p = njs_module_init; *p != NULL; p++) { > + obj = *p; > > module = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_module_t)); > if (nxt_slow_path(module == NULL)) { > return NJS_ERROR; > } > > - module->name = njs_module_init[i]->name; > - > ret = njs_object_hash_create(vm, &module->object.shared_hash, > - njs_module_init[i]->properties, > - njs_module_init[i]->items); > + obj->properties, obj->items); > if (nxt_slow_path(ret != NXT_OK)) { > return NXT_ERROR; > } > > + if (vm->options.sandbox) { > + lhq.key = sandbox_key; > + lhq.key_hash = nxt_djb_hash(sandbox_key.start, sandbox_key.length); > + lhq.proto = &njs_object_hash_proto; > + > + ret = nxt_lvlhsh_find(&module->object.shared_hash, &lhq); > + if (nxt_fast_path(ret != NXT_OK)) { > + continue; > + } > + } > + > + module->name = obj->name; > module->object.shared = 1; > > lhq.key = module->name; > lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); > + lhq.proto = &njs_modules_hash_proto; > lhq.value = module; > > ret = nxt_lvlhsh_insert(&vm->modules_hash, &lhq); > @@ -309,73 +322,88 @@ njs_builtin_objects_create(njs_vm_t *vm) > } > } > > - functions = vm->shared->functions; > + f = njs_native_functions; > + func = vm->shared->functions; > > - for (i = NJS_FUNCTION_EVAL; i < NJS_FUNCTION_MAX; i++) { > - if (njs_function_init[i]->items != 0) { > - ret = njs_object_hash_create(vm, &functions[i].object.shared_hash, > - njs_function_init[i]->properties, > - njs_function_init[i]->items); > - if (nxt_slow_path(ret != NXT_OK)) { > - return NXT_ERROR; > - } > + for (p = njs_function_init; *p != NULL; p++) { > + obj = *p; > + > + ret = njs_object_hash_create(vm, &func->object.shared_hash, > + obj->properties, obj->items); > + if (nxt_slow_path(ret != NXT_OK)) { > + return NXT_ERROR; > } > > - functions[i].object.shared = 1; > - functions[i].object.extensible = 1; > - functions[i].native = 1; > - functions[i].args_offset = 1; > - functions[i].u.native = njs_native_functions[i].native; > - functions[i].args_types[0] = njs_native_functions[i].args_types[0]; > - functions[i].args_types[1] = njs_native_functions[i].args_types[1]; > - functions[i].args_types[2] = njs_native_functions[i].args_types[2]; > - functions[i].args_types[3] = njs_native_functions[i].args_types[3]; > - functions[i].args_types[4] = njs_native_functions[i].args_types[4]; > + func->object.shared = 1; > + func->object.extensible = 1; > + func->native = 1; > + func->args_offset = 1; > + > + func->u.native = f->native; > + memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); > + > + f++; > + func++; > } > > - prototypes = vm->shared->prototypes; > + prototype = vm->shared->prototypes; > + memcpy(prototype, njs_prototype_values, sizeof(njs_prototype_values)); > > - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { > - prototypes[i] = prototype_values[i]; > + for (p = njs_prototype_init; *p != NULL; p++) { > + obj = *p; > > - ret = njs_object_hash_create(vm, &prototypes[i].object.shared_hash, > - njs_prototype_init[i]->properties, > - njs_prototype_init[i]->items); > + ret = njs_object_hash_create(vm, &prototype->object.shared_hash, > + obj->properties, obj->items); > if (nxt_slow_path(ret != NXT_OK)) { > return NXT_ERROR; > } > + > + prototype++; > } > > - prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = > + vm->shared->prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = > vm->shared->empty_regexp_pattern; > > - constructors = vm->shared->constructors; > + f = njs_native_constructors; > + func = vm->shared->constructors; > + > + for (p = njs_constructor_init; *p != NULL; p++) { > + obj = *p; > > - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { > - constructors[i].object.shared = 0; > - constructors[i].object.extensible = 1; > - constructors[i].native = 1; > - constructors[i].ctor = 1; > - constructors[i].args_offset = 1; > - constructors[i].u.native = native_constructors[i].native; > - constructors[i].args_types[0] = native_constructors[i].args_types[0]; > - constructors[i].args_types[1] = native_constructors[i].args_types[1]; > - constructors[i].args_types[2] = native_constructors[i].args_types[2]; > - constructors[i].args_types[3] = native_constructors[i].args_types[3]; > - constructors[i].args_types[4] = native_constructors[i].args_types[4]; > + func->object.shared = 0; > + func->object.extensible = 1; > + func->native = 1; > + func->ctor = 1; > + func->args_offset = 1; > > - ret = njs_object_hash_create(vm, &constructors[i].object.shared_hash, > - njs_constructor_init[i]->properties, > - njs_constructor_init[i]->items); > + func->u.native = f->native; > + > + memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); > + > + ret = njs_object_hash_create(vm, &func->object.shared_hash, > + obj->properties, obj->items); > if (nxt_slow_path(ret != NXT_OK)) { > return NXT_ERROR; > } > + > + f++; > + func++; > } > > return NXT_OK; > } > > > +static njs_ret_t > +njs_prototype_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, > + njs_index_t unused) > +{ > + vm->retval = njs_value_void; > + > + return NXT_OK; > +} > + > + > /* > * Object(), > * Object.__proto__ -> Function_Prototype, > @@ -493,53 +521,15 @@ njs_builtin_objects_clone(njs_vm_t *vm) > } > > > -nxt_array_t * > -njs_vm_completions(njs_vm_t *vm, nxt_str_t *expression) > +static size_t > +njs_builtin_completions_size(njs_vm_t *vm) > { > - size_t size; > - nxt_array_t *completions; > - > - if (expression == NULL) { > - if (njs_builtin_completions(vm, &size, NULL) != NXT_OK) { > - return NULL; > - } > - > - completions = nxt_array_create(size, sizeof(nxt_str_t), > - &njs_array_mem_proto, > - vm->mem_cache_pool); > - > - if (nxt_slow_path(completions == NULL)) { > - return NULL; > - } > - > - if (njs_builtin_completions(vm, &size, completions->start) != NXT_OK) { > - return NULL; > - } > - > - completions->items = size; > - > - return completions; > - } > - > - return njs_vm_expression_completions(vm, expression); > -} > - > - > -static nxt_int_t > -njs_builtin_completions(njs_vm_t *vm, size_t *size, nxt_str_t *completions) > -{ > - char *compl; > - size_t n, len; > - nxt_str_t string; > - nxt_uint_t i, k; > - njs_object_t *objects; > - njs_keyword_t *keyword; > - njs_function_t *constructors; > - njs_object_prop_t *prop; > - nxt_lvlhsh_each_t lhe, lhe_prop; > - njs_extern_value_t *ev; > - const njs_extern_t *ext_proto, *ext_prop; > - njs_object_prototype_t *prototypes; > + nxt_uint_t n; > + njs_keyword_t *keyword; > + nxt_lvlhsh_each_t lhe, lhe_prop; > + njs_extern_value_t *ev; > + const njs_extern_t *ext_proto, *ext_prop; > + const njs_object_init_t **p; > > n = 0; > > @@ -552,123 +542,147 @@ njs_builtin_completions(njs_vm_t *vm, si > break; > } > > - if (completions != NULL) { > - completions[n++] = keyword->name; > + n++; > + } > + > + for (p = njs_object_init; *p != NULL; p++) { > + n += (*p)->items; > + } > + > + for (p = njs_prototype_init; *p != NULL; p++) { > + n += (*p)->items; > + } > + > + for (p = njs_constructor_init; *p != NULL; p++) { > + n += (*p)->items; > + } > + > + nxt_lvlhsh_each_init(&lhe, &njs_extern_value_hash_proto); > > - } else { > + for ( ;; ) { > + ev = nxt_lvlhsh_each(&vm->externals_hash, &lhe); > + > + if (ev == NULL) { > + break; > + } > + > + ext_proto = ev->value.external.proto; > + > + nxt_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto); > + > + n++; > + > + for ( ;; ) { > + ext_prop = nxt_lvlhsh_each(&ext_proto->hash, &lhe_prop); > + > + if (ext_prop == NULL) { > + break; > + } > + > n++; > } > } > > - objects = vm->shared->objects; > + return n; > +} > + > > - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { > - if (njs_object_init[i] == NULL) { > - continue; > +static nxt_array_t * > +njs_builtin_completions(njs_vm_t *vm, nxt_array_t *array) > +{ > + char *compl; > + size_t n, len; > + nxt_str_t string, *completions; > + nxt_uint_t i, k; > + njs_keyword_t *keyword; > + nxt_lvlhsh_each_t lhe, lhe_prop; > + njs_extern_value_t *ev; > + const njs_extern_t *ext_proto, *ext_prop; > + const njs_object_prop_t *prop; > + const njs_object_init_t *obj, **p; > + > + n = 0; > + completions = array->start; > + > + nxt_lvlhsh_each_init(&lhe, &njs_keyword_hash_proto); > + > + for ( ;; ) { > + keyword = nxt_lvlhsh_each(&vm->shared->keywords_hash, &lhe); > + > + if (keyword == NULL) { > + break; > } > > - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); > + completions[n++] = keyword->name; > + } > + > + for (p = njs_object_init; *p != NULL; p++) { > + obj = *p; > > - for ( ;; ) { > - prop = nxt_lvlhsh_each(&objects[i].shared_hash, &lhe); > + for (i = 0; i < obj->items; i++) { > + prop = &obj->properties[i]; > + njs_string_get(&prop->name, &string); > + len = obj->name.length + string.length + 2; > > - if (prop == NULL) { > - break; > + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > + if (compl == NULL) { > + return NULL; > } > > - if (completions != NULL) { > - njs_string_get(&prop->name, &string); > - len = njs_object_init[i]->name.length + string.length + 2; > + snprintf(compl, len, "%s.%s", obj->name.start, string.start); > + > + completions[n].length = len; > + completions[n++].start = (u_char *) compl; > + } > + } > + > + for (p = njs_prototype_init; *p != NULL; p++) { > + obj = *p; > + > + for (i = 0; i < obj->items; i++) { > + prop = &obj->properties[i]; > + njs_string_get(&prop->name, &string); > + len = string.length + 2; > > - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > - if (compl == NULL) { > - return NXT_ERROR; > + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > + if (compl == NULL) { > + return NULL; > + } > + > + snprintf(compl, len, ".%s", string.start); > + > + for (k = 0; k < n; k++) { > + if (strncmp((char *) completions[k].start, compl, len) > + == 0) > + { > + break; > } > + } > > - snprintf(compl, len, "%s.%s", njs_object_init[i]->name.start, > - string.start); > - > + if (k == n) { > completions[n].length = len; > completions[n++].start = (u_char *) compl; > - > - } else { > - n++; > } > } > } > > - prototypes = vm->shared->prototypes; > - > - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { > - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); > + for (p = njs_constructor_init; *p != NULL; p++) { > + obj = *p; > > - for ( ;; ) { > - prop = nxt_lvlhsh_each(&prototypes[i].object.shared_hash, &lhe); > + for (i = 0; i < obj->items; i++) { > + prop = &obj->properties[i]; > + njs_string_get(&prop->name, &string); > + len = obj->name.length + string.length + 2; > > - if (prop == NULL) { > - break; > + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > + if (compl == NULL) { > + return NULL; > } > > - if (completions != NULL) { > - njs_string_get(&prop->name, &string); > - len = string.length + 2; > - > - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > - if (compl == NULL) { > - return NXT_ERROR; > - } > - > - snprintf(compl, len, ".%s", string.start); > - > - for (k = 0; k < n; k++) { > - if (strncmp((char *) completions[k].start, compl, len) > - == 0) > - { > - break; > - } > - } > - > - if (k == n) { > - completions[n].length = len; > - completions[n++].start = (u_char *) compl; > - } > - > - } else { > - n++; > - } > - } > - } > + snprintf(compl, len, "%s.%s", obj->name.start, string.start); > > - constructors = vm->shared->constructors; > - > - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { > - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); > - > - for ( ;; ) { > - prop = nxt_lvlhsh_each(&constructors[i].object.shared_hash, &lhe); > - > - if (prop == NULL) { > - break; > - } > - > - if (completions != NULL) { > - njs_string_get(&prop->name, &string); > - len = njs_constructor_init[i]->name.length + string.length + 2; > - > - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > - if (compl == NULL) { > - return NXT_ERROR; > - } > - > - snprintf(compl, len, "%s.%s", > - njs_constructor_init[i]->name.start, string.start); > - > - completions[n].length = len; > - completions[n++].start = (u_char *) compl; > - > - } else { > - n++; > - } > + completions[n].length = len; > + completions[n++].start = (u_char *) compl; > } > } > > @@ -685,21 +699,16 @@ njs_builtin_completions(njs_vm_t *vm, si > > nxt_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto); > > - if (completions != NULL) { > - len = ev->name.length + 1; > - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > - if (compl == NULL) { > - return NXT_ERROR; > - } > + len = ev->name.length + 1; > + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > + if (compl == NULL) { > + return NULL; > + } > > - snprintf(compl, len, "%.*s", (int) ev->name.length, ev->name.start); > + snprintf(compl, len, "%.*s", (int) ev->name.length, ev->name.start); > > - completions[n].length = len; > - completions[n++].start = (u_char *) compl; > - > - } else { > - n++; > - } > + completions[n].length = len; > + completions[n++].start = (u_char *) compl; > > for ( ;; ) { > ext_prop = nxt_lvlhsh_each(&ext_proto->hash, &lhe_prop); > @@ -708,31 +717,48 @@ njs_builtin_completions(njs_vm_t *vm, si > break; > } > > - if (completions != NULL) { > - len = ev->name.length + ev->name.length + 2; > - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > - if (compl == NULL) { > - return NXT_ERROR; > - } > + len = ev->name.length + ev->name.length + 2; > + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > + if (compl == NULL) { > + return NULL; > + } > > - snprintf(compl, len, "%.*s.%.*s", (int) ev->name.length, > - ev->name.start, (int) ext_prop->name.length, > - ext_prop->name.start); > + snprintf(compl, len, "%.*s.%.*s", (int) ev->name.length, > + ev->name.start, (int) ext_prop->name.length, > + ext_prop->name.start); > > - completions[n].length = len; > - completions[n++].start = (u_char *) compl; > - > - } else { > - n++; > - } > + completions[n].length = len; > + completions[n++].start = (u_char *) compl; > } > } > > - if (size) { > - *size = n; > + array->items = n; > + > + return array; > +} > + > + > +nxt_array_t * > +njs_vm_completions(njs_vm_t *vm, nxt_str_t *expression) > +{ > + size_t size; > + nxt_array_t *completions; > + > + if (expression == NULL) { > + size = njs_builtin_completions_size(vm); > + > + completions = nxt_array_create(size, sizeof(nxt_str_t), > + &njs_array_mem_proto, > + vm->mem_cache_pool); > + > + if (nxt_slow_path(completions == NULL)) { > + return NULL; > + } > + > + return njs_builtin_completions(vm, completions); > } > > - return NXT_OK; > + return njs_vm_expression_completions(vm, expression); > } > > > @@ -911,185 +937,135 @@ njs_object_completions(njs_vm_t *vm, njs > } > > > -nxt_int_t > -njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, > - nxt_str_t *name) > +static nxt_int_t > +njs_builtin_match(const njs_object_init_t **objects, njs_function_t *function, > + const njs_object_prop_t **prop, const njs_object_init_t **object) > { > - char *buf; > - size_t len; > - nxt_str_t string; > - nxt_uint_t i; > - njs_module_t *module; > - njs_object_t *objects; > - njs_function_t *constructors; > - njs_object_prop_t *prop; > - nxt_lvlhsh_each_t lhe, lhe_prop; > - njs_object_prototype_t *prototypes; > + nxt_uint_t i; > + const njs_object_init_t *o, **p; > + const njs_object_prop_t *pr; > > - objects = vm->shared->objects; > - > - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { > - if (njs_object_init[i] == NULL) { > - continue; > - } > - > - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); > + for (p = objects; *p != NULL; p++) { > + o = *p; > > - for ( ;; ) { > - prop = nxt_lvlhsh_each(&objects[i].shared_hash, &lhe); > + for (i = 0; i < o->items; i++) { > + pr = &o->properties[i]; > > - if (prop == NULL) { > - break; > - } > - > - if (!njs_is_function(&prop->value)) { > + if (pr->type != NJS_METHOD) { > continue; > } > > - if (function == prop->value.data.u.function) { > - njs_string_get(&prop->name, &string); > - len = njs_object_init[i]->name.length + string.length > - + sizeof("."); > - > - buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > - if (buf == NULL) { > - return NXT_ERROR; > - } > - > - snprintf(buf, len, "%s.%s", njs_object_init[i]->name.start, > - string.start); > - > - name->length = len; > - name->start = (u_char *) buf; > - > - return NXT_OK; > - } > - } > - } > - > - prototypes = vm->shared->prototypes; > - > - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { > - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); > - > - for ( ;; ) { > - prop = nxt_lvlhsh_each(&prototypes[i].object.shared_hash, &lhe); > - > - if (prop == NULL) { > - break; > - } > - > - if (!njs_is_function(&prop->value)) { > + if (function != pr->value.data.u.function) { > continue; > } > > - if (function == prop->value.data.u.function) { > - njs_string_get(&prop->name, &string); > - len = njs_prototype_init[i]->name.length + string.length > - + sizeof(".prototype."); > - > - buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); > - if (buf == NULL) { > - return NXT_ERROR; > - } > - > - snprintf(buf, len, "%s.prototype.%s", > - njs_prototype_init[i]->name.start, string.start); > - > - name->length = len; > - name->start = (u_char *) buf; > - > - return NXT_OK; > - } > - } > - } > - > - constructors = vm->shared->constructors; > - > - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { > - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); > - > - for ( ;; ) { > - prop = nxt_lvlhsh_each(&constructors[i].object.shared_hash, &lhe); > - > - if (prop == NULL) { > - break; > - } > - > - if (!njs_is_function(&prop->value)) { > - continue; > - } > - > - if (function == prop->value.data.u.function) { > - njs_string_get(&prop->name, &string); > > > ------------------------------ > > Subject: Digest Footer > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > ------------------------------ > > End of nginx-devel Digest, Vol 109, Issue 15 > ******************************************** From ramprasad.tamilselvan at quantil.com Thu Nov 15 20:17:15 2018 From: ramprasad.tamilselvan at quantil.com (Ramprasad Tamilselvan) Date: Thu, 15 Nov 2018 12:17:15 -0800 Subject: [PATCH] New directive to configure TLSv1.3 ciphers In-Reply-To: References: Message-ID: <38EDD810-9040-4ECF-91A3-92CD7C30E7EE@quantil.com> I have a question regarding the ticket. What if different TLSv1.3 ciphers need to be configured in different server blocks? In this case, changing openssl.conf will not help right. Thanks, Ramprasad > On Nov 15, 2018, at 10:55 AM, nginx-devel-request at nginx.org wrote: > > Send nginx-devel mailing list submissions to > nginx-devel at nginx.org > > To subscribe or unsubscribe via the World Wide Web, visit > http://mailman.nginx.org/mailman/listinfo/nginx-devel > or, via email, send a message with subject or body 'help' to > nginx-devel-request at nginx.org > > You can reach the person managing the list at > nginx-devel-owner at nginx.org > > When replying, please edit your Subject line so it is more specific > than "Re: Contents of nginx-devel digest..." > > > Today's Topics: > > 1. Re: [PATCH] New directive to configure TLSv1.3 ciphers > (Ramprasad Tamilselvan) > > > ---------------------------------------------------------------------- > > Message: 1 > Date: Thu, 15 Nov 2018 10:55:27 -0800 > From: Ramprasad Tamilselvan > To: nginx-devel at nginx.org > Subject: Re: [PATCH] New directive to configure TLSv1.3 ciphers > Message-ID: > Content-Type: text/plain; charset=us-ascii > > Thanks for the clarification. > In this case, I think the patch is not required. > > Regards, > Ramprasad > >> On Nov 15, 2018, at 9:32 AM, nginx-devel-request at nginx.org wrote: >> >> Send nginx-devel mailing list submissions to >> nginx-devel at nginx.org >> >> To subscribe or unsubscribe via the World Wide Web, visit >> http://mailman.nginx.org/mailman/listinfo/nginx-devel >> or, via email, send a message with subject or body 'help' to >> nginx-devel-request at nginx.org >> >> You can reach the person managing the list at >> nginx-devel-owner at nginx.org >> >> When replying, please edit your Subject line so it is more specific >> than "Re: Contents of nginx-devel digest..." >> >> >> Today's Topics: >> >> 1. [nginx] Core: free shared memory on cycle initialization >> failure. (Ruslan Ermilov) >> 2. Re: [PATCH] New directive to configure TLSv1.3 ciphers >> (Maxim Dounin) >> 3. [njs] console.time() and console.timeEnd() methods. >> (Dmitry Volyntsev) >> 4. [njs] Fixed global objects. (Dmitry Volyntsev) >> 5. [njs] Improved handling of builtin objects. (Dmitry Volyntsev) >> >> >> ---------------------------------------------------------------------- >> >> Message: 1 >> Date: Thu, 15 Nov 2018 14:19:57 +0000 >> From: Ruslan Ermilov >> To: nginx-devel at nginx.org >> Subject: [nginx] Core: free shared memory on cycle initialization >> failure. >> Message-ID: >> >> Content-Type: text/plain; charset="us-ascii" >> >> details: http://hg.nginx.org/nginx/rev/650574a44505 >> branches: >> changeset: 7394:650574a44505 >> user: Ruslan Ermilov >> date: Thu Nov 15 15:28:54 2018 +0300 >> description: >> Core: free shared memory on cycle initialization failure. >> >> diffstat: >> >> src/core/ngx_cycle.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 1 files changed, 64 insertions(+), 0 deletions(-) >> >> diffs (81 lines): >> >> diff -r 4698cede59ff -r 650574a44505 src/core/ngx_cycle.c >> --- a/src/core/ngx_cycle.c Mon Nov 12 16:29:30 2018 +0300 >> +++ b/src/core/ngx_cycle.c Thu Nov 15 15:28:54 2018 +0300 >> @@ -843,6 +843,69 @@ failed: >> } >> } >> >> + /* free the newly created shared memory */ >> + >> + part = &cycle->shared_memory.part; >> + shm_zone = part->elts; >> + >> + for (i = 0; /* void */ ; i++) { >> + >> + if (i >= part->nelts) { >> + if (part->next == NULL) { >> + break; >> + } >> + part = part->next; >> + shm_zone = part->elts; >> + i = 0; >> + } >> + >> + if (shm_zone[i].shm.addr == NULL) { >> + continue; >> + } >> + >> + opart = &old_cycle->shared_memory.part; >> + oshm_zone = opart->elts; >> + >> + for (n = 0; /* void */ ; n++) { >> + >> + if (n >= opart->nelts) { >> + if (opart->next == NULL) { >> + break; >> + } >> + opart = opart->next; >> + oshm_zone = opart->elts; >> + n = 0; >> + } >> + >> + if (shm_zone[i].shm.name.len != oshm_zone[n].shm.name.len) { >> + continue; >> + } >> + >> + if (ngx_strncmp(shm_zone[i].shm.name.data, >> + oshm_zone[n].shm.name.data, >> + shm_zone[i].shm.name.len) >> + != 0) >> + { >> + continue; >> + } >> + >> + if (shm_zone[i].tag == oshm_zone[n].tag >> + && shm_zone[i].shm.size == oshm_zone[n].shm.size >> + && !shm_zone[i].noreuse) >> + { >> + goto old_shm_zone_found; >> + } >> + >> + break; >> + } >> + >> + ngx_shm_free(&shm_zone[i].shm); >> + >> + old_shm_zone_found: >> + >> + continue; >> + } >> + >> if (ngx_test_config) { >> ngx_destroy_cycle_pools(&conf); >> return NULL; >> @@ -1274,6 +1337,7 @@ ngx_shared_memory_add(ngx_conf_t *cf, ng >> >> shm_zone->data = NULL; >> shm_zone->shm.log = cf->cycle->log; >> + shm_zone->shm.addr = NULL; >> shm_zone->shm.size = size; >> shm_zone->shm.name = *name; >> shm_zone->shm.exists = 0; >> >> >> ------------------------------ >> >> Message: 2 >> Date: Thu, 15 Nov 2018 17:53:53 +0300 >> From: Maxim Dounin >> To: nginx-devel at nginx.org >> Subject: Re: [PATCH] New directive to configure TLSv1.3 ciphers >> Message-ID: <20181115145353.GA99070 at mdounin.ru> >> Content-Type: text/plain; charset=us-ascii >> >> Hello! >> >> On Wed, Nov 14, 2018 at 05:24:52PM -0800, Ramprasad Tamilselvan wrote: >> >>> # HG changeset patch >>> # User Ramprasad Tamilselvan >>> # Date 1542241466 28800 >>> # Wed Nov 14 16:24:26 2018 -0800 >>> # Node ID 83b05772dbd657b31df16d712a64c908c371f0d9 >>> # Parent 4698cede59ffa438bcae1fd6c5d8fec4d69b2c92 >>> New directive to configure TLSv1.3 ciphers. >>> >>> In openssl 1.1.1, a new API is introduced to configure ciphers >>> for TLSv1.3. A new directive ssl_ciphersuites will call the new >>> API to configure the ciphers for TLSv1.3. >> >> Thank you for your patch. >> >> I do object introducing a new directive for this, see this ticket >> for details: >> >> https://trac.nginx.org/nginx/ticket/1529 >> >> -- >> Maxim Dounin >> http://mdounin.ru/ >> >> >> ------------------------------ >> >> Message: 3 >> Date: Thu, 15 Nov 2018 17:32:02 +0000 >> From: Dmitry Volyntsev >> To: nginx-devel at nginx.org >> Subject: [njs] console.time() and console.timeEnd() methods. >> Message-ID: >> >> Content-Type: text/plain; charset="utf-8" >> >> details: http://hg.nginx.org/njs/rev/46632012ac03 >> branches: >> changeset: 653:46632012ac03 >> user: Artem S. Povalyukhin >> date: Wed Nov 14 18:14:49 2018 +0300 >> description: >> console.time() and console.timeEnd() methods. >> >> This fixes #62 issue on Github. >> >> diffstat: >> >> njs/njs_shell.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ >> njs/test/njs_expect_test.exp | 18 ++++++++- >> 2 files changed, 103 insertions(+), 1 deletions(-) >> >> diffs (156 lines): >> >> diff -r 7f0f7d149709 -r 46632012ac03 njs/njs_shell.c >> --- a/njs/njs_shell.c Thu Nov 15 12:45:02 2018 +0300 >> +++ b/njs/njs_shell.c Wed Nov 14 18:14:49 2018 +0300 >> @@ -14,6 +14,7 @@ >> #include >> #include >> #include >> +#include >> #include >> >> #include >> @@ -63,6 +64,10 @@ static njs_ret_t njs_ext_console_dump(nj >> nxt_uint_t nargs, njs_index_t unused); >> static njs_ret_t njs_ext_console_help(njs_vm_t *vm, njs_value_t *args, >> nxt_uint_t nargs, njs_index_t unused); >> +static njs_ret_t njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, >> + nxt_uint_t nargs, njs_index_t unused); >> +static njs_ret_t njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, >> + nxt_uint_t nargs, njs_index_t unused); >> >> >> static njs_external_t njs_ext_console[] = { >> @@ -102,6 +107,30 @@ static njs_external_t njs_ext_console[] >> NULL, >> njs_ext_console_help, >> 0 }, >> + >> + { nxt_string("time"), >> + NJS_EXTERN_METHOD, >> + NULL, >> + 0, >> + NULL, >> + NULL, >> + NULL, >> + NULL, >> + NULL, >> + njs_ext_console_time, >> + 0 }, >> + >> + { nxt_string("timeEnd"), >> + NJS_EXTERN_METHOD, >> + NULL, >> + 0, >> + NULL, >> + NULL, >> + NULL, >> + NULL, >> + NULL, >> + njs_ext_console_time_end, >> + 0 }, >> }; >> >> static njs_external_t njs_externals[] = { >> @@ -123,6 +152,9 @@ static njs_external_t njs_externals[] = >> static njs_completion_t njs_completion; >> >> >> +static struct timeval njs_console_time; >> + >> + >> int >> main(int argc, char **argv) >> { >> @@ -727,3 +759,57 @@ njs_ext_console_help(njs_vm_t *vm, njs_v >> >> return NJS_OK; >> } >> + >> + >> +static njs_ret_t >> +njs_ext_console_time(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, >> + njs_index_t unused) >> +{ >> + if (!njs_value_is_void(njs_arg(args, nargs, 1))) { >> + njs_vm_error(vm, "labels not implemented"); >> + return NJS_ERROR; >> + } >> + >> + vm->retval = njs_value_void; >> + >> + gettimeofday(&njs_console_time, NULL); >> + >> + return NJS_OK; >> +} >> + >> + >> +static njs_ret_t >> +njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, >> + njs_index_t unused) >> +{ >> + int64_t us, ms; >> + struct timeval tv; >> + >> + gettimeofday(&tv, NULL); >> + >> + if (!njs_value_is_void(njs_arg(args, nargs, 1))) { >> + njs_vm_error(vm, "labels not implemented"); >> + return NJS_ERROR; >> + } >> + >> + if (nxt_fast_path(njs_console_time.tv_sec || njs_console_time.tv_usec)) { >> + >> + us = ((int64_t) tv.tv_sec - njs_console_time.tv_sec) * 1000000 >> + + ((int64_t) tv.tv_usec - njs_console_time.tv_usec); >> + >> + ms = us / 1000; >> + us = us % 1000; >> + >> + printf("default: %" PRIu64 ".%03" PRIu64 "ms\n", ms, us); >> + >> + njs_console_time.tv_sec = 0; >> + njs_console_time.tv_usec = 0; >> + >> + } else { >> + printf("Timer \"default\" doesn?t exist.\n"); >> + } >> + >> + vm->retval = njs_value_void; >> + >> + return NJS_OK; >> +} >> diff -r 7f0f7d149709 -r 46632012ac03 njs/test/njs_expect_test.exp >> --- a/njs/test/njs_expect_test.exp Thu Nov 15 12:45:02 2018 +0300 >> +++ b/njs/test/njs_expect_test.exp Wed Nov 14 18:14:49 2018 +0300 >> @@ -80,7 +80,7 @@ njs_test { >> # Global completions, multiple partial match >> njs_test { >> {"cons\t\t" >> - "console*console.help*console.log*const"} >> + "console*console.help*console.time*const"} >> } >> >> njs_test { >> @@ -190,6 +190,22 @@ njs_test { >> "console.help()\r\nVM built-in objects:"} >> } >> >> +# console.time* functions >> +njs_test { >> + {"console.time()\r\n" >> + "console.time()\r\nundefined\r\n>> "} >> + {"console.time(undefined)\r\n" >> + "console.time(undefined)\r\nundefined\r\n>> "} >> + {"console.timeEnd()\r\n" >> + "console.timeEnd()\r\ndefault: *.*ms\r\nundefined\r\n>> "} >> + {"console.time('a')\r\n" >> + "console.time('a')\r\nError: labels not implemented"} >> + {"console.timeEnd('a')\r\n" >> + "console.timeEnd('a')\r\nError: labels not implemented"} >> + {"console.timeEnd()\r\n" >> + "console.timeEnd()\r\nTimer \"default\" doesn?t exist."} >> +} >> + >> njs_test { >> {"console.ll()\r\n" >> "console.ll()\r\nTypeError: 'll' is not a function"} >> >> ------------------------------ >> >> Message: 4 >> Date: Thu, 15 Nov 2018 17:32:02 +0000 >> From: Dmitry Volyntsev >> To: nginx-devel at nginx.org >> Subject: [njs] Fixed global objects. >> Message-ID: >> >> Content-Type: text/plain; charset="us-ascii" >> >> details: http://hg.nginx.org/njs/rev/e11011d45499 >> branches: >> changeset: 655:e11011d45499 >> user: Dmitry Volyntsev >> date: Thu Nov 15 20:31:35 2018 +0300 >> description: >> Fixed global objects. >> >> 1) Making it extensible. >> 2) Adding default properties according to ES5.1:15.1.1. >> >> diffstat: >> >> njs/njs_builtin.c | 27 +++++++++++++++++++++++++-- >> njs/test/njs_unit_test.c | 30 ++++++++++++++++++++++++++++++ >> 2 files changed, 55 insertions(+), 2 deletions(-) >> >> diffs (91 lines): >> >> diff -r 2711e84ede6a -r e11011d45499 njs/njs_builtin.c >> --- a/njs/njs_builtin.c Wed Apr 04 17:38:10 2018 +0300 >> +++ b/njs/njs_builtin.c Thu Nov 15 20:31:35 2018 +0300 >> @@ -276,6 +276,7 @@ njs_builtin_objects_create(njs_vm_t *vm) >> } >> >> object->shared = 1; >> + object->extensible = 1; >> >> object++; >> } >> @@ -1118,8 +1119,30 @@ const njs_object_init_t njs_njs_object_ >> }; >> >> >> +static const njs_object_prop_t njs_global_this_object_properties[] = >> +{ >> + { >> + .type = NJS_PROPERTY, >> + .name = njs_string("NaN"), >> + .value = njs_value(NJS_NUMBER, 0, NAN), >> + }, >> + >> + { >> + .type = NJS_PROPERTY, >> + .name = njs_string("Infinity"), >> + .value = njs_value(NJS_NUMBER, 0, INFINITY), >> + }, >> + >> + { >> + .type = NJS_PROPERTY, >> + .name = njs_string("undefined"), >> + .value = njs_value(NJS_VOID, 0, NAN), >> + }, >> +}; >> + >> + >> const njs_object_init_t njs_global_this_init = { >> nxt_string("this"), >> - NULL, >> - 0 >> + njs_global_this_object_properties, >> + nxt_nitems(njs_global_this_object_properties) >> }; >> diff -r 2711e84ede6a -r e11011d45499 njs/test/njs_unit_test.c >> --- a/njs/test/njs_unit_test.c Wed Apr 04 17:38:10 2018 +0300 >> +++ b/njs/test/njs_unit_test.c Thu Nov 15 20:31:35 2018 +0300 >> @@ -6488,6 +6488,33 @@ static njs_unit_test_t njs_test[] = >> { nxt_string("this"), >> nxt_string("[object Object]") }, >> >> + { nxt_string("this.a = 1; this.a"), >> + nxt_string("1") }, >> + >> + { nxt_string("this.undefined = 42"), >> + nxt_string("TypeError: Cannot assign to read-only property 'undefined' of object") }, >> + >> + { nxt_string("this.Infinity = 42"), >> + nxt_string("TypeError: Cannot assign to read-only property 'Infinity' of object") }, >> + >> + { nxt_string("this.NaN = 42"), >> + nxt_string("TypeError: Cannot assign to read-only property 'NaN' of object") }, >> + >> + { nxt_string("typeof this.undefined"), >> + nxt_string("undefined") }, >> + >> + { nxt_string("typeof this.Infinity"), >> + nxt_string("number") }, >> + >> + { nxt_string("this.Infinity + 1"), >> + nxt_string("Infinity") }, >> + >> + { nxt_string("typeof this.NaN"), >> + nxt_string("number") }, >> + >> + { nxt_string("this.NaN + 1"), >> + nxt_string("NaN") }, >> + >> { nxt_string("njs"), >> nxt_string("[object Object]") }, >> >> @@ -9177,6 +9204,9 @@ static njs_unit_test_t njs_test[] = >> { nxt_string("Math"), >> nxt_string("[object Object]") }, >> >> + { nxt_string("Math.x = function (x) {return 2*x;}; Math.x(3)"), >> + nxt_string("6") }, >> + >> { nxt_string("isNaN"), >> nxt_string("[object Function]") }, >> >> >> >> ------------------------------ >> >> Message: 5 >> Date: Thu, 15 Nov 2018 17:32:02 +0000 >> From: Dmitry Volyntsev >> To: nginx-devel at nginx.org >> Subject: [njs] Improved handling of builtin objects. >> Message-ID: >> >> Content-Type: text/plain; charset="us-ascii" >> >> details: http://hg.nginx.org/njs/rev/2711e84ede6a >> branches: >> changeset: 654:2711e84ede6a >> user: Dmitry Volyntsev >> date: Wed Apr 04 17:38:10 2018 +0300 >> description: >> Improved handling of builtin objects. >> >> The handling of njs_object_init_t arrays is unified across >> njs_builtin.c functions. >> >> diffstat: >> >> njs/njs_builtin.c | 939 +++++++++++++++++++-------------------- >> njs/njs_crypto.c | 12 + >> njs/njs_fs.c | 6 + >> njs/njs_module.c | 16 - >> njs/njs_module.h | 1 - >> njs/njs_shell.c | 19 +- >> njs/njs_vm.h | 7 - >> njs/test/njs_expect_test.exp | 5 + >> njs/test/njs_interactive_test.c | 5 + >> 9 files changed, 499 insertions(+), 511 deletions(-) >> >> diffs (truncated from 1323 to 1000 lines): >> >> diff -r 46632012ac03 -r 2711e84ede6a njs/njs_builtin.c >> --- a/njs/njs_builtin.c Wed Nov 14 18:14:49 2018 +0300 >> +++ b/njs/njs_builtin.c Wed Apr 04 17:38:10 2018 +0300 >> @@ -1,6 +1,7 @@ >> >> /* >> * Copyright (C) Igor Sysoev >> + * Copyright (C) Dmitry Volyntsev >> * Copyright (C) NGINX, Inc. >> */ >> >> @@ -23,25 +24,30 @@ typedef struct { >> } njs_function_init_t; >> >> >> -static nxt_int_t njs_builtin_completions(njs_vm_t *vm, size_t *size, >> - nxt_str_t *completions); >> +static njs_ret_t njs_prototype_function(njs_vm_t *vm, njs_value_t *args, >> + nxt_uint_t nargs, njs_index_t unused); >> static nxt_array_t *njs_vm_expression_completions(njs_vm_t *vm, >> nxt_str_t *expression); >> static nxt_array_t *njs_object_completions(njs_vm_t *vm, njs_object_t *object); >> >> + >> const njs_object_init_t njs_njs_object_init; >> +const njs_object_init_t njs_global_this_init; >> + >> >> const njs_object_init_t *njs_object_init[] = { >> - NULL, /* global this */ >> + &njs_global_this_init, /* global this */ >> &njs_njs_object_init, /* global njs object */ >> &njs_math_object_init, /* Math */ >> &njs_json_object_init, /* JSON */ >> + NULL >> }; >> >> >> const njs_object_init_t *njs_module_init[] = { >> &njs_fs_object_init, /* fs */ >> - &njs_crypto_object_init /* crypto */ >> + &njs_crypto_object_init, /* crypto */ >> + NULL >> }; >> >> >> @@ -64,6 +70,7 @@ const njs_object_init_t *njs_prototype_ >> &njs_syntax_error_prototype_init, >> &njs_type_error_prototype_init, >> &njs_uri_error_prototype_init, >> + NULL >> }; >> >> >> @@ -87,6 +94,7 @@ const njs_object_init_t *njs_construc >> &njs_type_error_constructor_init, >> &njs_uri_error_constructor_init, >> &njs_memory_error_constructor_init, >> + NULL >> }; >> >> >> @@ -103,7 +111,8 @@ const njs_object_init_t *njs_function >> &njs_decode_uri_component_function_init, >> &njs_require_function_init, >> &njs_set_timeout_function_init, >> - &njs_clear_timeout_function_init >> + &njs_clear_timeout_function_init, >> + NULL >> }; >> >> >> @@ -143,102 +152,95 @@ const njs_object_prop_t njs_arguments_o >> }; >> >> >> -static njs_ret_t >> -njs_prototype_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, >> - njs_index_t unused) >> -{ >> - vm->retval = njs_value_void; >> +const njs_function_init_t njs_native_constructors[] = { >> + /* SunC does not allow empty array initialization. */ >> + { njs_object_constructor, { 0 } }, >> + { njs_array_constructor, { 0 } }, >> + { njs_boolean_constructor, { 0 } }, >> + { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, >> + { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> + { njs_function_constructor, { 0 } }, >> + { njs_regexp_constructor, >> + { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } }, >> + { njs_date_constructor, { 0 } }, >> + { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> + { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, >> + NJS_STRING_ARG } }, >> + { njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> + { njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> + { njs_internal_error_constructor, >> + { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> + { njs_range_error_constructor, >> + { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> + { njs_reference_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> + { njs_syntax_error_constructor, >> + { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> + { njs_type_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> + { njs_uri_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> + { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> +}; >> + >> +const njs_object_prototype_t njs_prototype_values[] = { >> + /* >> + * GCC 4 complains about uninitialized .shared field, >> + * if the .type field is initialized as .object.type. >> + */ >> + { .object = { .type = NJS_OBJECT } }, >> + { .object = { .type = NJS_ARRAY } }, >> >> - return NXT_OK; >> -} >> + /* >> + * The .object.type field must be initialzed after the .value field, >> + * otherwise SunC 5.9 treats the .value as .object.value or so. >> + */ >> + { .object_value = { .value = njs_value(NJS_BOOLEAN, 0, 0.0), >> + .object = { .type = NJS_OBJECT_BOOLEAN } } }, >> + >> + { .object_value = { .value = njs_value(NJS_NUMBER, 0, 0.0), >> + .object = { .type = NJS_OBJECT_NUMBER } } }, >> + >> + { .object_value = { .value = njs_string(""), >> + .object = { .type = NJS_OBJECT_STRING } } }, >> + >> + { .function = { .native = 1, >> + .args_offset = 1, >> + .u.native = njs_prototype_function, >> + .object = { .type = NJS_FUNCTION } } }, >> + >> + { .object = { .type = NJS_REGEXP } }, >> + >> + { .date = { .time = NAN, >> + .object = { .type = NJS_DATE } } }, >> + >> + { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), >> + .object = { .type = NJS_OBJECT } } }, >> + >> + { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), >> + .object = { .type = NJS_OBJECT } } }, >> + >> + { .object = { .type = NJS_OBJECT_ERROR } }, >> + { .object = { .type = NJS_OBJECT_EVAL_ERROR } }, >> + { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, >> + { .object = { .type = NJS_OBJECT_RANGE_ERROR } }, >> + { .object = { .type = NJS_OBJECT_REF_ERROR } }, >> + { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, >> + { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, >> + { .object = { .type = NJS_OBJECT_URI_ERROR } }, >> + { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, >> +}; >> + >> >> >> nxt_int_t >> njs_builtin_objects_create(njs_vm_t *vm) >> { >> - nxt_int_t ret; >> - nxt_uint_t i; >> - njs_module_t *module; >> - njs_object_t *objects; >> - njs_function_t *functions, *constructors; >> - nxt_lvlhsh_query_t lhq; >> - njs_object_prototype_t *prototypes; >> - >> - static const njs_object_prototype_t prototype_values[] = { >> - /* >> - * GCC 4 complains about uninitialized .shared field, >> - * if the .type field is initialized as .object.type. >> - */ >> - { .object = { .type = NJS_OBJECT } }, >> - { .object = { .type = NJS_ARRAY } }, >> - >> - /* >> - * The .object.type field must be initialzed after the .value field, >> - * otherwise SunC 5.9 treats the .value as .object.value or so. >> - */ >> - { .object_value = { .value = njs_value(NJS_BOOLEAN, 0, 0.0), >> - .object = { .type = NJS_OBJECT_BOOLEAN } } }, >> - >> - { .object_value = { .value = njs_value(NJS_NUMBER, 0, 0.0), >> - .object = { .type = NJS_OBJECT_NUMBER } } }, >> - >> - { .object_value = { .value = njs_string(""), >> - .object = { .type = NJS_OBJECT_STRING } } }, >> - >> - { .function = { .native = 1, >> - .args_offset = 1, >> - .u.native = njs_prototype_function, >> - .object = { .type = NJS_FUNCTION } } }, >> - >> - { .object = { .type = NJS_REGEXP } }, >> - >> - { .date = { .time = NAN, >> - .object = { .type = NJS_DATE } } }, >> - >> - { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), >> - .object = { .type = NJS_OBJECT } } }, >> - >> - { .object_value = { .value = njs_value(NJS_DATA, 0, 0.0), >> - .object = { .type = NJS_OBJECT } } }, >> - >> - { .object = { .type = NJS_OBJECT_ERROR } }, >> - { .object = { .type = NJS_OBJECT_EVAL_ERROR } }, >> - { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, >> - { .object = { .type = NJS_OBJECT_RANGE_ERROR } }, >> - { .object = { .type = NJS_OBJECT_REF_ERROR } }, >> - { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, >> - { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, >> - { .object = { .type = NJS_OBJECT_URI_ERROR } }, >> - { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, >> - }; >> - >> - static const njs_function_init_t native_constructors[] = { >> - /* SunC does not allow empty array initialization. */ >> - { njs_object_constructor, { 0 } }, >> - { njs_array_constructor, { 0 } }, >> - { njs_boolean_constructor, { 0 } }, >> - { njs_number_constructor, { NJS_SKIP_ARG, NJS_NUMBER_ARG } }, >> - { njs_string_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - { njs_function_constructor, { 0 } }, >> - { njs_regexp_constructor, >> - { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } }, >> - { njs_date_constructor, { 0 } }, >> - { njs_hash_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - { njs_hmac_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG, >> - NJS_STRING_ARG } }, >> - { njs_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - { njs_eval_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - { njs_internal_error_constructor, >> - { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - { njs_range_error_constructor, >> - { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - { njs_reference_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - { njs_syntax_error_constructor, >> - { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - { njs_type_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - { njs_uri_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - { njs_memory_error_constructor, { NJS_SKIP_ARG, NJS_STRING_ARG } }, >> - }; >> + nxt_int_t ret; >> + njs_module_t *module; >> + njs_object_t *object; >> + njs_function_t *func; >> + nxt_lvlhsh_query_t lhq; >> + njs_object_prototype_t *prototype; >> + const njs_object_init_t *obj, **p; >> + const njs_function_init_t *f; >> >> static const njs_object_prop_t function_prototype_property = { >> .type = NJS_PROPERTY_HANDLER, >> @@ -246,6 +248,8 @@ njs_builtin_objects_create(njs_vm_t *vm) >> .value = njs_prop_handler(njs_function_prototype_create), >> }; >> >> + static const nxt_str_t sandbox_key = nxt_string("sandbox"); >> + >> ret = njs_object_hash_create(vm, &vm->shared->function_prototype_hash, >> &function_prototype_property, 1); >> if (nxt_slow_path(ret != NXT_OK)) { >> @@ -259,48 +263,57 @@ njs_builtin_objects_create(njs_vm_t *vm) >> return NXT_ERROR; >> } >> >> - objects = vm->shared->objects; >> + object = vm->shared->objects; >> + >> + for (p = njs_object_init; *p != NULL; p++) { >> + obj = *p; >> >> - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { >> - if (njs_object_init[i] != NULL) { >> - ret = njs_object_hash_create(vm, &objects[i].shared_hash, >> - njs_object_init[i]->properties, >> - njs_object_init[i]->items); >> - if (nxt_slow_path(ret != NXT_OK)) { >> - return NXT_ERROR; >> - } >> + ret = njs_object_hash_create(vm, &object->shared_hash, >> + obj->properties, obj->items); >> + >> + if (nxt_slow_path(ret != NXT_OK)) { >> + return NXT_ERROR; >> } >> >> - objects[i].shared = 1; >> + object->shared = 1; >> + >> + object++; >> } >> >> lhq.replace = 0; >> - lhq.proto = &njs_modules_hash_proto; >> lhq.pool = vm->mem_cache_pool; >> >> - for (i = NJS_MODULE_FS; i < NJS_MODULE_MAX; i++) { >> - if (vm->options.sandbox && !njs_sandbox_module(i)) { >> - continue; >> - } >> + for (p = njs_module_init; *p != NULL; p++) { >> + obj = *p; >> >> module = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_module_t)); >> if (nxt_slow_path(module == NULL)) { >> return NJS_ERROR; >> } >> >> - module->name = njs_module_init[i]->name; >> - >> ret = njs_object_hash_create(vm, &module->object.shared_hash, >> - njs_module_init[i]->properties, >> - njs_module_init[i]->items); >> + obj->properties, obj->items); >> if (nxt_slow_path(ret != NXT_OK)) { >> return NXT_ERROR; >> } >> >> + if (vm->options.sandbox) { >> + lhq.key = sandbox_key; >> + lhq.key_hash = nxt_djb_hash(sandbox_key.start, sandbox_key.length); >> + lhq.proto = &njs_object_hash_proto; >> + >> + ret = nxt_lvlhsh_find(&module->object.shared_hash, &lhq); >> + if (nxt_fast_path(ret != NXT_OK)) { >> + continue; >> + } >> + } >> + >> + module->name = obj->name; >> module->object.shared = 1; >> >> lhq.key = module->name; >> lhq.key_hash = nxt_djb_hash(lhq.key.start, lhq.key.length); >> + lhq.proto = &njs_modules_hash_proto; >> lhq.value = module; >> >> ret = nxt_lvlhsh_insert(&vm->modules_hash, &lhq); >> @@ -309,73 +322,88 @@ njs_builtin_objects_create(njs_vm_t *vm) >> } >> } >> >> - functions = vm->shared->functions; >> + f = njs_native_functions; >> + func = vm->shared->functions; >> >> - for (i = NJS_FUNCTION_EVAL; i < NJS_FUNCTION_MAX; i++) { >> - if (njs_function_init[i]->items != 0) { >> - ret = njs_object_hash_create(vm, &functions[i].object.shared_hash, >> - njs_function_init[i]->properties, >> - njs_function_init[i]->items); >> - if (nxt_slow_path(ret != NXT_OK)) { >> - return NXT_ERROR; >> - } >> + for (p = njs_function_init; *p != NULL; p++) { >> + obj = *p; >> + >> + ret = njs_object_hash_create(vm, &func->object.shared_hash, >> + obj->properties, obj->items); >> + if (nxt_slow_path(ret != NXT_OK)) { >> + return NXT_ERROR; >> } >> >> - functions[i].object.shared = 1; >> - functions[i].object.extensible = 1; >> - functions[i].native = 1; >> - functions[i].args_offset = 1; >> - functions[i].u.native = njs_native_functions[i].native; >> - functions[i].args_types[0] = njs_native_functions[i].args_types[0]; >> - functions[i].args_types[1] = njs_native_functions[i].args_types[1]; >> - functions[i].args_types[2] = njs_native_functions[i].args_types[2]; >> - functions[i].args_types[3] = njs_native_functions[i].args_types[3]; >> - functions[i].args_types[4] = njs_native_functions[i].args_types[4]; >> + func->object.shared = 1; >> + func->object.extensible = 1; >> + func->native = 1; >> + func->args_offset = 1; >> + >> + func->u.native = f->native; >> + memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); >> + >> + f++; >> + func++; >> } >> >> - prototypes = vm->shared->prototypes; >> + prototype = vm->shared->prototypes; >> + memcpy(prototype, njs_prototype_values, sizeof(njs_prototype_values)); >> >> - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { >> - prototypes[i] = prototype_values[i]; >> + for (p = njs_prototype_init; *p != NULL; p++) { >> + obj = *p; >> >> - ret = njs_object_hash_create(vm, &prototypes[i].object.shared_hash, >> - njs_prototype_init[i]->properties, >> - njs_prototype_init[i]->items); >> + ret = njs_object_hash_create(vm, &prototype->object.shared_hash, >> + obj->properties, obj->items); >> if (nxt_slow_path(ret != NXT_OK)) { >> return NXT_ERROR; >> } >> + >> + prototype++; >> } >> >> - prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = >> + vm->shared->prototypes[NJS_PROTOTYPE_REGEXP].regexp.pattern = >> vm->shared->empty_regexp_pattern; >> >> - constructors = vm->shared->constructors; >> + f = njs_native_constructors; >> + func = vm->shared->constructors; >> + >> + for (p = njs_constructor_init; *p != NULL; p++) { >> + obj = *p; >> >> - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { >> - constructors[i].object.shared = 0; >> - constructors[i].object.extensible = 1; >> - constructors[i].native = 1; >> - constructors[i].ctor = 1; >> - constructors[i].args_offset = 1; >> - constructors[i].u.native = native_constructors[i].native; >> - constructors[i].args_types[0] = native_constructors[i].args_types[0]; >> - constructors[i].args_types[1] = native_constructors[i].args_types[1]; >> - constructors[i].args_types[2] = native_constructors[i].args_types[2]; >> - constructors[i].args_types[3] = native_constructors[i].args_types[3]; >> - constructors[i].args_types[4] = native_constructors[i].args_types[4]; >> + func->object.shared = 0; >> + func->object.extensible = 1; >> + func->native = 1; >> + func->ctor = 1; >> + func->args_offset = 1; >> >> - ret = njs_object_hash_create(vm, &constructors[i].object.shared_hash, >> - njs_constructor_init[i]->properties, >> - njs_constructor_init[i]->items); >> + func->u.native = f->native; >> + >> + memcpy(func->args_types, f->args_types, NJS_ARGS_TYPES_MAX); >> + >> + ret = njs_object_hash_create(vm, &func->object.shared_hash, >> + obj->properties, obj->items); >> if (nxt_slow_path(ret != NXT_OK)) { >> return NXT_ERROR; >> } >> + >> + f++; >> + func++; >> } >> >> return NXT_OK; >> } >> >> >> +static njs_ret_t >> +njs_prototype_function(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, >> + njs_index_t unused) >> +{ >> + vm->retval = njs_value_void; >> + >> + return NXT_OK; >> +} >> + >> + >> /* >> * Object(), >> * Object.__proto__ -> Function_Prototype, >> @@ -493,53 +521,15 @@ njs_builtin_objects_clone(njs_vm_t *vm) >> } >> >> >> -nxt_array_t * >> -njs_vm_completions(njs_vm_t *vm, nxt_str_t *expression) >> +static size_t >> +njs_builtin_completions_size(njs_vm_t *vm) >> { >> - size_t size; >> - nxt_array_t *completions; >> - >> - if (expression == NULL) { >> - if (njs_builtin_completions(vm, &size, NULL) != NXT_OK) { >> - return NULL; >> - } >> - >> - completions = nxt_array_create(size, sizeof(nxt_str_t), >> - &njs_array_mem_proto, >> - vm->mem_cache_pool); >> - >> - if (nxt_slow_path(completions == NULL)) { >> - return NULL; >> - } >> - >> - if (njs_builtin_completions(vm, &size, completions->start) != NXT_OK) { >> - return NULL; >> - } >> - >> - completions->items = size; >> - >> - return completions; >> - } >> - >> - return njs_vm_expression_completions(vm, expression); >> -} >> - >> - >> -static nxt_int_t >> -njs_builtin_completions(njs_vm_t *vm, size_t *size, nxt_str_t *completions) >> -{ >> - char *compl; >> - size_t n, len; >> - nxt_str_t string; >> - nxt_uint_t i, k; >> - njs_object_t *objects; >> - njs_keyword_t *keyword; >> - njs_function_t *constructors; >> - njs_object_prop_t *prop; >> - nxt_lvlhsh_each_t lhe, lhe_prop; >> - njs_extern_value_t *ev; >> - const njs_extern_t *ext_proto, *ext_prop; >> - njs_object_prototype_t *prototypes; >> + nxt_uint_t n; >> + njs_keyword_t *keyword; >> + nxt_lvlhsh_each_t lhe, lhe_prop; >> + njs_extern_value_t *ev; >> + const njs_extern_t *ext_proto, *ext_prop; >> + const njs_object_init_t **p; >> >> n = 0; >> >> @@ -552,123 +542,147 @@ njs_builtin_completions(njs_vm_t *vm, si >> break; >> } >> >> - if (completions != NULL) { >> - completions[n++] = keyword->name; >> + n++; >> + } >> + >> + for (p = njs_object_init; *p != NULL; p++) { >> + n += (*p)->items; >> + } >> + >> + for (p = njs_prototype_init; *p != NULL; p++) { >> + n += (*p)->items; >> + } >> + >> + for (p = njs_constructor_init; *p != NULL; p++) { >> + n += (*p)->items; >> + } >> + >> + nxt_lvlhsh_each_init(&lhe, &njs_extern_value_hash_proto); >> >> - } else { >> + for ( ;; ) { >> + ev = nxt_lvlhsh_each(&vm->externals_hash, &lhe); >> + >> + if (ev == NULL) { >> + break; >> + } >> + >> + ext_proto = ev->value.external.proto; >> + >> + nxt_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto); >> + >> + n++; >> + >> + for ( ;; ) { >> + ext_prop = nxt_lvlhsh_each(&ext_proto->hash, &lhe_prop); >> + >> + if (ext_prop == NULL) { >> + break; >> + } >> + >> n++; >> } >> } >> >> - objects = vm->shared->objects; >> + return n; >> +} >> + >> >> - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { >> - if (njs_object_init[i] == NULL) { >> - continue; >> +static nxt_array_t * >> +njs_builtin_completions(njs_vm_t *vm, nxt_array_t *array) >> +{ >> + char *compl; >> + size_t n, len; >> + nxt_str_t string, *completions; >> + nxt_uint_t i, k; >> + njs_keyword_t *keyword; >> + nxt_lvlhsh_each_t lhe, lhe_prop; >> + njs_extern_value_t *ev; >> + const njs_extern_t *ext_proto, *ext_prop; >> + const njs_object_prop_t *prop; >> + const njs_object_init_t *obj, **p; >> + >> + n = 0; >> + completions = array->start; >> + >> + nxt_lvlhsh_each_init(&lhe, &njs_keyword_hash_proto); >> + >> + for ( ;; ) { >> + keyword = nxt_lvlhsh_each(&vm->shared->keywords_hash, &lhe); >> + >> + if (keyword == NULL) { >> + break; >> } >> >> - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); >> + completions[n++] = keyword->name; >> + } >> + >> + for (p = njs_object_init; *p != NULL; p++) { >> + obj = *p; >> >> - for ( ;; ) { >> - prop = nxt_lvlhsh_each(&objects[i].shared_hash, &lhe); >> + for (i = 0; i < obj->items; i++) { >> + prop = &obj->properties[i]; >> + njs_string_get(&prop->name, &string); >> + len = obj->name.length + string.length + 2; >> >> - if (prop == NULL) { >> - break; >> + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> + if (compl == NULL) { >> + return NULL; >> } >> >> - if (completions != NULL) { >> - njs_string_get(&prop->name, &string); >> - len = njs_object_init[i]->name.length + string.length + 2; >> + snprintf(compl, len, "%s.%s", obj->name.start, string.start); >> + >> + completions[n].length = len; >> + completions[n++].start = (u_char *) compl; >> + } >> + } >> + >> + for (p = njs_prototype_init; *p != NULL; p++) { >> + obj = *p; >> + >> + for (i = 0; i < obj->items; i++) { >> + prop = &obj->properties[i]; >> + njs_string_get(&prop->name, &string); >> + len = string.length + 2; >> >> - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> - if (compl == NULL) { >> - return NXT_ERROR; >> + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> + if (compl == NULL) { >> + return NULL; >> + } >> + >> + snprintf(compl, len, ".%s", string.start); >> + >> + for (k = 0; k < n; k++) { >> + if (strncmp((char *) completions[k].start, compl, len) >> + == 0) >> + { >> + break; >> } >> + } >> >> - snprintf(compl, len, "%s.%s", njs_object_init[i]->name.start, >> - string.start); >> - >> + if (k == n) { >> completions[n].length = len; >> completions[n++].start = (u_char *) compl; >> - >> - } else { >> - n++; >> } >> } >> } >> >> - prototypes = vm->shared->prototypes; >> - >> - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { >> - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); >> + for (p = njs_constructor_init; *p != NULL; p++) { >> + obj = *p; >> >> - for ( ;; ) { >> - prop = nxt_lvlhsh_each(&prototypes[i].object.shared_hash, &lhe); >> + for (i = 0; i < obj->items; i++) { >> + prop = &obj->properties[i]; >> + njs_string_get(&prop->name, &string); >> + len = obj->name.length + string.length + 2; >> >> - if (prop == NULL) { >> - break; >> + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> + if (compl == NULL) { >> + return NULL; >> } >> >> - if (completions != NULL) { >> - njs_string_get(&prop->name, &string); >> - len = string.length + 2; >> - >> - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> - if (compl == NULL) { >> - return NXT_ERROR; >> - } >> - >> - snprintf(compl, len, ".%s", string.start); >> - >> - for (k = 0; k < n; k++) { >> - if (strncmp((char *) completions[k].start, compl, len) >> - == 0) >> - { >> - break; >> - } >> - } >> - >> - if (k == n) { >> - completions[n].length = len; >> - completions[n++].start = (u_char *) compl; >> - } >> - >> - } else { >> - n++; >> - } >> - } >> - } >> + snprintf(compl, len, "%s.%s", obj->name.start, string.start); >> >> - constructors = vm->shared->constructors; >> - >> - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { >> - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); >> - >> - for ( ;; ) { >> - prop = nxt_lvlhsh_each(&constructors[i].object.shared_hash, &lhe); >> - >> - if (prop == NULL) { >> - break; >> - } >> - >> - if (completions != NULL) { >> - njs_string_get(&prop->name, &string); >> - len = njs_constructor_init[i]->name.length + string.length + 2; >> - >> - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> - if (compl == NULL) { >> - return NXT_ERROR; >> - } >> - >> - snprintf(compl, len, "%s.%s", >> - njs_constructor_init[i]->name.start, string.start); >> - >> - completions[n].length = len; >> - completions[n++].start = (u_char *) compl; >> - >> - } else { >> - n++; >> - } >> + completions[n].length = len; >> + completions[n++].start = (u_char *) compl; >> } >> } >> >> @@ -685,21 +699,16 @@ njs_builtin_completions(njs_vm_t *vm, si >> >> nxt_lvlhsh_each_init(&lhe_prop, &njs_extern_hash_proto); >> >> - if (completions != NULL) { >> - len = ev->name.length + 1; >> - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> - if (compl == NULL) { >> - return NXT_ERROR; >> - } >> + len = ev->name.length + 1; >> + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> + if (compl == NULL) { >> + return NULL; >> + } >> >> - snprintf(compl, len, "%.*s", (int) ev->name.length, ev->name.start); >> + snprintf(compl, len, "%.*s", (int) ev->name.length, ev->name.start); >> >> - completions[n].length = len; >> - completions[n++].start = (u_char *) compl; >> - >> - } else { >> - n++; >> - } >> + completions[n].length = len; >> + completions[n++].start = (u_char *) compl; >> >> for ( ;; ) { >> ext_prop = nxt_lvlhsh_each(&ext_proto->hash, &lhe_prop); >> @@ -708,31 +717,48 @@ njs_builtin_completions(njs_vm_t *vm, si >> break; >> } >> >> - if (completions != NULL) { >> - len = ev->name.length + ev->name.length + 2; >> - compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> - if (compl == NULL) { >> - return NXT_ERROR; >> - } >> + len = ev->name.length + ev->name.length + 2; >> + compl = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> + if (compl == NULL) { >> + return NULL; >> + } >> >> - snprintf(compl, len, "%.*s.%.*s", (int) ev->name.length, >> - ev->name.start, (int) ext_prop->name.length, >> - ext_prop->name.start); >> + snprintf(compl, len, "%.*s.%.*s", (int) ev->name.length, >> + ev->name.start, (int) ext_prop->name.length, >> + ext_prop->name.start); >> >> - completions[n].length = len; >> - completions[n++].start = (u_char *) compl; >> - >> - } else { >> - n++; >> - } >> + completions[n].length = len; >> + completions[n++].start = (u_char *) compl; >> } >> } >> >> - if (size) { >> - *size = n; >> + array->items = n; >> + >> + return array; >> +} >> + >> + >> +nxt_array_t * >> +njs_vm_completions(njs_vm_t *vm, nxt_str_t *expression) >> +{ >> + size_t size; >> + nxt_array_t *completions; >> + >> + if (expression == NULL) { >> + size = njs_builtin_completions_size(vm); >> + >> + completions = nxt_array_create(size, sizeof(nxt_str_t), >> + &njs_array_mem_proto, >> + vm->mem_cache_pool); >> + >> + if (nxt_slow_path(completions == NULL)) { >> + return NULL; >> + } >> + >> + return njs_builtin_completions(vm, completions); >> } >> >> - return NXT_OK; >> + return njs_vm_expression_completions(vm, expression); >> } >> >> >> @@ -911,185 +937,135 @@ njs_object_completions(njs_vm_t *vm, njs >> } >> >> >> -nxt_int_t >> -njs_builtin_match_native_function(njs_vm_t *vm, njs_function_t *function, >> - nxt_str_t *name) >> +static nxt_int_t >> +njs_builtin_match(const njs_object_init_t **objects, njs_function_t *function, >> + const njs_object_prop_t **prop, const njs_object_init_t **object) >> { >> - char *buf; >> - size_t len; >> - nxt_str_t string; >> - nxt_uint_t i; >> - njs_module_t *module; >> - njs_object_t *objects; >> - njs_function_t *constructors; >> - njs_object_prop_t *prop; >> - nxt_lvlhsh_each_t lhe, lhe_prop; >> - njs_object_prototype_t *prototypes; >> + nxt_uint_t i; >> + const njs_object_init_t *o, **p; >> + const njs_object_prop_t *pr; >> >> - objects = vm->shared->objects; >> - >> - for (i = NJS_OBJECT_THIS; i < NJS_OBJECT_MAX; i++) { >> - if (njs_object_init[i] == NULL) { >> - continue; >> - } >> - >> - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); >> + for (p = objects; *p != NULL; p++) { >> + o = *p; >> >> - for ( ;; ) { >> - prop = nxt_lvlhsh_each(&objects[i].shared_hash, &lhe); >> + for (i = 0; i < o->items; i++) { >> + pr = &o->properties[i]; >> >> - if (prop == NULL) { >> - break; >> - } >> - >> - if (!njs_is_function(&prop->value)) { >> + if (pr->type != NJS_METHOD) { >> continue; >> } >> >> - if (function == prop->value.data.u.function) { >> - njs_string_get(&prop->name, &string); >> - len = njs_object_init[i]->name.length + string.length >> - + sizeof("."); >> - >> - buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> - if (buf == NULL) { >> - return NXT_ERROR; >> - } >> - >> - snprintf(buf, len, "%s.%s", njs_object_init[i]->name.start, >> - string.start); >> - >> - name->length = len; >> - name->start = (u_char *) buf; >> - >> - return NXT_OK; >> - } >> - } >> - } >> - >> - prototypes = vm->shared->prototypes; >> - >> - for (i = NJS_PROTOTYPE_OBJECT; i < NJS_PROTOTYPE_MAX; i++) { >> - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); >> - >> - for ( ;; ) { >> - prop = nxt_lvlhsh_each(&prototypes[i].object.shared_hash, &lhe); >> - >> - if (prop == NULL) { >> - break; >> - } >> - >> - if (!njs_is_function(&prop->value)) { >> + if (function != pr->value.data.u.function) { >> continue; >> } >> >> - if (function == prop->value.data.u.function) { >> - njs_string_get(&prop->name, &string); >> - len = njs_prototype_init[i]->name.length + string.length >> - + sizeof(".prototype."); >> - >> - buf = nxt_mem_cache_zalloc(vm->mem_cache_pool, len); >> - if (buf == NULL) { >> - return NXT_ERROR; >> - } >> - >> - snprintf(buf, len, "%s.prototype.%s", >> - njs_prototype_init[i]->name.start, string.start); >> - >> - name->length = len; >> - name->start = (u_char *) buf; >> - >> - return NXT_OK; >> - } >> - } >> - } >> - >> - constructors = vm->shared->constructors; >> - >> - for (i = NJS_CONSTRUCTOR_OBJECT; i < NJS_CONSTRUCTOR_MAX; i++) { >> - nxt_lvlhsh_each_init(&lhe, &njs_object_hash_proto); >> - >> - for ( ;; ) { >> - prop = nxt_lvlhsh_each(&constructors[i].object.shared_hash, &lhe); >> - >> - if (prop == NULL) { >> - break; >> - } >> - >> - if (!njs_is_function(&prop->value)) { >> - continue; >> - } >> - >> - if (function == prop->value.data.u.function) { >> - njs_string_get(&prop->name, &string); >> >> >> ------------------------------ >> >> Subject: Digest Footer >> >> _______________________________________________ >> nginx-devel mailing list >> nginx-devel at nginx.org >> http://mailman.nginx.org/mailman/listinfo/nginx-devel >> >> ------------------------------ >> >> End of nginx-devel Digest, Vol 109, Issue 15 >> ******************************************** > > > > ------------------------------ > > Subject: Digest Footer > > _______________________________________________ > nginx-devel mailing list > nginx-devel at nginx.org > http://mailman.nginx.org/mailman/listinfo/nginx-devel > > ------------------------------ > > End of nginx-devel Digest, Vol 109, Issue 17 > ******************************************** From kahing at cloudflare.com Thu Nov 15 22:53:46 2018 From: kahing at cloudflare.com (Ka-Hing Cheung) Date: Thu, 15 Nov 2018 14:53:46 -0800 Subject: cache: move open to thread pool In-Reply-To: References: <20180808181653.GX56558@mdounin.ru> <20180810113946.GG56558@mdounin.ru> <20180903160903.GI56558@mdounin.ru> Message-ID: Hi, I didn't forget about this. I am pretty swamped at the moment and there's a holiday freeze coming up. Will get to his in December. - Ka-Hing On Thu, Nov 8, 2018 at 6:19 AM Maxim Konovalov wrote: > > Hi Ka-Hing, > > would you mind to test Roman's most recent patches that add > "aio_open" directive? > > http://mailman.nginx.org/pipermail/nginx-devel/2018-November/011538.html > > We are looking for overall performance and stability metrics and > feedback. > > Much appreciated, > > Maxim > > -- > Maxim Konovalov From maxim at nginx.com Fri Nov 16 09:10:31 2018 From: maxim at nginx.com (Maxim Konovalov) Date: Fri, 16 Nov 2018 12:10:31 +0300 Subject: cache: move open to thread pool In-Reply-To: References: <20180808181653.GX56558@mdounin.ru> <20180810113946.GG56558@mdounin.ru> <20180903160903.GI56558@mdounin.ru> Message-ID: <4ba7414a-0eba-6bd3-5a50-2eca591ac25e@nginx.com> Thanks, Ka-Hing, we'll wait for your feedback. On 16/11/2018 01:53, Ka-Hing Cheung wrote: > Hi, > > I didn't forget about this. I am pretty swamped at the moment and > there's a holiday freeze coming up. Will get to his in December. > > - Ka-Hing > > On Thu, Nov 8, 2018 at 6:19 AM Maxim Konovalov wrote: >> >> Hi Ka-Hing, >> >> would you mind to test Roman's most recent patches that add >> "aio_open" directive? >> >> http://mailman.nginx.org/pipermail/nginx-devel/2018-November/011538.html >> >> We are looking for overall performance and stability metrics and >> feedback. >> >> Much appreciated, >> >> Maxim >> >> -- >> Maxim Konovalov -- Maxim Konovalov From mdounin at mdounin.ru Fri Nov 16 11:51:53 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Fri, 16 Nov 2018 14:51:53 +0300 Subject: [PATCH] New directive to configure TLSv1.3 ciphers In-Reply-To: <38EDD810-9040-4ECF-91A3-92CD7C30E7EE@quantil.com> References: <38EDD810-9040-4ECF-91A3-92CD7C30E7EE@quantil.com> Message-ID: <20181116115153.GJ99070@mdounin.ru> Hello! On Thu, Nov 15, 2018 at 12:17:15PM -0800, Ramprasad Tamilselvan wrote: > I have a question regarding the ticket. > What if different TLSv1.3 ciphers need to be configured in different server blocks? > In this case, changing openssl.conf will not help right. Sure, configuring ciphers via openssl.conf is at most workaround, and does not cover all possible use cases. The best solution would be to patch OpenSSL to support configuration of TLSv1.3 ciphers via SSL_CTX_set_cipher_list(). -- Maxim Dounin http://mdounin.ru/ From skrivy at skrivy.net Sun Nov 18 21:53:25 2018 From: skrivy at skrivy.net (=?utf-8?q?Jaroslav=20Sk=c5=99ivan?=) Date: Sun, 18 Nov 2018 21:53:25 +0000 Subject: limit_rate_after support variables Message-ID: Hi, I found this path http://mailman.nginx.org/pipermail/nginx-devel/2018-October/011505.html very useful in our environment. I would love to have it in upstream. What can I do in order to make it happe? Thanks Kind regards, Sk?ivan Jaroslav -------------- next part -------------- An HTML attachment was scrubbed... URL: From xeioex at nginx.com Mon Nov 19 13:30:51 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 19 Nov 2018 13:30:51 +0000 Subject: [njs] Fixed various clang static analyzer warnings. Message-ID: details: http://hg.nginx.org/njs/rev/2b18ef4e86d1 branches: changeset: 659:2b18ef4e86d1 user: Dmitry Volyntsev date: Mon Nov 19 16:30:35 2018 +0300 description: Fixed various clang static analyzer warnings. In njs_object_keys_array() function. diffstat: njs/njs_object.c | 20 ++------------------ 1 files changed, 2 insertions(+), 18 deletions(-) diffs (39 lines): diff -r 76e139b439ad -r 2b18ef4e86d1 njs/njs_object.c --- a/njs/njs_object.c Thu Nov 15 20:31:35 2018 +0300 +++ b/njs/njs_object.c Mon Nov 19 16:30:35 2018 +0300 @@ -959,33 +959,17 @@ njs_object_keys_array(njs_vm_t *vm, cons n = 0; - switch (value->type) { - case NJS_ARRAY: + if (array != NULL) { for (i = 0; i < length; i++) { if (njs_is_valid(&array->start[i])) { njs_uint32_to_string(&keys->start[n++], i); } } - break; - - case NJS_STRING: - case NJS_OBJECT_STRING: - if (value->type == NJS_OBJECT_STRING) { - string = &value->data.u.object_value->value; - - } else { - string = (njs_value_t *) value; - } - + } else if (length != 0) { for (i = 0; i < length; i++) { njs_uint32_to_string(&keys->start[n++], i); } - - break; - - default: - break; } if (nxt_fast_path(hash != NULL)) { From xeioex at nginx.com Mon Nov 19 14:38:30 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Mon, 19 Nov 2018 14:38:30 +0000 Subject: [njs] Fixed buffer overrun by memcpy() (CID 1441409). Message-ID: details: http://hg.nginx.org/njs/rev/6f29f93b0390 branches: changeset: 660:6f29f93b0390 user: Dmitry Volyntsev date: Mon Nov 19 16:55:37 2018 +0300 description: Fixed buffer overrun by memcpy() (CID 1441409). diffstat: njs/njs_builtin.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diffs (11 lines): diff -r 2b18ef4e86d1 -r 6f29f93b0390 njs/njs_builtin.c --- a/njs/njs_builtin.c Mon Nov 19 16:30:35 2018 +0300 +++ b/njs/njs_builtin.c Mon Nov 19 16:55:37 2018 +0300 @@ -225,7 +225,6 @@ const njs_object_prototype_t njs_protot { .object = { .type = NJS_OBJECT_SYNTAX_ERROR } }, { .object = { .type = NJS_OBJECT_TYPE_ERROR } }, { .object = { .type = NJS_OBJECT_URI_ERROR } }, - { .object = { .type = NJS_OBJECT_INTERNAL_ERROR } }, }; From ru at nginx.com Tue Nov 20 14:10:05 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Tue, 20 Nov 2018 17:10:05 +0300 Subject: limit_rate_after support variables In-Reply-To: References: <20180827112847.GE71000@lo0.su> <20180827160021.GG71000@lo0.su> <20180829114230.GC43480@lo0.su> Message-ID: <20181120141005.GA72348@lo0.su> Hi Miroslav, On Wed, Oct 17, 2018 at 12:49:13PM +0200, Miroslav Novy wrote: > Hello, > > I prepare patch on actual sources. Settings limit_rate and limit_rate_after > works good. Please make code review, our testing and merge to main branche. > Thank you > Miroslav Nov? > > Example of configration: > location / { > root /var/www/default/; > index index.html index.htm; > > set $my_limit_rate 4k; > set $my_limit_rate_after 4m; > > limit_rate $my_limit_rate; > limit_rate_after $my_limit_rate_after; > > access_by_lua_block { > ngx.var.my_limit_rate = '2k' > ngx.var.my_limit_rate_after = '10m' > } > } As I wrote on August 29, the patch is pending a code review. The patch you submitted is garbled by your email client, is somewhat different from the patch I submitted, also the while patch series became a single patch. I've updated my version of the patch series. You can help with the code review and testing, if you like: # HG changeset patch # User Ruslan Ermilov # Date 1542721399 -10800 # Tue Nov 20 16:43:19 2018 +0300 # Node ID 9926926b9d63c8cc9779877cb6c0f5e64193f1a8 # Parent 650574a445058a0ed9e9a83c29183a7bc13e85ba Added post processing to ngx_http_set_complex_value_slot(). diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -214,6 +214,7 @@ ngx_http_set_complex_value_slot(ngx_conf char *p = conf; ngx_str_t *value; + ngx_conf_post_t *post; ngx_http_complex_value_t **cv; ngx_http_compile_complex_value_t ccv; @@ -240,6 +241,11 @@ ngx_http_set_complex_value_slot(ngx_conf return NGX_CONF_ERROR; } + if (cmd->post) { + post = cmd->post; + return post->post_handler(cf, post, *cv); + } + return NGX_CONF_OK; } # HG changeset patch # User Ruslan Ermilov # Date 1542721408 -10800 # Tue Nov 20 16:43:28 2018 +0300 # Node ID cb171b06b70daa8ab230924eafa152fa28870cb5 # Parent 9926926b9d63c8cc9779877cb6c0f5e64193f1a8 Added size_t type support to ngx_http_set_complex_value_slot(). If a complex value is expected to be size_t, and the compiled value is constant, the ngx_http_complex_value_size_p post handler will remember the constant size_t value. The value is accessed through ngx_http_complex_value_size() which either returns the remembered constant or evaluates the expression and parses it as size_t. diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -10,6 +10,13 @@ #include +static char *ngx_http_complex_value_set_size(ngx_conf_t *cf, void *post, + void *data); + +ngx_conf_post_handler_pt ngx_http_complex_value_size_p = + ngx_http_complex_value_set_size; + + static ngx_int_t ngx_http_script_init_arrays(ngx_http_script_compile_t *sc); static ngx_int_t ngx_http_script_done(ngx_http_script_compile_t *sc); static ngx_int_t ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, @@ -105,6 +112,25 @@ ngx_http_complex_value(ngx_http_request_ ngx_int_t +ngx_http_complex_value_size(ngx_http_request_t *r, + ngx_http_complex_value_t *val, ngx_str_t *value, size_t *size) +{ + if (val->lengths == NULL) { + *size = val->u.size; + return NGX_OK; + } + + if (ngx_http_complex_value(r, val, value) != NGX_OK) { + return NGX_ERROR; + } + + *size = ngx_parse_size(value); + + return NGX_OK; +} + + +ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv) { ngx_str_t *v; @@ -250,6 +276,24 @@ ngx_http_set_complex_value_slot(ngx_conf } +static char * +ngx_http_complex_value_set_size(ngx_conf_t *cf, void *post, void *data) +{ + ngx_http_complex_value_t *cv = data; + + if (cv->lengths) { + return NGX_CONF_OK; + } + + cv->u.size = ngx_parse_size(&cv->value); + if (cv->u.size == (size_t) NGX_ERROR) { + return "invalid value"; + } + + return NGX_CONF_OK; +} + + ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates) { diff --git a/src/http/ngx_http_script.h b/src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h +++ b/src/http/ngx_http_script.h @@ -68,6 +68,10 @@ typedef struct { ngx_uint_t *flushes; void *lengths; void *values; + + union { + size_t size; + } u; } ngx_http_complex_value_t; @@ -207,6 +211,8 @@ void ngx_http_script_flush_complex_value ngx_http_complex_value_t *val); ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val, ngx_str_t *value); +ngx_int_t ngx_http_complex_value_size(ngx_http_request_t *r, + ngx_http_complex_value_t *val, ngx_str_t *value, size_t *size); ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -254,4 +260,7 @@ void ngx_http_script_var_code(ngx_http_s void ngx_http_script_nop_code(ngx_http_script_engine_t *e); +extern ngx_conf_post_handler_pt ngx_http_complex_value_size_p; + + #endif /* _NGX_HTTP_SCRIPT_H_INCLUDED_ */ # HG changeset patch # User Ruslan Ermilov # Date 1542722018 -10800 # Tue Nov 20 16:53:38 2018 +0300 # Node ID 1ab7dc1eb5fca6798e7412401302393023cd1ec6 # Parent cb171b06b70daa8ab230924eafa152fa28870cb5 Variables support in limit_rate and limit_rate_after (ticket #293). diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -479,18 +479,18 @@ static ngx_command_t ngx_http_core_comm { ngx_string("limit_rate"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_http_set_complex_value_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, limit_rate), - NULL }, + &ngx_http_complex_value_size_p }, { ngx_string("limit_rate_after"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, - ngx_conf_set_size_slot, + ngx_http_set_complex_value_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_core_loc_conf_t, limit_rate_after), - NULL }, + &ngx_http_complex_value_size_p }, { ngx_string("keepalive_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, @@ -1212,6 +1212,8 @@ ngx_http_core_content_phase(ngx_http_req void ngx_http_update_location_config(ngx_http_request_t *r) { + size_t limit_rate; + ngx_str_t val; ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -1281,8 +1283,18 @@ ngx_http_update_location_config(ngx_http r->connection->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; } - if (r->limit_rate == 0) { - r->limit_rate = clcf->limit_rate; + if (r->limit_rate == 0 + && clcf->limit_rate + && ngx_http_complex_value_size(r, clcf->limit_rate, &val, &limit_rate) + == NGX_OK) + { + if (limit_rate != (size_t) NGX_ERROR) { + r->limit_rate = limit_rate; + + } else if (val.len) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid \"limit_rate\" value \"%V\"", &val); + } } if (clcf->handler) { @@ -3362,6 +3374,8 @@ ngx_http_core_create_loc_conf(ngx_conf_t * clcf->exact_match = 0; * clcf->auto_redirect = 0; * clcf->alias = 0; + * clcf->limit_rate = NULL; + * clcf->limit_rate_after = NULL; * clcf->gzip_proxied = 0; * clcf->keepalive_disable = 0; */ @@ -3392,8 +3406,6 @@ ngx_http_core_create_loc_conf(ngx_conf_t clcf->send_timeout = NGX_CONF_UNSET_MSEC; clcf->send_lowat = NGX_CONF_UNSET_SIZE; clcf->postpone_output = NGX_CONF_UNSET_SIZE; - clcf->limit_rate = NGX_CONF_UNSET_SIZE; - clcf->limit_rate_after = NGX_CONF_UNSET_SIZE; clcf->keepalive_timeout = NGX_CONF_UNSET_MSEC; clcf->keepalive_header = NGX_CONF_UNSET; clcf->keepalive_requests = NGX_CONF_UNSET_UINT; @@ -3581,6 +3593,14 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_msec_value(conf->client_body_timeout, prev->client_body_timeout, 60000); + if (conf->limit_rate == NULL) { + conf->limit_rate = prev->limit_rate; + } + + if (conf->limit_rate_after == NULL) { + conf->limit_rate_after = prev->limit_rate_after; + } + ngx_conf_merge_bitmask_value(conf->keepalive_disable, prev->keepalive_disable, (NGX_CONF_BITMASK_SET @@ -3622,9 +3642,6 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0); ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output, 1460); - ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0); - ngx_conf_merge_size_value(conf->limit_rate_after, prev->limit_rate_after, - 0); ngx_conf_merge_msec_value(conf->keepalive_timeout, prev->keepalive_timeout, 75000); ngx_conf_merge_sec_value(conf->keepalive_header, diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -350,13 +350,14 @@ struct ngx_http_core_loc_conf_s { size_t client_body_buffer_size; /* client_body_buffer_size */ size_t send_lowat; /* send_lowat */ size_t postpone_output; /* postpone_output */ - size_t limit_rate; /* limit_rate */ - size_t limit_rate_after; /* limit_rate_after */ size_t sendfile_max_chunk; /* sendfile_max_chunk */ size_t read_ahead; /* read_ahead */ size_t subrequest_output_buffer_size; /* subrequest_output_buffer_size */ + ngx_http_complex_value_t *limit_rate; /* limit_rate */ + ngx_http_complex_value_t *limit_rate_after; /* limit_rate_after */ + ngx_msec_t client_body_timeout; /* client_body_timeout */ ngx_msec_t send_timeout; /* send_timeout */ ngx_msec_t keepalive_timeout; /* keepalive_timeout */ diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -48,6 +48,8 @@ ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) { off_t size, sent, nsent, limit; + size_t limit_rate_after; + ngx_str_t val; ngx_uint_t last, flush, sync; ngx_msec_t delay; ngx_chain_t *cl, *ln, **ll, *chain; @@ -219,8 +221,20 @@ ngx_http_write_filter(ngx_http_request_t } if (r->limit_rate) { - if (r->limit_rate_after == 0) { - r->limit_rate_after = clcf->limit_rate_after; + if (r->limit_rate_after == 0 + && clcf->limit_rate_after + && ngx_http_complex_value_size(r, clcf->limit_rate_after, &val, + &limit_rate_after) + == NGX_OK) + { + if (limit_rate_after != (size_t) NGX_ERROR) { + r->limit_rate_after = limit_rate_after; + + } else if (val.len) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "invalid \"limit_rate_after\" value \"%V\"", + &val); + } } limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) From ru at nginx.com Tue Nov 20 17:11:09 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Tue, 20 Nov 2018 20:11:09 +0300 Subject: limit_rate_after support variables In-Reply-To: References: Message-ID: <20181120171109.GB72348@lo0.su> On Sun, Nov 18, 2018 at 09:53:25PM +0000, Jaroslav Sk?ivan wrote: > Hi, > > I found this path > http://mailman.nginx.org/pipermail/nginx-devel/2018-October/011505.html > very useful in our environment. > > I would love to have it in upstream. What can I do in order to make it > happe? > > Thanks > > Kind regards, > Sk?ivan Jaroslav Please read the following: http://mailman.nginx.org/pipermail/nginx-devel/2018-November/011604.html Please also send your further replies to that thread instead, if possible. Thanks. From vl at nginx.com Wed Nov 21 10:41:14 2018 From: vl at nginx.com (Vladimir Homutov) Date: Wed, 21 Nov 2018 10:41:14 +0000 Subject: [nginx] Upstream: removed unused ngx_http_upstream_t.timeout field. Message-ID: details: http://hg.nginx.org/nginx/rev/e8bdd322d7a6 branches: changeset: 7396:e8bdd322d7a6 user: Vladimir Homutov date: Wed Nov 21 13:40:36 2018 +0300 description: Upstream: removed unused ngx_http_upstream_t.timeout field. diffstat: src/http/ngx_http_upstream.h | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diffs (12 lines): diff -r 9ca82f273967 -r e8bdd322d7a6 src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h Thu Nov 15 21:28:02 2018 +0300 +++ b/src/http/ngx_http_upstream.h Wed Nov 21 13:40:36 2018 +0300 @@ -365,8 +365,6 @@ struct ngx_http_upstream_s { ngx_int_t (*rewrite_cookie)(ngx_http_request_t *r, ngx_table_elt_t *h); - ngx_msec_t timeout; - ngx_http_upstream_state_t *state; ngx_str_t method; From vl at nginx.com Wed Nov 21 10:41:16 2018 From: vl at nginx.com (Vladimir Homutov) Date: Wed, 21 Nov 2018 10:41:16 +0000 Subject: [nginx] Upstream: revised upstream response time variables. Message-ID: details: http://hg.nginx.org/nginx/rev/860d3907da1c branches: changeset: 7397:860d3907da1c user: Vladimir Homutov date: Wed Nov 21 13:40:40 2018 +0300 description: Upstream: revised upstream response time variables. Variables now do not depend on presence of the HTTP status code in response. If the corresponding event occurred, variables contain time between request creation and the event, and "-" otherwise. Previously, intermediate value of the $upstream_response_time variable held unix timestamp. diffstat: src/http/ngx_http_upstream.c | 40 ++++++++++++++++++----------------- src/http/ngx_http_upstream.h | 2 + src/stream/ngx_stream_proxy_module.c | 14 ++++++++---- src/stream/ngx_stream_upstream.c | 16 ++++++-------- src/stream/ngx_stream_upstream.h | 1 + 5 files changed, 40 insertions(+), 33 deletions(-) diffs (197 lines): diff -r e8bdd322d7a6 -r 860d3907da1c src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c Wed Nov 21 13:40:36 2018 +0300 +++ b/src/http/ngx_http_upstream.c Wed Nov 21 13:40:40 2018 +0300 @@ -1505,8 +1505,8 @@ ngx_http_upstream_connect(ngx_http_reque r->connection->log->action = "connecting to upstream"; - if (u->state && u->state->response_time) { - u->state->response_time = ngx_current_msec - u->state->response_time; + if (u->state && u->state->response_time == (ngx_msec_t) -1) { + u->state->response_time = ngx_current_msec - u->start_time; } u->state = ngx_array_push(r->upstream_states); @@ -1518,7 +1518,9 @@ ngx_http_upstream_connect(ngx_http_reque ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t)); - u->state->response_time = ngx_current_msec; + u->start_time = ngx_current_msec; + + u->state->response_time = (ngx_msec_t) -1; u->state->connect_time = (ngx_msec_t) -1; u->state->header_time = (ngx_msec_t) -1; @@ -2002,7 +2004,7 @@ ngx_http_upstream_send_request(ngx_http_ "http upstream send request"); if (u->state->connect_time == (ngx_msec_t) -1) { - u->state->connect_time = ngx_current_msec - u->state->response_time; + u->state->connect_time = ngx_current_msec - u->start_time; } if (!u->request_sent && ngx_http_upstream_test_connect(c) != NGX_OK) { @@ -2413,7 +2415,7 @@ ngx_http_upstream_process_header(ngx_htt /* rc == NGX_OK */ - u->state->header_time = ngx_current_msec - u->state->response_time; + u->state->header_time = ngx_current_msec - u->start_time; if (u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE) { @@ -4309,8 +4311,8 @@ ngx_http_upstream_finalize_request(ngx_h u->resolved->ctx = NULL; } - if (u->state && u->state->response_time) { - u->state->response_time = ngx_current_msec - u->state->response_time; + if (u->state && u->state->response_time == (ngx_msec_t) -1) { + u->state->response_time = ngx_current_msec - u->start_time; if (u->pipe && u->pipe->read_length) { u->state->bytes_received += u->pipe->read_length @@ -5419,18 +5421,18 @@ ngx_http_upstream_response_time_variable state = r->upstream_states->elts; for ( ;; ) { - if (state[i].status) { - - if (data == 1 && state[i].header_time != (ngx_msec_t) -1) { - ms = state[i].header_time; - - } else if (data == 2 && state[i].connect_time != (ngx_msec_t) -1) { - ms = state[i].connect_time; - - } else { - ms = state[i].response_time; - } - + + if (data == 1) { + ms = state[i].header_time; + + } else if (data == 2) { + ms = state[i].connect_time; + + } else { + ms = state[i].response_time; + } + + if (ms != -1) { ms = ngx_max(ms, 0); p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000); diff -r e8bdd322d7a6 -r 860d3907da1c src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h Wed Nov 21 13:40:36 2018 +0300 +++ b/src/http/ngx_http_upstream.h Wed Nov 21 13:40:40 2018 +0300 @@ -365,6 +365,8 @@ struct ngx_http_upstream_s { ngx_int_t (*rewrite_cookie)(ngx_http_request_t *r, ngx_table_elt_t *h); + ngx_msec_t start_time; + ngx_http_upstream_state_t *state; ngx_str_t method; diff -r e8bdd322d7a6 -r 860d3907da1c src/stream/ngx_stream_proxy_module.c --- a/src/stream/ngx_stream_proxy_module.c Wed Nov 21 13:40:36 2018 +0300 +++ b/src/stream/ngx_stream_proxy_module.c Wed Nov 21 13:40:40 2018 +0300 @@ -690,7 +690,7 @@ ngx_stream_proxy_connect(ngx_stream_sess u->proxy_protocol = pscf->proxy_protocol; if (u->state) { - u->state->response_time = ngx_current_msec - u->state->response_time; + u->state->response_time = ngx_current_msec - u->start_time; } u->state = ngx_array_push(s->upstream_states); @@ -701,9 +701,11 @@ ngx_stream_proxy_connect(ngx_stream_sess ngx_memzero(u->state, sizeof(ngx_stream_upstream_state_t)); + u->start_time = ngx_current_msec; + u->state->connect_time = (ngx_msec_t) -1; u->state->first_byte_time = (ngx_msec_t) -1; - u->state->response_time = ngx_current_msec; + u->state->response_time = (ngx_msec_t) -1; rc = ngx_event_connect_peer(&u->peer); @@ -817,7 +819,7 @@ ngx_stream_proxy_init_upstream(ngx_strea } } - u->state->connect_time = ngx_current_msec - u->state->response_time; + u->state->connect_time = ngx_current_msec - u->start_time; if (u->peer.notify) { u->peer.notify(&u->peer, u->peer.data, @@ -1622,7 +1624,7 @@ ngx_stream_proxy_process(ngx_stream_sess if (from_upstream) { if (u->state->first_byte_time == (ngx_msec_t) -1) { u->state->first_byte_time = ngx_current_msec - - u->state->response_time; + - u->start_time; } } @@ -1857,7 +1859,9 @@ ngx_stream_proxy_finalize(ngx_stream_ses pc = u->peer.connection; if (u->state) { - u->state->response_time = ngx_current_msec - u->state->response_time; + if (u->state->response_time == (ngx_msec_t) -1) { + u->state->response_time = ngx_current_msec - u->start_time; + } if (pc) { u->state->bytes_received = u->received; diff -r e8bdd322d7a6 -r 860d3907da1c src/stream/ngx_stream_upstream.c --- a/src/stream/ngx_stream_upstream.c Wed Nov 21 13:40:36 2018 +0300 +++ b/src/stream/ngx_stream_upstream.c Wed Nov 21 13:40:40 2018 +0300 @@ -267,24 +267,22 @@ ngx_stream_upstream_response_time_variab for ( ;; ) { if (data == 1) { - if (state[i].first_byte_time == (ngx_msec_t) -1) { - *p++ = '-'; - goto next; - } - ms = state[i].first_byte_time; - } else if (data == 2 && state[i].connect_time != (ngx_msec_t) -1) { + } else if (data == 2) { ms = state[i].connect_time; } else { ms = state[i].response_time; } - ms = ngx_max(ms, 0); - p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000); + if (ms != -1) { + ms = ngx_max(ms, 0); + p = ngx_sprintf(p, "%T.%03M", (time_t) ms / 1000, ms % 1000); - next: + } else { + *p++ = '-'; + } if (++i == s->upstream_states->nelts) { break; diff -r e8bdd322d7a6 -r 860d3907da1c src/stream/ngx_stream_upstream.h --- a/src/stream/ngx_stream_upstream.h Wed Nov 21 13:40:36 2018 +0300 +++ b/src/stream/ngx_stream_upstream.h Wed Nov 21 13:40:40 2018 +0300 @@ -130,6 +130,7 @@ typedef struct { time_t start_sec; ngx_uint_t requests; ngx_uint_t responses; + ngx_msec_t start_time; ngx_str_t ssl_name; From miranovy at gmail.com Wed Nov 21 11:11:10 2018 From: miranovy at gmail.com (Miroslav Novy) Date: Wed, 21 Nov 2018 12:11:10 +0100 Subject: limit_rate_after support variables In-Reply-To: <20181120141005.GA72348@lo0.su> References: <20180827112847.GE71000@lo0.su> <20180827160021.GG71000@lo0.su> <20180829114230.GC43480@lo0.su> <20181120141005.GA72348@lo0.su> Message-ID: Hi Ruslan, > I've updated my version of the patch series. Thank you :) > You can help with the code review and testing, if you like: Yes, of corse. The first patch from the series "Added post processing to ngx_http_set_complex_value_slot()" is ok. For second patch "Added size_t type support to ngx_http_set_complex_value_slot()" I prepared fix, becouse return type of ngx_parse_size is ssize_t. These is my fix # HG changeset patch # User Miroslav Nov? # Date 1542796801 0 # Wed Nov 21 10:40:01 2018 +0000 # Node ID 82eed7650622fd780dcd4a86661de7b80b44199c # Parent 1090756c530aabe5e63882dcbf278b23807568d0 Added size_t type support to ngx_http_set_complex_value_slot() fix Return type of function ngx_parse_size is ssize_t diff -r 1090756c530a -r 82eed7650622 src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c Tue Nov 20 16:53:38 2018 +0300 +++ b/src/http/ngx_http_script.c Wed Nov 21 10:40:01 2018 +0000 @@ -113,7 +113,7 @@ ngx_int_t ngx_http_complex_value_size(ngx_http_request_t *r, - ngx_http_complex_value_t *val, ngx_str_t *value, size_t *size) + ngx_http_complex_value_t *val, ngx_str_t *value, ssize_t *size) { if (val->lengths == NULL) { *size = val->u.size; diff -r 1090756c530a -r 82eed7650622 src/http/ngx_http_script.h --- a/src/http/ngx_http_script.h Tue Nov 20 16:53:38 2018 +0300 +++ b/src/http/ngx_http_script.h Wed Nov 21 10:40:01 2018 +0000 @@ -212,7 +212,7 @@ ngx_int_t ngx_http_complex_value(ngx_http_request_t *r, ngx_http_complex_value_t *val, ngx_str_t *value); ngx_int_t ngx_http_complex_value_size(ngx_http_request_t *r, - ngx_http_complex_value_t *val, ngx_str_t *value, size_t *size); + ngx_http_complex_value_t *val, ngx_str_t *value, ssize_t *size); ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv); char *ngx_http_set_complex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); The last patch "Variables support in limit_rate and limit_rate_after (ticket #293)." throws warning "using uninitialized variable!. I am going to make the fix today later. Best regards Miroslav Nov? From xeioex at nginx.com Wed Nov 21 13:46:00 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 21 Nov 2018 13:46:00 +0000 Subject: [njs] Interactive shell: quiet mode. Message-ID: details: http://hg.nginx.org/njs/rev/db44b92af5f7 branches: changeset: 661:db44b92af5f7 user: Dmitry Volyntsev date: Wed Nov 21 16:45:10 2018 +0300 description: Interactive shell: quiet mode. diffstat: njs/njs_shell.c | 24 ++++++++++++++++-------- njs/test/njs_expect_test.exp | 4 ++++ 2 files changed, 20 insertions(+), 8 deletions(-) diffs (77 lines): diff -r 6f29f93b0390 -r db44b92af5f7 njs/njs_shell.c --- a/njs/njs_shell.c Mon Nov 19 16:55:37 2018 +0300 +++ b/njs/njs_shell.c Wed Nov 21 16:45:10 2018 +0300 @@ -33,6 +33,7 @@ typedef struct { nxt_int_t disassemble; nxt_int_t interactive; nxt_int_t sandbox; + nxt_int_t quiet; } njs_opts_t; @@ -203,9 +204,10 @@ njs_get_options(njs_opts_t *opts, int ar "Interactive njs shell.\n" "\n" "Options:\n" + " -d print disassembled code.\n" + " -q disable interactive introduction prompt.\n" + " -s sandbox mode.\n" " -v print njs version and exit.\n" - " -d print disassembled code.\n" - " -s sandbox mode.\n" " | - run code from a file or stdin.\n"; ret = NXT_DONE; @@ -232,15 +234,19 @@ njs_get_options(njs_opts_t *opts, int ar opts->disassemble = 1; break; - case 'v': - case 'V': - opts->version = 1; + case 'q': + opts->quiet = 1; break; case 's': opts->sandbox = 1; break; + case 'v': + case 'V': + opts->version = 1; + break; + default: fprintf(stderr, "Unknown argument: \"%s\" " "try \"%s -h\" for available options\n", argv[i], argv[0]); @@ -309,10 +315,12 @@ njs_interactive_shell(njs_opts_t *opts, return NXT_ERROR; } - printf("interactive njs %s\n\n", NJS_VERSION); + if (!opts->quiet) { + printf("interactive njs %s\n\n", NJS_VERSION); - printf("v. -> the properties and prototype methods of v.\n"); - printf("type console.help() for more information\n\n"); + printf("v. -> the properties and prototype methods of v.\n"); + printf("type console.help() for more information\n\n"); + } for ( ;; ) { line.start = (u_char *) readline(">> "); diff -r 6f29f93b0390 -r db44b92af5f7 njs/test/njs_expect_test.exp --- a/njs/test/njs_expect_test.exp Mon Nov 19 16:55:37 2018 +0300 +++ b/njs/test/njs_expect_test.exp Wed Nov 21 16:45:10 2018 +0300 @@ -522,6 +522,10 @@ njs_test { # CLI OPTIONS +# help + +njs_run "-h" "Interactive njs shell.\r\n\r\nOptions:" + # version njs_run "-v" "\\d+\.\\d+\.\\d+" From miranovy at gmail.com Wed Nov 21 14:50:30 2018 From: miranovy at gmail.com (Miroslav Novy) Date: Wed, 21 Nov 2018 15:50:30 +0100 Subject: limit_rate_after support variables In-Reply-To: <20181120141005.GA72348@lo0.su> References: <20180827112847.GE71000@lo0.su> <20180827160021.GG71000@lo0.su> <20180829114230.GC43480@lo0.su> <20181120141005.GA72348@lo0.su> Message-ID: Hi Ruslan, there is my fix to remove warning "using uninitialized variable". I have moved the reading value of limit_rate variable from function ngx_http_update_location_config to function ngx_http_write_filter because value is initialized later. Best regards Miroslav Nov? # HG changeset patch # User Miroslav Nov? # Date 1542811768 0 # Wed Nov 21 14:49:28 2018 +0000 # Node ID e2139cd62c7263dc182b11a847a6eaf2d9560a0d # Parent 82eed7650622fd780dcd4a86661de7b80b44199c Variables support in limit_rate and limit_rate_after fix Reading value of limit_rate variable moved to function ngx_http_write_filter because in function ngx_http_update_location_config is not inicialized yet. diff -r 82eed7650622 -r e2139cd62c72 src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c Wed Nov 21 10:40:01 2018 +0000 +++ b/src/http/ngx_http_core_module.c Wed Nov 21 14:49:28 2018 +0000 @@ -1212,8 +1212,6 @@ void ngx_http_update_location_config(ngx_http_request_t *r) { - size_t limit_rate; - ngx_str_t val; ngx_http_core_loc_conf_t *clcf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); @@ -1283,20 +1281,6 @@ r->connection->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; } - if (r->limit_rate == 0 - && clcf->limit_rate - && ngx_http_complex_value_size(r, clcf->limit_rate, &val, &limit_rate) - == NGX_OK) - { - if (limit_rate != (size_t) NGX_ERROR) { - r->limit_rate = limit_rate; - - } else if (val.len) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid \"limit_rate\" value \"%V\"", &val); - } - } - if (clcf->handler) { r->content_handler = clcf->handler; } diff -r 82eed7650622 -r e2139cd62c72 src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c Wed Nov 21 10:40:01 2018 +0000 +++ b/src/http/ngx_http_write_filter_module.c Wed Nov 21 14:49:28 2018 +0000 @@ -48,7 +48,7 @@ ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in) { off_t size, sent, nsent, limit; - size_t limit_rate_after; + ssize_t limit_rate, limit_rate_after; ngx_str_t val; ngx_uint_t last, flush, sync; ngx_msec_t delay; @@ -220,6 +220,25 @@ return NGX_ERROR; } + if (r->limit_rate == 0 + && clcf->limit_rate + && ngx_http_complex_value_size(r, clcf->limit_rate, &val, + &limit_rate) + == NGX_OK) + { + if (limit_rate_after != NGX_ERROR) { + r->limit_rate = limit_rate; + + } else if (val.len) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "invalid \"limit_rate\" value \"%V\"", + &val); + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http limit rate \"%z\"", + r->limit_rate); + if (r->limit_rate) { if (r->limit_rate_after == 0 && clcf->limit_rate_after @@ -227,7 +246,7 @@ &limit_rate_after) == NGX_OK) { - if (limit_rate_after != (size_t) NGX_ERROR) { + if (limit_rate_after != NGX_ERROR) { r->limit_rate_after = limit_rate_after; } else if (val.len) { From mdounin at mdounin.ru Wed Nov 21 17:19:11 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 21 Nov 2018 17:19:11 +0000 Subject: [nginx] Limit req: fixed error message wording. Message-ID: details: http://hg.nginx.org/nginx/rev/bca4dad0d3cb branches: changeset: 7398:bca4dad0d3cb user: Maxim Dounin date: Wed Nov 21 18:56:44 2018 +0300 description: Limit req: fixed error message wording. diffstat: src/http/modules/ngx_http_limit_req_module.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -908,7 +908,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_c burst = ngx_atoi(value[i].data + 6, value[i].len - 6); if (burst <= 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid burst rate \"%V\"", &value[i]); + "invalid burst value \"%V\"", &value[i]); return NGX_CONF_ERROR; } From mdounin at mdounin.ru Wed Nov 21 17:19:13 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 21 Nov 2018 17:19:13 +0000 Subject: [nginx] Limit req: "delay=" parameter. Message-ID: details: http://hg.nginx.org/nginx/rev/d6ca744c727e branches: changeset: 7399:d6ca744c727e user: Maxim Dounin date: Wed Nov 21 18:56:50 2018 +0300 description: Limit req: "delay=" parameter. This parameter specifies an additional "soft" burst limit at which requests become delayed (but not yet rejected as it happens if "burst=" limit is exceeded). Defaults to 0, i.e., all excess requests are delayed. Originally inspired by Vladislav Shabanov (http://mailman.nginx.org/pipermail/nginx-devel/2016-April/008126.html). Further improved based on a patch by Peter Shchuchkin (http://mailman.nginx.org/pipermail/nginx-devel/2018-October/011522.html). diffstat: src/http/modules/ngx_http_limit_req_module.c | 32 +++++++++++++++++++-------- 1 files changed, 22 insertions(+), 10 deletions(-) diffs (93 lines): diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -44,7 +44,7 @@ typedef struct { ngx_shm_zone_t *shm_zone; /* integer value, 1 corresponds to 0.001 r/s */ ngx_uint_t burst; - ngx_uint_t nodelay; /* unsigned nodelay:1 */ + ngx_uint_t delay; } ngx_http_limit_req_limit_t; @@ -499,12 +499,12 @@ ngx_http_limit_req_account(ngx_http_limi excess = *ep; - if (excess == 0 || (*limit)->nodelay) { + if ((ngx_uint_t) excess <= (*limit)->delay) { max_delay = 0; } else { ctx = (*limit)->shm_zone->data; - max_delay = excess * 1000 / ctx->rate; + max_delay = (excess - (*limit)->delay) * 1000 / ctx->rate; } while (n--) { @@ -544,11 +544,11 @@ ngx_http_limit_req_account(ngx_http_limi ctx->node = NULL; - if (limits[n].nodelay) { + if ((ngx_uint_t) excess <= limits[n].delay) { continue; } - delay = excess * 1000 / ctx->rate; + delay = (excess - limits[n].delay) * 1000 / ctx->rate; if (delay > max_delay) { max_delay = delay; @@ -875,9 +875,9 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_c { ngx_http_limit_req_conf_t *lrcf = conf; - ngx_int_t burst; + ngx_int_t burst, delay; ngx_str_t *value, s; - ngx_uint_t i, nodelay; + ngx_uint_t i; ngx_shm_zone_t *shm_zone; ngx_http_limit_req_limit_t *limit, *limits; @@ -885,7 +885,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_c shm_zone = NULL; burst = 0; - nodelay = 0; + delay = 0; for (i = 1; i < cf->args->nelts; i++) { @@ -915,8 +915,20 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_c continue; } + if (ngx_strncmp(value[i].data, "delay=", 6) == 0) { + + delay = ngx_atoi(value[i].data + 6, value[i].len - 6); + if (delay <= 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid delay value \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + if (ngx_strcmp(value[i].data, "nodelay") == 0) { - nodelay = 1; + delay = NGX_MAX_INT_T_VALUE / 1000; continue; } @@ -956,7 +968,7 @@ ngx_http_limit_req(ngx_conf_t *cf, ngx_c limit->shm_zone = shm_zone; limit->burst = burst * 1000; - limit->nodelay = nodelay; + limit->delay = delay * 1000; return NGX_CONF_OK; } From mdounin at mdounin.ru Wed Nov 21 17:22:21 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 21 Nov 2018 20:22:21 +0300 Subject: [PATCH] Allow using nodelay=N semantics in limit_req configuration In-Reply-To: <5852531540971929@myt3-964eae3a5b05.qloud-c.yandex.net> References: <70c0d476999d9b893c64.1540738725@petr-desktop.superjob.local> <20181029125842.GN56558@mdounin.ru> <1489321540822453@iva5-84bc572481fe.qloud-c.yandex.net> <20181030154539.GT56558@mdounin.ru> <5852531540971929@myt3-964eae3a5b05.qloud-c.yandex.net> Message-ID: <20181121172221.GX99070@mdounin.ru> Hello! On Wed, Oct 31, 2018 at 10:45:29AM +0300, ?????? ???? wrote: > It takes me some time to express new parameter with words, but finally > it is as simple as "start to delay after N requests". I agree it more > suitable then nodelay= and there is no need to warn about delay>burst. > > Thank you, I'll be very happy to see this feature in upstream. Finially committed after an internal review: http://hg.nginx.org/nginx/rev/d6ca744c727e Thanks to all involved. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Wed Nov 21 18:04:52 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 21 Nov 2018 18:04:52 +0000 Subject: [nginx] Mp4: fixed possible pointer overflow on 32-bit platforms. Message-ID: details: http://hg.nginx.org/nginx/rev/be5cb9c67c05 branches: changeset: 7400:be5cb9c67c05 user: Maxim Dounin date: Wed Nov 21 20:23:16 2018 +0300 description: Mp4: fixed possible pointer overflow on 32-bit platforms. On 32-bit platforms mp4->buffer_pos might overflow when a large enough (close to 4 gigabytes) atom is being skipped, resulting in incorrect memory addesses being read further in the code. In most cases this results in harmless errors being logged, though may also result in a segmentation fault if hitting unmapped pages. To address this, ngx_mp4_atom_next() now only increments mp4->buffer_pos up to mp4->buffer_end. This ensures that overflow cannot happen. diffstat: src/http/modules/ngx_http_mp4_module.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diffs (19 lines): diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -169,7 +169,14 @@ typedef struct { #define ngx_mp4_atom_next(mp4, n) \ - mp4->buffer_pos += (size_t) n; \ + \ + if (n > (size_t) (mp4->buffer_end - mp4->buffer_pos)) { \ + mp4->buffer_pos = mp4->buffer_end; \ + \ + } else { \ + mp4->buffer_pos += (size_t) n; \ + } \ + \ mp4->offset += n From xeioex at nginx.com Thu Nov 22 12:54:42 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 22 Nov 2018 12:54:42 +0000 Subject: [njs] Fixed handling of unexpected tokens in parser. Message-ID: details: https://hg.nginx.org/njs/rev/01f2cbf5acc4 branches: changeset: 662:01f2cbf5acc4 user: Dmitry Volyntsev date: Thu Nov 22 15:02:19 2018 +0300 description: Fixed handling of unexpected tokens in parser. This fixes #50 issue on Github. diffstat: njs/njs.c | 2 ++ njs/njs_parser.c | 8 ++++---- njs/test/njs_interactive_test.c | 4 ++++ njs/test/njs_unit_test.c | 3 +++ 4 files changed, 13 insertions(+), 4 deletions(-) diffs (78 lines): diff -r db44b92af5f7 -r 01f2cbf5acc4 njs/njs.c --- a/njs/njs.c Wed Nov 21 16:45:10 2018 +0300 +++ b/njs/njs.c Thu Nov 22 15:02:19 2018 +0300 @@ -252,6 +252,8 @@ njs_vm_compile(njs_vm_t *vm, u_char **st nxt_array_reset(vm->backtrace); } + vm->retval = njs_value_void; + node = njs_parser(vm, parser, prev); if (nxt_slow_path(node == NULL)) { goto fail; diff -r db44b92af5f7 -r 01f2cbf5acc4 njs/njs_parser.c --- a/njs/njs_parser.c Wed Nov 21 16:45:10 2018 +0300 +++ b/njs/njs_parser.c Thu Nov 22 15:02:19 2018 +0300 @@ -639,7 +639,7 @@ njs_parser_function_lambda(njs_vm_t *vm, while (token != NJS_TOKEN_CLOSE_PARENTHESIS) { if (nxt_slow_path(token != NJS_TOKEN_NAME)) { - return NJS_TOKEN_ERROR; + return NJS_TOKEN_ILLEGAL; } arg = njs_variable_add(vm, parser, NJS_VARIABLE_VAR); @@ -676,7 +676,7 @@ njs_parser_function_lambda(njs_vm_t *vm, } if (nxt_slow_path(token != NJS_TOKEN_OPEN_BRACE)) { - return NJS_TOKEN_ERROR; + return NJS_TOKEN_ILLEGAL; } token = njs_parser_token(parser); @@ -1649,7 +1649,7 @@ njs_parser_try_statement(njs_vm_t *vm, n } if (nxt_slow_path(token != NJS_TOKEN_CLOSE_PARENTHESIS)) { - return token; + return NJS_TOKEN_ILLEGAL; } token = njs_parser_try_block(vm, parser); @@ -1689,7 +1689,7 @@ njs_parser_try_statement(njs_vm_t *vm, n if (try->right == NULL) { njs_parser_syntax_error(vm, parser, - "Missing catch or finally after try", NULL); + "Missing catch or finally after try"); return NJS_TOKEN_ILLEGAL; } diff -r db44b92af5f7 -r 01f2cbf5acc4 njs/test/njs_interactive_test.c --- a/njs/test/njs_interactive_test.c Wed Nov 21 16:45:10 2018 +0300 +++ b/njs/test/njs_interactive_test.c Thu Nov 22 15:02:19 2018 +0300 @@ -106,6 +106,10 @@ static njs_interactive_test_t njs_test[ "f({})" ENTER), nxt_string("1") }, + { nxt_string("arguments" ENTER + "function(){}()" ENTER), + nxt_string("SyntaxError: Unexpected token \"(\" in 1") }, + /* Backtraces */ { nxt_string("function ff(o) {return o.a.a}" ENTER diff -r db44b92af5f7 -r 01f2cbf5acc4 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Wed Nov 21 16:45:10 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Nov 22 15:02:19 2018 +0300 @@ -6356,6 +6356,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("try {}"), nxt_string("SyntaxError: Missing catch or finally after try in 1") }, + { nxt_string("try{}catch(a[]"), + nxt_string("SyntaxError: Unexpected token \"[\" in 1") }, + { nxt_string("function f(a) {return a;}; " "function thrower() {throw TypeError('Oops')}; " "f(thrower())"), From xeioex at nginx.com Thu Nov 22 12:54:42 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 22 Nov 2018 12:54:42 +0000 Subject: [njs] Improved backtrace reporting for stack overflow. Message-ID: details: https://hg.nginx.org/njs/rev/987f7998a967 branches: changeset: 663:987f7998a967 user: Dmitry Volyntsev date: Thu Nov 22 15:35:25 2018 +0300 description: Improved backtrace reporting for stack overflow. diffstat: njs/njs_vm.c | 63 ++++++++++++++++++++++++++++++++-------- njs/test/njs_interactive_test.c | 6 +++ 2 files changed, 56 insertions(+), 13 deletions(-) diffs (117 lines): diff -r 01f2cbf5acc4 -r 987f7998a967 njs/njs_vm.c --- a/njs/njs_vm.c Thu Nov 22 15:02:19 2018 +0300 +++ b/njs/njs_vm.c Thu Nov 22 15:35:25 2018 +0300 @@ -3202,12 +3202,12 @@ njs_vm_value_to_ext_string(njs_vm_t *vm, nxt_uint_t handle_exception) { u_char *p, *start; - size_t len, size; + size_t len, size, count; njs_ret_t ret; nxt_uint_t i, exception; nxt_array_t *backtrace; njs_value_t value; - njs_backtrace_entry_t *be; + njs_backtrace_entry_t *be, *prev; exception = handle_exception; @@ -3273,17 +3273,35 @@ again: len = dst->length + 1; + count = 0; + prev = NULL; + be = backtrace->start; for (i = 0; i < backtrace->items; i++) { - if (be[i].line != 0) { - len += sizeof(" at (:)\n") + 10 - + be[i].name.length; + if (i != 0 && prev->name.start == be[i].name.start + && prev->line == be[i].line) + { + count++; } else { - len += sizeof(" at (native)\n") - + be[i].name.length; + + if (count != 0) { + len += sizeof(" repeats times\n") + 10; + count = 0; + } + + if (be[i].line != 0) { + len += sizeof(" at (:)\n") + 10 + + be[i].name.length; + + } else { + len += sizeof(" at (native)\n") + + be[i].name.length; + } } + + prev = &be[i]; } p = nxt_mem_cache_alloc(vm->mem_cache_pool, len); @@ -3297,16 +3315,35 @@ again: p = nxt_cpymem(p, dst->start, dst->length); *p++ = '\n'; + count = 0; + prev = NULL; + for (i = 0; i < backtrace->items; i++) { - if (be[i].line != 0) { - p += sprintf((char *) p, " at %.*s (:%u)\n", - (int) be[i].name.length, be[i].name.start, - be[i].line); + if (i != 0 && prev->name.start == be[i].name.start + && prev->line == be[i].line) + { + count++; } else { - p += sprintf((char *) p, " at %.*s (native)\n", - (int) be[i].name.length, be[i].name.start); + if (count != 0) { + p += sprintf((char *) p, + " repeats %zu times\n", count); + count =0; + } + + if (be[i].line != 0) { + p += sprintf((char *) p, " at %.*s (:%u)\n", + (int) be[i].name.length, + be[i].name.start, be[i].line); + + } else { + p += sprintf((char *) p, " at %.*s (native)\n", + (int) be[i].name.length, + be[i].name.start); + } } + + prev = &be[i]; } dst->start = start; diff -r 01f2cbf5acc4 -r 987f7998a967 njs/test/njs_interactive_test.c --- a/njs/test/njs_interactive_test.c Thu Nov 22 15:02:19 2018 +0300 +++ b/njs/test/njs_interactive_test.c Thu Nov 22 15:35:25 2018 +0300 @@ -220,6 +220,12 @@ static njs_interactive_test_t njs_test[ " at parseInt (native)\n" " at main (native)\n") }, + { nxt_string("function f(n) { if (n == 0) { throw 'a'; } return f(n-1); }; f(2)" ENTER), + nxt_string("a\n" + " at f (:1)\n" + " repeats 2 times\n" + " at main (native)\n") }, + /* Exception in njs_vm_retval_to_ext_string() */ { nxt_string("var o = { toString: function() { return [1] } }" ENTER From xeioex at nginx.com Thu Nov 22 14:39:04 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 22 Nov 2018 14:39:04 +0000 Subject: [njs] Fixed parsing of throw statement inside if. Message-ID: details: https://hg.nginx.org/njs/rev/b3691d847ff4 branches: changeset: 665:b3691d847ff4 user: Dmitry Volyntsev date: Thu Nov 22 17:38:40 2018 +0300 description: Fixed parsing of throw statement inside if. diffstat: njs/njs_parser.c | 18 +++++++++++++++++- njs/test/njs_unit_test.c | 9 +++++++++ 2 files changed, 26 insertions(+), 1 deletions(-) diffs (47 lines): diff -r 3b2689be3a57 -r b3691d847ff4 njs/njs_parser.c --- a/njs/njs_parser.c Thu Nov 22 17:38:25 2018 +0300 +++ b/njs/njs_parser.c Thu Nov 22 17:38:40 2018 +0300 @@ -1696,7 +1696,23 @@ njs_parser_try_statement(njs_vm_t *vm, n parser->node = try; - return token; + switch (token) { + + case NJS_TOKEN_SEMICOLON: + case NJS_TOKEN_LINE_END: + return njs_parser_token(parser); + + case NJS_TOKEN_CLOSE_BRACE: + case NJS_TOKEN_END: + return token; + + default: + if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) { + return token; + } + + return NJS_TOKEN_ILLEGAL; + } } diff -r 3b2689be3a57 -r b3691d847ff4 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 22 17:38:25 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Nov 22 17:38:40 2018 +0300 @@ -2159,6 +2159,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("(function(){ if(true) return 1\n;\n else return 0; })()"), nxt_string("1") }, + { nxt_string("function f(n) {if (n)\n throw 'foo'\nelse return 1}; f(0)"), + nxt_string("1") }, + + { nxt_string("function f(n) {if (n)\n throw 'foo'\nelse return 1}; f(1)"), + nxt_string("foo") }, + + { nxt_string("function f(n) {if (n == 1) throw 'foo'\nelse if (n == 2) return 1}; f(2)"), + nxt_string("1") }, + /* do while. */ { nxt_string("do { break } if (false)"), From xeioex at nginx.com Thu Nov 22 14:39:04 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 22 Nov 2018 14:39:04 +0000 Subject: [njs] Fixed size uint32_t overflow in njs_array_expand(). Message-ID: details: https://hg.nginx.org/njs/rev/3b2689be3a57 branches: changeset: 664:3b2689be3a57 user: Dmitry Volyntsev date: Thu Nov 22 17:38:25 2018 +0300 description: Fixed size uint32_t overflow in njs_array_expand(). diffstat: njs/njs_array.c | 21 ++++++++++++++++----- njs/test/njs_unit_test.c | 6 ++++++ nxt/nxt_mem_cache_pool.c | 3 ++- 3 files changed, 24 insertions(+), 6 deletions(-) diffs (108 lines): diff -r 987f7998a967 -r 3b2689be3a57 njs/njs_array.c --- a/njs/njs_array.c Thu Nov 22 15:35:25 2018 +0300 +++ b/njs/njs_array.c Thu Nov 22 17:38:25 2018 +0300 @@ -6,6 +6,7 @@ #include #include +#include typedef struct { @@ -136,7 +137,7 @@ njs_array_alloc(njs_vm_t *vm, uint32_t l size = (uint64_t) length + spare; - if (nxt_slow_path((size * sizeof(njs_value_t)) >= 0xffffffff)) { + if (nxt_slow_path((size * sizeof(njs_value_t)) >= UINT32_MAX)) { goto memory_error; } @@ -201,11 +202,12 @@ njs_array_string_add(njs_vm_t *vm, njs_a njs_ret_t njs_array_expand(njs_vm_t *vm, njs_array_t *array, uint32_t prepend, - uint32_t size) + uint32_t new_size) { + uint64_t size; njs_value_t *start, *old; - size += array->length; + size = (uint64_t) new_size + array->length; if (nxt_fast_path(size <= array->size && prepend == 0)) { return NXT_OK; @@ -218,11 +220,14 @@ njs_array_expand(njs_vm_t *vm, njs_array size += size / 2; } + if (nxt_slow_path(((prepend + size) * sizeof(njs_value_t)) >= UINT32_MAX)) { + goto memory_error; + } + start = nxt_mem_cache_align(vm->mem_cache_pool, sizeof(njs_value_t), (prepend + size) * sizeof(njs_value_t)); if (nxt_slow_path(start == NULL)) { - njs_memory_error(vm); - return NXT_ERROR; + goto memory_error; } array->size = size; @@ -238,6 +243,12 @@ njs_array_expand(njs_vm_t *vm, njs_array nxt_mem_cache_free(vm->mem_cache_pool, old); return NXT_OK; + +memory_error: + + njs_memory_error(vm); + + return NXT_ERROR; } diff -r 987f7998a967 -r 3b2689be3a57 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 22 15:35:25 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Nov 22 17:38:25 2018 +0300 @@ -2905,6 +2905,9 @@ static njs_unit_test_t njs_test[] = nxt_string("0:0,1:1,2:2,null:null,undefined:defined,false:false," "true:true,Infinity:Infinity,-Infinity:-Infinity,NaN:NaN,") }, + { nxt_string("--[][3e9]"), + nxt_string("MemoryError") }, + { nxt_string("[].length"), nxt_string("0") }, @@ -2933,6 +2936,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("[].length = 2**32 - 1"), nxt_string("MemoryError") }, + { nxt_string("[].length = 3e9"), + nxt_string("MemoryError") }, + { nxt_string("Object.defineProperty([], 'length',{value: 2**32 - 1})"), nxt_string("MemoryError") }, diff -r 987f7998a967 -r 3b2689be3a57 nxt/nxt_mem_cache_pool.c --- a/nxt/nxt_mem_cache_pool.c Thu Nov 22 15:35:25 2018 +0300 +++ b/nxt/nxt_mem_cache_pool.c Thu Nov 22 17:38:25 2018 +0300 @@ -14,6 +14,7 @@ #include #include #include +#include /* @@ -586,7 +587,7 @@ nxt_mem_cache_alloc_large(nxt_mem_cache_ nxt_mem_cache_block_t *block; /* Allocation must be less than 4G. */ - if (nxt_slow_path(size >= 0xffffffff)) { + if (nxt_slow_path(size >= UINT32_MAX)) { return NULL; } From xeioex at nginx.com Thu Nov 22 15:12:38 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 22 Nov 2018 15:12:38 +0000 Subject: [njs] Backed out changeset b3691d847ff4, reimplemented properly. Message-ID: details: https://hg.nginx.org/njs/rev/6577d408d494 branches: changeset: 666:6577d408d494 user: Dmitry Volyntsev date: Thu Nov 22 18:12:26 2018 +0300 description: Backed out changeset b3691d847ff4, reimplemented properly. diffstat: njs/njs_parser.c | 36 ++++++++++++++++++------------------ 1 files changed, 18 insertions(+), 18 deletions(-) diffs (53 lines): diff -r b3691d847ff4 -r 6577d408d494 njs/njs_parser.c --- a/njs/njs_parser.c Thu Nov 22 17:38:40 2018 +0300 +++ b/njs/njs_parser.c Thu Nov 22 18:12:26 2018 +0300 @@ -1696,23 +1696,7 @@ njs_parser_try_statement(njs_vm_t *vm, n parser->node = try; - switch (token) { - - case NJS_TOKEN_SEMICOLON: - case NJS_TOKEN_LINE_END: - return njs_parser_token(parser); - - case NJS_TOKEN_CLOSE_BRACE: - case NJS_TOKEN_END: - return token; - - default: - if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) { - return token; - } - - return NJS_TOKEN_ILLEGAL; - } + return token; } @@ -1758,7 +1742,23 @@ njs_parser_throw_statement(njs_vm_t *vm, parser->code_size += sizeof(njs_vmcode_throw_t); - return token; + switch (token) { + + case NJS_TOKEN_SEMICOLON: + case NJS_TOKEN_LINE_END: + return njs_parser_token(parser); + + case NJS_TOKEN_CLOSE_BRACE: + case NJS_TOKEN_END: + return token; + + default: + if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) { + return token; + } + + return NJS_TOKEN_ILLEGAL; + } } From xeioex at nginx.com Thu Nov 22 16:11:57 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 22 Nov 2018 16:11:57 +0000 Subject: [njs] Making built-in prototypes mutable. Message-ID: details: https://hg.nginx.org/njs/rev/82cbeec8fd19 branches: changeset: 667:82cbeec8fd19 user: Dmitry Volyntsev date: Thu Nov 22 18:55:32 2018 +0300 description: Making built-in prototypes mutable. diffstat: njs/njs_builtin.c | 2 ++ njs/test/njs_unit_test.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 0 deletions(-) diffs (67 lines): diff -r 6577d408d494 -r 82cbeec8fd19 njs/njs_builtin.c --- a/njs/njs_builtin.c Thu Nov 22 18:12:26 2018 +0300 +++ b/njs/njs_builtin.c Thu Nov 22 18:55:32 2018 +0300 @@ -358,6 +358,8 @@ njs_builtin_objects_create(njs_vm_t *vm) return NXT_ERROR; } + prototype->object.extensible = 1; + prototype++; } diff -r 6577d408d494 -r 82cbeec8fd19 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 22 18:12:26 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Nov 22 18:55:32 2018 +0300 @@ -338,6 +338,10 @@ static njs_unit_test_t njs_test[] = { nxt_string(".e1"), nxt_string("SyntaxError: Unexpected token \".\" in 1") }, + { nxt_string("Number.prototype.X = function(){return 123;};" + "(1).X()"), + nxt_string("123") }, + /* Indexes. */ { nxt_string("var a = []; a[-1] = 2; a[-1] == a['-1']"), @@ -2731,10 +2735,16 @@ static njs_unit_test_t njs_test[] = { nxt_string("var o = Object.create({a:1}); o.a = 2; delete o.a; o.a"), nxt_string("1") }, + /* Inheritance. */ + { nxt_string("function Foo() {this.bar = 10;}; Foo.prototype.bar = 42; " "var v = new Foo(); delete v.bar; v.bar"), nxt_string("42") }, + { nxt_string("function Cl(x,y) {this.x = x; this.y = y}; " + "var c = new Cl('a', 'b'); Cl.prototype.z = 1; c.z"), + nxt_string("1") }, + /* Math object is immutable. */ { nxt_string("delete Math.max"), @@ -3771,6 +3781,12 @@ static njs_unit_test_t njs_test[] = " a = b"), nxt_string("abcdefghijklmnop") }, + { nxt_string("String.prototype.my = function f() {return 7}; 'a'.my()"), + nxt_string("7") }, + + { nxt_string("'a'.my"), + nxt_string("undefined") }, + /* Escape strings. */ { nxt_string("'\\a \\' \\\" \\\\ \\0 \\b \\f \\n \\r \\t \\v'"), @@ -5271,6 +5287,10 @@ static njs_unit_test_t njs_test[] = "(function(){(function(){(function(){})})})})})})})"), nxt_string("SyntaxError: The maximum function nesting level is \"5\" in 1") }, + { nxt_string("Function.prototype.toString = function () {return 'X'};" + "eval"), + nxt_string("X") }, + /* Recursive factorial. */ { nxt_string("function f(a) {" From xeioex at nginx.com Thu Nov 22 17:07:03 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 22 Nov 2018 17:07:03 +0000 Subject: [njs] Fixed typeof for object_value type. Message-ID: details: https://hg.nginx.org/njs/rev/ec82852f909a branches: changeset: 668:ec82852f909a user: Dmitry Volyntsev date: Thu Nov 22 19:32:48 2018 +0300 description: Fixed typeof for object_value type. diffstat: njs/njs_object.c | 2 +- njs/njs_vm.c | 3 ++- njs/njs_vm.h | 1 + njs/test/njs_unit_test.c | 8 +++++++- 4 files changed, 11 insertions(+), 3 deletions(-) diffs (68 lines): diff -r 82cbeec8fd19 -r ec82852f909a njs/njs_object.c --- a/njs/njs_object.c Thu Nov 22 18:55:32 2018 +0300 +++ b/njs/njs_object.c Thu Nov 22 19:32:48 2018 +0300 @@ -2098,7 +2098,7 @@ njs_object_prototype_to_string(njs_vm_t { const njs_value_t *name; - static const njs_value_t *class_name[] = { + static const njs_value_t *class_name[NJS_TYPE_MAX] = { /* Primitives. */ &njs_object_null_string, &njs_object_undefined_string, diff -r 82cbeec8fd19 -r ec82852f909a njs/njs_vm.c --- a/njs/njs_vm.c Thu Nov 22 18:55:32 2018 +0300 +++ b/njs/njs_vm.c Thu Nov 22 19:32:48 2018 +0300 @@ -1024,7 +1024,7 @@ njs_vmcode_typeof(njs_vm_t *vm, njs_valu /* ECMAScript 5.1: null, array and regexp are objects. */ - static const njs_value_t *types[] = { + static const njs_value_t *types[NJS_TYPE_MAX] = { &njs_string_object, &njs_string_void, &njs_string_boolean, @@ -1058,6 +1058,7 @@ njs_vmcode_typeof(njs_vm_t *vm, njs_valu &njs_string_object, &njs_string_object, &njs_string_object, + &njs_string_object, }; /* A zero index means non-declared variable. */ diff -r 82cbeec8fd19 -r ec82852f909a njs/njs_vm.h --- a/njs/njs_vm.h Thu Nov 22 18:55:32 2018 +0300 +++ b/njs/njs_vm.h Thu Nov 22 19:32:48 2018 +0300 @@ -134,6 +134,7 @@ typedef enum { NJS_OBJECT_TYPE_ERROR = 0x1e, NJS_OBJECT_URI_ERROR = 0x1f, NJS_OBJECT_VALUE = 0x20, +#define NJS_TYPE_MAX (NJS_OBJECT_VALUE + 1) } njs_value_type_t; diff -r 82cbeec8fd19 -r ec82852f909a njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 22 18:55:32 2018 +0300 +++ b/njs/test/njs_unit_test.c Thu Nov 22 19:32:48 2018 +0300 @@ -10302,7 +10302,10 @@ static njs_unit_test_t njs_test[] = "h.update('A').digest('hex'); h.update('B')"), nxt_string("Error: Digest already called") }, - /* require('crypto').createHash() */ + { nxt_string("typeof require('crypto').createHash('md5')"), + nxt_string("object") }, + + /* require('crypto').createHmac() */ { nxt_string("require('crypto').createHmac('sha1', '')"), nxt_string("[object Hmac]") }, @@ -10411,6 +10414,9 @@ static njs_unit_test_t njs_test[] = "h.update('A').digest('hex'); h.update('B')"), nxt_string("Error: Digest already called") }, + { nxt_string("typeof require('crypto').createHmac('md5', 'a')"), + nxt_string("object") }, + /* setTimeout(). */ { nxt_string("setTimeout()"), From xeioex at nginx.com Fri Nov 23 14:46:58 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 23 Nov 2018 14:46:58 +0000 Subject: [njs] Fixed parser for newline after throw. Message-ID: details: https://hg.nginx.org/njs/rev/185aa0986f71 branches: changeset: 669:185aa0986f71 user: Dmitry Volyntsev date: Fri Nov 23 14:30:24 2018 +0300 description: Fixed parser for newline after throw. diffstat: njs/njs_parser.c | 30 +++++++++++------------------- njs/test/njs_unit_test.c | 3 +++ 2 files changed, 14 insertions(+), 19 deletions(-) diffs (72 lines): diff -r ec82852f909a -r 185aa0986f71 njs/njs_parser.c --- a/njs/njs_parser.c Thu Nov 22 19:32:48 2018 +0300 +++ b/njs/njs_parser.c Fri Nov 23 14:30:24 2018 +0300 @@ -1720,11 +1720,6 @@ njs_parser_throw_statement(njs_vm_t *vm, njs_token_t token; njs_parser_node_t *node; - token = njs_parser_token(parser); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - node = njs_parser_node_alloc(vm); if (nxt_slow_path(node == NULL)) { return NJS_TOKEN_ERROR; @@ -1732,32 +1727,29 @@ njs_parser_throw_statement(njs_vm_t *vm, node->token = NJS_TOKEN_THROW; - token = njs_parser_expression(vm, parser, token); + token = njs_lexer_token(parser->lexer); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } - node->right = parser->node; - parser->node = node; - - parser->code_size += sizeof(njs_vmcode_throw_t); - switch (token) { - case NJS_TOKEN_SEMICOLON: case NJS_TOKEN_LINE_END: - return njs_parser_token(parser); - - case NJS_TOKEN_CLOSE_BRACE: - case NJS_TOKEN_END: - return token; + njs_parser_syntax_error(vm, parser, "Illegal newline after throw"); + return NJS_TOKEN_ILLEGAL; default: - if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) { + token = njs_parser_expression(vm, parser, token); + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } - return NJS_TOKEN_ILLEGAL; + node->right = parser->node; + parser->node = node; + + parser->code_size += sizeof(njs_vmcode_throw_t); + + return token; } } diff -r ec82852f909a -r 185aa0986f71 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 22 19:32:48 2018 +0300 +++ b/njs/test/njs_unit_test.c Fri Nov 23 14:30:24 2018 +0300 @@ -6441,6 +6441,9 @@ static njs_unit_test_t njs_test[] = " catch(x) { a += x } a"), nxt_string("8") }, + { nxt_string("throw\nnull"), + nxt_string("SyntaxError: Illegal newline after throw in 2") }, + { nxt_string("var o = { valueOf: function() { return '3' } }; --o"), nxt_string("2") }, From xeioex at nginx.com Fri Nov 23 14:46:59 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 23 Nov 2018 14:46:59 +0000 Subject: [njs] Fixed parsing of statements in if without newline. Message-ID: details: https://hg.nginx.org/njs/rev/fa98656237f0 branches: changeset: 670:fa98656237f0 user: Dmitry Volyntsev date: Fri Nov 23 17:46:30 2018 +0300 description: Fixed parsing of statements in if without newline. This fixes #8 issue on Github. Thanks to ??? (Hong Zhi Dao) diffstat: njs/njs_parser.c | 75 ++++++++++++++++++++--------------------------- njs/test/njs_unit_test.c | 37 ++++++++++++++++++++--- 2 files changed, 64 insertions(+), 48 deletions(-) diffs (243 lines): diff -r 185aa0986f71 -r fa98656237f0 njs/njs_parser.c --- a/njs/njs_parser.c Fri Nov 23 14:30:24 2018 +0300 +++ b/njs/njs_parser.c Fri Nov 23 17:46:30 2018 +0300 @@ -311,12 +311,6 @@ njs_parser_statement(njs_vm_t *vm, njs_p case NJS_TOKEN_FUNCTION: return njs_parser_function_declaration(vm, parser); - case NJS_TOKEN_RETURN: - return njs_parser_return_statement(vm, parser); - - case NJS_TOKEN_VAR: - return njs_parser_var_statement(vm, parser); - case NJS_TOKEN_IF: return njs_parser_if_statement(vm, parser); @@ -332,18 +326,9 @@ njs_parser_statement(njs_vm_t *vm, njs_p case NJS_TOKEN_FOR: return njs_parser_for_statement(vm, parser); - case NJS_TOKEN_CONTINUE: - return njs_parser_continue_statement(vm, parser); - - case NJS_TOKEN_BREAK: - return njs_parser_break_statement(vm, parser); - case NJS_TOKEN_TRY: return njs_parser_try_statement(vm, parser); - case NJS_TOKEN_THROW: - return njs_parser_throw_statement(vm, parser); - case NJS_TOKEN_SEMICOLON: return njs_parser_token(parser); @@ -360,7 +345,33 @@ njs_parser_statement(njs_vm_t *vm, njs_p /* Fall through. */ default: - token = njs_parser_expression(vm, parser, token); + + switch (token) { + case NJS_TOKEN_VAR: + token = njs_parser_var_statement(vm, parser); + break; + + case NJS_TOKEN_CONTINUE: + token = njs_parser_continue_statement(vm, parser); + break; + + case NJS_TOKEN_BREAK: + token = njs_parser_break_statement(vm, parser); + break; + + case NJS_TOKEN_RETURN: + token = njs_parser_return_statement(vm, parser); + break; + + case NJS_TOKEN_THROW: + token = njs_parser_throw_statement(vm, parser); + break; + + default: + token = njs_parser_expression(vm, parser, token); + break; + } + if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -781,11 +792,12 @@ njs_parser_return_statement(njs_vm_t *vm switch (token) { - case NJS_TOKEN_SEMICOLON: case NJS_TOKEN_LINE_END: return njs_parser_token(parser); + case NJS_TOKEN_SEMICOLON: case NJS_TOKEN_CLOSE_BRACE: + case NJS_TOKEN_END: return token; default: @@ -801,10 +813,6 @@ njs_parser_return_statement(njs_vm_t *vm node->right = parser->node; parser->node = node; - if (token == NJS_TOKEN_SEMICOLON) { - return njs_parser_token(parser); - } - return token; } } @@ -902,26 +910,7 @@ njs_parser_var_statement(njs_vm_t *vm, n } while (token == NJS_TOKEN_COMMA); - /* - * A var statement must be terminated by semicolon, - * or by a close curly brace or by the end of line. - */ - switch (token) { - - case NJS_TOKEN_SEMICOLON: - return njs_parser_token(parser); - - case NJS_TOKEN_CLOSE_BRACE: - case NJS_TOKEN_END: - return token; - - default: - if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) { - return token; - } - - return NJS_TOKEN_ILLEGAL; - } + return token; } @@ -1516,10 +1505,10 @@ njs_parser_continue_statement(njs_vm_t * switch (token) { - case NJS_TOKEN_SEMICOLON: case NJS_TOKEN_LINE_END: return njs_parser_token(parser); + case NJS_TOKEN_SEMICOLON: case NJS_TOKEN_CLOSE_BRACE: case NJS_TOKEN_END: return token; @@ -1551,10 +1540,10 @@ njs_parser_break_statement(njs_vm_t *vm, switch (token) { - case NJS_TOKEN_SEMICOLON: case NJS_TOKEN_LINE_END: return njs_parser_token(parser); + case NJS_TOKEN_SEMICOLON: case NJS_TOKEN_CLOSE_BRACE: case NJS_TOKEN_END: return token; diff -r 185aa0986f71 -r fa98656237f0 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Fri Nov 23 14:30:24 2018 +0300 +++ b/njs/test/njs_unit_test.c Fri Nov 23 17:46:30 2018 +0300 @@ -2149,7 +2149,7 @@ static njs_unit_test_t njs_test[] = nxt_string("123") }, { nxt_string("(function(){ if(true) return 1 else return 0; })()"), - nxt_string("1") }, + nxt_string("SyntaxError: Unexpected token \"else\" in 1") }, { nxt_string("(function(){ if(true) return 1; else return 0; })()"), nxt_string("1") }, @@ -2163,6 +2163,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("(function(){ if(true) return 1\n;\n else return 0; })()"), nxt_string("1") }, + { nxt_string("function f(n) {if (n) throw 'foo' else return 1}; f(0)"), + nxt_string("SyntaxError: Unexpected token \"else\" in 1") }, + { nxt_string("function f(n) {if (n)\n throw 'foo'\nelse return 1}; f(0)"), nxt_string("1") }, @@ -2172,6 +2175,24 @@ static njs_unit_test_t njs_test[] = { nxt_string("function f(n) {if (n == 1) throw 'foo'\nelse if (n == 2) return 1}; f(2)"), nxt_string("1") }, + { nxt_string("(function(){ for (var p in [1] ){ if (1) break else return 0; }})()"), + nxt_string("SyntaxError: Unexpected token \"else\" in 1") }, + + { nxt_string("(function(){ for (var p in [1] ){ if (1) break\n else return 0; }})()"), + nxt_string("undefined") }, + + { nxt_string("(function(){ for (var p in [1] ){ if (1) break; else return 0; }})()"), + nxt_string("undefined") }, + + { nxt_string("(function(){ for (var p in [1] ){ if (1) continue else return 0; }})()"), + nxt_string("SyntaxError: Unexpected token \"else\" in 1") }, + + { nxt_string("(function(){ for (var p in [1] ){ if (1) continue\n else return 0; }})()"), + nxt_string("undefined") }, + + { nxt_string("(function(){ for (var p in [1] ){ if (1) continue; else return 0; }})()"), + nxt_string("undefined") }, + /* do while. */ { nxt_string("do { break } if (false)"), @@ -5259,6 +5280,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("function f() { return 1\n 2 } f()"), nxt_string("1") }, + { nxt_string("(function f() { return 2.toString(); })()"), + nxt_string("SyntaxError: Unexpected token \"toString\" in 1") }, + + { nxt_string("(function f() { return 2..toString(); })()"), + nxt_string("2") }, + { nxt_string("function f(a) { if (a) return 'OK' } f(1)+f(0)"), nxt_string("OKundefined") }, @@ -5295,7 +5322,7 @@ static njs_unit_test_t njs_test[] = { nxt_string("function f(a) {" " if (a > 1)" - " return a * f(a - 1)" + " return a * f(a - 1)\n" " return 1" "}" "f(10)"), @@ -5420,7 +5447,7 @@ static njs_unit_test_t njs_test[] = { nxt_string("function fibo(n) {" " if (n > 1)" - " return fibo(n-1) + fibo(n-2)" + " return fibo(n-1) + fibo(n-2)\n" " return 1" "}" "fibo(10)"), @@ -5428,7 +5455,7 @@ static njs_unit_test_t njs_test[] = { nxt_string("function fibo(n) {" " if (n > 1)" - " return fibo(n-1) + fibo(n-2)" + " return fibo(n-1) + fibo(n-2)\n" " return '.'" "}" "fibo(10).length"), @@ -5436,7 +5463,7 @@ static njs_unit_test_t njs_test[] = { nxt_string("function fibo(n) {" " if (n > 1)" - " return fibo(n-1) + fibo(n-2)" + " return fibo(n-1) + fibo(n-2)\n" " return 1" "}" "fibo('10')"), From coles.david at gmail.com Fri Nov 23 22:31:17 2018 From: coles.david at gmail.com (David Coles) Date: Fri, 23 Nov 2018 14:31:17 -0800 Subject: PATCH: Add $fqdn stream and http variable. Message-ID: # HG changeset patch # User David Coles # Date 1543000128 0 # Fri Nov 23 19:08:48 2018 +0000 # Node ID 8e014e3bdfbda3c7a22c7980c163bcea1c4474b3 # Parent be5cb9c67c05ccaf22dab7abba78aa4c1545a8ee Add $fqdn stream and http variable. This exposes the system's fully-qualified domain name as reported by calling getaddrbyname on the hostname. Typically $hostname will only contain the first segment of the host's domainname. diff -r be5cb9c67c05 -r 8e014e3bdfbd src/core/ngx_config.h --- a/src/core/ngx_config.h Wed Nov 21 20:23:16 2018 +0300 +++ b/src/core/ngx_config.h Fri Nov 23 19:08:48 2018 +0000 @@ -124,6 +124,11 @@ #define NGX_MAXHOSTNAMELEN 256 #endif +#ifdef MAXFQDNLEN +#define NGX_MAXFQDNLEN MAXFQDNLEN +#else +#define NGX_MAXFQDNLEN 256 +#endif #define NGX_MAX_UINT32_VALUE (uint32_t) 0xffffffff #define NGX_MAX_INT32_VALUE (uint32_t) 0x7fffffff diff -r be5cb9c67c05 -r 8e014e3bdfbd src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c Wed Nov 21 20:23:16 2018 +0300 +++ b/src/core/ngx_cycle.c Fri Nov 23 19:08:48 2018 +0000 @@ -9,6 +9,8 @@ #include #include +#include + static void ngx_destroy_cycle_pools(ngx_conf_t *conf); static ngx_int_t ngx_init_zone_pool(ngx_cycle_t *cycle, @@ -53,6 +55,7 @@ ngx_core_conf_t *ccf, *old_ccf; ngx_core_module_t *module; char hostname[NGX_MAXHOSTNAMELEN]; + struct hostent *hostent; ngx_timezone_update(); @@ -213,6 +216,23 @@ ngx_strlow(cycle->hostname.data, (u_char *) hostname, cycle->hostname.len); + hostent = gethostbyname(hostname); + if (hostent == NULL) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "gethostbyname() failed"); + ngx_destroy_pool(pool); + return NULL; + } + + cycle->fqdn.len = ngx_strlen(hostent->h_name); + + cycle->fqdn.data = ngx_pnalloc(pool, cycle->fqdn.len); + if (cycle->fqdn.data == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + ngx_strlow(cycle->fqdn.data, (u_char *) hostent->h_name, cycle->fqdn.len); + + if (ngx_cycle_modules(cycle) != NGX_OK) { ngx_destroy_pool(pool); return NULL; diff -r be5cb9c67c05 -r 8e014e3bdfbd src/core/ngx_cycle.h --- a/src/core/ngx_cycle.h Wed Nov 21 20:23:16 2018 +0300 +++ b/src/core/ngx_cycle.h Fri Nov 23 19:08:48 2018 +0000 @@ -81,6 +81,7 @@ ngx_str_t prefix; ngx_str_t lock_file; ngx_str_t hostname; + ngx_str_t fqdn; }; diff -r be5cb9c67c05 -r 8e014e3bdfbd src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c Wed Nov 21 20:23:16 2018 +0300 +++ b/src/http/ngx_http_variables.c Fri Nov 23 19:08:48 2018 +0000 @@ -134,6 +134,8 @@ ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_hostname(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_fqdn(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_pid(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_msec(ngx_http_request_t *r, @@ -338,6 +340,9 @@ { ngx_string("hostname"), NULL, ngx_http_variable_hostname, 0, 0, 0 }, + { ngx_string("fqdn"), NULL, ngx_http_variable_fqdn, + 0, 0, 0 }, + { ngx_string("pid"), NULL, ngx_http_variable_pid, 0, 0, 0 }, @@ -2256,6 +2261,20 @@ static ngx_int_t +ngx_http_variable_fqdn(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + v->len = ngx_cycle->fqdn.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = ngx_cycle->fqdn.data; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_variable_pid(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { diff -r be5cb9c67c05 -r 8e014e3bdfbd src/stream/ngx_stream_variables.c --- a/src/stream/ngx_stream_variables.c Wed Nov 21 20:23:16 2018 +0300 +++ b/src/stream/ngx_stream_variables.c Fri Nov 23 19:08:48 2018 +0000 @@ -40,6 +40,8 @@ ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_hostname(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_stream_variable_fqdn(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_pid(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_stream_variable_msec(ngx_stream_session_t *s, @@ -96,6 +98,9 @@ { ngx_string("hostname"), NULL, ngx_stream_variable_hostname, 0, 0, 0 }, + { ngx_string("fqdn"), NULL, ngx_stream_variable_fqdn, + 0, 0, 0 }, + { ngx_string("pid"), NULL, ngx_stream_variable_pid, 0, 0, 0 }, @@ -778,6 +783,20 @@ static ngx_int_t +ngx_stream_variable_fqdn(ngx_stream_session_t *s, + ngx_stream_variable_value_t *v, uintptr_t data) +{ + v->len = ngx_cycle->fqdn.len; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = ngx_cycle->fqdn.data; + + return NGX_OK; +} + + +static ngx_int_t ngx_stream_variable_pid(ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data) { From mdounin at mdounin.ru Sat Nov 24 12:35:07 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Sat, 24 Nov 2018 15:35:07 +0300 Subject: PATCH: Add $fqdn stream and http variable. In-Reply-To: References: Message-ID: <20181124123507.GJ99070@mdounin.ru> Hello! On Fri, Nov 23, 2018 at 02:31:17PM -0800, David Coles wrote: > # HG changeset patch > # User David Coles > # Date 1543000128 0 > # Fri Nov 23 19:08:48 2018 +0000 > # Node ID 8e014e3bdfbda3c7a22c7980c163bcea1c4474b3 > # Parent be5cb9c67c05ccaf22dab7abba78aa4c1545a8ee > Add $fqdn stream and http variable. > > This exposes the system's fully-qualified domain name as reported by calling > getaddrbyname on the hostname. Typically $hostname will only contain the first > segment of the host's domainname. [...] No, thank you. This change makes nginx startup unconditionally dependant on the DNS availability. This is not something we are going to accept. Also, the $hostname variable is expected to be FQDN on systems participating in the DNS. If it's not FQDN in your case, you may want to consider reconfiguring your system. See http://mailman.nginx.org/pipermail/nginx/2017-February/052885.html for a previous discussion on the topic. -- Maxim Dounin http://mdounin.ru/ From coles.david at gmail.com Sun Nov 25 22:49:12 2018 From: coles.david at gmail.com (David Coles) Date: Sun, 25 Nov 2018 14:49:12 -0800 Subject: PATCH: Add $fqdn stream and http variable. In-Reply-To: <20181124123507.GJ99070@mdounin.ru> References: <20181124123507.GJ99070@mdounin.ru> Message-ID: Hi Maxim. Thanks for your comments. On Sat, Nov 24, 2018 at 4:35 AM Maxim Dounin wrote: > No, thank you. This change makes nginx startup unconditionally > dependant on the DNS availability. This is not something we are > going to accept. That's reasonable. I based this behaviour off `hostname -f` which also uses `gethostbyname` for resolving the FQDN. Note, on most systems this doesn't trigger an actual DNS lookup provided that hosts canonical name (usually the FQDN) is configured in `/etc/hosts` (See paragraph 5 of THE FQDN ). On some systems `gethostent` can be used to explicitly walk `/etc/hosts`, but behaviour is so inconsistent I would avoid it. How would you feel about trying to resolve the FQDN at nginx startup and, if unavailable falling back to `$hostname`? This matches the behaviour of other languages (e.g. Python's `socket.getfqdn()` ). I could also make this a runtime evaluation, but it would be nice to only evaluate once as it would often be used in hot paths like logging and tracing. > Also, the $hostname variable is expected to be FQDN on systems > participating in the DNS. If it's not FQDN in your case, you may > want to consider reconfiguring your system. See > http://mailman.nginx.org/pipermail/nginx/2017-February/052885.html > for a previous discussion on the topic. Thank you for the pointer to the previous discussion. Doing some investigation I've found several contrary recommendations: https://www.gnu.org/software/libc/manual/html_node/Host-Identification.html : Function: int gethostname (char *name, size_t size) ... : If the system participates in the DNS, this is the FQDN (see : above). https://manpages.debian.org/testing/hostname/hostname.1.en.html : The recommended method of setting the FQDN is to make the hostname be an alias : for the fully qualified name using /etc/hosts, DNS, or NIS. For example, if the : hostname was "ursula", one might have a line in /etc/hosts which reads : : 127.0.1.1 ursula.example.com ursula The Linux programming interface. Kerrisk, M. (2010). ?12.2 (p. 299) : Often, this name is something like the hostname prefix from the system?s DNS : domain name. Advanced programming in the UNIX environment. Stevens, W. R., & Rago, S. A. (2013). ?6.9 (p. 172) : Historically, BSD-derived systems provide the `gethostname` function to return : only the name of the host. : ... : If the host is connected to a TCP/IP network, the host name is normally the : fully qualified domain name of the host. Linux in particular seems to have interpreted `gethostname` as returning a DNS label (maximum of 63 characters) rather than a full DNS name (up to 213 characters). Thus it's impossible to represent certain DNS names as the system hostname. From mdounin at mdounin.ru Mon Nov 26 14:51:31 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 26 Nov 2018 17:51:31 +0300 Subject: PATCH: Add $fqdn stream and http variable. In-Reply-To: References: <20181124123507.GJ99070@mdounin.ru> Message-ID: <20181126145131.GL99070@mdounin.ru> Hello! On Sun, Nov 25, 2018 at 02:49:12PM -0800, David Coles wrote: > Hi Maxim. Thanks for your comments. > > On Sat, Nov 24, 2018 at 4:35 AM Maxim Dounin wrote: > > No, thank you. This change makes nginx startup unconditionally > > dependant on the DNS availability. This is not something we are > > going to accept. > > That's reasonable. I based this behaviour off `hostname -f` which also > uses `gethostbyname` for resolving the FQDN. > Note, on most systems this doesn't trigger an actual DNS lookup > provided that hosts canonical name (usually the FQDN) is configured in > `/etc/hosts` (See paragraph 5 of THE FQDN > ). The "no DNS lookup on most systems" is not something we can rely on. > On some systems `gethostent` can be used to explicitly walk > `/etc/hosts`, but behaviour is so inconsistent I would avoid it. Trying to use /etc/hosts will lead to results different from results of normal name resolution, so this doesn't looks like an option. > How would you feel about trying to resolve the FQDN at nginx startup > and, if unavailable falling back to `$hostname`? This matches the > behaviour of other languages (e.g. Python's `socket.getfqdn()` > ). Even trying to resolve the FQDN will imply DNS dependency. If DNS is not availble it will wait for a timeout to expire before proceeding any further. > I could also make this a runtime evaluation, but it would be nice to > only evaluate once as it would often be used in hot paths like logging > and tracing. Using system resolver at runtime is basically not possible, because there is no non-blocking interface to system resolver, and using blocking one will will block the whole worker process during name resolution - which can take significant time. That's basically why nginx has resolver in it. The only option I see is doing name resolution only conditionally, either when requested by a configuration directive, or when the variable is actually used in the configuration. But I don't think this worth the effort - configuring appropriate hostname and/or using the name directly in nginx configuration would be a better idea. [...] > Linux in particular seems to have interpreted `gethostname` as > returning a DNS label (maximum of 63 characters) rather than a full > DNS name (up to 213 characters). > Thus it's impossible to represent certain DNS names as the system hostname. There is more than one Linux distribution, and Debian is just one of them. There are others which use FQDN: https://serverfault.com/questions/331936/setting-the-hostname-fqdn-or-short-name Note well that Debian can use FQDN as well, and "hostname -f" is smart enough to use such name without looking further. While length restrictions might make it impossible to represent some names, this is unlikely a practical problem. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Mon Nov 26 16:42:18 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Mon, 26 Nov 2018 16:42:18 +0000 Subject: [nginx] Negative size buffers detection. Message-ID: details: https://hg.nginx.org/nginx/rev/a7ff19afbb14 branches: changeset: 7401:a7ff19afbb14 user: Maxim Dounin date: Mon Nov 26 18:29:56 2018 +0300 description: Negative size buffers detection. In the past, there were several security issues which resulted in worker process memory disclosure due to buffers with negative size. It looks reasonable to check for such buffers in various places, much like we already check for zero size buffers. While here, removed "#if 1 / #endif" around zero size buffer checks. It looks highly unlikely that we'll disable these checks anytime soon. diffstat: src/core/ngx_output_chain.c | 64 +++++++++++++++++++++++++++- src/http/ngx_http_write_filter_module.c | 40 ++++++++++++++++- src/stream/ngx_stream_write_filter_module.c | 40 ++++++++++++++++- 3 files changed, 132 insertions(+), 12 deletions(-) diffs (244 lines): diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -126,6 +126,26 @@ ngx_output_chain(ngx_output_chain_ctx_t continue; } + if (bsize < 0) { + + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, + "negative size buf in output " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + ctx->in->buf->temporary, + ctx->in->buf->recycled, + ctx->in->buf->in_file, + ctx->in->buf->start, + ctx->in->buf->pos, + ctx->in->buf->last, + ctx->in->buf->file, + ctx->in->buf->file_pos, + ctx->in->buf->file_last); + + ngx_debug_point(); + + return NGX_ERROR; + } + if (ngx_output_chain_as_is(ctx, ctx->in->buf)) { /* move the chain link to the output chain */ @@ -665,7 +685,6 @@ ngx_chain_writer(void *data, ngx_chain_t for (size = 0; in; in = in->next) { -#if 1 if (ngx_buf_size(in->buf) == 0 && !ngx_buf_special(in->buf)) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, @@ -685,7 +704,26 @@ ngx_chain_writer(void *data, ngx_chain_t continue; } -#endif + + if (ngx_buf_size(in->buf) < 0) { + + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, + "negative size buf in chain writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + in->buf->temporary, + in->buf->recycled, + in->buf->in_file, + in->buf->start, + in->buf->pos, + in->buf->last, + in->buf->file, + in->buf->file_pos, + in->buf->file_last); + + ngx_debug_point(); + + return NGX_ERROR; + } size += ngx_buf_size(in->buf); @@ -709,7 +747,6 @@ ngx_chain_writer(void *data, ngx_chain_t for (cl = ctx->out; cl; cl = cl->next) { -#if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, @@ -729,7 +766,26 @@ ngx_chain_writer(void *data, ngx_chain_t continue; } -#endif + + if (ngx_buf_size(cl->buf) < 0) { + + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, + "negative size buf in chain writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + + return NGX_ERROR; + } size += ngx_buf_size(cl->buf); } diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -80,7 +80,6 @@ ngx_http_write_filter(ngx_http_request_t cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); -#if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in writer " @@ -98,7 +97,24 @@ ngx_http_write_filter(ngx_http_request_t ngx_debug_point(); return NGX_ERROR; } -#endif + + if (ngx_buf_size(cl->buf) < 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "negative size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } size += ngx_buf_size(cl->buf); @@ -136,7 +152,6 @@ ngx_http_write_filter(ngx_http_request_t cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); -#if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in writer " @@ -154,7 +169,24 @@ ngx_http_write_filter(ngx_http_request_t ngx_debug_point(); return NGX_ERROR; } -#endif + + if (ngx_buf_size(cl->buf) < 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "negative size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } size += ngx_buf_size(cl->buf); diff --git a/src/stream/ngx_stream_write_filter_module.c b/src/stream/ngx_stream_write_filter_module.c --- a/src/stream/ngx_stream_write_filter_module.c +++ b/src/stream/ngx_stream_write_filter_module.c @@ -104,7 +104,6 @@ ngx_stream_write_filter(ngx_stream_sessi cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); -#if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in writer " @@ -122,7 +121,24 @@ ngx_stream_write_filter(ngx_stream_sessi ngx_debug_point(); return NGX_ERROR; } -#endif + + if (ngx_buf_size(cl->buf) < 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "negative size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } size += ngx_buf_size(cl->buf); @@ -160,7 +176,6 @@ ngx_stream_write_filter(ngx_stream_sessi cl->buf->file_pos, cl->buf->file_last - cl->buf->file_pos); -#if 1 if (ngx_buf_size(cl->buf) == 0 && !ngx_buf_special(cl->buf)) { ngx_log_error(NGX_LOG_ALERT, c->log, 0, "zero size buf in writer " @@ -178,7 +193,24 @@ ngx_stream_write_filter(ngx_stream_sessi ngx_debug_point(); return NGX_ERROR; } -#endif + + if (ngx_buf_size(cl->buf) < 0) { + ngx_log_error(NGX_LOG_ALERT, c->log, 0, + "negative size buf in writer " + "t:%d r:%d f:%d %p %p-%p %p %O-%O", + cl->buf->temporary, + cl->buf->recycled, + cl->buf->in_file, + cl->buf->start, + cl->buf->pos, + cl->buf->last, + cl->buf->file, + cl->buf->file_pos, + cl->buf->file_last); + + ngx_debug_point(); + return NGX_ERROR; + } size += ngx_buf_size(cl->buf); From yongguang.bai at quantil.com Tue Nov 27 02:11:33 2018 From: yongguang.bai at quantil.com (Yongguang Bai) Date: Mon, 26 Nov 2018 18:11:33 -0800 Subject: [PATCH] Mail: nginx_error:cache file has too long header Message-ID: <4d48e1f3ebf6f0634e8e.1543284693@puppetagent> # HG changeset patch # User Yongguang Bai # Date 1543276278 28800 # Mon Nov 26 15:51:18 2018 -0800 # Node ID 4d48e1f3ebf6f0634e8e2cbd057d9fcfbea9d988 # Parent a7ff19afbb14795fef14f599a304d0ad21052b70 Mail: nginx_error:cache file has too long header This error is printed when cached file is expired and the response is changed in proxied server, and Nginx is under heavy load. diff -r a7ff19afbb14 -r 4d48e1f3ebf6 src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c Mon Nov 26 18:29:56 2018 +0300 +++ b/src/http/ngx_http_file_cache.c Mon Nov 26 15:51:18 2018 -0800 @@ -376,6 +376,10 @@ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http file cache fd: %d", of.fd); + if(c->uniq != of.uniq){ + c->body_start = ngx_pagesize; + } + c->file.fd = of.fd; c->file.log = r->connection->log; c->uniq = of.uniq; From kenhys at gmail.com Tue Nov 27 05:07:45 2018 From: kenhys at gmail.com (Kentaro Hayashi) Date: Tue, 27 Nov 2018 14:07:45 +0900 Subject: [PATCH] Win32: Don't discards const qualifiers for WriteFile Message-ID: Hi, It seems that there is a mismatch between ngx_write_fd and WriteFile prototype. I've attached a patch for it. # HG changeset patch # User hayashi at clear-code.com # Date 1543294459 -32400 # Tue Nov 27 13:54:19 2018 +0900 # Branch use-const-void-pointer # Node ID 04809b6012bd8a744e3beded6fc385cdb3f788ee # Parent a7ff19afbb14795fef14f599a304d0ad21052b70 Win32: Don't discards const qualifiers for WriteFile The 2nd argument of ngx_write_fd() is declared as void pointer instead of const void pointer. It means that void pointer is passed to WriteFile which accepts LPCVOID pointer, instead of LPVOID. Thus const qualifier isn't respected. ref. https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-writefile It causes a compile warning. diff -r a7ff19afbb14 -r 04809b6012bd src/os/win32/ngx_files.c --- a/src/os/win32/ngx_files.c Mon Nov 26 18:29:56 2018 +0300 +++ b/src/os/win32/ngx_files.c Tue Nov 27 13:54:19 2018 +0900 @@ -175,7 +175,7 @@ ssize_t -ngx_write_fd(ngx_fd_t fd, void *buf, size_t size) +ngx_write_fd(ngx_fd_t fd, const void *buf, size_t size) { u_long n; diff -r a7ff19afbb14 -r 04809b6012bd src/os/win32/ngx_files.h --- a/src/os/win32/ngx_files.h Mon Nov 26 18:29:56 2018 +0300 +++ b/src/os/win32/ngx_files.h Tue Nov 27 13:54:19 2018 +0900 @@ -107,7 +107,7 @@ #define ngx_read_fd_n "ReadFile()" -ssize_t ngx_write_fd(ngx_fd_t fd, void *buf, size_t size); +ssize_t ngx_write_fd(ngx_fd_t fd, const void *buf, size_t size); #define ngx_write_fd_n "WriteFile()" -- Kentaro Hayashi -------------- next part -------------- An HTML attachment was scrubbed... URL: From deepbluemistake at gmail.com Tue Nov 27 05:19:31 2018 From: deepbluemistake at gmail.com (Andras Farkas) Date: Tue, 27 Nov 2018 00:19:31 -0500 Subject: Patch to make 404 pages etc and autoindex pages use valid HTML Message-ID: Hello! The following two patches make it so that whenever nginx provides an autoindexed page or a special response page, the HTML page sent uses valid HTML. This means browsers will use a standards-compliant mode rather than quirks mode to render those pages. Thanks for reading! -------------- next part -------------- A non-text attachment was scrubbed... Name: ngx_http_special_responsec.diff Type: text/x-patch Size: 9799 bytes Desc: not available URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: ngx_http_autoindex_modulec.diff Type: text/x-patch Size: 390 bytes Desc: not available URL: From piotrsikora at google.com Tue Nov 27 10:34:10 2018 From: piotrsikora at google.com (Piotr Sikora) Date: Tue, 27 Nov 2018 02:34:10 -0800 Subject: [PATCH] Upstream: added $upstream_bytes_sent variable Message-ID: # HG changeset patch # User Piotr Sikora # Date 1494129075 25200 # Sat May 06 20:51:15 2017 -0700 # Node ID fafbb3ee41e5bb03bcfba73f7d4367b8ab7d36cc # Parent be5cb9c67c05ccaf22dab7abba78aa4c1545a8ee Upstream: added $upstream_bytes_sent variable. Signed-off-by: Piotr Sikora diff -r be5cb9c67c05 -r fafbb3ee41e5 src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -162,8 +162,8 @@ static ngx_int_t ngx_http_upstream_statu ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); -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_bytes_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_upstream_trailer_variable(ngx_http_request_t *r, @@ -402,11 +402,15 @@ static ngx_http_variable_t ngx_http_ups NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("upstream_response_length"), NULL, - ngx_http_upstream_response_length_variable, 0, + ngx_http_upstream_bytes_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("upstream_bytes_received"), NULL, - ngx_http_upstream_response_length_variable, 1, + ngx_http_upstream_bytes_variable, 1, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("upstream_bytes_sent"), NULL, + ngx_http_upstream_bytes_variable, 2, NGX_HTTP_VAR_NOCACHEABLE, 0 }, #if (NGX_HTTP_CACHE) @@ -4134,6 +4138,10 @@ ngx_http_upstream_next(ngx_http_request_ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http next upstream, %xi", ft_type); + if (u->state && u->state->bytes_sent == 0 && u->peer.connection) { + u->state->bytes_sent = u->peer.connection->sent; + } + if (u->peer.sockaddr) { if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403 @@ -4319,6 +4327,10 @@ ngx_http_upstream_finalize_request(ngx_h - u->pipe->preread_size; u->state->response_length = u->pipe->read_length; } + + if (u->state->bytes_sent == 0 && u->peer.connection) { + u->state->bytes_sent = u->peer.connection->sent; + } } u->finalize_request(r, rc); @@ -5468,7 +5480,7 @@ ngx_http_upstream_response_time_variable static ngx_int_t -ngx_http_upstream_response_length_variable(ngx_http_request_t *r, +ngx_http_upstream_bytes_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { u_char *p; @@ -5499,7 +5511,10 @@ ngx_http_upstream_response_length_variab for ( ;; ) { - if (data == 1) { + if (data == 2) { + p = ngx_sprintf(p, "%O", state[i].bytes_sent); + + } else if (data == 1) { p = ngx_sprintf(p, "%O", state[i].bytes_received); } else { diff -r be5cb9c67c05 -r fafbb3ee41e5 src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -64,6 +64,7 @@ typedef struct { ngx_msec_t queue_time; off_t response_length; off_t bytes_received; + off_t bytes_sent; ngx_str_t *peer; } ngx_http_upstream_state_t; From piotrsikora at google.com Tue Nov 27 10:34:16 2018 From: piotrsikora at google.com (Piotr Sikora) Date: Tue, 27 Nov 2018 02:34:16 -0800 Subject: [PATCH] HTTP/2: fixed handling of fully preread request bodies Message-ID: <466c154c5c53b9566602.1543314856@piotrsikora.c.googlers.com> # HG changeset patch # User Piotr Sikora # Date 1540435636 25200 # Wed Oct 24 19:47:16 2018 -0700 # Node ID 466c154c5c53b956660211df96331b3c25669485 # Parent be5cb9c67c05ccaf22dab7abba78aa4c1545a8ee HTTP/2: fixed handling of fully preread request bodies. Previously, fully preread request body of a request without the "Content-Length" header was always written to a temporary file. Reported by Wayne Zhang. Signed-off-by: Piotr Sikora diff -r be5cb9c67c05 -r 466c154c5c53 src/http/v2/ngx_http_v2.c --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -3863,6 +3863,12 @@ ngx_http_v2_read_request_body(ngx_http_r { rb->buf = ngx_create_temp_buf(r->pool, (size_t) len); + } else if (len < 0 && stream->in_closed && stream->preread + && !r->request_body_in_file_only) + { + rb->buf = ngx_create_temp_buf(r->pool, + (size_t) ngx_buf_size(stream->preread)); + } else { rb->buf = ngx_calloc_buf(r->pool); From xeioex at nginx.com Tue Nov 27 12:20:19 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 27 Nov 2018 12:20:19 +0000 Subject: [njs] Version 0.2.6. Message-ID: details: https://hg.nginx.org/njs/rev/0709b8b4f11e branches: changeset: 671:0709b8b4f11e user: Dmitry Volyntsev date: Tue Nov 27 15:18:45 2018 +0300 description: Version 0.2.6. diffstat: CHANGES | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 42 insertions(+), 0 deletions(-) diffs (49 lines): diff -r fa98656237f0 -r 0709b8b4f11e CHANGES --- a/CHANGES Fri Nov 23 17:46:30 2018 +0300 +++ b/CHANGES Tue Nov 27 15:18:45 2018 +0300 @@ -1,3 +1,45 @@ + +Changes with njs 0.2.6 27 Nov 2018 + + Core: + + *) Feature: making built-in prototypes mutable. + + *) Feature: making global object mutable. + + *) Feature: console.time() and console.timeEnd() methods. + + *) Feature: allowing variables and functions to be redeclared. + + *) Feature: extending Object.defineProperty() spec conformance. + + *) Feature: introduced quiet mode for CLI to handle simple expressions + from stdin. + + *) Feature: introduced compact form of backtraces to handle stack + overflows. + + *) Improvement: improved wording for various exceptions. + + *) Bugfix: fixed closure values handling. + + *) Bugfix: fixed equality operator for various value types. + + *) Bugfix: fixed handling of "this" keyword in various scopes. + + *) Bugfix: fixed handling non-object values in Object.keys(). + + *) Bugfix: fixed parsing of throw statement inside if statement. + + *) Bugfix: fixed parsing of newline after throw statement. + + *) Bugfix: fixed parsing of statements in if statement without newline. + + *) Bugfix: fixed size uint32_t overflow in njs_array_expand(). + + *) Bugfix: fixed typeof operator for object_value type. + + *) Bugfix: miscellaneous additional bugs have been fixed. Changes with njs 0.2.5 30 Oct 2018 From xeioex at nginx.com Tue Nov 27 12:20:19 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 27 Nov 2018 12:20:19 +0000 Subject: [njs] Added tag 0.2.6 for changeset 0709b8b4f11e Message-ID: details: https://hg.nginx.org/njs/rev/b3d92bc35b97 branches: changeset: 672:b3d92bc35b97 user: Dmitry Volyntsev date: Tue Nov 27 15:20:11 2018 +0300 description: Added tag 0.2.6 for changeset 0709b8b4f11e diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff -r 0709b8b4f11e -r b3d92bc35b97 .hgtags --- a/.hgtags Tue Nov 27 15:18:45 2018 +0300 +++ b/.hgtags Tue Nov 27 15:20:11 2018 +0300 @@ -20,3 +20,4 @@ 4adbb035caa39dae58611a061d78bc974652231e e83f41520613987542472275d49633a9aa5955d1 0.2.3 3e6c38f64bdbc53e783813541559034ed6890aee 0.2.4 3315f6aa6000ce6d2dbc74c73660becf4178a549 0.2.5 +0709b8b4f11ebec95dd4f72d5bb38044682f77e6 0.2.6 From mdounin at mdounin.ru Tue Nov 27 13:27:06 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 27 Nov 2018 16:27:06 +0300 Subject: [PATCH] Win32: Don't discards const qualifiers for WriteFile In-Reply-To: References: Message-ID: <20181127132705.GN99070@mdounin.ru> Hello! On Tue, Nov 27, 2018 at 02:07:45PM +0900, Kentaro Hayashi wrote: > Hi, > It seems that there is a mismatch between ngx_write_fd and WriteFile > prototype. > I've attached a patch for it. > > # HG changeset patch > # User hayashi at clear-code.com > # Date 1543294459 -32400 > # Tue Nov 27 13:54:19 2018 +0900 > # Branch use-const-void-pointer > # Node ID 04809b6012bd8a744e3beded6fc385cdb3f788ee > # Parent a7ff19afbb14795fef14f599a304d0ad21052b70 > Win32: Don't discards const qualifiers for WriteFile > > The 2nd argument of ngx_write_fd() is declared as > void pointer instead of const void pointer. > It means that void pointer is passed to WriteFile which accepts > LPCVOID pointer, instead of LPVOID. Thus const qualifier isn't respected. > > ref. > https://docs.microsoft.com/en-us/windows/desktop/api/fileapi/nf-fileapi-writefile > > It causes a compile warning. Could you please elaborate a bit more about the compile warning? Which compiler you use, how the warning looks like? The const qualifier is only important when it's removed from a variable - that is, when you pass something declared as "const" into a function with non-const argument. That is, when you pass a constant variable into a function which does not promise to handle it as a constant variable. The opposite is perfectly fine, so you can safely pass a non-constant variable into a function which promises not to change the variable. From this point of view there are no problems in ngx_write_fd(), it simply passes a non-constant string to a function which promises not to change this string. [...] -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Tue Nov 27 14:50:25 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 27 Nov 2018 14:50:25 +0000 Subject: [nginx] Updated OpenSSL used for win32 builds. Message-ID: details: https://hg.nginx.org/nginx/rev/aeb2d11c2731 branches: changeset: 7402:aeb2d11c2731 user: Maxim Dounin date: Tue Nov 27 17:02:56 2018 +0300 description: Updated OpenSSL used for win32 builds. diffstat: misc/GNUmakefile | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff --git a/misc/GNUmakefile b/misc/GNUmakefile --- a/misc/GNUmakefile +++ b/misc/GNUmakefile @@ -6,7 +6,7 @@ TEMP = tmp CC = cl OBJS = objs.msvc8 -OPENSSL = openssl-1.0.2p +OPENSSL = openssl-1.0.2q ZLIB = zlib-1.2.11 PCRE = pcre-8.42 From mdounin at mdounin.ru Tue Nov 27 14:50:26 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 27 Nov 2018 14:50:26 +0000 Subject: [nginx] nginx-1.15.7-RELEASE Message-ID: details: https://hg.nginx.org/nginx/rev/051a039ce1c7 branches: changeset: 7403:051a039ce1c7 user: Maxim Dounin date: Tue Nov 27 17:40:20 2018 +0300 description: nginx-1.15.7-RELEASE diffstat: docs/xml/nginx/changes.xml | 56 ++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 56 insertions(+), 0 deletions(-) diffs (66 lines): diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -5,6 +5,62 @@ + + + + +????????? proxy_requests ? ?????? stream. + + +the "proxy_requests" directive in the stream module. + + + + + +???????? "delay" ????????? "limit_req".
+??????? ?????????? ???????? ? ????? ???????. +
+ +the "delay" parameter of the "limit_req" directive.
+Thanks to Vladislav Shabanov and Peter Shchuchkin. +
+
+ + + +?????? ?????? ? ?????? ?????? ??? ????????????????. + + +memory leak on errors during reconfiguration. + + + + + +? ?????????? $upstream_response_time, $upstream_connect_time ? +$upstream_header_time. + + +in the $upstream_response_time, $upstream_connect_time, and +$upstream_header_time variables. + + + + + +? ??????? ???????? ??? ????????? segmentation fault, +???? ????????????? ?????? ngx_http_mp4_module ?? 32-?????? ??????????. + + +a segmentation fault might occur in a worker process +if the ngx_http_mp4_module was used on 32-bit platforms. + + + +
+ + From mdounin at mdounin.ru Tue Nov 27 14:50:28 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Tue, 27 Nov 2018 14:50:28 +0000 Subject: [nginx] release-1.15.7 tag Message-ID: details: https://hg.nginx.org/nginx/rev/2117637f64e9 branches: changeset: 7404:2117637f64e9 user: Maxim Dounin date: Tue Nov 27 17:40:21 2018 +0300 description: release-1.15.7 tag diffstat: .hgtags | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diffs (8 lines): diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -432,3 +432,4 @@ 28b3e17ca7eba1e6a0891afde0e4bc5bcc99c861 49d49835653857daa418e68d6cbfed4958c78fca release-1.15.4 f062e43d74fc2578bb100a9e82a953efa1eb9e4e release-1.15.5 2351853ce6867b6166823bdf94333c0a76633c0a release-1.15.6 +051a039ce1c7e09144de4a4846669ec7116cecea release-1.15.7 From xeioex at nginx.com Tue Nov 27 16:28:01 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 27 Nov 2018 16:28:01 +0000 Subject: [njs] Version bump. Message-ID: details: https://hg.nginx.org/njs/rev/b529a8b72e3b branches: changeset: 673:b529a8b72e3b user: Dmitry Volyntsev date: Tue Nov 27 18:58:26 2018 +0300 description: Version bump. diffstat: njs/njs.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r b3d92bc35b97 -r b529a8b72e3b njs/njs.h --- a/njs/njs.h Tue Nov 27 15:20:11 2018 +0300 +++ b/njs/njs.h Tue Nov 27 18:58:26 2018 +0300 @@ -11,7 +11,7 @@ #include -#define NJS_VERSION "0.2.6" +#define NJS_VERSION "0.2.7" #include From xeioex at nginx.com Tue Nov 27 16:28:02 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Tue, 27 Nov 2018 16:28:02 +0000 Subject: [njs] Fixed automatic semicolon insertion. Message-ID: details: https://hg.nginx.org/njs/rev/4e62b7a295e0 branches: changeset: 674:4e62b7a295e0 user: Dmitry Volyntsev date: Tue Nov 27 18:58:30 2018 +0300 description: Fixed automatic semicolon insertion. diffstat: njs/njs_lexer.c | 8 +++++ njs/njs_parser.c | 23 +++----------- njs/njs_parser.h | 6 +-- njs/njs_parser_expression.c | 63 ++++------------------------------------- njs/test/njs_unit_test.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 78 deletions(-) diffs (351 lines): diff -r b529a8b72e3b -r 4e62b7a295e0 njs/njs_lexer.c --- a/njs/njs_lexer.c Tue Nov 27 18:58:26 2018 +0300 +++ b/njs/njs_lexer.c Tue Nov 27 18:58:30 2018 +0300 @@ -277,6 +277,7 @@ njs_lexer_token(njs_lexer_t *lexer) { njs_token_t token; + lexer->prev_start = lexer->start; lexer->prev_token = lexer->token; token = njs_lexer_next_token(lexer); @@ -287,6 +288,13 @@ njs_lexer_token(njs_lexer_t *lexer) } +void +njs_lexer_rollback(njs_lexer_t *lexer) +{ + lexer->start = lexer->prev_start; +} + + static njs_token_t njs_lexer_next_token(njs_lexer_t *lexer) { diff -r b529a8b72e3b -r 4e62b7a295e0 njs/njs_parser.c --- a/njs/njs_parser.c Tue Nov 27 18:58:26 2018 +0300 +++ b/njs/njs_parser.c Tue Nov 27 18:58:30 2018 +0300 @@ -10,17 +10,6 @@ #include -/* - * The LL(2) parser. The two lookahead tokens are required because - * JavaScript inserts automatically semicolon at the end of line in - * a = 1 - * b = 2 - * whilst - * a = 1 - * + b - * is treated as a single expiression. - */ - static njs_ret_t njs_parser_scope_begin(njs_vm_t *vm, njs_parser_t *parser, njs_scope_t type); static void njs_parser_scope_end(njs_vm_t *vm, njs_parser_t *parser); @@ -282,9 +271,7 @@ njs_parser_statement_chain(njs_vm_t *vm, node->right = parser->node; parser->node = node; - while (token == NJS_TOKEN_SEMICOLON - || token == NJS_TOKEN_LINE_END) - { + while (token == NJS_TOKEN_SEMICOLON) { token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { break; @@ -1811,7 +1798,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa if (token == NJS_TOKEN_OPEN_PARENTHESIS) { - token = njs_lexer_token(parser->lexer); + token = njs_parser_token(parser); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } @@ -2109,7 +2096,7 @@ njs_parser_terminal(njs_vm_t *vm, njs_pa parser->node = node; - return njs_lexer_token(parser->lexer); + return njs_parser_token(parser); } @@ -2142,7 +2129,7 @@ njs_parser_builtin_object(njs_vm_t *vm, parser->node = node; parser->code_size += sizeof(njs_vmcode_object_copy_t); - return njs_lexer_token(parser->lexer); + return njs_parser_token(parser); } @@ -2175,7 +2162,7 @@ njs_parser_builtin_function(njs_vm_t *vm parser->node = node; parser->code_size += sizeof(njs_vmcode_object_copy_t); - return njs_lexer_token(parser->lexer); + return njs_parser_token(parser); } diff -r b529a8b72e3b -r 4e62b7a295e0 njs/njs_parser.h --- a/njs/njs_parser.h Tue Nov 27 18:58:26 2018 +0300 +++ b/njs/njs_parser.h Tue Nov 27 18:58:30 2018 +0300 @@ -31,8 +31,6 @@ typedef enum { NJS_TOKEN_DOT, NJS_TOKEN_SEMICOLON, -#define NJS_TOKEN_FIRST_OPERATOR NJS_TOKEN_COLON - NJS_TOKEN_COLON, NJS_TOKEN_CONDITIONAL, @@ -103,8 +101,6 @@ typedef enum { NJS_TOKEN_DELETE, NJS_TOKEN_YIELD, -#define NJS_TOKEN_LAST_OPERATOR NJS_TOKEN_YIELD - NJS_TOKEN_DIGIT, NJS_TOKEN_LETTER, @@ -223,6 +219,7 @@ typedef struct { nxt_lvlhsh_t keywords_hash; u_char *start; + u_char *prev_start; u_char *end; } njs_lexer_t; @@ -360,6 +357,7 @@ typedef struct { njs_token_t njs_lexer_token(njs_lexer_t *lexer); +void njs_lexer_rollback(njs_lexer_t *lexer); nxt_int_t njs_lexer_keywords_init(nxt_mem_cache_pool_t *mcp, nxt_lvlhsh_t *hash); njs_token_t njs_lexer_keyword(njs_lexer_t *lexer); diff -r b529a8b72e3b -r 4e62b7a295e0 njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Tue Nov 27 18:58:26 2018 +0300 +++ b/njs/njs_parser_expression.c Tue Nov 27 18:58:30 2018 +0300 @@ -230,14 +230,6 @@ njs_parser_expression(njs_vm_t *vm, njs_ } -nxt_inline nxt_bool_t -njs_parser_expression_operator(njs_token_t token) -{ - return (token >= NJS_TOKEN_FIRST_OPERATOR - && token <= NJS_TOKEN_LAST_OPERATOR); -} - - njs_token_t njs_parser_var_expression(njs_vm_t *vm, njs_parser_t *parser, njs_token_t token) { @@ -259,18 +251,6 @@ njs_parser_var_expression(njs_vm_t *vm, size = sizeof(njs_vmcode_move_t); break; - case NJS_TOKEN_LINE_END: - token = njs_lexer_token(parser->lexer); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (njs_parser_expression_operator(token)) { - continue; - } - - /* Fall through. */ - default: return token; } @@ -397,18 +377,6 @@ njs_parser_assignment_expression(njs_vm_ operation = njs_vmcode_bitwise_or; break; - case NJS_TOKEN_LINE_END: - token = njs_lexer_token(parser->lexer); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (njs_parser_expression_operator(token)) { - continue; - } - - /* Fall through. */ - default: return token; } @@ -588,18 +556,6 @@ njs_parser_binary_expression(njs_vm_t *v } while (n != 0); - if (token == NJS_TOKEN_LINE_END) { - - token = njs_lexer_token(parser->lexer); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (njs_parser_expression_operator(token)) { - continue; - } - } - return token; found: @@ -676,18 +632,6 @@ njs_parser_exponential_expression(njs_vm parser->node = node; } - if (token == NJS_TOKEN_LINE_END) { - - token = njs_lexer_token(parser->lexer); - if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { - return token; - } - - if (njs_parser_expression_operator(token)) { - continue; - } - } - return token; } } @@ -902,6 +846,13 @@ njs_parser_post_inc_dec_expression(njs_v return token; } + /* Automatic semicolon insertion. */ + + if (parser->lexer->prev_token == NJS_TOKEN_LINE_END) { + njs_lexer_rollback(parser->lexer); + return NJS_TOKEN_SEMICOLON; + } + if (!njs_parser_is_lvalue(parser->node)) { njs_parser_ref_error(vm, parser, "Invalid left-hand side in postfix operation"); diff -r b529a8b72e3b -r 4e62b7a295e0 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Nov 27 18:58:26 2018 +0300 +++ b/njs/test/njs_unit_test.c Tue Nov 27 18:58:30 2018 +0300 @@ -2046,6 +2046,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("a = 0; a \n ++"), nxt_string("SyntaxError: Unexpected end of input in 2") }, + { nxt_string("a = 0; a \n --"), + nxt_string("SyntaxError: Unexpected end of input in 2") }, + + { nxt_string("var a = 0; a \n + 1"), + nxt_string("1") }, + + { nxt_string("var a = 0; a \n +\n 1"), + nxt_string("1") }, + { nxt_string("var a; a = 1 ? 2 \n : 3"), nxt_string("2") }, @@ -2119,6 +2128,11 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a \n if (!a) a = 3; a"), nxt_string("3") }, + /* automatic semicolon insertion. */ + + { nxt_string("var x = 0, y = 2; x\n--\ny; [x,y]"), + nxt_string("0,1") }, + /* if. */ { nxt_string("if (0);"), @@ -2193,6 +2207,21 @@ static njs_unit_test_t njs_test[] = { nxt_string("(function(){ for (var p in [1] ){ if (1) continue; else return 0; }})()"), nxt_string("undefined") }, + { nxt_string("(function(x){ if\n(x) return -1; else return 0; })(0)"), + nxt_string("0") }, + + { nxt_string("(function(x){ if\n(\nx) return -1; else return 0; })(0)"), + nxt_string("0") }, + + { nxt_string("(function(x){ if\n(\nx)\nreturn -1; else return 0; })(0)"), + nxt_string("0") }, + + { nxt_string("(function(x){ if\n(\nx)\nreturn -1\n else return 0; })(0)"), + nxt_string("0") }, + + { nxt_string("(function(x){ if\n(\nx)\nreturn -1\n else\nreturn 0; })(0)"), + nxt_string("0") }, + /* do while. */ { nxt_string("do { break } if (false)"), @@ -2957,6 +2986,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = [1,2]; a.length"), nxt_string("2") }, + { nxt_string("[\n1]"), + nxt_string("1") }, + + { nxt_string("\n[\n1\n]"), + nxt_string("1") }, + + { nxt_string("\n[\n1\n,\n2]\n[\n0]"), + nxt_string("1") }, + #if 0 { nxt_string("Object.create([1,2]).length"), nxt_string("2") }, @@ -3808,6 +3846,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("'a'.my"), nxt_string("undefined") }, + { nxt_string("var a = '123'\n[2].toString();a"), + nxt_string("3") }, + /* Escape strings. */ { nxt_string("'\\a \\' \\\" \\\\ \\0 \\b \\f \\n \\r \\t \\v'"), @@ -5318,6 +5359,33 @@ static njs_unit_test_t njs_test[] = "eval"), nxt_string("X") }, + { nxt_string("var o = {f:function(x){ return x**2}}; o.f\n(2)"), + nxt_string("4") }, + + { nxt_string("var o = {f:function(x){ return x**2}}; o\n.f\n(2)"), + nxt_string("4") }, + + { nxt_string("var o = {f:function(x){ return x**2}}; o\n.\nf\n(2)"), + nxt_string("4") }, + + { nxt_string("function f(x){ return x**2}; [f(2)\n, f\n(2),\nf\n(\n2),\nf\n(\n2\n)]"), + nxt_string("4,4,4,4") }, + + { nxt_string("function f (x){ return x**2}; f\n(2)"), + nxt_string("4") }, + + { nxt_string("function f (x){ return x**2}; f\n(\n2)"), + nxt_string("4") }, + + { nxt_string("function f (x){ return x**2}; f\n(\n2\n)"), + nxt_string("4") }, + + { nxt_string("function f (x){ return x**2}; f\n(2\n)"), + nxt_string("4") }, + + { nxt_string("function f (x){ return x**2}; f(2\n)"), + nxt_string("4") }, + /* Recursive factorial. */ { nxt_string("function f(a) {" From mdounin at mdounin.ru Wed Nov 28 12:45:43 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 28 Nov 2018 15:45:43 +0300 Subject: [PATCH] Mail: nginx_error:cache file has too long header In-Reply-To: <4d48e1f3ebf6f0634e8e.1543284693@puppetagent> References: <4d48e1f3ebf6f0634e8e.1543284693@puppetagent> Message-ID: <20181128124543.GX99070@mdounin.ru> Hello! On Mon, Nov 26, 2018 at 06:11:33PM -0800, Yongguang Bai wrote: > # HG changeset patch > # User Yongguang Bai > # Date 1543276278 28800 > # Mon Nov 26 15:51:18 2018 -0800 > # Node ID 4d48e1f3ebf6f0634e8e2cbd057d9fcfbea9d988 > # Parent a7ff19afbb14795fef14f599a304d0ad21052b70 > Mail: nginx_error:cache file has too long header > > This error is printed when cached file is expired and the > response is changed in proxied server, and Nginx is under > heavy load. > > diff -r a7ff19afbb14 -r 4d48e1f3ebf6 src/http/ngx_http_file_cache.c > --- a/src/http/ngx_http_file_cache.c Mon Nov 26 18:29:56 2018 +0300 > +++ b/src/http/ngx_http_file_cache.c Mon Nov 26 15:51:18 2018 -0800 > @@ -376,6 +376,10 @@ > ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, > "http file cache fd: %d", of.fd); > > + if(c->uniq != of.uniq){ > + c->body_start = ngx_pagesize; > + } > + > c->file.fd = of.fd; > c->file.log = r->connection->log; > c->uniq = of.uniq; This change looks wrong. In particular, ngx_pagesize, which is usually 4k, can be smaller than existing c->body_start, and this change will make things worse instead of fixing anything. Also, could you please elaborate what exactly you are trying to fix? There is a known race which may lead to "cache file has too long header" error - and, actually the error was added to ensure that this race is properly handled if happens, see here: http://hg.nginx.org/nginx/rev/6f97afc238de http://mailman.nginx.org/pipermail/nginx-devel/2011-September/001287.html Note that this race can only result in problems if for some reason the backend returns responses with different headers nearly at the same time. This may indicate that there is something wrong with the backend. Also, there is a known bug with multiple variants which also can lead to the same error. The patch can be found here: http://mailman.nginx.org/pipermail/nginx-devel/2018-January/010774.html If you are hitting this bug, please test if the patch works for you. -- Maxim Dounin http://mdounin.ru/ From xeioex at nginx.com Wed Nov 28 13:44:41 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Wed, 28 Nov 2018 13:44:41 +0000 Subject: [njs] Fixed assignment expression from compound assignment. Message-ID: details: https://hg.nginx.org/njs/rev/da67f08d365e branches: changeset: 675:da67f08d365e user: Dmitry Volyntsev date: Wed Nov 28 15:47:05 2018 +0300 description: Fixed assignment expression from compound assignment. diffstat: njs/njs_parser_expression.c | 2 +- njs/test/njs_unit_test.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletions(-) diffs (31 lines): diff -r 4e62b7a295e0 -r da67f08d365e njs/njs_parser_expression.c --- a/njs/njs_parser_expression.c Tue Nov 27 18:58:30 2018 +0300 +++ b/njs/njs_parser_expression.c Wed Nov 28 15:47:05 2018 +0300 @@ -237,7 +237,7 @@ njs_parser_var_expression(njs_vm_t *vm, njs_parser_node_t *node; njs_vmcode_operation_t operation; - token = njs_parser_conditional_expression(vm, parser, token); + token = njs_parser_assignment_expression(vm, parser, token); if (nxt_slow_path(token <= NJS_TOKEN_ILLEGAL)) { return token; } diff -r 4e62b7a295e0 -r da67f08d365e njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Tue Nov 27 18:58:30 2018 +0300 +++ b/njs/test/njs_unit_test.c Wed Nov 28 15:47:05 2018 +0300 @@ -597,6 +597,15 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a, b = (a = [2]) * (3 * 4); a +' '+ b"), nxt_string("2 24") }, + { nxt_string("var a = 1; var b = a += 1; b"), + nxt_string("2") }, + + { nxt_string("var a = 1; var b = a -= 1; b"), + nxt_string("0") }, + + { nxt_string("var a = 1; var b = a <<= 1; b"), + nxt_string("2") }, + /* 3 address operation and side effect. */ { nxt_string("var a = 1; function f(x) { a = x; return 2 }; a+f(5)+' '+a"), From greearb at candelatech.com Wed Nov 28 14:31:59 2018 From: greearb at candelatech.com (Ben Greear) Date: Wed, 28 Nov 2018 06:31:59 -0800 Subject: nginx fails to build on F29 Message-ID: <0fd4306a-f48a-7de7-12ac-2127723ab06f@candelatech.com> I just pulled the latest from github, and it fails to compile. Any ideas? bjs/src/http/modules/ngx_http_upstream_keepalive_module.o \ objs/src/http/modules/ngx_http_upstream_zone_module.o \ objs/ngx_modules.o \ -ldl -lpthread -lcrypt -lssl -lcrypto -ldl -lz \ -Wl,-E /usr/bin/ld: objs/src/core/ngx_connection.o: in function `ngx_create_listening': /home/greearb/btbits/x64_btbits/3plibs/nginx/src/core/ngx_connection.c:76: undefined reference to `ngx_udp_rbtree_insert_value' /usr/bin/ld: objs/src/event/ngx_event.o: in function `ngx_event_process_init': /home/greearb/btbits/x64_btbits/3plibs/nginx/src/event/ngx_event.c:862: undefined reference to `ngx_event_recvmsg' collect2: error: ld returned 1 exit status make[2]: *** [objs/Makefile:228: objs/nginx] Error 1 Thanks, Ben -- Ben Greear Candela Technologies Inc http://www.candelatech.com From greearb at candelatech.com Wed Nov 28 14:43:32 2018 From: greearb at candelatech.com (Ben Greear) Date: Wed, 28 Nov 2018 06:43:32 -0800 Subject: nginx fails to build on F29 In-Reply-To: <0fd4306a-f48a-7de7-12ac-2127723ab06f@candelatech.com> References: <0fd4306a-f48a-7de7-12ac-2127723ab06f@candelatech.com> Message-ID: <44e4d7ac-6bbc-e32a-d55e-6f5449cffdb3@candelatech.com> Err, nevermind...just needed to do a full rebuild. Thanks, Ben On 11/28/2018 06:31 AM, Ben Greear wrote: > I just pulled the latest from github, and it fails to compile. > > Any ideas? > > bjs/src/http/modules/ngx_http_upstream_keepalive_module.o \ > objs/src/http/modules/ngx_http_upstream_zone_module.o \ > objs/ngx_modules.o \ > -ldl -lpthread -lcrypt -lssl -lcrypto -ldl -lz \ > -Wl,-E > /usr/bin/ld: objs/src/core/ngx_connection.o: in function `ngx_create_listening': > /home/greearb/btbits/x64_btbits/3plibs/nginx/src/core/ngx_connection.c:76: undefined reference to `ngx_udp_rbtree_insert_value' > /usr/bin/ld: objs/src/event/ngx_event.o: in function `ngx_event_process_init': > /home/greearb/btbits/x64_btbits/3plibs/nginx/src/event/ngx_event.c:862: undefined reference to `ngx_event_recvmsg' > collect2: error: ld returned 1 exit status > make[2]: *** [objs/Makefile:228: objs/nginx] Error 1 > > Thanks, > Ben > -- Ben Greear Candela Technologies Inc http://www.candelatech.com From mdounin at mdounin.ru Wed Nov 28 16:31:08 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Wed, 28 Nov 2018 19:31:08 +0300 Subject: Patch to make 404 pages etc and autoindex pages use valid HTML In-Reply-To: References: Message-ID: <20181128163108.GB99070@mdounin.ru> Hello! On Tue, Nov 27, 2018 at 12:19:31AM -0500, Andras Farkas wrote: > Hello! > The following two patches make it so that whenever nginx provides an > autoindexed page or a special response page, the HTML page sent uses > valid HTML. > This means browsers will use a standards-compliant mode rather than > quirks mode to render those pages. > Thanks for reading! Thank you for your patch. Such a change will significantly modify typical rendering of error pages, so I would rather refrain from it unless there are more practical reasons than triggering standards-complaint mode instead of quirks mode - which does no seem to make any difference for pages nginx generates. -- Maxim Dounin http://mdounin.ru/ From mdounin at mdounin.ru Thu Nov 29 15:00:51 2018 From: mdounin at mdounin.ru (Maxim Dounin) Date: Thu, 29 Nov 2018 18:00:51 +0300 Subject: [PATCH] Upstream: added $upstream_bytes_sent variable In-Reply-To: References: Message-ID: <20181129150051.GK99070@mdounin.ru> Hello! On Tue, Nov 27, 2018 at 02:34:10AM -0800, Piotr Sikora via nginx-devel wrote: > # HG changeset patch > # User Piotr Sikora > # Date 1494129075 25200 > # Sat May 06 20:51:15 2017 -0700 > # Node ID fafbb3ee41e5bb03bcfba73f7d4367b8ab7d36cc > # Parent be5cb9c67c05ccaf22dab7abba78aa4c1545a8ee > Upstream: added $upstream_bytes_sent variable. [...] Ruslan made a similar patch a while ago. It wasn't committed since there were questions if such a variable is actually needed - I think we are aware of at most one feature request for this: http://mailman.nginx.org/pipermail/nginx/2018-March/055940.html I've asked Ruslan to post his version of the patch (or, rather, a patch series), please review. -- Maxim Dounin http://mdounin.ru/ From Neil.Craig at bbc.co.uk Thu Nov 29 15:09:11 2018 From: Neil.Craig at bbc.co.uk (Neil Craig) Date: Thu, 29 Nov 2018 15:09:11 +0000 Subject: [PATCH] Upstream: added $upstream_bytes_sent variable In-Reply-To: <20181129150051.GK99070@mdounin.ru> References: <20181129150051.GK99070@mdounin.ru> Message-ID: ?Hello FWIW, I?d appreciate a $upstream_bytes_sent var in ngx. Cheers Neil Craig Lead Technical Architect | Online Technology Group Broadcast Centre, London W12 7TQ | BC4 A3 Twitter: https://twitter.com/tdp_org On 29/11/2018, 15:00, "nginx-devel on behalf of Maxim Dounin" wrote: >Hello! > >On Tue, Nov 27, 2018 at 02:34:10AM -0800, Piotr Sikora via nginx-devel >wrote: > >> # HG changeset patch >> # User Piotr Sikora >> # Date 1494129075 25200 >> # Sat May 06 20:51:15 2017 -0700 >> # Node ID fafbb3ee41e5bb03bcfba73f7d4367b8ab7d36cc >> # Parent be5cb9c67c05ccaf22dab7abba78aa4c1545a8ee >> Upstream: added $upstream_bytes_sent variable. > >[...] > >Ruslan made a similar patch a while ago. It wasn't committed >since there were questions if such a variable is actually needed - >I think we are aware of at most one feature request for this: > >http://mailman.nginx.org/pipermail/nginx/2018-March/055940.html > >I've asked Ruslan to post his version of the patch (or, rather, a >patch series), please review. > >-- >Maxim Dounin >http://mdounin.ru/ >_______________________________________________ >nginx-devel mailing list >nginx-devel at nginx.org >http://mailman.nginx.org/mailman/listinfo/nginx-devel ----------------------------- http://www.bbc.co.uk This e-mail (and any attachments) is confidential and may contain personal views which are not the views of the BBC unless specifically stated. If you have received it in error, please delete it from your system. Do not use, copy or disclose the information in any way nor act in reliance on it and notify the sender immediately. Please note that the BBC monitors e-mails sent or received. Further communication will signify your consent to this. ----------------------------- From xeioex at nginx.com Thu Nov 29 15:16:43 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 29 Nov 2018 15:16:43 +0000 Subject: [njs] Fixed conversion of NAN and INF to uint32_t on some platforms. Message-ID: details: https://hg.nginx.org/njs/rev/cf424d6313ae branches: changeset: 676:cf424d6313ae user: Dmitry Volyntsev date: Thu Nov 29 18:14:12 2018 +0300 description: Fixed conversion of NAN and INF to uint32_t on some platforms. diffstat: njs/njs_builtin.c | 2 +- njs/njs_number.c | 11 +++++++++++ nxt/auto/clang | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletions(-) diffs (57 lines): diff -r da67f08d365e -r cf424d6313ae njs/njs_builtin.c --- a/njs/njs_builtin.c Wed Nov 28 15:47:05 2018 +0300 +++ b/njs/njs_builtin.c Thu Nov 29 18:14:12 2018 +0300 @@ -1085,7 +1085,7 @@ njs_dump_value(njs_vm_t *vm, njs_value_t value = njs_arg(args, nargs, 1); indent = njs_arg(args, nargs, 2); - n = indent->data.u.number; + n = njs_primitive_value_to_integer(indent); n = nxt_min(n, 5); if (njs_vm_value_dump(vm, &str, value, n) != NXT_OK) { diff -r da67f08d365e -r cf424d6313ae njs/njs_number.c --- a/njs/njs_number.c Wed Nov 28 15:47:05 2018 +0300 +++ b/njs/njs_number.c Thu Nov 29 18:14:12 2018 +0300 @@ -789,6 +789,17 @@ njs_number_to_integer(double num) { int64_t i64; +#if (NXT_NAN_TO_UINT_CONVERSION != 0) + /* + * PPC32: NaN and Inf are converted to 0x8000000080000000 + * and become non-zero after truncation. + */ + + if (isnan(num) || isinf(num)) { + return 0; + } +#endif + /* * ES5.1: integer must be modulo 2^32. * 2^53 is the largest integer number which can be stored safely diff -r da67f08d365e -r cf424d6313ae nxt/auto/clang --- a/nxt/auto/clang Wed Nov 28 15:47:05 2018 +0300 +++ b/nxt/auto/clang Thu Nov 29 18:14:12 2018 +0300 @@ -302,3 +302,20 @@ else . ${NXT_AUTO}feature fi + + +nxt_feature="NAN to uint conversion" +nxt_feature_name=NXT_NAN_TO_UINT_CONVERSION +nxt_feature_run=value +nxt_feature_incs= +nxt_feature_libs=-lm +nxt_feature_test="#include + #include + #include + + int main(void) { + int64_t i64 = sqrt(-1); + printf(\"%x\", (uint32_t) i64); + return 0; + }" +. ${NXT_AUTO}feature From xeioex at nginx.com Thu Nov 29 18:16:46 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 29 Nov 2018 18:16:46 +0000 Subject: [njs] Improved accuracy of console.time()/console.timeEnd(). Message-ID: details: https://hg.nginx.org/njs/rev/b7706e03babc branches: changeset: 678:b7706e03babc user: Artem S. Povalyukhin date: Wed Nov 28 21:56:19 2018 +0300 description: Improved accuracy of console.time()/console.timeEnd(). diffstat: njs/njs_shell.c | 23 ++++++++++------------- 1 files changed, 10 insertions(+), 13 deletions(-) diffs (58 lines): diff -r 2ad7533bcbae -r b7706e03babc njs/njs_shell.c --- a/njs/njs_shell.c Wed Nov 28 21:50:28 2018 +0300 +++ b/njs/njs_shell.c Wed Nov 28 21:56:19 2018 +0300 @@ -153,7 +153,7 @@ static njs_external_t njs_externals[] = static njs_completion_t njs_completion; -static struct timeval njs_console_time; +static uint64_t njs_console_time = UINT64_MAX; int @@ -781,7 +781,7 @@ njs_ext_console_time(njs_vm_t *vm, njs_v vm->retval = njs_value_void; - gettimeofday(&njs_console_time, NULL); + njs_console_time = nxt_time(); return NJS_OK; } @@ -791,28 +791,25 @@ static njs_ret_t njs_ext_console_time_end(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - int64_t us, ms; - struct timeval tv; + uint64_t ns, ms; - gettimeofday(&tv, NULL); + ns = nxt_time(); if (!njs_value_is_void(njs_arg(args, nargs, 1))) { njs_vm_error(vm, "labels not implemented"); return NJS_ERROR; } - if (nxt_fast_path(njs_console_time.tv_sec || njs_console_time.tv_usec)) { + if (nxt_fast_path(njs_console_time != UINT64_MAX)) { - us = ((int64_t) tv.tv_sec - njs_console_time.tv_sec) * 1000000 - + ((int64_t) tv.tv_usec - njs_console_time.tv_usec); + ns = ns - njs_console_time; - ms = us / 1000; - us = us % 1000; + ms = ns / 1000000; + ns = ns % 1000000; - printf("default: %" PRIu64 ".%03" PRIu64 "ms\n", ms, us); + printf("default: %" PRIu64 ".%06" PRIu64 "ms\n", ms, ns); - njs_console_time.tv_sec = 0; - njs_console_time.tv_usec = 0; + njs_console_time = UINT64_MAX; } else { printf("Timer \"default\" doesn?t exist.\n"); From xeioex at nginx.com Thu Nov 29 18:16:45 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 29 Nov 2018 18:16:45 +0000 Subject: [njs] Added nxt_time(). Message-ID: details: https://hg.nginx.org/njs/rev/2ad7533bcbae branches: changeset: 677:2ad7533bcbae user: Artem S. Povalyukhin date: Wed Nov 28 21:50:28 2018 +0300 description: Added nxt_time(). Returns the current high-resolution real time. diffstat: Makefile | 10 ++++++---- nxt/Makefile | 13 +++++++++++++ nxt/auto/time | 40 ++++++++++++++++++++++++++++++++++++++++ nxt/nxt_time.c | 30 ++++++++++++++++++++++++++++++ nxt/nxt_time.h | 3 +++ 5 files changed, 92 insertions(+), 4 deletions(-) diffs (186 lines): diff -r cf424d6313ae -r 2ad7533bcbae Makefile --- a/Makefile Thu Nov 29 18:14:12 2018 +0300 +++ b/Makefile Wed Nov 28 21:50:28 2018 +0300 @@ -48,6 +48,7 @@ NXT_BUILDDIR = build $(NXT_BUILDDIR)/nxt_sha1.o \ $(NXT_BUILDDIR)/nxt_sha2.o \ $(NXT_BUILDDIR)/nxt_pcre.o \ + $(NXT_BUILDDIR)/nxt_time.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ @@ -93,6 +94,7 @@ NXT_BUILDDIR = build $(NXT_BUILDDIR)/nxt_sha1.o \ $(NXT_BUILDDIR)/nxt_sha2.o \ $(NXT_BUILDDIR)/nxt_pcre.o \ + $(NXT_BUILDDIR)/nxt_time.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ @@ -535,7 +537,7 @@ dist: -I$(NXT_LIB) $(NXT_EDITLINE_CFLAGS) -Injs \ njs/njs_shell.c \ $(NXT_BUILDDIR)/libnjs.a \ - -lm $(NXT_PCRE_LIB) $(NXT_EDITLINE_LIB) + -lm $(NXT_PCRE_LIB) $(NXT_LIBRT) $(NXT_EDITLINE_LIB) $(NXT_BUILDDIR)/njs_unit_test: \ $(NXT_BUILDDIR)/libnxt.a \ @@ -546,7 +548,7 @@ dist: -I$(NXT_LIB) -Injs \ njs/test/njs_unit_test.c \ $(NXT_BUILDDIR)/libnjs.a \ - -lm $(NXT_PCRE_LIB) + -lm $(NXT_PCRE_LIB) $(NXT_LIBRT) $(NXT_BUILDDIR)/njs_interactive_test: \ $(NXT_BUILDDIR)/libnxt.a \ @@ -557,7 +559,7 @@ dist: -I$(NXT_LIB) -Injs \ njs/test/njs_interactive_test.c \ $(NXT_BUILDDIR)/libnjs.a \ - -lm $(NXT_PCRE_LIB) + -lm $(NXT_PCRE_LIB) $(NXT_LIBRT) $(NXT_BUILDDIR)/njs_benchmark: \ $(NXT_BUILDDIR)/libnxt.a \ @@ -568,6 +570,6 @@ dist: -I$(NXT_LIB) -Injs \ njs/test/njs_benchmark.c \ $(NXT_BUILDDIR)/libnjs.a \ - -lm $(NXT_PCRE_LIB) + -lm $(NXT_PCRE_LIB) $(NXT_LIBRT) include $(NXT_LIB)/Makefile diff -r cf424d6313ae -r 2ad7533bcbae nxt/Makefile --- a/nxt/Makefile Thu Nov 29 18:14:12 2018 +0300 +++ b/nxt/Makefile Wed Nov 28 21:50:28 2018 +0300 @@ -20,6 +20,7 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_pcre.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ $(NXT_BUILDDIR)/nxt_trace.o \ + $(NXT_BUILDDIR)/nxt_time.o \ $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ ar -r -c $(NXT_BUILDDIR)/libnxt.a \ @@ -37,6 +38,7 @@ NXT_LIB = nxt $(NXT_BUILDDIR)/nxt_sha2.o \ $(NXT_BUILDDIR)/nxt_pcre.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ + $(NXT_BUILDDIR)/nxt_time.o \ $(NXT_BUILDDIR)/nxt_trace.o \ $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ @@ -206,6 +208,17 @@ NXT_LIB = nxt -I$(NXT_LIB) \ $(NXT_LIB)/nxt_malloc.c +$(NXT_BUILDDIR)/nxt_time.o: \ + $(NXT_LIB)/nxt_auto_config.h \ + $(NXT_LIB)/nxt_types.h \ + $(NXT_LIB)/nxt_clang.h \ + $(NXT_LIB)/nxt_time.h \ + $(NXT_LIB)/nxt_time.c \ + + $(NXT_CC) -c -o $(NXT_BUILDDIR)/nxt_time.o $(NXT_CFLAGS) \ + -I$(NXT_LIB) \ + $(NXT_LIB)/nxt_time.c + $(NXT_BUILDDIR)/nxt_trace.o: \ $(NXT_LIB)/nxt_auto_config.h \ $(NXT_LIB)/nxt_types.h \ diff -r cf424d6313ae -r 2ad7533bcbae nxt/auto/time --- a/nxt/auto/time Thu Nov 29 18:14:12 2018 +0300 +++ b/nxt/auto/time Wed Nov 28 21:50:28 2018 +0300 @@ -3,6 +3,46 @@ # Copyright (C) NGINX, Inc. +nxt_feature="clock_gettime(CLOCK_MONOTONIC)" +nxt_feature_name=NXT_HAVE_CLOCK_MONOTONIC +nxt_feature_run=yes +nxt_feature_incs= +nxt_feature_libs= +nxt_feature_test="#include + + int main() { + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) + return 1; + return 0; + }" +. ${NXT_AUTO}feature + + +if [ $nxt_found = no ]; then + + # Linux and Solaris 10 clock_gettime() are in librt. + + nxt_feature="clock_gettime(CLOCK_MONOTONIC) in librt" + nxt_feature_libs="-lrt" + . ${NXT_AUTO}feature +fi + +if [ $nxt_found = yes ]; then + cat << END >> $NXT_MAKEFILE_CONF + +NXT_LIBRT = -lrt +END + +else + cat << END >> $NXT_MAKEFILE_CONF + +NXT_LIBRT = +END + +fi + # Linux, FreeBSD, MacOSX. nxt_feature="struct tm.tm_gmtoff" diff -r cf424d6313ae -r 2ad7533bcbae nxt/nxt_time.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nxt/nxt_time.c Wed Nov 28 21:50:28 2018 +0300 @@ -0,0 +1,30 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) NGINX, Inc. + */ + +#include +#include +#include +#include + +#include + +uint64_t +nxt_time(void) +{ +#if (NXT_HAVE_CLOCK_MONOTONIC) + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + return (uint64_t) ts.tv_sec * 1000000000 + ts.tv_nsec; +#else + struct timeval tv; + + gettimeofday(&tv, NULL); + + return (uint64_t) tv.tv_sec * 1000000000 + tv.tv_usec * 1000; +#endif +} diff -r cf424d6313ae -r 2ad7533bcbae nxt/nxt_time.h --- a/nxt/nxt_time.h Thu Nov 29 18:14:12 2018 +0300 +++ b/nxt/nxt_time.h Wed Nov 28 21:50:28 2018 +0300 @@ -21,4 +21,7 @@ #endif +uint64_t nxt_time(void); + + #endif /* _NXT_TIME_H_INCLUDED_ */ From xeioex at nginx.com Thu Nov 29 18:16:46 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Thu, 29 Nov 2018 18:16:46 +0000 Subject: [njs] Using acosh(0) to get NaN in runtime. Message-ID: details: https://hg.nginx.org/njs/rev/83b64328fbb2 branches: changeset: 679:83b64328fbb2 user: Dmitry Volyntsev date: Thu Nov 29 21:01:59 2018 +0300 description: Using acosh(0) to get NaN in runtime. macOS clang 10 optimizes sqrt(-1) out using garbage value instead. diffstat: nxt/auto/clang | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diffs (12 lines): diff -r b7706e03babc -r 83b64328fbb2 nxt/auto/clang --- a/nxt/auto/clang Wed Nov 28 21:56:19 2018 +0300 +++ b/nxt/auto/clang Thu Nov 29 21:01:59 2018 +0300 @@ -314,7 +314,7 @@ nxt_feature_test="#include #include int main(void) { - int64_t i64 = sqrt(-1); + int64_t i64 = acosh(0); printf(\"%x\", (uint32_t) i64); return 0; }" From xeioex at nginx.com Fri Nov 30 15:11:38 2018 From: xeioex at nginx.com (Dmitry Volyntsev) Date: Fri, 30 Nov 2018 15:11:38 +0000 Subject: [njs] Fixed comparison of Byte and UTF8 strings. Message-ID: details: https://hg.nginx.org/njs/rev/e713f648ef71 branches: changeset: 680:e713f648ef71 user: Dmitry Volyntsev date: Fri Nov 30 17:52:02 2018 +0300 description: Fixed comparison of Byte and UTF8 strings. diffstat: njs/njs_vm.c | 22 +++++++++++++++++----- njs/test/njs_unit_test.c | 21 ++++++++++++++++++++- 2 files changed, 37 insertions(+), 6 deletions(-) diffs (98 lines): diff -r 83b64328fbb2 -r e713f648ef71 njs/njs_vm.c --- a/njs/njs_vm.c Thu Nov 29 21:01:59 2018 +0300 +++ b/njs/njs_vm.c Fri Nov 30 17:52:02 2018 +0300 @@ -1712,7 +1712,7 @@ njs_vmcode_strict_not_equal(njs_vm_t *vm nxt_noinline nxt_bool_t njs_values_strict_equal(const njs_value_t *val1, const njs_value_t *val2) { - size_t size; + size_t size, length1, length2; const u_char *start1, *start2; if (val1->type != val2->type) { @@ -1737,7 +1737,14 @@ njs_values_strict_equal(const njs_value_ } if (size != NJS_STRING_LONG) { - if (val1->short_string.length != val2->short_string.length) { + length1 = val1->short_string.length; + length2 = val2->short_string.length; + + /* + * Using full memcmp() comparison if at least one string + * is a Byte string. + */ + if (length1 != 0 && length2 != 0 && length1 != length2) { return 0; } @@ -1751,9 +1758,14 @@ njs_values_strict_equal(const njs_value_ return 0; } - if (val1->long_string.data->length - != val2->long_string.data->length) - { + length1 = val1->long_string.data->length; + length2 = val2->long_string.data->length; + + /* + * Using full memcmp() comparison if at least one string + * is a Byte string. + */ + if (length1 != 0 && length2 != 0 && length1 != length2) { return 0; } diff -r 83b64328fbb2 -r e713f648ef71 njs/test/njs_unit_test.c --- a/njs/test/njs_unit_test.c Thu Nov 29 21:01:59 2018 +0300 +++ b/njs/test/njs_unit_test.c Fri Nov 30 17:52:02 2018 +0300 @@ -2337,6 +2337,16 @@ static njs_unit_test_t njs_test[] = "} a"), nxt_string("A123DT") }, + { nxt_string("var t; " + "switch ($r3.uri) {" + "case 'abc': " + " t='A'; " + " break; " + "default: " + " t='F'; " + "}; t"), + nxt_string("A") }, + /* continue. */ { nxt_string("continue"), @@ -4045,7 +4055,7 @@ static njs_unit_test_t njs_test[] = nxt_string("true") }, { nxt_string("'\\u00CE\\u00B1'.toBytes() === '?'"), - nxt_string("false") }, + nxt_string("true") }, { nxt_string("var b = '\\u00C2\\u00B6'.toBytes(), u = b.fromUTF8();" "b.length +' '+ b +' '+ u.length +' '+ u"), @@ -4087,6 +4097,12 @@ static njs_unit_test_t njs_test[] = { nxt_string("var a = '\\xB5\\xA7\\xB1\\xAE'.toBytes(); a.fromBytes(1, 3)"), nxt_string("??") }, + { nxt_string("'A'.repeat(8).toBytes() === 'A'.repeat(8)"), + nxt_string("true") }, + + { nxt_string("'A'.repeat(16).toBytes() === 'A'.repeat(16)"), + nxt_string("true") }, + { nxt_string("var a = 'abcdefgh'; a.substr(3, 15)"), nxt_string("defgh") }, @@ -4476,6 +4492,9 @@ static njs_unit_test_t njs_test[] = { nxt_string("var o = {b:$r.props.b}; o.b"), nxt_string("42") }, + { nxt_string("$r2.uri == '???' && $r2.uri === '???'"), + nxt_string("true") }, + /**/ { nxt_string("'?????????????????????????????????'.charCodeAt(5)"), From ru at nginx.com Fri Nov 30 15:39:32 2018 From: ru at nginx.com (Ruslan Ermilov) Date: Fri, 30 Nov 2018 18:39:32 +0300 Subject: [PATCH] Upstream: added $upstream_bytes_sent variable In-Reply-To: <20181129150051.GK99070@mdounin.ru> References: <20181129150051.GK99070@mdounin.ru> Message-ID: <20181130153932.GB50234@lo0.su> On Thu, Nov 29, 2018 at 06:00:51PM +0300, Maxim Dounin wrote: > Hello! > > On Tue, Nov 27, 2018 at 02:34:10AM -0800, Piotr Sikora via nginx-devel wrote: > > > # HG changeset patch > > # User Piotr Sikora > > # Date 1494129075 25200 > > # Sat May 06 20:51:15 2017 -0700 > > # Node ID fafbb3ee41e5bb03bcfba73f7d4367b8ab7d36cc > > # Parent be5cb9c67c05ccaf22dab7abba78aa4c1545a8ee > > Upstream: added $upstream_bytes_sent variable. > > [...] > > Ruslan made a similar patch a while ago. It wasn't committed > since there were questions if such a variable is actually needed - > I think we are aware of at most one feature request for this: > > http://mailman.nginx.org/pipermail/nginx/2018-March/055940.html > > I've asked Ruslan to post his version of the patch (or, rather, a > patch series), please review. # HG changeset patch # User Ruslan Ermilov # Date 1543592116 -10800 # Fri Nov 30 18:35:16 2018 +0300 # Node ID 79c7b169816cdc63044838b03084c631c0d2f0a3 # Parent 5cff15dd07cd298e4eff44c04c2833066c217318 Upstream: style. Introduced local variable "c" in ngx_http_upstream_next() and ngx_http_upstream_finalize_request(). No functional changes. diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -4128,8 +4128,9 @@ static void ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_uint_t ft_type) { - ngx_msec_t timeout; - ngx_uint_t status, state; + ngx_msec_t timeout; + ngx_uint_t status, state; + ngx_connection_t *c; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http next upstream, %xi", ft_type); @@ -4250,25 +4251,26 @@ ngx_http_upstream_next(ngx_http_request_ return; } - if (u->peer.connection) { + c = u->peer.connection; + + if (c) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "close http upstream connection: %d", - u->peer.connection->fd); + "close http upstream connection: %d", c->fd); #if (NGX_HTTP_SSL) - if (u->peer.connection->ssl) { - u->peer.connection->ssl->no_wait_shutdown = 1; - u->peer.connection->ssl->no_send_shutdown = 1; - - (void) ngx_ssl_shutdown(u->peer.connection); + if (c->ssl) { + c->ssl->no_wait_shutdown = 1; + c->ssl->no_send_shutdown = 1; + + (void) ngx_ssl_shutdown(c); } #endif - if (u->peer.connection->pool) { - ngx_destroy_pool(u->peer.connection->pool); - } - - ngx_close_connection(u->peer.connection); + if (c->pool) { + ngx_destroy_pool(c->pool); + } + + ngx_close_connection(c); u->peer.connection = NULL; } @@ -4292,7 +4294,8 @@ static void ngx_http_upstream_finalize_request(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_int_t rc) { - ngx_uint_t flush; + ngx_uint_t flush; + ngx_connection_t *c; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "finalize http upstream request: %i", rc); @@ -4328,13 +4331,15 @@ ngx_http_upstream_finalize_request(ngx_h u->peer.sockaddr = NULL; } - if (u->peer.connection) { + c = u->peer.connection; + + if (c) { #if (NGX_HTTP_SSL) /* TODO: do not shutdown persistent connection */ - if (u->peer.connection->ssl) { + if (c->ssl) { /* * We send the "close notify" shutdown alert to the upstream only @@ -4342,21 +4347,20 @@ ngx_http_upstream_finalize_request(ngx_h * It is acceptable according to the TLS standard. */ - u->peer.connection->ssl->no_wait_shutdown = 1; - - (void) ngx_ssl_shutdown(u->peer.connection); + c->ssl->no_wait_shutdown = 1; + + (void) ngx_ssl_shutdown(c); } #endif ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "close http upstream connection: %d", - u->peer.connection->fd); - - if (u->peer.connection->pool) { - ngx_destroy_pool(u->peer.connection->pool); - } - - ngx_close_connection(u->peer.connection); + "close http upstream connection: %d", c->fd); + + if (c->pool) { + ngx_destroy_pool(c->pool); + } + + ngx_close_connection(c); } u->peer.connection = NULL; # HG changeset patch # User Ruslan Ermilov # Date 1543592133 -10800 # Fri Nov 30 18:35:33 2018 +0300 # Node ID 95b0ee9297fc3b8782ee1a383e3221b935639cc3 # Parent 79c7b169816cdc63044838b03084c631c0d2f0a3 Upstream: implemented $upstream_bytes_sent. diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -162,7 +162,7 @@ static ngx_int_t ngx_http_upstream_statu ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); -static ngx_int_t ngx_http_upstream_response_length_variable( +static ngx_int_t ngx_http_upstream_bytes_variable( ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -402,11 +402,15 @@ static ngx_http_variable_t ngx_http_ups NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("upstream_response_length"), NULL, - ngx_http_upstream_response_length_variable, 0, + ngx_http_upstream_bytes_variable, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 }, { ngx_string("upstream_bytes_received"), NULL, - ngx_http_upstream_response_length_variable, 1, + ngx_http_upstream_bytes_variable, 1, + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("upstream_bytes_sent"), NULL, + ngx_http_upstream_bytes_variable, 2, NGX_HTTP_VAR_NOCACHEABLE, 0 }, #if (NGX_HTTP_CACHE) @@ -4137,6 +4141,8 @@ ngx_http_upstream_next(ngx_http_request_ if (u->peer.sockaddr) { + u->state->bytes_sent = u->peer.connection->sent; + if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_403 || ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) { @@ -4322,6 +4328,10 @@ ngx_http_upstream_finalize_request(ngx_h - u->pipe->preread_size; u->state->response_length = u->pipe->read_length; } + + if (u->peer.connection) { + u->state->bytes_sent = u->peer.connection->sent; + } } u->finalize_request(r, rc); @@ -5472,7 +5482,7 @@ ngx_http_upstream_response_time_variable static ngx_int_t -ngx_http_upstream_response_length_variable(ngx_http_request_t *r, +ngx_http_upstream_bytes_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { u_char *p; @@ -5506,6 +5516,9 @@ ngx_http_upstream_response_length_variab if (data == 1) { p = ngx_sprintf(p, "%O", state[i].bytes_received); + } else if (data == 2) { + p = ngx_sprintf(p, "%O", state[i].bytes_sent); + } else { p = ngx_sprintf(p, "%O", state[i].response_length); } diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -63,6 +63,7 @@ typedef struct { ngx_msec_t header_time; ngx_msec_t queue_time; off_t response_length; + off_t bytes_sent; off_t bytes_received; ngx_str_t *peer;