Skip to content

introduce zstd for compression - #4185

Open
gipeshka wants to merge 5 commits into
zio:mainfrom
LiveIntent:introduce-zstd-for-compression
Open

introduce zstd for compression#4185
gipeshka wants to merge 5 commits into
zio:mainfrom
LiveIntent:introduce-zstd-for-compression

Conversation

@gipeshka

Copy link
Copy Markdown

Addressing #4184.

Not including zstd jni, to use this I assume one would have to manually enable it (just like one has to do it now for zio-http to start accepting zstd content-encoding)

Copilot AI review requested due to automatic review settings June 24, 2026 14:52
@CLAassistant

CLAassistant commented Jun 24, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@netlify

netlify Bot commented Jun 24, 2026

Copy link
Copy Markdown

Deploy Preview for zio-http ready!

Name Link
🔨 Latest commit 2ce45f2
🔍 Latest deploy log https://app.netlify.com/projects/zio-http/deploys/6a3bef29ffdf390008d2e85f
😎 Deploy Preview https://deploy-preview-4185--zio-http.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds server-side zstd response compression support (Accept-Encoding negotiation via Netty HttpContentCompressor), aligning with the existing ability to accept Content-Encoding: zstd when users provide the JNI dependency.

Changes:

  • Introduces CompressionOptions.Zstd plus ZstdConfig and a CompressionOptions.zstd(...) constructor.
  • Extends CompressionOptions.config parsing to recognize "type" = "zstd" and read zstd-specific parameters.
  • Adds Netty conversion support for zstd via StandardCompressionOptions.zstd(...).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
zio-http/shared/src/main/scala/zio/http/Server.scala Adds zstd compression option/config and updates config parsing to support selecting zstd.
zio-http/jvm/src/main/scala/zio/http/netty/model/Conversions.scala Maps the new zstd compression option into Netty StandardCompressionOptions.zstd(...).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread zio-http/shared/src/main/scala/zio/http/Server.scala
Comment thread zio-http/shared/src/main/scala/zio/http/Server.scala Outdated
@netlify

netlify Bot commented Jun 24, 2026

Copy link
Copy Markdown

Deploy Preview for zio-http ready!

Name Link
🔨 Latest commit bcbb9d4
🔍 Latest deploy log https://app.netlify.com/projects/zio-http/deploys/6aa122f11d7f3e0007ed0ce4
😎 Deploy Preview https://deploy-preview-4185--zio-http.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@987Nabil

Copy link
Copy Markdown
Contributor

@gipeshka Please fix the build. Rebase might just do it

@gipeshka
gipeshka force-pushed the introduce-zstd-for-compression branch from 348ecb6 to dfcbdf6 Compare July 1, 2026 16:21
@gipeshka

gipeshka commented Jul 1, 2026

Copy link
Copy Markdown
Author

@987Nabil thanks for letting me know, it's fixed now

@987Nabil 987Nabil left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Found a functional bug in the zstd defaults — see inline comment. The blockSize/maxEncodeSize defaults are swapped relative to Netty's actual ZstdConstants. With the current values, CompressionOptions.zstd() (no args) sets maxEncodeSize = 65536, so any response body that compresses to more than 64 KB will throw (maxEncodeSize bounds the largest compressible object), while blockSize = Integer.MAX_VALUE is backwards too. Everything else (Conversions.scala mapping, param order into StandardCompressionOptions.zstd(level, blockSize, maxEncodeSize), config parsing wiring, CI/Mima) checks out — this is the one blocking issue.

Comment thread zio-http/shared/src/main/scala/zio/http/Server.scala Outdated
@gipeshka
gipeshka force-pushed the introduce-zstd-for-compression branch from 19bf52c to 31d500d Compare July 6, 2026 09:08
@gipeshka
gipeshka requested review from 987Nabil and Copilot July 6, 2026 09:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

