🔥 feat: Add request inspection helpers#3727
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds five boolean query methods to the Ctx API (Matched, IsMiddleware, HasBody, IsWebSocket, IsPreflight), updates the Ctx interface and DefaultCtx implementation, adds unit tests for those methods, and documents them in API and "what's new" docs. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant App
participant Middleware as Middleware Handler
participant Router
participant Ctx
Client->>App: HTTP request
App->>Middleware: invoke middleware(c)
Middleware->>Ctx: call c.Matched()/c.IsMiddleware()/c.HasBody()/c.IsWebSocket()/c.IsPreflight()
Middleware->>Router: c.Next()
Router-->>Middleware: route handler (found) / no handler
Middleware->>App: return (may use inspected flags)
App-->>Client: response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3727 +/- ##
==========================================
- Coverage 92.08% 92.02% -0.07%
==========================================
Files 115 115
Lines 11535 11585 +50
==========================================
+ Hits 10622 10661 +39
- Misses 662 670 +8
- Partials 251 254 +3
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
⚠️ Performance Alert ⚠️
Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.
| Benchmark suite | Current: dd6a8f7 | Previous: e83a762 | Ratio |
|---|---|---|---|
Benchmark_Compress_Levels_Parallel/Brotli_LevelBestCompression - B/op |
1 B/op |
0 B/op |
+∞ |
This comment was automatically generated by workflow using github-action-benchmark.
|
Nice PR for me. Suggestions from me:
|
Makes sense, will update! |
There was a problem hiding this comment.
Pull Request Overview
This PR adds five new inspection helper methods to the Fiber Ctx interface to simplify common request analysis patterns. The helpers detect route matching status, middleware execution, request body presence, WebSocket upgrades, and CORS preflight requests.
- Adds
Matched(),IsMiddleware(),HasBody(),IsWebSocket(), andIsPreflight()methods to the Ctx interface - Provides comprehensive test coverage for all new helper methods
- Documents the new methods in the API guide with usage examples
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| ctx.go | Implements the five new helper methods with proper HTTP header inspection logic |
| ctx_interface_gen.go | Adds method signatures to the Ctx interface |
| ctx_test.go | Comprehensive test suite covering all scenarios for the new helpers |
| docs/api/ctx.md | Documentation with signatures and usage examples |
| docs/whats_new.md | Brief changelog entries for the new features |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (14)
docs/whats_new.md (1)
491-496: Polish phrasing of new Ctx helpers (and align with code semantics).Minor grammar/style tweaks and clarify IsMiddleware intent. Also addresses the linter hint.
- - **Matched**: Detects when the current request path matched a registered route. - - **IsMiddleware**: Indicates if the current handler was registered as middleware. - - **HasBody**: Quickly checks whether the request includes a body. - - **IsWebSocket**: Reports if the request attempts a WebSocket upgrade. - - **IsPreflight**: Identifies CORS preflight requests before handlers run. + - **Matched**: Returns true when the current request path was matched by the router. + - **IsMiddleware**: Returns true if the current handler comes from a middleware route (registered via `app.Use`). + - **HasBody**: Returns true if the request includes a body. + - **IsWebSocket**: Returns true if the request attempts a WebSocket upgrade. + - **IsPreflight**: Returns true for CORS preflight requests.ctx.go (4)
309-313: IsMiddleware(): clarify semantics vs route-level middleware.This reports true only for routes registered via App.Use (c.route.use). Route-level middleware attached to a non-use route will return false, which is fine if that’s the intended contract. Consider reflecting that nuance in the function comment (and docs) to avoid confusion.
Apply the same docstring refinement suggested in ctx_interface_gen.go.
314-321: HasBody(): acceptable heuristic.Content-Length > 0 OR non-empty body covers common cases. If you want to avoid touching the body buffer when CL is unknown (chunked), you could first check Transfer-Encoding, but this is optional.
322-330: IsWebSocket(): solid header checks; minor micro-optimization optional.Logic matches the typical handshake. Optional: avoid an allocation from ToLowerBytes by scanning for 'u'/'U' and comparing case-insensitively, but readability likely wins here.
331-335: IsPreflight(): consider requiring Origin header to avoid false positives.Per CORS, preflights are OPTIONS requests with both Origin and Access-Control-Request-Method. Tightening the check reduces accidental matches from generic OPTIONS requests.
-func (c *DefaultCtx) IsPreflight() bool { - return c.Method() == MethodOptions && len(c.fasthttp.Request.Header.Peek(HeaderAccessControlRequestMethod)) > 0 -} +func (c *DefaultCtx) IsPreflight() bool { + if c.Method() != MethodOptions { + return false + } + hdr := &c.fasthttp.Request.Header + if len(hdr.Peek(HeaderAccessControlRequestMethod)) == 0 { + return false + } + // Guard on Origin to align with CORS preflight semantics + return len(hdr.Peek(HeaderOrigin)) > 0 +}ctx_test.go (5)
4931-4955: Matched(): add an after-Next assertion to exercise both matched and 404 pathsExercise Matched() from middleware after c.Next() to confirm true on matched routes and false on 404s.
app.Get("/two", func(c Ctx) error { return c.SendStatus(StatusOK) }) + // Assert Matched() after the downstream chain has executed + app.Use(func(c Ctx) error { + err := c.Next() + if c.Response().StatusCode() == StatusNotFound { + require.False(t, c.Matched(), "Matched() should be false on 404") + } else { + require.True(t, c.Matched(), "Matched() should be true when a route matched") + } + return err + }) + app.Use(func(c Ctx) error { require.False(t, c.Matched()) return c.Status(StatusNotFound).SendString("not found") })
4957-4973: Nit: assert error handler bodyAlso assert the body content to fully specify behavior.
resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil)) require.NoError(t, err) require.Equal(t, StatusNotFound, resp.StatusCode) + b, _ := io.ReadAll(resp.Body) + require.Equal(t, "Not Found", string(b))
5017-5037: HasBody: add Content-Length: 0 caseGuard against regressions where zero length is treated as present.
require.True(t, ctxWithHeader.HasBody()) + ctxZero := app.AcquireCtx(&fasthttp.RequestCtx{}) + require.NotNil(t, ctxZero) + t.Cleanup(func() { app.ReleaseCtx(ctxZero) }) + ctxZero.Request().Header.SetContentLength(0) + require.False(t, ctxZero.HasBody()) + ctxWithoutBody := app.AcquireCtx(&fasthttp.RequestCtx{})
5039-5054: IsWebSocket: add case-insensitivity and multi-token ConnectionIncrease robustness of the check.
require.True(t, ws.IsWebSocket()) + ws2 := app.AcquireCtx(&fasthttp.RequestCtx{}) + require.NotNil(t, ws2) + t.Cleanup(func() { app.ReleaseCtx(ws2) }) + ws2.Request().Header.Set(HeaderConnection, "keep-alive, Upgrade") + ws2.Request().Header.Set(HeaderUpgrade, "WebSocket") + require.True(t, ws2.IsWebSocket()) + non := app.AcquireCtx(&fasthttp.RequestCtx{})
5056-5074: IsPreflight: add non-OPTIONS guardPreflight must be OPTIONS even if ACRM is present.
require.True(t, pre.IsPreflight()) + notOpt := &fasthttp.RequestCtx{} + notOpt.Request.Header.SetMethod(MethodGet) + notOpt.Request.Header.Set(HeaderAccessControlRequestMethod, MethodGet) + pre2 := app.AcquireCtx(notOpt) + require.NotNil(t, pre2) + t.Cleanup(func() { app.ReleaseCtx(pre2) }) + require.False(t, pre2.IsPreflight()) + optCtx := &fasthttp.RequestCtx{}docs/api/ctx.md (4)
387-403: Clarify when to use Matched() vs Route()Explicitly call out safe usage timing relative to Next().
### Matched -Returns `true` if the current request path was matched by the router. +Returns `true` if the current request path was matched by the router. +Note: Unlike c.Route(), Matched() can be called in middleware before c.Next().
419-435: HasBody: document zero-length behaviorTiny clarification improves predictability.
### HasBody -Returns `true` if the incoming request contains a body or a `Content-Length` header greater than zero. +Returns `true` if the incoming request contains a body or a `Content-Length` header greater than zero. Returns `false` when `Content-Length` is `0`.
444-451: IsWebSocket example: avoid calling Next() from a terminal handlerUse a simple OK to keep the example minimal and accurate.
app.Get("/", func(c fiber.Ctx) error { if c.IsWebSocket() { // handle websocket } - return c.Next() + return c.Status(fiber.StatusOK).SendString("OK") })
453-469: IsPreflight: emphasize both conditionsMinor wording tweak for clarity.
-Returns `true` if the request is a CORS preflight (`OPTIONS` + `Access-Control-Request-Method`). +Returns `true` only if the request is a CORS preflight (`OPTIONS` method and an `Access-Control-Request-Method` header).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
ctx.go(2 hunks)ctx_interface_gen.go(1 hunks)ctx_test.go(1 hunks)docs/api/ctx.md(1 hunks)docs/whats_new.md(1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Format Go code using gofumpt (enforced viamake format)
Ensure code passes golangci-lint checks (enforced viamake lint)
Optimize struct field alignment using betteralign (enforced viamake betteralign)
Modernize Go code using gopls modernize (enforced viamake modernize)
Files:
ctx_interface_gen.goctx.goctx_test.go
docs/**
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Review and update the contents of the
docsfolder if necessary when modifying code
Files:
docs/whats_new.mddocs/api/ctx.md
🧠 Learnings (2)
📚 Learning: 2024-11-10T23:44:13.704Z
Learnt from: gaby
PR: gofiber/fiber#3193
File: middleware/adaptor/adaptor.go:111-111
Timestamp: 2024-11-10T23:44:13.704Z
Learning: In the `middleware/adaptor/adaptor.go` file of the Fiber framework, when updating context handling, replacing `c.Context()` with `c.RequestCtx()` is appropriate to access the `fasthttp.RequestCtx`.
Applied to files:
ctx_interface_gen.goctx.godocs/whats_new.mddocs/api/ctx.md
📚 Learning: 2024-11-08T04:10:42.990Z
Learnt from: gaby
PR: gofiber/fiber#3193
File: middleware/cache/cache_test.go:897-897
Timestamp: 2024-11-08T04:10:42.990Z
Learning: In the Fiber framework, `Context()` is being renamed to `RequestCtx()`, and `UserContext()` to `Context()` to improve clarity and align with Go's context conventions.
Applied to files:
ctx.go
🧬 Code graph analysis (2)
ctx.go (1)
constants.go (4)
HeaderConnection(188-188)HeaderUpgrade(278-278)MethodOptions(12-12)HeaderAccessControlRequestMethod(205-205)
ctx_test.go (3)
app.go (3)
New(515-628)Config(113-418)Error(62-65)ctx_interface_gen.go (1)
Ctx(17-424)constants.go (8)
StatusOK(52-52)StatusNotFound(77-77)MethodGet(5-5)ErrNotFound(122-122)HeaderConnection(188-188)HeaderUpgrade(278-278)MethodOptions(12-12)HeaderAccessControlRequestMethod(205-205)
🪛 LanguageTool
docs/whats_new.md
[grammar] ~491-~491: There might be a mistake here.
Context: ...request path matched a registered route. - IsMiddleware: Indicates if the current...
(QB_NEW_EN)
🔇 Additional comments (5)
ctx_interface_gen.go (1)
111-120: Public Ctx surface LGTM; tighten docstrings for clarity.Tighten the docs as follows:
- // IsMiddleware returns true if the current request handler was registered as middleware. + // IsMiddleware returns true if the current handler comes from a middleware route (registered via App.Use). - // IsWebSocket returns true if the request includes a WebSocket upgrade handshake. + // IsWebSocket returns true if Connection contains "upgrade" and Upgrade equals "websocket" (case-insensitive).The
IsPreflightdoc is already sufficiently clear. No staleIsFound/IsNotFoundreferences remain.ctx.go (2)
8-8: bytes import – OK.Required for EqualFold/Contains usage in IsWebSocket.
304-307: Matched(): simple and correct.ctx_test.go (2)
4975-4996: LGTM: baseline coverage for Matched()Covers positive path and fallback middleware path.
4998-5015: LGTM: IsMiddleware semantics validatedAsserts true in Use and false in route handler.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces several useful request inspection helpers to the Ctx object, namely HasBody, IsWebSocket, IsPreflight, and Matched, complete with documentation and tests. The implementation is solid, but I've identified a couple of areas for improvement. The HasBody function can be made more concise. More importantly, the IsWebSocket function has a potential correctness issue in how it parses the Connection header, which could result in false positives. I've provided suggestions to address these points.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
ctx.go (1)
321-327: Simplify HasBody() to a single return.Minor readability win; same behavior.
Apply this diff:
func (c *DefaultCtx) HasBody() bool { - if c.fasthttp.Request.Header.ContentLength() > 0 { - return true - } - return len(c.fasthttp.Request.Body()) > 0 + return c.fasthttp.Request.Header.ContentLength() > 0 || + len(c.fasthttp.Request.Body()) > 0 }
🧹 Nitpick comments (1)
ctx.go (1)
345-355: IsPreflight(): logic is correct; optional micro-tweak.Consider hoisting the header pointer here as well (matches IsWebSocket style) for tiny clarity/consistency.
Apply this diff:
func (c *DefaultCtx) IsPreflight() bool { if c.Method() != MethodOptions { return false } - hdr := &c.fasthttp.Request.Header + hdr := &c.fasthttp.Request.Header if len(hdr.Peek(HeaderAccessControlRequestMethod)) == 0 { return false } return len(hdr.Peek(HeaderOrigin)) > 0 }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (3)
ctx.go(2 hunks)ctx_test.go(1 hunks)docs/api/ctx.md(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- ctx_test.go
- docs/api/ctx.md
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go
📄 CodeRabbit inference engine (AGENTS.md)
**/*.go: Format Go code using gofumpt (enforced viamake format)
Ensure code passes golangci-lint checks (enforced viamake lint)
Optimize struct field alignment using betteralign (enforced viamake betteralign)
Modernize Go code using gopls modernize (enforced viamake modernize)
Files:
ctx.go
🧠 Learnings (1)
📚 Learning: 2024-11-10T23:44:13.704Z
Learnt from: gaby
PR: gofiber/fiber#3193
File: middleware/adaptor/adaptor.go:111-111
Timestamp: 2024-11-10T23:44:13.704Z
Learning: In the `middleware/adaptor/adaptor.go` file of the Fiber framework, when updating context handling, replacing `c.Context()` with `c.RequestCtx()` is appropriate to access the `fasthttp.RequestCtx`.
Applied to files:
ctx.go
🧬 Code graph analysis (1)
ctx.go (1)
constants.go (5)
HeaderConnection(188-188)HeaderUpgrade(278-278)MethodOptions(12-12)HeaderAccessControlRequestMethod(205-205)HeaderOrigin(206-206)
🪛 GitHub Check: modernize
ctx.go
[failure] 352-352:
Ranging over SplitSeq is more efficient
🪛 GitHub Actions: Modernize Lint
ctx.go
[error] 352-352: Command failed: go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -test=false ./...: /home/runner/work/fiber/fiber/ctx.go:352:20: Ranging over SplitSeq is more efficient
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: unit (1.25.x, macos-13)
- GitHub Check: unit (1.25.x, ubuntu-latest)
- GitHub Check: unit (1.25.x, windows-latest)
- GitHub Check: repeated
- GitHub Check: unit (1.25.x, macos-latest)
- GitHub Check: Compare
- GitHub Check: lint
- GitHub Check: govulncheck-check
🔇 Additional comments (4)
ctx.go (4)
8-8: Import addition is appropriate.bytes is required for the tokenized header parsing below.
304-307: Matched(): simple, correct exposure of router outcome.Returns the internal flag; reset path and router set/update already manage it. LGTM.
309-319: IsMiddleware() semantics—double‑check edge cases.Logic looks sane: true for app/group
.Use(...)routes, and for early handlers in a multi-handler chain. Please verify it returns false for the last handler in a multi-handler route and true for earlier ones (two test cases).
329-343: Use bytes.SplitSeq and hoist Header lookup for efficiencyReplace the allocation-heavy split and repeated header lookups:
func (c *DefaultCtx) IsWebSocket() bool { - conn := c.fasthttp.Request.Header.Peek(HeaderConnection) + hdr := &c.fasthttp.Request.Header + conn := hdr.Peek(HeaderConnection) var isUpgrade bool - for _, v := range bytes.Split(conn, []byte{','}) { + for v := range bytes.SplitSeq(conn, []byte{','}) { if bytes.EqualFold(bytes.TrimSpace(v), []byte("upgrade")) { isUpgrade = true break } } if !isUpgrade { return false } - return bytes.EqualFold(c.fasthttp.Request.Header.Peek(HeaderUpgrade), []byte("websocket")) + return bytes.EqualFold(hdr.Peek(HeaderUpgrade), []byte("websocket")) }Ensure the project’s minimum Go version is 1.24 or newer before applying.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces several helpful request inspection methods to the Ctx object: Matched, IsMiddleware, HasBody, IsWebSocket, and IsPreflight. The changes are well-implemented, include thorough tests, and are properly documented. My feedback is minor and focuses on a small code simplification for better readability and maintainability.
Summary
HasBody,IsWebSocket,IsPreflight, andMatchedhelpers onCtxFixes #3721