Skip to content

Add ZSTD bindings to the node:zlib package.#6007

Open
alistairjevans wants to merge 13 commits intocloudflare:mainfrom
alistairjevans:alistairjevans/zstd-support
Open

Add ZSTD bindings to the node:zlib package.#6007
alistairjevans wants to merge 13 commits intocloudflare:mainfrom
alistairjevans:alistairjevans/zstd-support

Conversation

@alistairjevans
Copy link

Based pretty heavily on the brotli support.

Closes #4013

@alistairjevans alistairjevans requested review from a team as code owners February 3, 2026 11:09
@github-actions
Copy link

github-actions bot commented Feb 3, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@alistairjevans
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

ZstdEncoderContext::~ZstdEncoderContext() {
if (cctx_ != nullptr) {
ZSTD_freeCCtx(cctx_);
cctx_ = nullptr;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth wrapping this in a custom smart pointer to ensure the cleanup is correct. Non-blocking tho.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added (brotli implementation does already do this)

@jasnell jasnell requested a review from anonrig February 3, 2026 15:25
@jasnell
Copy link
Collaborator

jasnell commented Feb 3, 2026

@anonrig ... given your familiarity with the zlib impl in workerd, it would be good to have your review on this as well.

@alistairjevans
Copy link
Author

Thank you for the feedback @anonrig and @jasnell! 🙏 I believe I've addressed all your comments now.

@alistairjevans
Copy link
Author

Merged latest; @anonrig / @jasnell , any chance of a re-review? 🙏

@anonrig
Copy link
Member

anonrig commented Feb 11, 2026

LGTM. @alistairjevans formatter seems to be failing: https://github.com/cloudflare/workerd/actions/runs/21922721360/job/63307147452?pr=6007

@jasnell can you take a look?

@alistairjevans
Copy link
Author

alistairjevans commented Feb 11, 2026

Thanks @anonrig, formatting fix pushed, linter passes locally now.

@jasnell
Copy link
Collaborator

jasnell commented Feb 11, 2026

Overall I think this looks good. What I'm considering... (something I wish I had thought to do on the previous node:zlib additions)... is adding this initially behind an experimental compat flag and having the security team do some quick fuzz testing on it. Anything new that is dealing with bytes being passed around makes me just a bit nervous and a little extra testing doesn't hurt. That's not to say I see anything in here concretely questionable, just thinking about taking the extra precaution. @danlapid what do you think?

@alistairjevans
Copy link
Author

@jasnell, would such a compatibility flag still allow us to opt-in to using the feature in Cloudflare Workers while we wait for the fuzz test to complete?

@jasnell
Copy link
Collaborator

jasnell commented Feb 12, 2026

@alistairjevans ... while the fuzz testing would happening (if we go that route) the compat flag would be marked as "experimental" which means only cloudflare accounts would be able to use it until that annotation is removed. Still need to decide tho if this is the path we'd want to take. Should have a decision soon.

@danlapid
Copy link
Collaborator

danlapid commented Feb 12, 2026

Let's not block - good idea to do as follow up - still want to see this land.
Let's review the code until we're confident this is safe.

Copy link
Collaborator

@jasnell jasnell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, LGTM with a couple nits and a question about error handling that might need addressing before this lands. I'll do the sign off once the question is looked at :-) .. great job overall!!

There is a pre-existing issue we need to address with CompressionStream::write's validation of flush values but that's not introduced or made worse with this change (it's relevant for the brotli support also). And, there's missing external memory tracking here that can be done as a follow-up (see, for instance, the CompressionAllocator::AllocForBrotli, CompressionAllocator::FreeForZlib, etc). We'll want to come back to that.

// For decompression, lastResult == 0 means frame is complete
// If we have flush_ == ZSTD_e_end equivalent and there's input left, that's an error
if (flush_ == ZSTD_e_end && input_.pos < input_.size && lastResult == 0) {
// Frame completed but there's still input - could be trailing data
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: what is this if block for if it's empty?

Copy link
Author

@alistairjevans alistairjevans Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sent me on a bit of a rabbit-hole, initially this code block was added as documentation only, but going back over it made me realise that, unlike the zlib or brotli implementations, you won't get an EOF error if a zstd frame you're decoding got truncated! But you will for brotli and zlib. 😕

Whats even more interesting is that neither will nodejs zstd, which was surprising, a truncated stream will just silently succeed; I'm pretty sure this is a bug in the ZSTD implementation in nodejs, because the tests in https://github.com/nodejs/node/blob/main/test/parallel/test-zlib-truncated.js do not verify zstd behaviour for truncated input as they do with gzip and deflate algorithms, which feels like an oversight.

I've pushed a fairly simple fix for workerd that ensures you do get an EOF error if a payload is truncated. Instinctively I'd go with correctness since this feels like a bug in nodejs, but do say if I should match nodejs behaviour exactly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixing bugs is good. I'm happy with this and I'd encourage you to open a PR fixing it in node.js also :-)

@alistairjevans
Copy link
Author

Pushed fixes for linter formatting issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

node:zlib implement zstd

4 participants