Skip to content

fix: use gzip only#212

Merged
rustatian merged 2 commits intomasterfrom
fix/use-gzip-only
Feb 19, 2026
Merged

fix: use gzip only#212
rustatian merged 2 commits intomasterfrom
fix/use-gzip-only

Conversation

@rustatian
Copy link
Member

@rustatian rustatian commented Feb 19, 2026

Reason for This PR

closes: roadrunner-server/roadrunner#2293

Description of Changes

  • Turn off compressors other than gzip.

License Acceptance

By submitting this pull request, I confirm that my contribution is made under
the terms of the MIT license.

PR Checklist

[Author TODO: Meet these criteria.]
[Reviewer TODO: Verify that these criteria are met. Request changes if not]

  • All commits in this PR are signed (git commit -s).
  • The reason for this PR is clearly provided (issue no. or explanation).
  • The description of changes is clear and encompassing.
  • Any required documentation changes (code and docs) are included in this PR.
  • Any user-facing changes are mentioned in CHANGELOG.md.
  • All added/changed functionality is tested.

Summary by CodeRabbit

  • Chores

    • Updated Go toolchain to 1.26
    • Enhanced linter configuration (enabled revive defaults; disabled var-naming)
  • Documentation

    • Added gzip plugin package documentation
    • Added test package documentation scaffolds for integration and mock logger tests
  • CI

    • Updated workflow matrix (PHP 8.5) and refined coverage artifact collection and summary generation

Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
@rustatian rustatian self-assigned this Feb 19, 2026
Copilot AI review requested due to automatic review settings February 19, 2026 13:47
@rustatian rustatian added bug Something isn't working enhancement New feature or request labels Feb 19, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

📝 Walkthrough

Walkthrough

This PR adds lazy, concurrency-safe initialization for the gzip middleware, explicitly disables zstd while enabling gzip, updates the Go toolchain to 1.26, adds package doc files for plugin and tests, and updates revive linter settings.

Changes

Cohort / File(s) Summary
Linter & CI config
\.golangci\.yml, .github/workflows/linux.yml
Adds revive linter settings (enable-default-rules, disables var-naming), updates CI matrix formatting and codecov artifact handling/paths.
Go toolchain
go.mod
Bumps Go version to go 1.26.
Package docs (plugin & tests)
doc.go, tests/doc.go, tests/mock/doc.go
Adds minimal package documentation files for the gzip plugin and test/mock packages.
Gzip middleware logic
plugin.go
Introduces sync.Once + defaultWrapper for lazy, concurrency-safe gzip wrapper initialization; replaces direct gzhttp.GzipHandler usage and configures wrapper to disable zstd and enable gzip.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🐰 I wove a wrapper, soft and spry,

once it wakes, zstd says goodbye,
gzip hums low, responses fly,
a rabbit cheers beneath the sky.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Out of Scope Changes check ❓ Inconclusive Most changes are directly scoped to fixing gzip compression; however, the Go version bump from 1.25 to 1.26 and PHP 8.4 to 8.5 updates in CI are maintenance changes that may not be directly related to the issue. Verify whether the Go and PHP version updates are necessary for the gzip fix or if they should be in a separate PR.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: use gzip only' clearly summarizes the main change - disabling other compressors to use only gzip, matching the PR's primary objective.
Description check ✅ Passed The PR description includes the required sections: reason with issue link, description of changes, license acceptance, and completed checklist items covering commits, documentation, and testing.
Linked Issues check ✅ Passed The code changes implement the primary objective from issue #2293 by adding Zstd disablement in the gzip middleware configuration and wrapper initialization.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/use-gzip-only

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the RoadRunner gzip plugin to ensure only gzip compression is used, addressing roadrunner-server/roadrunner#2293, while also adjusting Go/tooling and lint configuration.

Changes:

  • Replace gzhttp.GzipHandler usage with a gzhttp.NewWrapper(...) configured to disable Zstd.
  • Bump workspace/module Go version declarations and remove the root toolchain pin.
  • Enable Revive default rules and add missing package doc stubs to satisfy linting expectations.

Reviewed changes

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

Show a summary per file
File Description
plugin.go Wrap middleware with a lazily-initialized gzhttp wrapper configured to disable Zstd.
go.mod Updates go directive to 1.26 and removes toolchain directive.
go.work Updates workspace go directive to 1.26.
.golangci.yml Enables Revive default rules (with var-naming disabled).
doc.go Adds package documentation comment for gzip package.
tests/doc.go Adds package documentation comment for tests package.
tests/mock/doc.go Adds package documentation comment for mock logger package.
Comments suppressed due to low confidence (1)

plugin.go:28

  • The doc comment refers to GzipHandler, but the function is named gzipHandler (unexported). Please update the comment to match the identifier name (and consider rephrasing “allows to easily” for correct grammar).
