Fixes #22995. Fixes #23000.
There were a handful of bugs here causing the hang (each with a
corresponding minimized test):
- We were canceling recv futures when `receiveMessageOnPort` was called,
but this caused the "receive loop" in the message port to exit. This was
due to the fact that `CancelHandle`s are never reset (i.e., once you
`cancel` a `CancelHandle`, it remains cancelled). That meant that after
`receieveMessageOnPort` was called, the subsequent calls to
`op_message_port_recv_message` would throw `Interrupted` exceptions, and
we would exit the loop.
The cancellation, however, isn't actually necessary.
`op_message_port_recv_message` only borrows the underlying port for long
enough to poll the receiver, so the borrow there could never overlap
with `op_message_port_recv_message_sync`.
- Calling `MessagePort.unref()` caused the "receive loop" in the message
port to exit. This was because we were setting
`messageEventListenerCount` to 0 on unref. Not only does that break the
counter when multiple `MessagePort`s are present in the same thread, but
we also exited the "receive loop" whenever the listener count was 0. I
assume this was to prevent the recv promise from keeping the event loop
open.
Instead of this, I chose to just unref the recv promise as needed to
control the event loop.
- The last bug causing the hang (which was a doozy to debug) ended up
being an unfortunate interaction between how we implement our
messageport "receive loop" and a pattern found in `npm:piscina` (which
angular uses). The gist of it is that piscina uses an atomic wait loop
along with `receiveMessageOnPort` in its worker threads, and as the
worker is getting started, the following incredibly convoluted series of
events occurs:
1. Parent sends a MessagePort `p` to worker
2. Parent sends a message `m` to the port `p`
3. Parent notifies the worker with `Atomics.notify` that a new message
is available
4. Worker receives message, adds "message" listener to port `p`
5. Adding the listener triggers `MessagePort.start()` on `p`
6. Receive loop in MessagePort.start receives the message `m`, but then
hits an await point and yields (before dispatching the "message" event)
7. Worker continues execution, starts the atomic wait loop, and
immediately receives the existing notification from the parent that a
message is available
8. Worker attempts to receive the new message `m` with
`receiveMessageOnPort`, but this returns `undefined` because the receive
loop already took the message in 6
9. Atomic wait loop continues to next iteration, waiting for the next
message with `Atomic.wait`
10. `Atomic.wait` blocks the worker thread, which prevents the receive
loop from continuing and dispatching the "message" event for the
received message
11. The parent waits for the worker to respond to the first message, and
waits
12. The thread can't make any more progress, and the whole process hangs
The fix I've chosen here (which I don't particularly love, but it works)
is to just delay the `MessagePort.start` call until the end of the event
loop turn, so that the atomic wait loop receives the message first. This
prevents the hang.
---
Those were the main issues causing the hang. There ended up being a few
other small bugs as well, namely `exit` being emitted multiple times,
and not patching up the message port when it's received by
`receiveMessageOnPort`.
This commit removes all occurrences of `--unstable` flag
from all the tests that are run in CI.
Turns out none of the tests actually required that flag
anymore.
A workaround for the issue #25480
`Deno.Listener` can't be closed synchronously after `accept()` is
called. This PR delays the `accept` call 2 ticks (The listener callback
is called 1 tick later. So the 1 tick delay is not enough), and makes
`net.Server` capable of being closed synchronously.
This unblocks `npm:detect-port` and `npm:portfinder`
closes #18301
closes #25175
This commit adds:
- `addAbortListener` in `node:events`
- `aborted` in `node:util`
- `execPath` and `execvArgs` named export from `node:process`
- `getDefaultHighWaterMark` from `node:stream`
The `execPath` is very hacky - because module namespaces can not have
real getters, `execPath` is an object with a `toString()` method that on
call returns the actual `execPath`, and replaces the `execPath` binding
with the string. This is done so that we don't require the `execPath`
permission on startup.
This commit changes when to cause the hostname substition of `0.0.0.0` ->
`localhost`.
Currently we substitute `localhost` to the hostname on windows before
calling `options.onListen`, which prevents the users to do more advanced
thing using hostname string like
https://github.com/denoland/std/issues/5558. This PR changes it not to
substitute it when the user provide `onListen` callback.
closes #24776
unblocks https://github.com/denoland/std/issues/5558
This change fixes the handling of upgraded socket from `node:http` module.
In `op_node_http_fetch_response_upgrade`, we create DuplexStream paired
with `hyper::upgrade::Upgraded`. When the connection is closed from the
server, the read result from `Upgraded` becomes 0. However because we
don't close the paired DuplexStream at that point, the Socket object in
JS side keeps alive even after the server closed. That caused the issue
#20179
This change fixes it by closing the paired DuplexStream when the
`Upgraded` stream returns 0 read result.
closes #20179
This is blocking https://github.com/denoland/deno/pull/25213.
Turns out a bunch of FS APIs are completely broken because they
use RIDs (resource IDs) instead of FDs (file descriptors).
Fixes #23281. Part of #20613.
We were emitting the `online` event in the constructor, so the caller
could never receive it (since there was no time for them to add a
listener). Instead, emit the event where it's intended – after the
worker is initialized.
---
After this parcel no longer freezes, but still will fail due to other
bugs (which will be fixed in other PRs)
- Add missing exports to `node:cluster`
- Fix default export not being an instance of `EventEmitter`
- Fix aliasing of properties
- Fix `disconnected` -> `disconnect` export naming
This makes `log4js` work in Deno. `karma` starts too, but somehow the
server isn't responding. That looks like a different issue.
Fixes https://github.com/denoland/deno/issues/24858
This PR addresses a regression introduced in
https://github.com/denoland/deno/pull/25021 that would cause the
`req.url` parameter in Node's http server to always be a single
character instead of the expected value. The regression was caused by
effectively calling `.indexOf()` on an empty string and thus passing the
wrong index for slicing.
```js
"".indexOf("/") // -> -1
request.url.slice(-1) // effectively only giving us the last character
```
Fixes https://github.com/denoland/deno/issues/25080
My fix in #25030 was buggy, I forgot to pass the `byteOffset` and
`byteLength`. Whoops.
I also discovered that fs.read was not respecting the `offset` argument,
and we were constructing a new `Buffer` for the callback instead of just
passing the original one (which is what node does, and the @types/node
definitions also indicate the callback should get the same type).
Fixes #25028.
Part of #25028.
Our underlying read/write operations in `io` assume the buffer is a
Uint8Array, but we were passing in other typed arrays (in the case above
it was `Int8Array`).
There is no constructor code when creating an inspector `Session`
instance in Node. Also get rid of some symbols which should've been
private properties. This PR doesn't yet add any new implementations
though as these are mostly cosmetic changes.
For some reason we didn't register the `node:inspector` module, which
lead to a panic when trying to import it. This PR registers it.
Related: https://github.com/denoland/deno/issues/25004
This is commonly used to register loading non standard file types. But
some libs also register TS loaders which Deno supports natively, like
the npm `payload` package. This PR unblocks those.
Fixes https://github.com/denoland/deno/issues/24902
This completely rewrites how we handle key material in ext/node. Changes
in this
PR:
- **Signing**
- RSA
- RSA-PSS 🆕
- DSA 🆕
- EC
- ED25519 🆕
- **Verifying**
- RSA
- RSA-PSS 🆕
- DSA 🆕
- EC 🆕
- ED25519 🆕
- **Private key import**
- Passphrase encrypted private keys 🆕
- RSA
- PEM
- DER (PKCS#1) 🆕
- DER (PKCS#8) 🆕
- RSA-PSS
- PEM
- DER (PKCS#1) 🆕
- DER (PKCS#8) 🆕
- DSA 🆕
- EC
- PEM
- DER (SEC1) 🆕
- DER (PKCS#8) 🆕
- X25519 🆕
- ED25519 🆕
- DH
- **Public key import**
- RSA
- PEM
- DER (PKCS#1) 🆕
- DER (PKCS#8) 🆕
- RSA-PSS 🆕
- DSA 🆕
- EC 🆕
- X25519 🆕
- ED25519 🆕
- DH 🆕
- **Private key export**
- RSA 🆕
- DSA 🆕
- EC 🆕
- X25519 🆕
- ED25519 🆕
- DH 🆕
- **Public key export**
- RSA
- DSA 🆕
- EC 🆕
- X25519 🆕
- ED25519 🆕
- DH 🆕
- **Key pair generation**
- Overhauled, but supported APIs unchanged
This PR adds a lot of new individual functionality. But most importantly
because
of the new key material representation, it is now trivial to add new
algorithms
(as shown by this PR).
Now, when adding a new algorithm, it is also widely supported - for
example
previously we supported ED25519 key pair generation, but we could not
import,
export, sign or verify with ED25519. We can now do all of those things.
Fixes https://github.com/denoland/deno/issues/24756. Fixes
https://github.com/denoland/deno/issues/24796.
This also gets vitest working when using
[`--pool=forks`](https://vitest.dev/guide/improving-performance#pool)
(which is the default as of vitest 2.0). Ref
https://github.com/denoland/deno/issues/23882.
---
This PR resolves a handful of issues with child_process IPC. In
particular:
- We didn't support sending typed array views over IPC
- Opening an IPC channel resulted in the event loop never exiting
- Sending a `null` over IPC would terminate the channel
- There was some UB in the read implementation (transmuting an `&[u8]`
to `&mut [u8]`)
- The `send` method wasn't returning anything, so there was no way to
signal backpressure (this also resulted in the benchmark
`child_process_ipc.mjs` being misleading, as it tried to respect
backpressure. That gave node much worse results at larger message sizes,
and gave us much worse results at smaller message sizes).
- We weren't setting up the `channel` property on the `process` global
(or on the `ChildProcess` object), and also didn't have a way to
ref/unref the channel
- Calling `kill` multiple times (or disconnecting the channel, then
calling kill) would throw an error
- Node couldn't spawn a deno subprocess and communicate with it over IPC
This PR stubs `perf_hooks.eventLoopUtilization` to make the tests of
[hapi](https://github.com/hapijs/hapi) start. Previously, they'd all
error because of this function throwing a not implemented error. This
brings down the test failures in their suite from 982 to 68 failures.
The implementation for `assert.throws()` from `node:assert` didn't work
when the expected value was an `Error` constructor. In this case the
thrown error should checked if it's an instance of said constructor.
Fixes https://github.com/denoland/deno/issues/24464
Previously we had many different code paths all
handling digests in different places, all with
wildly different digest support. This commit
rewrites this to use a single digest handling
mechanism for all digest operations.
It adds various aliases for digest algorithms,
like node does. For example
`sha1WithRSAEncryption` is an alias for `sha1`.
It also adds support for `md5-sha1` digests in
various places.
It's perfectly valid to access `server.address()` before calling
`.listen()`. Until a server actively listens on a socket Node will
return `null` here, but we threw a "Cannot access property 'port' of
undefined" instead.
This was discovered when inspecting failures in Koa's test suite with
Deno.
Changes in this PR:
- Added new fixed size hash algorithms (blake2b512, blake2s256,
sha512-224, sha512-256, sha3-224, sha3-256, sha3-384, sha3-512, sm3)
- Added variable size hash algorithms (the concept), with the algorithms
shake128 and shake256
- Use cppgc instead of resources for the hasher
- Enable Node's crypto.Hash tests and fix found bugs
Previously res.setHeader("foo", ["bar", "baz"]) added a single header
with a value of `bar,baz`. Really this should add two separate headers.
This is visible in `set-cookie` for example.
Factoring out `dlint` upgrade from
https://github.com/denoland/deno/pull/24034 as it
requires us to change the lint step on mac to use ARM runners.
---------
Co-authored-by: Luca Casonato <hello@lcas.dev>
Co-authored-by: David Sherret <dsherret@users.noreply.github.com>