Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 fix: Align cache middleware with RFC7231 #3283

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

miyamo2
Copy link
Contributor

@miyamo2 miyamo2 commented Jan 18, 2025

Description

This pull request updates the cache middleware to avoid caching uncacheable status codes.
This change improves cache accuracy and saves cache storage size.

Responses with status codes that are defined as cacheable by default
(e.g., 200, 203, 204, 206, 300, 301, 404, 405, 410, 414, and 501 in
this specification)

https://datatracker.ietf.org/doc/html/rfc7231#section-6.1

See also:

However, for 418: TeaPot, although not actually cacheable, it continues to be cacheable since it is used in benchmark tests.

Thank you.

Fixes -

Type of change

  • Enhancement (improvement to existing features and functionality)

Checklist

  • Followed the inspiration of the Express.js framework for new functionalities, making them similar in usage.
  • Conducted a self-review of the code and provided comments for complex or critical parts.
  • Updated the documentation in the /docs/ directory for Fiber's documentation.
  • Added or updated unit tests to validate the effectiveness of the changes or new features.
  • Ensured that new and existing unit tests pass locally with the changes.
  • Verified that any new dependencies are essential and have been agreed upon by the maintainers/community.
  • Aimed for optimal performance with minimal allocations in the new code.
  • Provided benchmarks for the new code to analyze and improve upon.

Benchmarks(on GitHub Codespaces)

Before

goos: linux
goarch: amd64
pkg: github.com/gofiber/fiber/v3/middleware/cache
cpu: AMD EPYC 7763 64-Core Processor                
Benchmark_Cache
Benchmark_Cache-2                        3266803               371.2 ns/op            16 B/op          2 allocs/op
Benchmark_Cache-2                        3526135               428.6 ns/op            16 B/op          2 allocs/op
Benchmark_Cache-2                        2984780               349.5 ns/op            16 B/op          2 allocs/op
Benchmark_Cache-2                        3376264               368.0 ns/op            16 B/op          2 allocs/op
Benchmark_Cache_Storage
Benchmark_Cache_Storage-2                1553983               802.6 ns/op           224 B/op          6 allocs/op
Benchmark_Cache_Storage-2                1389811               756.7 ns/op           224 B/op          6 allocs/op
Benchmark_Cache_Storage-2                1411192               758.8 ns/op           224 B/op          6 allocs/op
Benchmark_Cache_Storage-2                1491530               949.3 ns/op           224 B/op          6 allocs/op
Benchmark_Cache_AdditionalHeaders
Benchmark_Cache_AdditionalHeaders-2      2644476               455.1 ns/op            16 B/op          2 allocs/op
Benchmark_Cache_AdditionalHeaders-2      2749446               443.8 ns/op            16 B/op          2 allocs/op
Benchmark_Cache_AdditionalHeaders-2      2726913               494.1 ns/op            16 B/op          2 allocs/op
Benchmark_Cache_AdditionalHeaders-2      2745980               471.7 ns/op            16 B/op          2 allocs/op
Benchmark_Cache_MaxSize
Benchmark_Cache_MaxSize/Disabled
Benchmark_Cache_MaxSize/Disabled-2        824889              1547 ns/op             312 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Disabled-2        980916              2092 ns/op             388 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Disabled-2        844003              1499 ns/op             310 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Disabled-2        940033              1803 ns/op             397 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Unlim
Benchmark_Cache_MaxSize/Unlim-2           863776              1964 ns/op             663 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Unlim-2           879492              1974 ns/op             704 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Unlim-2           881145              2397 ns/op             703 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Unlim-2           652623              2232 ns/op             589 B/op          7 allocs/op
Benchmark_Cache_MaxSize/LowBounded
Benchmark_Cache_MaxSize/LowBounded-2      693243              1658 ns/op             284 B/op          7 allocs/op
Benchmark_Cache_MaxSize/LowBounded-2      794901              1644 ns/op             232 B/op          7 allocs/op
Benchmark_Cache_MaxSize/LowBounded-2      818232              1630 ns/op             266 B/op          7 allocs/op
Benchmark_Cache_MaxSize/LowBounded-2      849585              1538 ns/op             231 B/op          7 allocs/op
PASS
ok      github.com/gofiber/fiber/v3/middleware/cache    108.535s

After

