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.
The directive allows to declare a dictionary that is shared among the
working processes. A dictionary expects strings as keys. It stores
string or number as values. The value type is declared using
type= argument of the directive. The default type is string.
example.conf:
# Declares a shared dictionary of strings of size 1 Mb that
# removes key-value after 60 seconds of inactivity.
js_shared_dict_zone zone=foo:1M timeout=60s;
# Declares a shared dictionary of strings of size 512Kb that
# forcibly remove oldest key-value pairs when memory is not enough.
js_shared_dict_zone zone=bar:512K timeout=30s evict;
# Declares a permanent number shared dictionary of size 32Kb.
js_shared_dict_zone zone=num:32k type=number;
example.js:
function get(r) {
r.return(200, ngx.shared.foo.get(r.args.key));
}
function set(r) {
r.return(200, ngx.shared.foo.set(r.args.key, r.args.value));
}
function delete(r) {
r.return(200, ngx.shared.bar.delete(r.args.key));
}
function increment(r) {
r.return(200, ngx.shared.num.incr(r.args.key, 2));
}
In collaboration with Artem S. Povalyukhin, Jakub Jirutka and
洪志道 (Hong Zhi Dao).
Dmitry Volyntsev [Thu, 22 Jun 2023 22:40:36 +0000 (15:40 -0700)]
Fetch: fixed setting of Content-Type header.
Previously, Content-Type was set unconditionally to
"text/plain;charset=UTF-8" when fetch request contained a string body.
This may overlap with user's Content-Type.
The fix is to set the header only if it was not set before.
Dmitry Volyntsev [Wed, 21 Jun 2023 23:30:00 +0000 (16:30 -0700)]
WebCrypto: added back custom exception types using new public API.
In f1432043a6a4, when rewriting webcrypto module using public API all
the exceptions types were squashed into a single Error type. This patch
reintroduces the standard exception types back using new API.
Dmitry Volyntsev [Wed, 21 Jun 2023 23:29:51 +0000 (16:29 -0700)]
QueryString: added back custom exception types using new public API.
In fd956d2a25a3, when rewriting querystring module using public API all
the exceptions types were squashed into a single Error type. This patch
reintroduces the standard exception types back using new API.
Dmitry Volyntsev [Wed, 21 Jun 2023 23:29:48 +0000 (16:29 -0700)]
Crypto: added back custom exception types using new public API.
In b2cbf06ba017, when rewriting crypto module using public API all the
exceptions types were squashed into a single Error type. This patch
reintroduces the standard exception types back using new API.