From 781f71a0d14507a6291c4de95875f20f5880dc40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Tue, 7 Nov 2023 19:04:00 +0100 Subject: [PATCH 01/19] add v3 issue/pr templates --- .../ISSUE_TEMPLATE/feature-request-v3.yaml | 74 +++++++++++++++++++ .../ISSUE_TEMPLATE/maintenance-task-v3.yaml | 54 ++++++++++++++ .../v2-changes.md} | 0 .github/PULL_REQUEST_TEMPLATE/v3-changes.md | 45 +++++++++++ 4 files changed, 173 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/feature-request-v3.yaml create mode 100644 .github/ISSUE_TEMPLATE/maintenance-task-v3.yaml rename .github/{pull_request_template.md => PULL_REQUEST_TEMPLATE/v2-changes.md} (100%) create mode 100644 .github/PULL_REQUEST_TEMPLATE/v3-changes.md diff --git a/.github/ISSUE_TEMPLATE/feature-request-v3.yaml b/.github/ISSUE_TEMPLATE/feature-request-v3.yaml new file mode 100644 index 00000000..c7551b6d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request-v3.yaml @@ -0,0 +1,74 @@ +name: "๐Ÿ“ Feature Proposal for v3" +title: "๐Ÿ“ [v3 Proposal]: " +description: Propose a feature or improvement for Fiber v3. +labels: ["๐Ÿ“ Proposal", "v3"] + +body: + - type: markdown + id: notice + attributes: + value: | + ### Notice + - For questions, join our [Discord server](https://gofiber.io/discord). + - Please write in clear, understandable English. + - Ensure your proposal aligns with Express design principles and HTTP RFC standards. + - Describe features expected to remain stable and not require changes in the foreseeable future. + + - type: textarea + id: description + attributes: + label: "Feature Proposal Description" + description: "A clear and detailed description of the feature you are proposing for Fiber v3. How should it work, and what API endpoints and methods would it involve?" + placeholder: "Describe your feature proposal clearly and in detail, including API endpoints and methods." + validations: + required: true + + - type: textarea + id: express-alignment + attributes: + label: "Alignment with Express API" + description: "Explain how your proposal aligns with the design and API of Express.js. Provide comparative examples if possible." + placeholder: "Outline how the feature aligns with Express.js design principles and API standards." + validations: + required: true + + - type: textarea + id: standards-compliance + attributes: + label: "HTTP RFC Standards Compliance" + description: "Confirm that the feature complies with HTTP RFC standards, and describe any relevant aspects." + placeholder: "Detail how the feature adheres to HTTP RFC standards." + validations: + required: true + + - type: textarea + id: stability + attributes: + label: "API Stability" + description: "Discuss the expected stability of the feature and its API. How do you ensure that it will not require changes or deprecations in the near future?" + placeholder: "Describe measures taken to ensure the feature's API stability over time." + validations: + required: true + + - type: textarea + id: examples + attributes: + label: "Feature Examples" + description: "Provide concrete examples and code snippets to illustrate how the proposed feature should function." + placeholder: "Share code snippets that exemplify the proposed feature and its usage." + render: go + validations: + required: true + + - type: checkboxes + id: terms + attributes: + label: "Checklist:" + description: "By submitting this issue, you confirm that:" + options: + - label: "I agree to follow Fiber's [Code of Conduct](https://github.com/gofiber/fiber/blob/master/.github/CODE_OF_CONDUCT.md)." + required: true + - label: "I have searched for existing issues that describe my proposal before opening this one." + required: true + - label: "I understand that a proposal that does not meet these guidelines may be closed without explanation." + required: true diff --git a/.github/ISSUE_TEMPLATE/maintenance-task-v3.yaml b/.github/ISSUE_TEMPLATE/maintenance-task-v3.yaml new file mode 100644 index 00000000..2a58f789 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/maintenance-task-v3.yaml @@ -0,0 +1,54 @@ +name: "๐Ÿงน v3 Maintenance Task" +title: "๐Ÿงน [v3 Maintenance]: " +description: Describe a maintenance task for the v3 of the Fiber project. +labels: ["๐Ÿงน Updates", "v3"] + +body: + - type: markdown + id: notice + attributes: + value: | + ### Notice + - Before submitting a maintenance task, please check if a similar task has already been filed. + - Clearly outline the purpose of the maintenance task and its impact on the project. + - Use clear and understandable English. + + - type: textarea + id: task-description + attributes: + label: "Maintenance Task Description" + description: "Provide a detailed description of the maintenance task. Include any specific areas of the codebase that require attention, and the desired outcomes of this task." + placeholder: "Detail the maintenance task, specifying what needs to be done and why it is necessary." + validations: + required: true + + - type: textarea + id: impact + attributes: + label: "Impact on the Project" + description: "Explain the impact this maintenance will have on the project. Include benefits and potential risks if applicable." + placeholder: "Describe how completing this task will benefit the project, or the risks of not addressing it." + validations: + required: false + + - type: textarea + id: additional-context + attributes: + label: "Additional Context (optional)" + description: "Any additional information or context regarding the maintenance task that might be helpful." + placeholder: "Provide any additional information that may be relevant to the task at hand." + validations: + required: false + + - type: checkboxes + id: terms + attributes: + label: "Checklist:" + description: "Please confirm the following:" + options: + - label: "I have confirmed that this maintenance task is currently not being addressed." + required: true + - label: "I understand that this task will be evaluated by the maintainers and prioritized accordingly." + required: true + - label: "I am available to provide further information if needed." + required: true diff --git a/.github/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/v2-changes.md similarity index 100% rename from .github/pull_request_template.md rename to .github/PULL_REQUEST_TEMPLATE/v2-changes.md diff --git a/.github/PULL_REQUEST_TEMPLATE/v3-changes.md b/.github/PULL_REQUEST_TEMPLATE/v3-changes.md new file mode 100644 index 00000000..3f4b0957 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/v3-changes.md @@ -0,0 +1,45 @@ +## Description + +Please provide a clear and concise description of the changes you've made and the problem they address. Include the purpose of the change, any relevant issues it solves, and the benefits it brings to the project. If this change introduces new features or adjustments, highlight them here. + +Related to # (issue) + +## Changes Introduced + +List the new features or adjustments introduced in this pull request. Provide details on benchmarks, documentation updates, changelog entries, and if applicable, the migration guide. + +- [ ] Benchmarks: Describe any performance benchmarks and improvements related to the changes. +- [ ] Documentation Update: Detail the updates made to the documentation and links to the changed files. +- [ ] Changelog/What's New: Include a summary of the additions for the upcoming release notes. +- [ ] Migration Guide: If necessary, provide a guide or steps for users to migrate their existing code to accommodate these changes. +- [ ] API Alignment with Express: Explain how the changes align with the Express API. +- [ ] API Longevity: Discuss the steps taken to ensure that the new or updated APIs are consistent and not prone to breaking changes. +- [ ] Examples: Provide examples demonstrating the new features or changes in action. + +## Type of Change + +Please delete options that are not relevant. + +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Enhancement (improvement to existing features and functionality) +- [ ] Documentation update (changes to documentation) +- [ ] Performance improvement (non-breaking change which improves efficiency) +- [ ] Code consistency (non-breaking change which improves code reliability and robustness) + +## Checklist + +Before you submit your pull request, please make sure you meet these requirements: + +- [ ] 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](https://docs.gofiber.io/). +- [ ] 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. + +## Commit Formatting + +Please use emojis in commit messages for an easy way to identify the purpose or intention of a commit. You can refer to the emoji cheatsheet here: https://gitmoji.carloscuesta.me/ + From efdd0093b347c2cbfbdfa619244b439ac2fecc8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Tue, 7 Nov 2023 19:09:23 +0100 Subject: [PATCH 02/19] add v3 issue/pr templates --- .../v2-changes.md => pull_request_template.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{PULL_REQUEST_TEMPLATE/v2-changes.md => pull_request_template.md} (100%) diff --git a/.github/PULL_REQUEST_TEMPLATE/v2-changes.md b/.github/pull_request_template.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE/v2-changes.md rename to .github/pull_request_template.md From 862ea7dbf63c48af29b6bbccbaa4ae212b492fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Wed, 8 Nov 2023 13:23:46 +0100 Subject: [PATCH 03/19] add v3 pr templates info --- .github/pull_request_template.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 8d259296..675ea9ad 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,6 +5,8 @@ Explain the *details* for making this change. What existing problem does the pul Fixes # (issue) +:warning: **For changes specific to v3, please switch to the [v3 Pull Request Template](?template=v3-changes.md).** + ## Type of change Please delete options that are not relevant. From b99712f13e0a51a89ba4cebaf7067199241f450f Mon Sep 17 00:00:00 2001 From: database64128 Date: Thu, 9 Nov 2023 15:05:54 +0800 Subject: [PATCH 04/19] =?UTF-8?q?=E2=9A=A1=20middleware/pprof:=20improve?= =?UTF-8?q?=20performance=20(#2709)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * โšก middleware/pprof: improve performance Concatenate the custom and fixed prefixes beforehand, so the trimmed path can be switched on against constant strings. goos: linux goarch: amd64 pkg: github.com/gofiber/fiber/v2/middleware/pprof cpu: 13th Gen Intel(R) Core(TM) i9-13900K BenchmarkPprof/Slow-32 4912642 246.3 ns/op 480 B/op 10 allocs/op BenchmarkPprof/Fast-32 411908472 2.913 ns/op 0 B/op 0 allocs/op PASS * ๐ŸŒ‚ middleware/pprof: disable nonamedreturns linter on cutPrefix --- middleware/pprof/pprof.go | 43 ++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/middleware/pprof/pprof.go b/middleware/pprof/pprof.go index 6978d325..7e0c8cc4 100644 --- a/middleware/pprof/pprof.go +++ b/middleware/pprof/pprof.go @@ -29,6 +29,9 @@ func New(config ...Config) fiber.Handler { pprofThreadcreate = fasthttpadaptor.NewFastHTTPHandlerFunc(pprof.Handler("threadcreate").ServeHTTP) ) + // Construct actual prefix + prefix := cfg.Prefix + "/debug/pprof" + // Return new handler return func(c *fiber.Ctx) error { // Don't execute middleware if Next returns true @@ -38,39 +41,40 @@ func New(config ...Config) fiber.Handler { path := c.Path() // We are only interested in /debug/pprof routes - if len(path) < 12 || !strings.HasPrefix(path, cfg.Prefix+"/debug/pprof") { + path, found := cutPrefix(path, prefix) + if !found { return c.Next() } - // Switch to original path without stripped slashes + // Switch on trimmed path against constant strings switch path { - case cfg.Prefix + "/debug/pprof/": + case "/": pprofIndex(c.Context()) - case cfg.Prefix + "/debug/pprof/cmdline": + case "/cmdline": pprofCmdline(c.Context()) - case cfg.Prefix + "/debug/pprof/profile": + case "/profile": pprofProfile(c.Context()) - case cfg.Prefix + "/debug/pprof/symbol": + case "/symbol": pprofSymbol(c.Context()) - case cfg.Prefix + "/debug/pprof/trace": + case "/trace": pprofTrace(c.Context()) - case cfg.Prefix + "/debug/pprof/allocs": + case "/allocs": pprofAllocs(c.Context()) - case cfg.Prefix + "/debug/pprof/block": + case "/block": pprofBlock(c.Context()) - case cfg.Prefix + "/debug/pprof/goroutine": + case "/goroutine": pprofGoroutine(c.Context()) - case cfg.Prefix + "/debug/pprof/heap": + case "/heap": pprofHeap(c.Context()) - case cfg.Prefix + "/debug/pprof/mutex": + case "/mutex": pprofMutex(c.Context()) - case cfg.Prefix + "/debug/pprof/threadcreate": + case "/threadcreate": pprofThreadcreate(c.Context()) default: // pprof index only works with trailing slash if strings.HasSuffix(path, "/") { path = strings.TrimRight(path, "/") } else { - path = cfg.Prefix + "/debug/pprof/" + path = prefix + "/" } return c.Redirect(path, fiber.StatusFound) @@ -78,3 +82,14 @@ func New(config ...Config) fiber.Handler { return nil } } + +// cutPrefix is a copy of [strings.CutPrefix] added in Go 1.20. +// Remove this function when we drop support for Go 1.19. +// +//nolint:nonamedreturns // Align with its original form in std. +func cutPrefix(s, prefix string) (after string, found bool) { + if !strings.HasPrefix(s, prefix) { + return s, false + } + return s[len(prefix):], true +} From 5d888cee3d5fa43aeb329df3b630f2a89ddde32f Mon Sep 17 00:00:00 2001 From: nickajacks1 <128185314+nickajacks1@users.noreply.github.com> Date: Fri, 10 Nov 2023 02:32:25 -0800 Subject: [PATCH 05/19] =?UTF-8?q?=E2=9A=A1=EF=B8=8F=20perf(ctx.Range):=20r?= =?UTF-8?q?educe=20allocations=20(#2705)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * perf(ctx.Range): reduce allocations strings.Split was causing extra allocations where using strings.IndexByte can suffice. ALso switch from strconv.Atoi because it causes an allocation when parsing a non-integer, which is common for Ranges. * chore: fix lint --- ctx.go | 58 ++++++++++++++++++++++++----------- ctx_test.go | 88 +++++++++++++++++++++++++++++++++++------------------ 2 files changed, 98 insertions(+), 48 deletions(-) diff --git a/ctx.go b/ctx.go index 34d49a9b..944ea40b 100644 --- a/ctx.go +++ b/ctx.go @@ -115,10 +115,13 @@ func (t *TLSHandler) GetClientInfo(info *tls.ClientHelloInfo) (*tls.Certificate, // Range data for c.Range type Range struct { Type string - Ranges []struct { - Start int - End int - } + Ranges []RangeSet +} + +// RangeSet represents a single content range from a request. +type RangeSet struct { + Start int + End int } // Cookie data for c.Cookie @@ -1392,25 +1395,44 @@ var ( // Range returns a struct containing the type and a slice of ranges. func (c *Ctx) Range(size int) (Range, error) { - var rangeData Range + var ( + rangeData Range + ranges string + ) rangeStr := c.Get(HeaderRange) - if rangeStr == "" || !strings.Contains(rangeStr, "=") { + + i := strings.IndexByte(rangeStr, '=') + if i == -1 || strings.Contains(rangeStr[i+1:], "=") { return rangeData, ErrRangeMalformed } - data := strings.Split(rangeStr, "=") - const expectedDataParts = 2 - if len(data) != expectedDataParts { - return rangeData, ErrRangeMalformed - } - rangeData.Type = data[0] - arr := strings.Split(data[1], ",") - for i := 0; i < len(arr); i++ { - item := strings.Split(arr[i], "-") - if len(item) == 1 { + rangeData.Type = rangeStr[:i] + ranges = rangeStr[i+1:] + + var ( + singleRange string + moreRanges = ranges + ) + for moreRanges != "" { + singleRange = moreRanges + if i := strings.IndexByte(moreRanges, ','); i >= 0 { + singleRange = moreRanges[:i] + moreRanges = moreRanges[i+1:] + } else { + moreRanges = "" + } + + var ( + startStr, endStr string + i int + ) + if i = strings.IndexByte(singleRange, '-'); i == -1 { return rangeData, ErrRangeMalformed } - start, startErr := strconv.Atoi(item[0]) - end, endErr := strconv.Atoi(item[1]) + startStr = singleRange[:i] + endStr = singleRange[i+1:] + + start, startErr := fasthttp.ParseUint(utils.UnsafeBytes(startStr)) + end, endErr := fasthttp.ParseUint(utils.UnsafeBytes(endStr)) if startErr != nil { // -nnn start = size - end end = size - 1 diff --git a/ctx_test.go b/ctx_test.go index ef900729..28f04699 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -2521,39 +2521,67 @@ func Test_Ctx_Range(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) - var ( - result Range - err error - ) - - _, err = c.Range(1000) - utils.AssertEqual(t, true, err != nil) - - c.Request().Header.Set(HeaderRange, "bytes=500") - _, err = c.Range(1000) - utils.AssertEqual(t, true, err != nil) - - c.Request().Header.Set(HeaderRange, "bytes=500=") - _, err = c.Range(1000) - utils.AssertEqual(t, true, err != nil) - - c.Request().Header.Set(HeaderRange, "bytes=500-300") - _, err = c.Range(1000) - utils.AssertEqual(t, true, err != nil) - - testRange := func(header string, start, end int) { + testRange := func(header string, ranges ...RangeSet) { c.Request().Header.Set(HeaderRange, header) - result, err = c.Range(1000) - utils.AssertEqual(t, nil, err) - utils.AssertEqual(t, "bytes", result.Type) - utils.AssertEqual(t, start, result.Ranges[0].Start) - utils.AssertEqual(t, end, result.Ranges[0].End) + result, err := c.Range(1000) + if len(ranges) == 0 { + utils.AssertEqual(t, true, err != nil) + } else { + utils.AssertEqual(t, "bytes", result.Type) + utils.AssertEqual(t, true, err == nil) + } + utils.AssertEqual(t, len(ranges), len(result.Ranges)) + for i := range ranges { + utils.AssertEqual(t, ranges[i], result.Ranges[i]) + } } - testRange("bytes=a-700", 300, 999) - testRange("bytes=500-b", 500, 999) - testRange("bytes=500-1000", 500, 999) - testRange("bytes=500-700", 500, 700) + testRange("bytes=500") + testRange("bytes=") + testRange("bytes=500=") + testRange("bytes=500-300") + testRange("bytes=a-700", RangeSet{300, 999}) + testRange("bytes=500-b", RangeSet{500, 999}) + testRange("bytes=500-1000", RangeSet{500, 999}) + testRange("bytes=500-700", RangeSet{500, 700}) + testRange("bytes=0-0,2-1000", RangeSet{0, 0}, RangeSet{2, 999}) + testRange("bytes=0-99,450-549,-100", RangeSet{0, 99}, RangeSet{450, 549}, RangeSet{900, 999}) + testRange("bytes=500-700,601-999", RangeSet{500, 700}, RangeSet{601, 999}) +} + +// go test -v -run=^$ -bench=Benchmark_Ctx_Range -benchmem -count=4 +func Benchmark_Ctx_Range(b *testing.B) { + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + + testCases := []struct { + str string + start int + end int + }{ + {"bytes=-700", 300, 999}, + {"bytes=500-", 500, 999}, + {"bytes=500-1000", 500, 999}, + {"bytes=0-700,800-1000", 0, 700}, + } + + for _, tc := range testCases { + b.Run(tc.str, func(b *testing.B) { + c.Request().Header.Set(HeaderRange, tc.str) + var ( + result Range + err error + ) + for n := 0; n < b.N; n++ { + result, err = c.Range(1000) + } + utils.AssertEqual(b, nil, err) + utils.AssertEqual(b, "bytes", result.Type) + utils.AssertEqual(b, tc.start, result.Ranges[0].Start) + utils.AssertEqual(b, tc.end, result.Ranges[0].End) + }) + } } // go test -run Test_Ctx_Route From 1e55045a309acc8584a3e4425c51cad2e474692b Mon Sep 17 00:00:00 2001 From: nickajacks1 <128185314+nickajacks1@users.noreply.github.com> Date: Fri, 10 Nov 2023 02:33:10 -0800 Subject: [PATCH 06/19] test(limiter): fix intermittent failures (#2716) The limiter middleware unit tests are failing due to a race between the storage garbage collector and the unit test itself. The sliding window limiter tracks requests using memory storage. In several of the unit tests, this storage expiry ends up being 4 seconds. The test waits for 4 seconds, then sends a request, expecting it to succeed. However, the unit test occasionally wakes up before the storage GC kicks in. As an effect of the very coarse timer (using seconds as units), the middleware correctly rejects the request, causing the test to fail. Update the sleep to 4.5 seconds. This will not slow down the execution of the test suite, as these tests run in parallel with a separate 9 second long test. I'm not 100% sure this solves the issue, and ideally we'd be able to run tests without time.Sleep. --- middleware/limiter/limiter_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/middleware/limiter/limiter_test.go b/middleware/limiter/limiter_test.go index d27b3b80..5392982f 100644 --- a/middleware/limiter/limiter_test.go +++ b/middleware/limiter/limiter_test.go @@ -218,7 +218,7 @@ func Test_Limiter_Sliding_Window_No_Skip_Choices(t *testing.T) { utils.AssertEqual(t, nil, err) utils.AssertEqual(t, 429, resp.StatusCode) - time.Sleep(4 * time.Second) + time.Sleep(4*time.Second + 500*time.Millisecond) resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) utils.AssertEqual(t, nil, err) @@ -258,7 +258,7 @@ func Test_Limiter_Sliding_Window_Custom_Storage_No_Skip_Choices(t *testing.T) { utils.AssertEqual(t, nil, err) utils.AssertEqual(t, 429, resp.StatusCode) - time.Sleep(4 * time.Second) + time.Sleep(4*time.Second + 500*time.Millisecond) resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) utils.AssertEqual(t, nil, err) @@ -373,7 +373,7 @@ func Test_Limiter_Sliding_Window_Skip_Failed_Requests(t *testing.T) { utils.AssertEqual(t, nil, err) utils.AssertEqual(t, 429, resp.StatusCode) - time.Sleep(4 * time.Second) + time.Sleep(4*time.Second + 500*time.Millisecond) resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) utils.AssertEqual(t, nil, err) @@ -412,7 +412,7 @@ func Test_Limiter_Sliding_Window_Custom_Storage_Skip_Failed_Requests(t *testing. utils.AssertEqual(t, nil, err) utils.AssertEqual(t, 429, resp.StatusCode) - time.Sleep(4 * time.Second) + time.Sleep(4*time.Second + 500*time.Millisecond) resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/success", nil)) utils.AssertEqual(t, nil, err) @@ -533,7 +533,7 @@ func Test_Limiter_Sliding_Window_Skip_Successful_Requests(t *testing.T) { utils.AssertEqual(t, nil, err) utils.AssertEqual(t, 429, resp.StatusCode) - time.Sleep(4 * time.Second) + time.Sleep(4*time.Second + 500*time.Millisecond) resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) utils.AssertEqual(t, nil, err) @@ -574,7 +574,7 @@ func Test_Limiter_Sliding_Window_Custom_Storage_Skip_Successful_Requests(t *test utils.AssertEqual(t, nil, err) utils.AssertEqual(t, 429, resp.StatusCode) - time.Sleep(4 * time.Second) + time.Sleep(4*time.Second + 500*time.Millisecond) resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/fail", nil)) utils.AssertEqual(t, nil, err) From 9f082af04517dec9695d8dc92dd29f5919c906ed Mon Sep 17 00:00:00 2001 From: Reid Hurlburt Date: Mon, 13 Nov 2023 10:18:05 -0400 Subject: [PATCH 07/19] =?UTF-8?q?=F0=9F=94=A5=20Add=20support=20for=20appl?= =?UTF-8?q?ication/problem+json=20(#2704)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐Ÿ”ฅ Add support for custom JSON content headers --- client.go | 8 +++++-- client_test.go | 14 ++++++++++++ ctx.go | 21 +++++++++++++---- ctx_test.go | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ docs/api/ctx.md | 20 ++++++++++++++-- 5 files changed, 116 insertions(+), 8 deletions(-) diff --git a/client.go b/client.go index fe1daf72..ee191a63 100644 --- a/client.go +++ b/client.go @@ -460,12 +460,16 @@ func (a *Agent) BodyStream(bodyStream io.Reader, bodySize int) *Agent { } // JSON sends a JSON request. -func (a *Agent) JSON(v interface{}) *Agent { +func (a *Agent) JSON(v interface{}, ctype ...string) *Agent { if a.jsonEncoder == nil { a.jsonEncoder = json.Marshal } - a.req.Header.SetContentType(MIMEApplicationJSON) + if len(ctype) > 0 { + a.req.Header.SetContentType(ctype[0]) + } else { + a.req.Header.SetContentType(MIMEApplicationJSON) + } if body, err := a.jsonEncoder(v); err != nil { a.errs = append(a.errs, err) diff --git a/client_test.go b/client_test.go index 395a18e0..580e2d35 100644 --- a/client_test.go +++ b/client_test.go @@ -651,6 +651,7 @@ func Test_Client_Agent_RetryIf(t *testing.T) { func Test_Client_Agent_Json(t *testing.T) { t.Parallel() + // Test without ctype parameter handler := func(c *Ctx) error { utils.AssertEqual(t, MIMEApplicationJSON, string(c.Request().Header.ContentType())) @@ -662,6 +663,19 @@ func Test_Client_Agent_Json(t *testing.T) { } testAgent(t, handler, wrapAgent, `{"success":true}`) + + // Test with ctype parameter + handler = func(c *Ctx) error { + utils.AssertEqual(t, "application/problem+json", string(c.Request().Header.ContentType())) + + return c.Send(c.Request().Body()) + } + + wrapAgent = func(a *Agent) { + a.JSON(data{Success: true}, "application/problem+json") + } + + testAgent(t, handler, wrapAgent, `{"success":true}`) } func Test_Client_Agent_Json_Error(t *testing.T) { diff --git a/ctx.go b/ctx.go index 944ea40b..55b81cf2 100644 --- a/ctx.go +++ b/ctx.go @@ -373,6 +373,7 @@ func decoderBuilder(parserConfig ParserConfig) interface{} { // BodyParser binds the request body to a struct. // It supports decoding the following content types based on the Content-Type header: // application/json, application/xml, application/x-www-form-urlencoded, multipart/form-data +// All JSON extenstion mime types are supported (eg. application/problem+json) // If none of the content types above are matched, it will return a ErrUnprocessableEntity error func (c *Ctx) BodyParser(out interface{}) error { // Get content-type @@ -380,8 +381,14 @@ func (c *Ctx) BodyParser(out interface{}) error { ctype = utils.ParseVendorSpecificContentType(ctype) + // Only use ctype string up to and excluding byte ';' + ctypeEnd := strings.IndexByte(ctype, ';') + if ctypeEnd != -1 { + ctype = ctype[:ctypeEnd] + } + // Parse body accordingly - if strings.HasPrefix(ctype, MIMEApplicationJSON) { + if strings.HasSuffix(ctype, "json") { return c.app.config.JSONDecoder(c.Body(), out) } if strings.HasPrefix(ctype, MIMEApplicationForm) { @@ -886,14 +893,20 @@ func (c *Ctx) Is(extension string) bool { // Array and slice values encode as JSON arrays, // except that []byte encodes as a base64-encoded string, // and a nil slice encodes as the null JSON value. -// This method also sets the content header to application/json. -func (c *Ctx) JSON(data interface{}) error { +// If the ctype parameter is given, this method will set the +// Content-Type header equal to ctype. If ctype is not given, +// The Content-Type header will be set to application/json. +func (c *Ctx) JSON(data interface{}, ctype ...string) error { raw, err := c.app.config.JSONEncoder(data) if err != nil { return err } c.fasthttp.Response.SetBodyRaw(raw) - c.fasthttp.Response.Header.SetContentType(MIMEApplicationJSON) + if len(ctype) > 0 { + c.fasthttp.Response.Header.SetContentType(ctype[0]) + } else { + c.fasthttp.Response.Header.SetContentType(MIMEApplicationJSON) + } return nil } diff --git a/ctx_test.go b/ctx_test.go index 28f04699..16df8262 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -574,6 +574,9 @@ func Test_Ctx_BodyParser(t *testing.T) { testDecodeParser(MIMEApplicationForm, "name=john") testDecodeParser(MIMEMultipartForm+`;boundary="b"`, "--b\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\njohn\r\n--b--") + // Ensure JSON extension MIME type gets parsed as JSON + testDecodeParser("application/problem+json", `{"name":"john"}`) + testDecodeParserError := func(contentType, body string) { c.Request().Header.SetContentType(contentType) c.Request().SetBody([]byte(body)) @@ -708,6 +711,30 @@ func Benchmark_Ctx_BodyParser_JSON(b *testing.B) { utils.AssertEqual(b, "john", d.Name) } +// go test -v -run=^$ -bench=Benchmark_Ctx_BodyParser_JSON_Extension -benchmem -count=4 +func Benchmark_Ctx_BodyParser_JSON_Extension(b *testing.B) { + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + type Demo struct { + Name string `json:"name"` + } + body := []byte(`{"name":"john"}`) + c.Request().SetBody(body) + c.Request().Header.SetContentType("application/problem+json") + c.Request().Header.SetContentLength(len(body)) + d := new(Demo) + + b.ReportAllocs() + b.ResetTimer() + + for n := 0; n < b.N; n++ { + _ = c.BodyParser(d) //nolint:errcheck // It is fine to ignore the error here as we check it once further below + } + utils.AssertEqual(b, nil, c.BodyParser(d)) + utils.AssertEqual(b, "john", d.Name) +} + // go test -v -run=^$ -bench=Benchmark_Ctx_BodyParser_XML -benchmem -count=4 func Benchmark_Ctx_BodyParser_XML(b *testing.B) { app := New() @@ -2927,6 +2954,7 @@ func Test_Ctx_JSON(t *testing.T) { utils.AssertEqual(t, true, c.JSON(complex(1, 1)) != nil) + // Test without ctype err := c.JSON(Map{ // map has no order "Name": "Grame", "Age": 20, @@ -2935,6 +2963,15 @@ func Test_Ctx_JSON(t *testing.T) { utils.AssertEqual(t, `{"Age":20,"Name":"Grame"}`, string(c.Response().Body())) utils.AssertEqual(t, "application/json", string(c.Response().Header.Peek("content-type"))) + // Test with ctype + err = c.JSON(Map{ // map has no order + "Name": "Grame", + "Age": 20, + }, "application/problem+json") + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, `{"Age":20,"Name":"Grame"}`, string(c.Response().Body())) + utils.AssertEqual(t, "application/problem+json", string(c.Response().Header.Peek("content-type"))) + testEmpty := func(v interface{}, r string) { err := c.JSON(v) utils.AssertEqual(t, nil, err) @@ -2990,6 +3027,30 @@ func Benchmark_Ctx_JSON(b *testing.B) { utils.AssertEqual(b, `{"Name":"Grame","Age":20}`, string(c.Response().Body())) } +// go test -run=^$ -bench=Benchmark_Ctx_JSON_Ctype -benchmem -count=4 +func Benchmark_Ctx_JSON_Ctype(b *testing.B) { + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + type SomeStruct struct { + Name string + Age uint8 + } + data := SomeStruct{ + Name: "Grame", + Age: 20, + } + var err error + b.ReportAllocs() + b.ResetTimer() + for n := 0; n < b.N; n++ { + err = c.JSON(data, "application/problem+json") + } + utils.AssertEqual(b, nil, err) + utils.AssertEqual(b, `{"Name":"Grame","Age":20}`, string(c.Response().Body())) + utils.AssertEqual(b, "application/problem+json", string(c.Response().Header.Peek("content-type"))) +} + // go test -run Test_Ctx_JSONP func Test_Ctx_JSONP(t *testing.T) { t.Parallel() diff --git a/docs/api/ctx.md b/docs/api/ctx.md index 860799f4..7b195683 100644 --- a/docs/api/ctx.md +++ b/docs/api/ctx.md @@ -797,11 +797,11 @@ app.Get("/", func(c *fiber.Ctx) error { Converts any **interface** or **string** to JSON using the [encoding/json](https://pkg.go.dev/encoding/json) package. :::info -JSON also sets the content header to **application/json**. +JSON also sets the content header to the `ctype` parameter. If no `ctype` is passed in, the header is set to **application/json**. ::: ```go title="Signature" -func (c *Ctx) JSON(data interface{}) error +func (c *Ctx) JSON(data interface{}, ctype ...string) error ``` ```go title="Example" @@ -827,6 +827,22 @@ app.Get("/json", func(c *fiber.Ctx) error { }) // => Content-Type: application/json // => "{"name": "Grame", "age": 20}" + + return c.JSON(fiber.Map{ + "type": "https://example.com/probs/out-of-credit", + "title": "You do not have enough credit.", + "status": 403, + "detail": "Your current balance is 30, but that costs 50.", + "instance": "/account/12345/msgs/abc", + }, "application/problem+json") + // => Content-Type: application/problem+json + // => "{ + // => "type": "https://example.com/probs/out-of-credit", + // => "title": "You do not have enough credit.", + // => "status": 403, + // => "detail": "Your current balance is 30, but that costs 50.", + // => "instance": "/account/12345/msgs/abc", + // => }" }) ``` From dceb0b4c452a16770d8cded49614e408bcf649d5 Mon Sep 17 00:00:00 2001 From: RW Date: Tue, 14 Nov 2023 08:18:46 +0100 Subject: [PATCH 08/19] Update app.go prepare release v2.51.0 --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index ebf10251..47a01dd0 100644 --- a/app.go +++ b/app.go @@ -30,7 +30,7 @@ import ( ) // Version of current fiber package -const Version = "2.50.0" +const Version = "2.51.0" // Handler defines a function to serve HTTP requests. type Handler = func(*Ctx) error From 239e36e0f6507ed81539620d2bac32189e1e51d6 Mon Sep 17 00:00:00 2001 From: RW Date: Wed, 15 Nov 2023 08:50:26 +0100 Subject: [PATCH 09/19] Update sync_docs.sh --- .github/scripts/sync_docs.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/scripts/sync_docs.sh b/.github/scripts/sync_docs.sh index a05e1ab2..b9b4cefd 100755 --- a/.github/scripts/sync_docs.sh +++ b/.github/scripts/sync_docs.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +set -e # Some env variables BRANCH="master" From 3ab3d151c74ff0c491a43c4f198a5c8b522f9cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Wed, 15 Nov 2023 09:23:08 +0100 Subject: [PATCH 10/19] =?UTF-8?q?refresh=20docs=20for=20=F0=9F=94=A5=20Add?= =?UTF-8?q?=20support=20for=20application/problem+json=20#2704?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/api/client.md | 4 ++-- docs/api/ctx.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/api/client.md b/docs/api/client.md index 7ec9f3b0..ffbe308f 100644 --- a/docs/api/client.md +++ b/docs/api/client.md @@ -268,10 +268,10 @@ agent.BodyStream(strings.NewReader("body=stream"), -1) ### JSON -JSON sends a JSON request by setting the Content-Type header to `application/json`. +JSON sends a JSON request by setting the Content-Type header to the `ctype` parameter. If no `ctype` is passed in, the header is set to `application/json`. ```go title="Signature" -func (a *Agent) JSON(v interface{}) *Agent +func (a *Agent) JSON(v interface{}, ctype ...string) *Agent ``` ```go title="Example" diff --git a/docs/api/ctx.md b/docs/api/ctx.md index 7b195683..2c324492 100644 --- a/docs/api/ctx.md +++ b/docs/api/ctx.md @@ -797,7 +797,7 @@ app.Get("/", func(c *fiber.Ctx) error { Converts any **interface** or **string** to JSON using the [encoding/json](https://pkg.go.dev/encoding/json) package. :::info -JSON also sets the content header to the `ctype` parameter. If no `ctype` is passed in, the header is set to **application/json**. +JSON also sets the content header to the `ctype` parameter. If no `ctype` is passed in, the header is set to `application/json`. ::: ```go title="Signature" From 2374cad3cd109d3bf33f5863e6eb14c32de1882e Mon Sep 17 00:00:00 2001 From: Jason McNeil Date: Thu, 16 Nov 2023 06:34:31 -0500 Subject: [PATCH 11/19] =?UTF-8?q?=F0=9F=93=84=20docs:=20improve=20csrf=20d?= =?UTF-8?q?ocs=20(#2726)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: improve csrf docs - fix issues with `X-Csrf-Token` capitalization inconsistency. - reduce redundancy and repetition. - improve grammar. * docs: update middleware description * docs: within vs in * docs: deleting tokens * docs: MUST * docs: add colon * docs: all modern browsers * docs: patterns * docs: improve phrasing of pattern options --- docs/api/middleware/csrf.md | 48 ++++++++++++++++++------------------ middleware/csrf/config.go | 2 +- middleware/csrf/csrf_test.go | 6 ++--- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/docs/api/middleware/csrf.md b/docs/api/middleware/csrf.md index 58cd4f13..2c30ed5c 100644 --- a/docs/api/middleware/csrf.md +++ b/docs/api/middleware/csrf.md @@ -4,13 +4,15 @@ id: csrf # CSRF -The CSRF middleware for [Fiber](https://github.com/gofiber/fiber) provides protection against [Cross-Site Request Forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery) (CSRF) attacks using tokens. These tokens verify requests made using methods other than those defined as "safe" by [RFC9110#section-9.2.1](https://datatracker.ietf.org/doc/html/rfc9110.html#section-9.2.1) (Safe-Methods: GET, HEAD, OPTIONS, and TRACE). If a potential attack is detected this middleware will, by default, return a 403 Forbidden error. +The CSRF middleware for [Fiber](https://github.com/gofiber/fiber) provides protection against [Cross-Site Request Forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery) (CSRF) attacks. Requests made using methods other than those defined as 'safe' by [RFC9110#section-9.2.1](https://datatracker.ietf.org/doc/html/rfc9110.html#section-9.2.1) (GET, HEAD, OPTIONS, and TRACE) are validated using tokens. If a potential attack is detected, the middleware will return a default 403 Forbidden error. -This middleware can be used with or without a user session and offers two token validation patterns. In addition, it implements strict referer checking for HTTPS requests, ensuring the security of your application. For HTTPS requests, even if a subdomain can set or modify cookies on your domain, it can't force a user to post to your application since that request won't come from your own exact domain. +This middleware offers two [Token Validation Patterns](#token-validation-patterns): the [Double Submit Cookie Pattern (default)](#double-submit-cookie-pattern-default), and the [Synchronizer Token Pattern (with Session)](#synchronizer-token-pattern-session). + +As a [Defense In Depth](#defense-in-depth) measure, this middleware performs [Referer Checking](#referer-checking) for HTTPS requests. ## Token Generation -CSRF tokens are generated on 'safe' requests and when the existing token has expired or hasn't been set yet. If `SingleUseToken` is `true`, a new token is generated after each use. Retrieve the CSRF token using `c.Locals(contextKey)`, where `contextKey` is defined in the configuration. +CSRF tokens are generated on 'safe' requests and when the existing token has expired or hasn't been set yet. If `SingleUseToken` is `true`, a new token is generated after each use. Retrieve the CSRF token using `c.Locals(contextKey)`, where `contextKey` is defined within the configuration. ## Security Considerations @@ -24,26 +26,26 @@ Never use 'safe' methods to mutate data, for example, never use a GET request to #### Double Submit Cookie Pattern (Default) -In the default configuration, the middleware generates and stores tokens using the `fiber.Storage` interface. These tokens are not associated with a user session, and a Double Submit Cookie pattern is used to validate the token. The token is stored in a cookie and sent as a header on requests. The middleware compares the cookie value with the header value to validate the token. This is a secure pattern that does not require a user session. +By default, the middleware generates and stores tokens using the `fiber.Storage` interface. These tokens are not linked to any particular user session, and they are validated using the Double Submit Cookie pattern. The token is stored in a cookie, and then sent as a header on requests. The middleware compares the cookie value with the header value to validate the token. This is a secure pattern that does not require a user session. -When using this pattern, it's important to delete the token when the authorization status changes, see: [Token Lifecycle](#token-lifecycle) for more information. +When the authorization status changes, the previously issued token MUST be deleted, and a new one generated. See [Token Lifecycle](#token-lifecycle) [Deleting Tokens](#deleting-tokens) for more information. :::caution -When using this method, it's important to set the `CookieSameSite` option to `Lax` or `Strict` and ensure that the Extractor is not `CsrfFromCookie`, and KeyLookup is not `cookie:`. +When using this pattern, it's important to set the `CookieSameSite` option to `Lax` or `Strict` and ensure that the Extractor is not `CsrfFromCookie`, and KeyLookup is not `cookie:`. ::: :::note When using this pattern, this middleware uses our [Storage](https://github.com/gofiber/storage) package to support various databases through a single interface. The default configuration for Storage saves data to memory. See [Custom Storage/Database](#custom-storagedatabase) for customizing the storage. ::: -#### Synchronizer Token Pattern (Session) +#### Synchronizer Token Pattern (with Session) -When using this middleware with a user session, the middleware can be configured to store the token in the session. This method is recommended when using a user session, as it is generally more secure than the Double Submit Cookie Pattern. +When using this middleware with a user session, the middleware can be configured to store the token within the session. This method is recommended when using a user session, as it is generally more secure than the Double Submit Cookie Pattern. When using this pattern it's important to regenerate the session when the authorization status changes, this will also delete the token. See: [Token Lifecycle](#token-lifecycle) for more information. :::caution -When using this method, pre-sessions are required and will be created if a session is not already present. This means the middleware will create a session for every safe request, even if the request does not require a session. Therefore, the existence of a session should not be used to indicate that a user is logged in or authenticated; a session value should be used for this purpose. +Pre-sessions are required and will be created automatically if not present. Use a session value to indicate authentication instead of relying on presence of a session. ::: ### Defense In Depth @@ -51,7 +53,7 @@ When using this method, pre-sessions are required and will be created if a sessi When using this middleware, it's recommended to serve your pages over HTTPS, set the `CookieSecure` option to `true`, and set the `CookieSameSite` option to `Lax` or `Strict`. This ensures that the cookie is only sent over HTTPS and not on requests from external sites. :::note -Cookie prefixes __Host- and __Secure- can be used to further secure the cookie. However, these prefixes are not supported by all browsers and there are some other limitations. See [MDN#Set-Cookie#cookie_prefixes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie_prefixes) for more information. +Cookie prefixes `__Host-` and `__Secure-` can be used to further secure the cookie. Note that these prefixes are not supported by all browsers and there are other limitations. See [MDN#Set-Cookie#cookie_prefixes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#cookie_prefixes) for more information. To use these prefixes, set the `CookieName` option to `__Host-csrf_` or `__Secure-csrf_`. ::: @@ -61,7 +63,9 @@ To use these prefixes, set the `CookieName` option to `__Host-csrf_` or `__Secur For HTTPS requests, this middleware performs strict referer checking. Even if a subdomain can set or modify cookies on your domain, it can't force a user to post to your application since that request won't come from your own exact domain. :::caution -Referer checking is required for https requests protected by CSRF. All modern browsers will automatically include the Referer header in requests, including those made with the JS Fetch API. However, if you are using this middleware with a custom client you must ensure that the client sends a valid Referer header. +When HTTPS requests are protected by CSRF, referer checking is always carried out. + +The Referer header is automatically included in requests by all modern browsers, including those made using the JS Fetch API. However, if you're making use of this middleware with a custom client, it's important to ensure that the client sends a valid Referer header. ::: @@ -74,7 +78,7 @@ Tokens are valid until they expire or until they are deleted. By default, tokens By default, tokens may be used multiple times. If you want to delete the token after it has been used, you can set the `SingleUseToken` option to `true`. This will delete the token after it has been used, and a new token will be generated on the next request. :::info -Using `SingleUseToken` comes with usability trade-offs and is not enabled by default. It can interfere with the user experience if the user has multiple tabs open or uses the back button. +Using `SingleUseToken` comes with usability trade-offs and is not enabled by default. For example, it can interfere with the user experience if the user has multiple tabs open or uses the back button. ::: #### Deleting Tokens @@ -82,7 +86,7 @@ Using `SingleUseToken` comes with usability trade-offs and is not enabled by def When the authorization status changes, the CSRF token MUST be deleted, and a new one generated. This can be done by calling `handler.DeleteToken(c)`. ```go -if handler, ok := app.AcquireCtx(ctx).Locals(ConfigDefault.HandlerContextKey).(*CSRFHandler); ok { +if handler, ok := app.AcquireCtx(ctx).Locals(csrf.ConfigDefault.HandlerContextKey).(*CSRFHandler); ok { if err := handler.DeleteToken(app.AcquireCtx(ctx)); err != nil { // handle error } @@ -127,20 +131,15 @@ app.Use(csrf.New(csrf.Config{ CookieSameSite: "Lax", Expiration: 1 * time.Hour, KeyGenerator: utils.UUIDv4, - Extractor: func(c *fiber.Ctx) (string, error) { ... }, })) ``` -:::info -KeyLookup will be ignored if Extractor is explicitly set. -::: - ## Config | Property | Type | Description | Default | |:------------------|:-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------| | Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | -| KeyLookup | `string` | KeyLookup is a string in the form of "`:`" that is used to create an Extractor that extracts the token from the request. Possible values: "`header:`", "`query:`", "`param:`", "`form:`", "`cookie:`". Ignored if an Extractor is explicitly set. | "header:X-CSRF-Token" | +| KeyLookup | `string` | KeyLookup is a string in the form of "`:`" that is used to create an Extractor that extracts the token from the request. Possible values: "`header:`", "`query:`", "`param:`", "`form:`", "`cookie:`". Ignored if an Extractor is explicitly set. | "header:X-Csrf-Token" | | CookieName | `string` | Name of the csrf cookie. This cookie will store the csrf key. | "csrf_" | | CookieDomain | `string` | Domain of the CSRF cookie. | "" | | CookiePath | `string` | Path of the CSRF cookie. | "" | @@ -152,8 +151,8 @@ KeyLookup will be ignored if Extractor is explicitly set. | SingleUseToken | `bool` | SingleUseToken indicates if the CSRF token be destroyed and a new one generated on each use. (See TokenLifecycle) | false | | Storage | `fiber.Storage` | Store is used to store the state of the middleware. | `nil` | | Session | `*session.Store` | Session is used to store the state of the middleware. Overrides Storage if set. | `nil` | -| SessionKey | `string` | SessionKey is the key used to store the token in the session. | "fiber.csrf.token" | -| ContextKey | `string` | Context key to store the generated CSRF token into the context. If left empty, the token will not be stored in the context. | "" | +| SessionKey | `string` | SessionKey is the key used to store the token within the session. | "fiber.csrf.token" | +| ContextKey | `string` | Context key to store the generated CSRF token into the context. If left empty, the token will not be stored within the context. | "" | | KeyGenerator | `func() string` | KeyGenerator creates a new CSRF token. | utils.UUID | | CookieExpires | `time.Duration` (Deprecated) | Deprecated: Please use Expiration. | 0 | | Cookie | `*fiber.Cookie` (Deprecated) | Deprecated: Please use Cookie* related fields. | `nil` | @@ -180,13 +179,14 @@ var ConfigDefault = Config{ ### Recommended Config (with session) -It's recommended to use this middleware with [fiber/middleware/session](https://docs.gofiber.io/api/middleware/session) to store the CSRF token in the session. This is generally more secure than the default configuration. +It's recommended to use this middleware with [fiber/middleware/session](https://docs.gofiber.io/api/middleware/session) to store the CSRF token within the session. This is generally more secure than the default configuration. ```go var ConfigDefault = Config{ KeyLookup: "header:" + HeaderName, - CookieName: "csrf_", + CookieName: "__Host-csrf_", CookieSameSite: "Lax", + CookieSecure: true, CookieSessionOnly: true, CookieHTTPOnly: true, Expiration: 1 * time.Hour, @@ -218,7 +218,7 @@ The CSRF middleware utilizes a set of sentinel errors to handle various scenario - `ErrNoReferer`: Indicates that the referer was not supplied. - `ErrBadReferer`: Indicates that the referer is invalid. -If you are using the default error handler, it will return a 403 Forbidden error for any of these errors without providing any additional information to the client. +If you use the default error handler, the client will receive a 403 Forbidden error without any additional information. ## Custom Error Handler diff --git a/middleware/csrf/config.go b/middleware/csrf/config.go index baab88e9..539e8496 100644 --- a/middleware/csrf/config.go +++ b/middleware/csrf/config.go @@ -29,7 +29,7 @@ type Config struct { // // Ignored if an Extractor is explicitly set. // - // Optional. Default: "header:X-CSRF-Token" + // Optional. Default: "header:X-Csrf-Token" KeyLookup string // Name of the session cookie. This cookie will store session key. diff --git a/middleware/csrf/csrf_test.go b/middleware/csrf/csrf_test.go index 562bfaf6..92cf77d8 100644 --- a/middleware/csrf/csrf_test.go +++ b/middleware/csrf/csrf_test.go @@ -280,7 +280,7 @@ func Test_CSRF_MultiUseToken(t *testing.T) { app := fiber.New() app.Use(New(Config{ - KeyLookup: "header:X-CSRF-Token", + KeyLookup: "header:X-Csrf-Token", })) app.Post("/", func(c *fiber.Ctx) error { @@ -292,7 +292,7 @@ func Test_CSRF_MultiUseToken(t *testing.T) { // Invalid CSRF token ctx.Request.Header.SetMethod(fiber.MethodPost) - ctx.Request.Header.Set("X-CSRF-Token", "johndoe") + ctx.Request.Header.Set("X-Csrf-Token", "johndoe") h(ctx) utils.AssertEqual(t, 403, ctx.Response.StatusCode()) @@ -307,7 +307,7 @@ func Test_CSRF_MultiUseToken(t *testing.T) { ctx.Request.Reset() ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodPost) - ctx.Request.Header.Set("X-CSRF-Token", token) + ctx.Request.Header.Set("X-Csrf-Token", token) ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) h(ctx) newToken := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) From 2c5d883a693747eafccd6bbebefe2d0202c36718 Mon Sep 17 00:00:00 2001 From: Jmper Date: Tue, 21 Nov 2023 17:48:37 +0800 Subject: [PATCH 12/19] [Bug]: utils.IsIPv4 and net.ParseIP have inconsistent results #2735 (#2736) --- utils/ips.go | 2 +- utils/ips_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/utils/ips.go b/utils/ips.go index 4886c117..54ab11b9 100644 --- a/utils/ips.go +++ b/utils/ips.go @@ -23,7 +23,7 @@ func IsIPv4(s string) bool { for ci = 0; ci < len(s) && '0' <= s[ci] && s[ci] <= '9'; ci++ { n = n*10 + int(s[ci]-'0') - if n >= 0xFF { + if n > 0xFF { return false } } diff --git a/utils/ips_test.go b/utils/ips_test.go index 862319f3..7a8a5e17 100644 --- a/utils/ips_test.go +++ b/utils/ips_test.go @@ -14,6 +14,7 @@ func Test_IsIPv4(t *testing.T) { AssertEqual(t, true, IsIPv4("174.23.33.100")) AssertEqual(t, true, IsIPv4("127.0.0.1")) + AssertEqual(t, true, IsIPv4("127.255.255.255")) AssertEqual(t, true, IsIPv4("0.0.0.0")) AssertEqual(t, false, IsIPv4(".0.0.0")) From 12e0e487ce775d446b659950c9131d63ffbce0a3 Mon Sep 17 00:00:00 2001 From: nickajacks1 <128185314+nickajacks1@users.noreply.github.com> Date: Wed, 22 Nov 2023 09:38:49 -0800 Subject: [PATCH 13/19] =?UTF-8?q?=F0=9F=9A=A8=20Test:=20fix=20race=20condi?= =?UTF-8?q?tion=20in=20parallel=20tests=20(#2734)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tests that call SetParserDecoder were causing a race condition with other tests that read from decoderPoolMap. Fix by making the offending tests not run in parallel. --- ctx_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/ctx_test.go b/ctx_test.go index 16df8262..ea9dfa84 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -636,7 +636,6 @@ func Test_Ctx_ParamParser(t *testing.T) { // go test -run Test_Ctx_BodyParser_WithSetParserDecoder func Test_Ctx_BodyParser_WithSetParserDecoder(t *testing.T) { - t.Parallel() type CustomTime time.Time timeConverter := func(value string) reflect.Value { @@ -4555,7 +4554,6 @@ func Test_Ctx_QueryParser_WithoutSplitting(t *testing.T) { // go test -run Test_Ctx_QueryParser_WithSetParserDecoder -v func Test_Ctx_QueryParser_WithSetParserDecoder(t *testing.T) { - t.Parallel() type NonRFCTime time.Time nonRFCConverter := func(value string) reflect.Value { @@ -4885,7 +4883,6 @@ func Test_Ctx_ReqHeaderParser_WithoutSplitting(t *testing.T) { // go test -run Test_Ctx_ReqHeaderParser_WithSetParserDecoder -v func Test_Ctx_ReqHeaderParser_WithSetParserDecoder(t *testing.T) { - t.Parallel() type NonRFCTime time.Time nonRFCConverter := func(value string) reflect.Value { From eeced206edfbfd605c016562d3466ca19a2ad6cf Mon Sep 17 00:00:00 2001 From: nickajacks1 <128185314+nickajacks1@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:21:30 -0800 Subject: [PATCH 14/19] =?UTF-8?q?=E2=9C=85=20test:=20Fix=20failing=20CSRF?= =?UTF-8?q?=20tests=20(#2720)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit โœ… test: fix failing csrf test A test validating that expired tokens fail was hitting a race condition with garbage collection. Sometimes, an assertion that expects memory storage GC to have triggered happens too quickly, causing the assertion to fail. Give the GC a little bit more time to process before asserting. --- middleware/csrf/csrf_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/middleware/csrf/csrf_test.go b/middleware/csrf/csrf_test.go index 92cf77d8..a51a9323 100644 --- a/middleware/csrf/csrf_test.go +++ b/middleware/csrf/csrf_test.go @@ -186,7 +186,7 @@ func Test_CSRF_ExpiredToken(t *testing.T) { utils.AssertEqual(t, 200, ctx.Response.StatusCode()) // Wait for the token to expire - time.Sleep(1 * time.Second) + time.Sleep(1250 * time.Millisecond) // Expired CSRF token ctx.Request.Reset() From 93c5f2830fdcd77d3973b2fe20c6b01556e03efd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Nov 2023 20:12:15 +0100 Subject: [PATCH 15/19] build(deps): bump github.com/valyala/fasthttp from 1.50.0 to 1.51.0 (#2721) Bumps [github.com/valyala/fasthttp](https://github.com/valyala/fasthttp) from 1.50.0 to 1.51.0. - [Release notes](https://github.com/valyala/fasthttp/releases) - [Commits](https://github.com/valyala/fasthttp/compare/v1.50.0...v1.51.0) --- updated-dependencies: - dependency-name: github.com/valyala/fasthttp dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index aa0abbe4..f84ef24a 100644 --- a/go.mod +++ b/go.mod @@ -9,13 +9,13 @@ require ( github.com/mattn/go-runewidth v0.0.15 github.com/tinylib/msgp v1.1.8 github.com/valyala/bytebufferpool v1.0.0 - github.com/valyala/fasthttp v1.50.0 + github.com/valyala/fasthttp v1.51.0 golang.org/x/sys v0.14.0 ) require ( github.com/andybalholm/brotli v1.0.5 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.0 // indirect github.com/philhofer/fwd v1.1.2 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/valyala/tcplisten v1.0.0 // indirect diff --git a/go.sum b/go.sum index 5b72a92d..34102262 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/ github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= +github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -19,8 +19,8 @@ github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0= github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.50.0 h1:H7fweIlBm0rXLs2q0XbalvJ6r0CUPFWK3/bB4N13e9M= -github.com/valyala/fasthttp v1.50.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA= +github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= From 6b9630b5f70d3bc732ecc3244225077b85724eeb Mon Sep 17 00:00:00 2001 From: nickajacks1 <128185314+nickajacks1@users.noreply.github.com> Date: Thu, 23 Nov 2023 00:36:22 -0800 Subject: [PATCH 16/19] =?UTF-8?q?=F0=9F=9A=A8=20Test:=20improve=20benchmar?= =?UTF-8?q?ks=20for=20getOffer=20(#2739)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helpers_test.go | 114 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 81 insertions(+), 33 deletions(-) diff --git a/helpers_test.go b/helpers_test.go index 39292d77..9f7f88c0 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -111,41 +111,89 @@ func Test_Utils_GetOffer(t *testing.T) { // go test -v -run=^$ -bench=Benchmark_Utils_GetOffer -benchmem -count=4 func Benchmark_Utils_GetOffer(b *testing.B) { - headers := []string{ - "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", - "application/json", - "utf-8, iso-8859-1;q=0.5", - "gzip, deflate", + testCases := []struct { + description string + accept string + offers []string + }{ + { + description: "simple", + accept: "application/json", + offers: []string{"application/json"}, + }, + { + description: "6 offers", + accept: "text/plain", + offers: []string{"junk/a", "junk/b", "junk/c", "junk/d", "junk/e", "text/plain"}, + }, + { + description: "1 parameter", + accept: "application/json; version=1", + offers: []string{"application/json;version=1"}, + }, + { + description: "2 parameters", + accept: "application/json; version=1; foo=bar", + offers: []string{"application/json;version=1;foo=bar"}, + }, + { + // 1 alloc: + // The implementation uses a slice of length 2 allocated on the stack, + // so a third parameters causes a heap allocation. + description: "3 parameters", + accept: "application/json; version=1; foo=bar; charset=utf-8", + offers: []string{"application/json;version=1;foo=bar;charset=utf-8"}, + }, + { + description: "10 parameters", + accept: "text/plain;a=1;b=2;c=3;d=4;e=5;f=6;g=7;h=8;i=9;j=10", + offers: []string{"text/plain;a=1;b=2;c=3;d=4;e=5;f=6;g=7;h=8;i=9;j=10"}, + }, + { + description: "6 offers w/params", + accept: "text/plain; format=flowed", + offers: []string{ + "junk/a;a=b", + "junk/b;b=c", + "junk/c;c=d", + "text/plain; format=justified", + "text/plain; format=flat", + "text/plain; format=flowed", + }, + }, + { + description: "mime extension", + accept: "utf-8, iso-8859-1;q=0.5", + offers: []string{"utf-8"}, + }, + { + description: "mime extension", + accept: "utf-8, iso-8859-1;q=0.5", + offers: []string{"iso-8859-1"}, + }, + { + description: "mime extension", + accept: "utf-8, iso-8859-1;q=0.5", + offers: []string{"iso-8859-1", "utf-8"}, + }, + { + description: "mime extension", + accept: "gzip, deflate", + offers: []string{"deflate"}, + }, + { + description: "web browser", + accept: "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", + offers: []string{"text/html", "application/xml", "application/xml+xhtml"}, + }, } - offers := [][]string{ - {"text/html", "application/xml", "application/xml+xhtml"}, - {"application/json"}, - {"utf-8"}, - {"deflate"}, - } - for n := 0; n < b.N; n++ { - for i, header := range headers { - getOffer(header, acceptsOfferType, offers[i]...) - } - } -} -// go test -v -run=^$ -bench=Benchmark_Utils_GetOffer_WithParams -benchmem -count=4 -func Benchmark_Utils_GetOffer_WithParams(b *testing.B) { - headers := []string{ - "text/html;p=1,application/xhtml+xml;p=1;b=2,application/xml;a=2;q=0.9,*/*;q=0.8", - "application/json; version=1", - "utf-8, iso-8859-1;q=0.5", - } - offers := [][]string{ - {"text/html;p=1", "application/xml;a=2", "application/xml+xhtml; p=1; b=2"}, - {"application/json; version=2"}, - {`utf-8;charset="utf-16"`}, - } - for n := 0; n < b.N; n++ { - for i, header := range headers { - getOffer(header, acceptsOfferType, offers[i]...) - } + for _, tc := range testCases { + b.Run(tc.description, func(b *testing.B) { + for n := 0; n < b.N; n++ { + getOffer(tc.accept, acceptsOfferType, tc.offers...) + } + }) } } From 28be17f929cfa7d3c27dd292fc3956f2f9882e22 Mon Sep 17 00:00:00 2001 From: RW Date: Mon, 27 Nov 2023 14:35:49 +0100 Subject: [PATCH 17/19] Revert ":bug: requestid.Config.ContextKey is interface{} (#2369)" (#2742) This reverts commit d7b36cde --- docs/api/middleware/requestid.md | 2 +- middleware/requestid/config.go | 2 +- middleware/requestid/requestid_test.go | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/api/middleware/requestid.md b/docs/api/middleware/requestid.md index c8ca8d59..112d21d4 100644 --- a/docs/api/middleware/requestid.md +++ b/docs/api/middleware/requestid.md @@ -45,7 +45,7 @@ app.Use(requestid.New(requestid.Config{ | Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | | Header | `string` | Header is the header key where to get/set the unique request ID. | "X-Request-ID" | | Generator | `func() string` | Generator defines a function to generate the unique identifier. | utils.UUID | -| ContextKey | `interface{}` | ContextKey defines the key used when storing the request ID in the locals for a specific request. | "requestid" | +| ContextKey | `string` | ContextKey defines the key used when storing the request ID in the locals for a specific request. | "requestid" | ## Default Config The default config uses a fast UUID generator which will expose the number of diff --git a/middleware/requestid/config.go b/middleware/requestid/config.go index cc699078..b3b605e5 100644 --- a/middleware/requestid/config.go +++ b/middleware/requestid/config.go @@ -26,7 +26,7 @@ type Config struct { // the locals for a specific request. // // Optional. Default: requestid - ContextKey interface{} + ContextKey string } // ConfigDefault is the default config diff --git a/middleware/requestid/requestid_test.go b/middleware/requestid/requestid_test.go index ee3d33d6..451e96b4 100644 --- a/middleware/requestid/requestid_test.go +++ b/middleware/requestid/requestid_test.go @@ -55,21 +55,20 @@ func Test_RequestID_Next(t *testing.T) { func Test_RequestID_Locals(t *testing.T) { t.Parallel() reqID := "ThisIsARequestId" - type ContextKey int - const requestContextKey ContextKey = iota + ctxKey := "ThisIsAContextKey" app := fiber.New() app.Use(New(Config{ Generator: func() string { return reqID }, - ContextKey: requestContextKey, + ContextKey: ctxKey, })) var ctxVal string app.Use(func(c *fiber.Ctx) error { - ctxVal = c.Locals(requestContextKey).(string) //nolint:forcetypeassert,errcheck // We always store a string in here + ctxVal = c.Locals(ctxKey).(string) //nolint:forcetypeassert,errcheck // We always store a string in here return c.Next() }) From 8d5248bee605aa75b5053e6791e4f2a878072819 Mon Sep 17 00:00:00 2001 From: nickajacks1 <128185314+nickajacks1@users.noreply.github.com> Date: Mon, 27 Nov 2023 05:38:31 -0800 Subject: [PATCH 18/19] =?UTF-8?q?=F0=9F=9A=A8=20Test:=20race=20in=20sessio?= =?UTF-8?q?n=20middleware=20tests=20(#2740)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A Session must not be accessed after Save() is called, but a unit test calls Session.ID() after Session.Save(), sometimes causing the test to fail when -race is enabled. The assertions that ID() was being used in were redundant with the previous two assertions (checking that the session name header is empty), so we can just remove the offending code. --- middleware/session/session_test.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/middleware/session/session_test.go b/middleware/session/session_test.go index 5fdad004..788a3c82 100644 --- a/middleware/session/session_test.go +++ b/middleware/session/session_test.go @@ -503,6 +503,7 @@ func Test_Session_Reset(t *testing.T) { utils.AssertEqual(t, nil, err) utils.AssertEqual(t, false, acquiredSession.ID() == originalSessionUUIDString) + utils.AssertEqual(t, false, acquiredSession.ID() == "") // acquiredSession.fresh should be true after resetting utils.AssertEqual(t, true, acquiredSession.Fresh()) @@ -523,10 +524,6 @@ func Test_Session_Reset(t *testing.T) { // Check that the session id is not in the header or cookie anymore utils.AssertEqual(t, "", string(ctx.Response().Header.Peek(store.sessionName))) utils.AssertEqual(t, "", string(ctx.Request().Header.Peek(store.sessionName))) - - // But the new session id should be in the header or cookie - utils.AssertEqual(t, acquiredSession.ID(), string(ctx.Response().Header.Peek(store.sessionName))) - utils.AssertEqual(t, acquiredSession.ID(), string(ctx.Request().Header.Peek(store.sessionName))) }) } From fa30b4e9d0c937875384e0ef59007d7685112920 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 22:42:05 +0300 Subject: [PATCH 19/19] build(deps): bump golang.org/x/sys from 0.14.0 to 0.15.0 (#2744) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.14.0 to 0.15.0. - [Commits](https://github.com/golang/sys/compare/v0.14.0...v0.15.0) --- updated-dependencies: - dependency-name: golang.org/x/sys dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f84ef24a..eac01a31 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/tinylib/msgp v1.1.8 github.com/valyala/bytebufferpool v1.0.0 github.com/valyala/fasthttp v1.51.0 - golang.org/x/sys v0.14.0 + golang.org/x/sys v0.15.0 ) require ( diff --git a/go.sum b/go.sum index 34102262..56bcdc96 100644 --- a/go.sum +++ b/go.sum @@ -43,8 +43,8 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q= -golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=