goos: linux
goarch: amd64
pkg: github.com/gofiber/fiber/v3/middleware/cache
cpu: AMD EPYC 7763 64-Core Processor                
Benchmark_Cache
Benchmark_Cache-2                        3589620               345.4 ns/op            16 B/op          2 allocs/op
Benchmark_Cache-2                        3495650               356.5 ns/op            16 B/op          2 allocs/op
Benchmark_Cache-2                        3435940               363.9 ns/op            16 B/op          2 allocs/op
Benchmark_Cache-2                        3654991               334.5 ns/op            16 B/op          2 allocs/op
Benchmark_Cache_Storage
Benchmark_Cache_Storage-2                1303766               791.9 ns/op           224 B/op          6 allocs/op
Benchmark_Cache_Storage-2                1543819               825.2 ns/op           224 B/op          6 allocs/op
Benchmark_Cache_Storage-2                1560447               777.8 ns/op           224 B/op          6 allocs/op
Benchmark_Cache_Storage-2                1523350               809.8 ns/op           224 B/op          6 allocs/op
Benchmark_Cache_AdditionalHeaders
Benchmark_Cache_AdditionalHeaders-2      2691138               465.4 ns/op            16 B/op          2 allocs/op
Benchmark_Cache_AdditionalHeaders-2      2833256               493.1 ns/op            16 B/op          2 allocs/op
Benchmark_Cache_AdditionalHeaders-2      2475060               437.5 ns/op            16 B/op          2 allocs/op
Benchmark_Cache_AdditionalHeaders-2      2601472               470.0 ns/op            16 B/op          2 allocs/op
Benchmark_Cache_MaxSize
Benchmark_Cache_MaxSize/Disabled
Benchmark_Cache_MaxSize/Disabled-2        796167              1723 ns/op             315 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Disabled-2        616742              1952 ns/op             346 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Disabled-2       1000000              2083 ns/op             384 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Disabled-2        915212              1586 ns/op             403 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Unlim
Benchmark_Cache_MaxSize/Unlim-2           903932              1856 ns/op             690 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Unlim-2           923966              1656 ns/op             679 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Unlim-2           898255              2191 ns/op             693 B/op          7 allocs/op
Benchmark_Cache_MaxSize/Unlim-2           778410              1902 ns/op             581 B/op          7 allocs/op
Benchmark_Cache_MaxSize/LowBounded
Benchmark_Cache_MaxSize/LowBounded-2      833415              1533 ns/op             231 B/op          7 allocs/op
Benchmark_Cache_MaxSize/LowBounded-2      692738              1702 ns/op             231 B/op          7 allocs/op
Benchmark_Cache_MaxSize/LowBounded-2      928842              1437 ns/op             231 B/op          7 allocs/op
Benchmark_Cache_MaxSize/LowBounded-2      838443              1329 ns/op             231 B/op          7 allocs/op
PASS
ok      github.com/gofiber/fiber/v3/middleware/cache    97.527s

@miyamo2 miyamo2 requested a review from a team as a code owner January 18, 2025 09:20
@miyamo2 miyamo2 requested review from gaby, sixcolors, ReneWerner87 and efectn and removed request for a team January 18, 2025 09:20
Copy link
Contributor

coderabbitai bot commented Jan 18, 2025

Walkthrough

This pull request enhances the caching middleware in the Fiber framework by introducing a new variable, cacheableStatusCodes, which defines HTTP status codes that can be cached. A conditional check is implemented in the middleware handler to prevent caching for responses with non-cacheable status codes. If a status code is not in the cacheableStatusCodes map, the cache header is set to cacheUnreachable, and the response is returned without caching.

Changes

File Change Summary
middleware/cache/cache.go Added cacheableStatusCodes map with predefined cacheable HTTP status codes; implemented conditional logic to prevent caching for uncacheable status codes.
middleware/cache/cache_test.go Added Test_Cache_UncacheableStatusCodes test function to verify cache behavior for various uncacheable status codes.

Possibly related PRs

Suggested labels

🧹 Updates

Suggested reviewers

  • sixcolors
  • gaby
  • efectn
  • ReneWerner87

Poem

🐰 Caching Rabbit's Delight

In middleware's embrace so tight,
Status codes dance left and right,
Some cached, some not—a clever sight!
With headers clear and logic bright,
Our cache now knows just what is right! 🍃


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45a7b06 and 04eb05e.