// GzipHandler allows to easily wrap an http handler with default settings.
func gzipHandler(h http.Handler) http.HandlerFunc {

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

@@ -1,4 +1,4 @@
go 1.25
go 1.26
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

Bumping the workspace go version to 1.26 changes the minimum Go toolchain needed to work in this repo (including the ./tests module used in the workspace). Please confirm this is intended and kept consistent with the module go.mod / CI toolchains.

Suggested change
go 1.26
go 1.22

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +64
revive:
enable-default-rules: true
rules:
- name: var-naming
disabled: true
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

Enabling Revive’s default rules can introduce new lint failures and effectively changes the repo’s lint policy. Since the PR description is about gzip-only compression, consider calling this out explicitly (or splitting lint-policy changes into a separate PR) to keep scope clear.

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +35
var onceDefault sync.Once //nolint:gochecknoglobals
var defaultWrapper func(http.Handler) http.HandlerFunc //nolint:gochecknoglobals

// GzipHandler allows to easily wrap an http handler with default settings.
func gzipHandler(h http.Handler) http.HandlerFunc {
onceDefault.Do(func() {
var err error
defaultWrapper, err = gzhttp.NewWrapper(gzhttp.PreferZstd(false), gzhttp.EnableZstd(false), gzhttp.EnableGzip(true))
if err != nil {
panic(err)
}
})
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

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

gzhttp.NewWrapper errors are currently handled via panic, which can crash the whole process at runtime. Consider constructing the wrapper during (*Plugin).Init() (storing it on the Plugin struct) and returning the error from Init, which also avoids the need for global state and //nolint:gochecknoglobals.

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
plugin.go (3)

24-25: Group related package-level variables into a single var block.

Two consecutive top-level var declarations for tightly coupled variables is unconventional; grouping them is the idiomatic Go style and allows a single //nolint directive.

✏️ Proposed grouping
-var onceDefault sync.Once                              //nolint:gochecknoglobals
-var defaultWrapper func(http.Handler) http.HandlerFunc //nolint:gochecknoglobals
+var ( //nolint:gochecknoglobals
+	onceDefault    sync.Once
+	defaultWrapper func(http.Handler) http.HandlerFunc
+)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin.go` around lines 24 - 25, Group the two package-level variables into a
single var block: replace the separate declarations of onceDefault and
defaultWrapper with one var (...) block containing both onceDefault sync.Once
and defaultWrapper func(http.Handler) http.HandlerFunc, and move the single
//nolint:gochecknoglobals comment to apply to that var block so the linter
exemption covers both symbols.

31-31: PreferZstd(false) and EnableGzip(true) are redundant.

EnableGzip enables or disables gzip compression, and it is enabled by default. The PreferZstd option controls which codec is preferred when the client accepts both with equal quality values. Since EnableZstd(false) already disables zstd entirely, the tie-breaking PreferZstd(false) has no effect. Dropping both redundant options makes the intent clearer: only EnableZstd(false) is needed to enforce gzip-only behavior.

✏️ Proposed simplification
-		defaultWrapper, err = gzhttp.NewWrapper(gzhttp.PreferZstd(false), gzhttp.EnableZstd(false), gzhttp.EnableGzip(true))
+		defaultWrapper, err = gzhttp.NewWrapper(gzhttp.EnableZstd(false))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin.go` at line 31, Remove the redundant gzip-related options when
constructing the wrapper: in the call to gzhttp.NewWrapper that sets
defaultWrapper, drop gzhttp.PreferZstd(false) and gzhttp.EnableGzip(true) and
keep only gzhttp.EnableZstd(false) so the intent (disable zstd, use gzip
default) is clear; update the invocation of gzhttp.NewWrapper accordingly around
the defaultWrapper variable.

27-27: Doc comment mentions GzipHandler but function is gzipHandler.

Go's doc-comment convention requires the first word to match the declared identifier. The current comment will not render correctly with go doc or godoc.

✏️ Proposed fix
-// GzipHandler allows to easily wrap an http handler with default settings.
+// gzipHandler allows to easily wrap an http handler with default settings.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugin.go` at line 27, The doc comment's first word must match the declared
identifier: update the comment to start with "gzipHandler" to match the
unexported function name gzipHandler, or if the function was meant to be
exported, rename the function to GzipHandler and keep the comment as-is; ensure
the chosen identifier (gzipHandler or GzipHandler) is used consistently in the
comment so it follows Go's godoc convention.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugin.go`:
- Around line 29-35: The sync.Once initializer currently panics inside
onceDefault.Do (calling gzhttp.NewWrapper) which can leave defaultWrapper nil if
the panic is recovered; change this by moving the wrapper initialization into
the package Init() function (call gzhttp.NewWrapper there, handle the error with
a fatal log or return an error) and then simplify Middleware to call
defaultWrapper(h) directly; remove gzipHandler, onceDefault, and the sync import
after moving initialization so there is no panic inside Do and error handling is
explicit.

---

Nitpick comments:
In `@plugin.go`:
- Around line 24-25: Group the two package-level variables into a single var
block: replace the separate declarations of onceDefault and defaultWrapper with
one var (...) block containing both onceDefault sync.Once and defaultWrapper
func(http.Handler) http.HandlerFunc, and move the single
//nolint:gochecknoglobals comment to apply to that var block so the linter
exemption covers both symbols.
- Line 31: Remove the redundant gzip-related options when constructing the
wrapper: in the call to gzhttp.NewWrapper that sets defaultWrapper, drop
gzhttp.PreferZstd(false) and gzhttp.EnableGzip(true) and keep only
gzhttp.EnableZstd(false) so the intent (disable zstd, use gzip default) is
clear; update the invocation of gzhttp.NewWrapper accordingly around the
defaultWrapper variable.
- Line 27: The doc comment's first word must match the declared identifier:
update the comment to start with "gzipHandler" to match the unexported function
name gzipHandler, or if the function was meant to be exported, rename the
function to GzipHandler and keep the comment as-is; ensure the chosen identifier
(gzipHandler or GzipHandler) is used consistently in the comment so it follows
Go's godoc convention.

Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
@codecov
Copy link

codecov bot commented Feb 19, 2026

Codecov Report

❌ Patch coverage is 75.00000% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 56.52%. Comparing base (d604ac0) to head (cd3b3f2).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
plugin.go 75.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           master     #212       +/-   ##
===========================================
+ Coverage        0   56.52%   +56.52%     
===========================================
  Files           0        1        +1     
  Lines           0       23       +23     
===========================================
+ Hits            0       13       +13     
- Misses          0        8        +8     
- Partials        0        2        +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
.github/workflows/linux.yml (1)

82-88: Hardcoded module path in the awk filter will silently drop all coverage on a major-version bump.

The pattern /^github\.com\/roadrunner-server\/gzip\/v5\// hardcodes the module major version (v5). If the module is ever bumped to v6, every coverage line will fail to match, the sub will never fire, and summary.txt will contain only the mode: atomic header — producing a zero-coverage report with no error surfacing from either awk or codecov-action (since fail_ci_if_error: false).

♻️ Suggested fix: derive the prefix dynamically
-          tail -q -n +2 coverage/*.out >> summary.txt
-          awk '
-            NR == 1 { print; next }
-            /^github\.com\/roadrunner-server\/gzip\/v5\// {
-              sub(/^github\.com\/roadrunner-server\/gzip\/v5\//, "", $0)
-              print
-            }
-          ' summary.txt > summary.filtered.txt
-          mv summary.filtered.txt summary.txt
+          tail -q -n +2 coverage/*.out >> summary.txt
+          MODULE=$(go list -m)
+          awk -v mod="$MODULE/" '
+            NR == 1 { print; next }
+            index($0, mod) == 1 {
+              sub(mod, "", $0)
+              print
+            }
+          ' summary.txt > summary.filtered.txt
+          mv summary.filtered.txt summary.txt

go list -m reads the module path directly from go.mod, so the filter stays correct across any future major version change without a manual edit. The codecov job already has the repo checked out (Line 72–73), so go is available via actions/setup-go in the prior job — though go must also be available in the codecov job. If preferred, the prefix can be extracted from the first coverage file's path instead:

+          MODULE_PREFIX=$(head -2 summary.txt | tail -1 | grep -oP '^[^:]+' | sed 's|/[^/]*$|/|')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/linux.yml around lines 82 - 88, The awk filter is
hardcoded to the module major version via the pattern
/^github\.com\/roadrunner-server\/gzip\/v5\// which will stop matching on a
major-version bump; update the pipeline so the prefix is derived dynamically
(e.g., call `go list -m` to get the module path or extract the prefix from the
first coverage file path) and then use that computed prefix in the awk
substitution that transforms summary.txt into summary.filtered.txt; ensure the
computed prefix replaces the literal
`github\.com\/roadrunner-server\/gzip\/v5\//` in the awk script so the sub(...)
runs correctly across major-version changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.github/workflows/linux.yml:
- Around line 82-88: The awk filter is hardcoded to the module major version via
the pattern /^github\.com\/roadrunner-server\/gzip\/v5\// which will stop
matching on a major-version bump; update the pipeline so the prefix is derived
dynamically (e.g., call `go list -m` to get the module path or extract the
prefix from the first coverage file path) and then use that computed prefix in
the awk substitution that transforms summary.txt into summary.filtered.txt;
ensure the computed prefix replaces the literal
`github\.com\/roadrunner-server\/gzip\/v5\//` in the awk script so the sub(...)
runs correctly across major-version changes.

@rustatian rustatian merged commit 13d2ae8 into master Feb 19, 2026
9 checks passed
@rustatian rustatian deleted the fix/use-gzip-only branch February 19, 2026 14:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[🐛 BUG]: zip middleware broken after upgrading from

2 participants