Dmitry Volyntsev [Fri, 19 Jan 2024 02:03:24 +0000 (18:03 -0800)]
Fixed tracking of unhandled rejected promises.
Checking for unhandled promise rejections while looping for pending jobs
produces false-positive reports when an rejected promised is handled
by one of the pending jobs later.
The fix is to check for unhandled promise rejections only at top level
calls like ngx_js_name_invoke() and ngx_js_name_call() and only after
all pending jobs are processed.
The issue was introduced in bc80bcb3102c (not released yet).
Fixed initialization of external prototypes with object entry.
When external was NULL (for example, when .u.object.properties is not
declared), an arithmetic operation was performed with NULL pointer which
is undefined behavior.
Fixed external values initialization in unit tests.
Since 0.8.0 modules can create their own constructors and prototypes.
A modules has two method: preinit() and init(). A module should
add its constructors and prototypes in preinit() and create its own
values in init(). Creating a value in preinit() results in an error.
The patch fixes the issue by creating an external value in init()
instead of preinit().
To align njs with other JS engines, async events are removed from njs
core. The following functions were removed: njs_vm_add_event(),
njs_vm_del_event(), njs_vm_waiting(). Instead the host is expected
to manage async events by itself.
In addition, the posted events are renamed to jobs, to better align with
the ECMA specs. The following methods are removed: njs_vm_run().
Instead, the host is expected to call njs_vm_execute_pending_job() in a
loop to execute pending jobs. The following functions were added:
njs_vm_enqueue_job().
Vadim Zhestikov [Thu, 30 Nov 2023 04:46:32 +0000 (20:46 -0800)]
Fixed memory over-read in njs_utf8_prev() and njs_utf8_next().
Previously, njs_utf8_next() might over-read up to 1 byte
beyond the string memory. Whereas njs_utf8_prev() might
over-read unlimited number of bytes before the string.
Dmitry Volyntsev [Tue, 21 Nov 2023 16:57:03 +0000 (08:57 -0800)]
Modules: fixed js_set with Buffer values.
Previously, a Buffer value which contains invalid UTF-8 when returned as a
value for js_set handler was mangled because the bytes value was converted to a
string value.
The fix is to use bytes value of Buffer, TypedArray and ArrayBuffer as is,
and not convert it to a string first.
Dmitry Volyntsev [Thu, 19 Oct 2023 01:36:00 +0000 (18:36 -0700)]
XML: fixed compilation with certain GCC versions.
external/njs_xml_module.c:541:16: error: 'name.length' may be used
uninitialized [-Werror=maybe-uninitialized]
541 | if (name.length != njs_strlen(node->name).
Dmitry Volyntsev [Wed, 18 Oct 2023 00:51:39 +0000 (17:51 -0700)]
Fixed RegExp.prototype.exec() with global regexp and unicode input.
Previously, when exactly 32 characters unicode string was provided and
the "lastIndex" value of "this" regexp was equal to 32 too, the
njs_string_utf8_offset() was called with invalid index argument (longer
than a size of the string). As a result njs_string_utf8_offset()
returned garbage values.
This was manifested in the following ways:
1) InternalError: pcre2_match() failed: bad offset value
2) Very slow replace calls with global regexps, for
example in expressions like: str.replace(/<re>/g).
Fixed Array.prototype.sort() with --debug=YES and --debug-memory=YES.
Previously, --debug-memory=YES activated a different allocation
mechanism that was not able to properly handle the 0 size allocation.
Specifically, njs_mp_free() failed to find a block to free when the size
of the block is 0.
The fix is to alloc at least 1 byte in the --debug-memory=YES mode.
1) Ensuring that consistent prefixes are used:
"http js" in HTTP module and "stream js" in Stream module.
2) Added debug for every event/callback handler entrance.
3) Added debug with a method name for every JS call.
Tests: fixed incr() tests for a shared dictionary.
Previously, the incr() method called SharedDict.incr() with a NaN value
as a second argument because parseInt(undefined) returns NaN.
The test itself failed to capture the issue because it matches the whole
HTTP response and the pattern itself was too short, so it matched
accidentally.
Modules: added a session object for js_periodic handler.
Now js_periodic handler is provided with a session object as its first
argument. Session object can be used to access variables created with
js_set, js_var or map directives.
Modules: added worker_affinity parameter for js_periodic directive.
worker_affinity specifies on what set of workers the js_periodic handler
should be executed. By default the js_handler is executed only on worker 0.
The parameter accepts a binary mask or "all" to specify all workers.
example.conf:
worker_processes 4;
...
location @periodics {
# to be run at 1 minute intervals in worker 0
js_periodic main.handler interval=60s;
# to be run at 1 minute intervals in all the workers
js_periodic main.handler interval=60s worker_affinity=all;
# to be run at 1 minute intervals in workers 1 and 3
js_periodic main.handler interval=60s worker_affinity=0101;
}
Dmitry Volyntsev [Thu, 31 Aug 2023 01:59:28 +0000 (18:59 -0700)]
Modules: fixed size() and keys() methods of a shared dictionary.
Previously, these methods did not take into the account exprired
entries. The expired entries appear in js_shared_dict_zone when timeout
directive is specified as the expired elements are not removed at the
moment they become stale right away.
Dmitry Volyntsev [Tue, 22 Aug 2023 18:13:09 +0000 (11:13 -0700)]
Modules: introduced js_periodic directive.
The directive specifies a JS handler to run at regular intervals. The JS
handler will be executed in each worker process. The handler receives no
arguments. It has access to ngx and other global objects.
example.conf:
location @periodics {
# Specifies a JS handler to be run at 1 minute intervals
js_periodic main.handler interval=60s jitter=5s;
Previously, r.headersOut['Last-Modified'] setter did not update
r->headers_out.last_modified. As a result a client might get two
Last-Modified headers.