📒 Files selected for processing (1)
  • middleware/cache/cache.go (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • middleware/cache/cache.go
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: repeated
  • GitHub Check: Compare

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Jan 18, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 84.04%. Comparing base (a42ddc1) to head (04eb05e).
Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3283      +/-   ##
==========================================
- Coverage   84.14%   84.04%   -0.10%     
==========================================
  Files         116      116              
  Lines       11553    11557       +4     
==========================================
- Hits         9721     9713       -8     
- Misses       1402     1411       +9     
- Partials      430      433       +3     
Flag Coverage Δ
unittests 84.04% <100.00%> (-0.10%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

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

Copy link
Contributor

@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 (1)
middleware/cache/cache.go (1)

51-56: LGTM! Consider adding a comment to explain TeaPot status code inclusion.

The list of cacheable status codes aligns well with RFC 7231. However, it would be helpful to add a comment explaining why the TeaPot status code (418) is included despite not being cacheable according to the RFC.

 var cacheableStatusCodes = []int{
 	fiber.StatusOK, fiber.StatusNonAuthoritativeInformation, fiber.StatusNoContent, fiber.StatusPartialContent,
 	fiber.StatusMultipleChoices, fiber.StatusMovedPermanently,
+	// TeaPot status code is included for benchmarking purposes despite not being cacheable according to RFC 7231
 	fiber.StatusNotFound, fiber.StatusMethodNotAllowed, fiber.StatusGone, fiber.StatusTeapot, fiber.StatusRequestURITooLong,
 	fiber.StatusNotImplemented,
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a42ddc1 and 86f9577.

📒 Files selected for processing (2)
  • middleware/cache/cache.go (2 hunks)
  • middleware/cache/cache_test.go (1 hunks)
🧰 Additional context used
🪛 golangci-lint (1.62.2)
middleware/cache/cache_test.go

929-929: error returned from external package is unwrapped: sig: func strconv.Atoi(s string) (int, error)

(wrapcheck)

🪛 GitHub Check: lint
middleware/cache/cache_test.go

[failure] 929-929:
error returned from external package is unwrapped: sig: func strconv.Atoi(s string) (int, error) (wrapcheck)

🪛 GitHub Actions: golangci-lint
middleware/cache/cache_test.go

[error] 929-929: Error returned from external package strconv.Atoi is unwrapped. Consider wrapping the error using fmt.Errorf or custom error types.

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: unit (1.23.x, windows-latest)
  • GitHub Check: Compare
  • GitHub Check: repeated
🔇 Additional comments (2)
middleware/cache/cache.go (1)

180-184: LGTM! The implementation effectively prevents caching of non-cacheable status codes.

The conditional check is well-placed and correctly implements the PR objective of preventing responses with non-cacheable status codes from being stored in the cache.

middleware/cache/cache_test.go (1)

934-995: LGTM! Comprehensive test coverage for non-cacheable status codes.

The test covers all categories of HTTP status codes (informational, successful, redirection, client error, and server error responses) ensuring thorough validation of the caching behavior.

middleware/cache/cache_test.go Outdated Show resolved Hide resolved
Copy link
Contributor

coderabbitai bot commented Jan 18, 2025

Caution

An unexpected error occurred while opening a pull request: Not Found - https://docs.github.com/rest/git/refs#get-a-reference

@gaby gaby added this to the v3 milestone Jan 18, 2025
@gaby gaby changed the title 🩹 Fix(v3;middleware/cache): don't cache if status code is not cacheable 🐛 fix: Align cache middleware with RFC7231 Jan 18, 2025
Copy link
Member

@gaby gaby left a comment

Choose a reason for hiding this comment

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

Small change to improve performance

middleware/cache/cache.go Outdated Show resolved Hide resolved
middleware/cache/cache.go Outdated Show resolved Hide resolved
Copy link
Member

@gaby gaby left a comment

Choose a reason for hiding this comment

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

Small change to improve performance

@miyamo2
Copy link
Contributor Author

miyamo2 commented Jan 18, 2025

@gaby
Thanks for reviewing and pointing it out. I fixed it and committed it.

Copy link
Member

@gaby gaby left a comment

Choose a reason for hiding this comment

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

👍 LGTM

fiber.StatusMethodNotAllowed: true,
fiber.StatusGone: true,
fiber.StatusRequestURITooLong: true,
fiber.StatusTeapot: true,
Copy link
Member

Choose a reason for hiding this comment

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

Maybe we should remove this one? Not sure?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In a word, yes, that's sure.
418: Teapot was used in the benchmark test, so I kept it.
Also, there is the point that 418: Teapot itself was a joke and did not much care about it.
https://github.com/miyamo2/fiber/blob/04eb05e98b21b7a7b93448beceec3c28b0e45b3a/middleware/cache/cache_test.go#L1010C19-L1010C37

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: In Progress
Development

Successfully merging this pull request may close these issues.

2 participants