Comment on lines +441 to +445
typ.toLowerCase match {
case "gzip" => gzip(level, bits, mem)
case "deflate" => deflate(level, bits, mem)
case "brotli" => brotli(quantity, lgwin, mode)
case "zstd" => zstd(level, block, maxencode)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@gipeshka this seems to be a legit concern

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

makes sense. @987Nabil what would be the preferred way of solving it? Would isolating level for zstd under a dedicated config prefix like zstdlevel work?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

@987Nabil I've adjusted it via optional. Please have a look

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (3)

zio-http/shared/src/main/scala/zio/http/Server.scala:422

  • All sibling public compression factories document that their defaults correspond to Netty's default option object, but the newly added zstd factory omits that API documentation. Document the same default relationship here so callers can understand the three otherwise non-obvious tuning parameters.
      def zstd(

zio-http/shared/src/main/scala/zio/http/Server.scala:321

  • The new supported encoding is not represented by the typed header API. Header.AcceptEncoding still exposes zstd only as Unknown, and Header.ContentEncoding.parse drops zstd, so a response compressed by this option cannot be observed through response.header(Header.ContentEncoding). Add Zstd variants to both header algebras, update their parsers/rendering, and cover them in HeaderSpec.
      final case class Zstd(cfg: ZstdConfig)       extends CompressionOptions { val name = "zstd"    }

zio-http/jvm/src/main/scala/zio/http/netty/model/Conversions.scala:174

  • This new conversion branch has no end-to-end coverage, although ResponseCompressionSpec verifies the existing response codecs. Add a test-scoped zstd-jni dependency and an integration test that enables only this option, requests Accept-Encoding: zstd, verifies Content-Encoding: zstd, and decompresses the body; a test-scoped dependency would not impose JNI on library consumers.
      case CompressionOptions.Zstd(cfg)    =>
        StandardCompressionOptions.zstd(cfg.level, cfg.blockSize, cfg.maxEncodeSize)

@gipeshka
gipeshka force-pushed the introduce-zstd-for-compression branch from 141aaa5 to fdbbd4c Compare September 4, 2026 14:43
@gipeshka
gipeshka requested a balanced review from Copilot September 7, 2026 09:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The Zstandard path lacks integration coverage, and its configuration keys need normalization.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread zio-http/jvm/src/main/scala/zio/http/netty/model/Conversions.scala
Comment thread zio-http/shared/src/main/scala/zio/http/Server.scala Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Unknown compression types still cause an untyped MatchError during configuration loading.

Review details

Suppressed comments (1)

zio-http/shared/src/main/scala/zio/http/Server.scala:471

  • The algorithm-specific level defaults are fixed, but an unsupported type still falls through this partial match and throws MatchError while loading configuration. Parse with mapOrFail and return InvalidData for unknown values so configuration failures stay typed and actionable.
            case "zstd"    => zstd(level.getOrElse(ZstdConfig.DefaultLevel), block, maxencode)
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Balanced

gipeshka and others added 4 commits September 9, 2026 11:12
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@gipeshka
gipeshka force-pushed the introduce-zstd-for-compression branch from 8d6267e to bcbb9d4 Compare September 9, 2026 09:12
case CompressionOptions.Brotli(cfg) =>
StandardCompressionOptions.brotli(cfg.quality, cfg.lgwin, brotliModeToJava(cfg.mode))
case CompressionOptions.Zstd(cfg) =>
StandardCompressionOptions.zstd(cfg.level, cfg.blockSize, cfg.maxEncodeSize)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please add an end-to-end test for this new path. A test-scoped zstd-jni dependency can configure only CompressionOptions.zstd(), request Accept-Encoding: zstd, assert the response encoding, and decompress the body. Including a response larger than 64 KiB would also protect the corrected blockSize/maxEncodeSize defaults.

@@ -344,6 +344,7 @@ object Server extends ServerPlatformSpecific {
final case class GZip(cfg: DeflateConfig) extends CompressionOptions { val name = "gzip" }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Adding Zstd here makes it a supported response content coding, but the typed header API is not updated: Header.ContentEncoding.parse("zstd") currently fails, and AcceptEncoding can represent it only as Unknown. Please add typed Zstd variants to both header algebras, update parsing/rendering, and cover them in HeaderSpec.

@@ -432,20 +445,30 @@ object Server extends ServerPlatformSpecific {
): CompressionOptions =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could this public factory get Scaladoc like the gzip/deflate/brotli factories above? In particular, document the Netty defaults and that callers must provide the optional zstd-jni runtime dependency; otherwise selecting this option fails during Netty option construction.

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.

4 participants