From f29f39b1b3f640b29a1df5e315b126ca24b67ba7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Victor=20Oliveira=20Couto?= Date: Sun, 6 Aug 2023 12:23:37 -0300 Subject: [PATCH 01/84] fix: Decompress request body when multi Content-Encoding sent on request headers (#2555) * :wrench: feat: Decode body in order when sent a list on content-encoding * :rocket: perf: Change `getSplicedStrList` to have 0 allocations * :tea: test: Add tests for the new features * :tea: test: Ensure session test will not raise an error unexpectedly * :boar: feat: Replace strings.TrimLeft by utils.TrimLeft Add docs to functions to inform correctly what the change is * :tulip: refactor: Apply linter rules * :tea: test: Add test cases to the new body method change * :wrench: feat: Remove return problems to be able to reach original body * :tulip: refactor: Split Body method into two to make it more maintainable Also, with the previous fix to problems detected by tests, it becomes really hard to make the linter happy, so this change also helps in it * :rocket: perf: Came back with Header.VisitAll, to improve speed * :page_with_curl: docs: Update Context docs --- ctx.go | 89 ++++++++++-- ctx_test.go | 225 +++++++++++++++++++++++++---- docs/api/ctx.md | 61 +++++--- helpers.go | 35 +++++ helpers_test.go | 47 ++++++ middleware/session/session_test.go | 5 +- 6 files changed, 395 insertions(+), 67 deletions(-) diff --git a/ctx.go b/ctx.go index 901b51744c..86fae50dde 100644 --- a/ctx.go +++ b/ctx.go @@ -260,31 +260,92 @@ func (c *Ctx) BaseURL() string { return c.baseURI } -// Body contains the raw body submitted in a POST request. +// BodyRaw contains the raw body submitted in a POST request. // Returned value is only valid within the handler. Do not store any references. // Make copies or use the Immutable setting instead. +func (c *Ctx) BodyRaw() []byte { + return c.fasthttp.Request.Body() +} + +func (c *Ctx) tryDecodeBodyInOrder( + originalBody *[]byte, + encodings []string, +) ([]byte, uint8, error) { + var ( + err error + body []byte + decodesRealized uint8 + ) + + for index, encoding := range encodings { + decodesRealized++ + switch encoding { + case StrGzip: + body, err = c.fasthttp.Request.BodyGunzip() + case StrBr, StrBrotli: + body, err = c.fasthttp.Request.BodyUnbrotli() + case StrDeflate: + body, err = c.fasthttp.Request.BodyInflate() + default: + decodesRealized-- + if len(encodings) == 1 { + body = c.fasthttp.Request.Body() + } + return body, decodesRealized, nil + } + + if err != nil { + return nil, decodesRealized, err + } + + // Only execute body raw update if it has a next iteration to try to decode + if index < len(encodings)-1 && decodesRealized > 0 { + if index == 0 { + tempBody := c.fasthttp.Request.Body() + *originalBody = make([]byte, len(tempBody)) + copy(*originalBody, tempBody) + } + c.fasthttp.Request.SetBodyRaw(body) + } + } + + return body, decodesRealized, nil +} + +// Body contains the raw body submitted in a POST request. +// This method will decompress the body if the 'Content-Encoding' header is provided. +// It returns the original (or decompressed) body data which is valid only within the handler. +// Don't store direct references to the returned data. +// If you need to keep the body's data later, make a copy or use the Immutable option. func (c *Ctx) Body() []byte { - var err error - var encoding string - var body []byte + var ( + err error + body, originalBody []byte + headerEncoding string + encodingOrder = []string{"", "", ""} + ) + // faster than peek c.Request().Header.VisitAll(func(key, value []byte) { if c.app.getString(key) == HeaderContentEncoding { - encoding = c.app.getString(value) + headerEncoding = c.app.getString(value) } }) - switch encoding { - case StrGzip: - body, err = c.fasthttp.Request.BodyGunzip() - case StrBr, StrBrotli: - body, err = c.fasthttp.Request.BodyUnbrotli() - case StrDeflate: - body, err = c.fasthttp.Request.BodyInflate() - default: - body = c.fasthttp.Request.Body() + // Split and get the encodings list, in order to attend the + // rule defined at: https://www.rfc-editor.org/rfc/rfc9110#section-8.4-5 + encodingOrder = getSplicedStrList(headerEncoding, encodingOrder) + if len(encodingOrder) == 0 { + return c.fasthttp.Request.Body() } + var decodesRealized uint8 + body, decodesRealized, err = c.tryDecodeBodyInOrder(&originalBody, encodingOrder) + + // Ensure that the body will be the original + if originalBody != nil && decodesRealized > 0 { + c.fasthttp.Request.SetBodyRaw(originalBody) + } if err != nil { return []byte(err.Error()) } diff --git a/ctx_test.go b/ctx_test.go index 38e83ca9e2..e092fcd322 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -9,6 +9,7 @@ import ( "bufio" "bytes" "compress/gzip" + "compress/zlib" "context" "crypto/tls" "encoding/xml" @@ -323,47 +324,211 @@ func Test_Ctx_Body(t *testing.T) { utils.AssertEqual(t, []byte("john=doe"), c.Body()) } -// go test -run Test_Ctx_Body_With_Compression -func Test_Ctx_Body_With_Compression(t *testing.T) { - t.Parallel() +func Benchmark_Ctx_Body(b *testing.B) { + const input = "john=doe" + app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) - c.Request().Header.Set("Content-Encoding", "gzip") - var b bytes.Buffer - gz := gzip.NewWriter(&b) - _, err := gz.Write([]byte("john=doe")) - utils.AssertEqual(t, nil, err) - err = gz.Flush() - utils.AssertEqual(t, nil, err) - err = gz.Close() - utils.AssertEqual(t, nil, err) - c.Request().SetBody(b.Bytes()) - utils.AssertEqual(t, []byte("john=doe"), c.Body()) + + c.Request().SetBody([]byte(input)) + for i := 0; i < b.N; i++ { + _ = c.Body() + } + + utils.AssertEqual(b, []byte(input), c.Body()) +} + +// go test -run Test_Ctx_Body_With_Compression +func Test_Ctx_Body_With_Compression(t *testing.T) { + t.Parallel() + tests := []struct { + name string + contentEncoding string + body []byte + expectedBody []byte + }{ + { + name: "gzip", + contentEncoding: "gzip", + body: []byte("john=doe"), + expectedBody: []byte("john=doe"), + }, + { + name: "unsupported_encoding", + contentEncoding: "undefined", + body: []byte("keeps_ORIGINAL"), + expectedBody: []byte("keeps_ORIGINAL"), + }, + { + name: "gzip then unsupported", + contentEncoding: "gzip, undefined", + body: []byte("Go, be gzipped"), + expectedBody: []byte("Go, be gzipped"), + }, + { + name: "invalid_deflate", + contentEncoding: "gzip,deflate", + body: []byte("I'm not correctly compressed"), + expectedBody: []byte(zlib.ErrHeader.Error()), + }, + } + + for _, testObject := range tests { + tCase := testObject // Duplicate object to ensure it will be unique across all runs + t.Run(tCase.name, func(t *testing.T) { + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + c.Request().Header.Set("Content-Encoding", tCase.contentEncoding) + + if strings.Contains(tCase.contentEncoding, "gzip") { + var b bytes.Buffer + gz := gzip.NewWriter(&b) + _, err := gz.Write(tCase.body) + if err != nil { + t.Fatal(err) + } + if err = gz.Flush(); err != nil { + t.Fatal(err) + } + if err = gz.Close(); err != nil { + t.Fatal(err) + } + tCase.body = b.Bytes() + } + + c.Request().SetBody(tCase.body) + body := c.Body() + utils.AssertEqual(t, tCase.expectedBody, body) + + // Check if body raw is the same as previous before decompression + utils.AssertEqual( + t, tCase.body, c.Request().Body(), + "Body raw must be the same as set before", + ) + }) + } } // go test -v -run=^$ -bench=Benchmark_Ctx_Body_With_Compression -benchmem -count=4 func Benchmark_Ctx_Body_With_Compression(b *testing.B) { - app := New() - c := app.AcquireCtx(&fasthttp.RequestCtx{}) - defer app.ReleaseCtx(c) - c.Request().Header.Set("Content-Encoding", "gzip") - var buf bytes.Buffer - gz := gzip.NewWriter(&buf) - _, err := gz.Write([]byte("john=doe")) - utils.AssertEqual(b, nil, err) - err = gz.Flush() - utils.AssertEqual(b, nil, err) - err = gz.Close() - utils.AssertEqual(b, nil, err) + encodingErr := errors.New("failed to encoding data") + + var ( + compressGzip = func(data []byte) ([]byte, error) { + var buf bytes.Buffer + writer := gzip.NewWriter(&buf) + if _, err := writer.Write(data); err != nil { + return nil, encodingErr + } + if err := writer.Flush(); err != nil { + return nil, encodingErr + } + if err := writer.Close(); err != nil { + return nil, encodingErr + } + return buf.Bytes(), nil + } + compressDeflate = func(data []byte) ([]byte, error) { + var buf bytes.Buffer + writer := zlib.NewWriter(&buf) + if _, err := writer.Write(data); err != nil { + return nil, encodingErr + } + if err := writer.Flush(); err != nil { + return nil, encodingErr + } + if err := writer.Close(); err != nil { + return nil, encodingErr + } + return buf.Bytes(), nil + } + ) + compressionTests := []struct { + contentEncoding string + compressWriter func([]byte) ([]byte, error) + }{ + { + contentEncoding: "gzip", + compressWriter: compressGzip, + }, + { + contentEncoding: "gzip,invalid", + compressWriter: compressGzip, + }, + { + contentEncoding: "deflate", + compressWriter: compressDeflate, + }, + { + contentEncoding: "gzip,deflate", + compressWriter: func(data []byte) ([]byte, error) { + var ( + buf bytes.Buffer + writer interface { + io.WriteCloser + Flush() error + } + err error + ) + + // deflate + { + writer = zlib.NewWriter(&buf) + if _, err = writer.Write(data); err != nil { + return nil, encodingErr + } + if err = writer.Flush(); err != nil { + return nil, encodingErr + } + if err = writer.Close(); err != nil { + return nil, encodingErr + } + } - c.Request().SetBody(buf.Bytes()) + data = make([]byte, buf.Len()) + copy(data, buf.Bytes()) + buf.Reset() + + // gzip + { + writer = gzip.NewWriter(&buf) + if _, err = writer.Write(data); err != nil { + return nil, encodingErr + } + if err = writer.Flush(); err != nil { + return nil, encodingErr + } + if err = writer.Close(); err != nil { + return nil, encodingErr + } + } - for i := 0; i < b.N; i++ { - _ = c.Body() + return buf.Bytes(), nil + }, + }, } - utils.AssertEqual(b, []byte("john=doe"), c.Body()) + for _, ct := range compressionTests { + b.Run(ct.contentEncoding, func(b *testing.B) { + app := New() + const input = "john=doe" + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + + c.Request().Header.Set("Content-Encoding", ct.contentEncoding) + compressedBody, err := ct.compressWriter([]byte(input)) + utils.AssertEqual(b, nil, err) + + c.Request().SetBody(compressedBody) + for i := 0; i < b.N; i++ { + _ = c.Body() + } + + utils.AssertEqual(b, []byte(input), c.Body()) + }) + } } // go test -run Test_Ctx_BodyParser diff --git a/docs/api/ctx.md b/docs/api/ctx.md index aa48c60929..1da3db9795 100644 --- a/docs/api/ctx.md +++ b/docs/api/ctx.md @@ -57,13 +57,13 @@ Fiber provides similar functions for the other accept headers. // Accept-Language: en;q=0.8, nl, ru app.Get("/", func(c *fiber.Ctx) error { - c.AcceptsCharsets("utf-16", "iso-8859-1") + c.AcceptsCharsets("utf-16", "iso-8859-1") // "iso-8859-1" - c.AcceptsEncodings("compress", "br") + c.AcceptsEncodings("compress", "br") // "compress" - c.AcceptsLanguages("pt", "nl", "ru") + c.AcceptsLanguages("pt", "nl", "ru") // "nl" // ... }) @@ -171,6 +171,7 @@ app.Get("/", func(c *fiber.Ctx) error { ``` ## Bind + Add vars to default view var map binding to template engine. Variables are read by the Render method and may be overwritten. @@ -190,12 +191,12 @@ app.Get("/", func(c *fiber.Ctx) error { }) ``` -## Body +## BodyRaw Returns the raw request **body**. ```go title="Signature" -func (c *Ctx) Body() []byte +func (c *Ctx) BodyRaw() []byte ``` ```go title="Example" @@ -203,6 +204,26 @@ func (c *Ctx) Body() []byte app.Post("/", func(c *fiber.Ctx) error { // Get raw body from POST request: + return c.Send(c.BodyRaw()) // []byte("user=john") +}) +``` + +> _Returned value is only valid within the handler. Do not store any references. +> Make copies or use the_ [_**`Immutable`**_](ctx.md) _setting instead._ [_Read more..._](../#zero-allocation) + +## Body + +As per the header `Content-Encoding`, this method will try to perform a file decompression from the **body** bytes. In case no `Content-Encoding` header is sent, it will perform as [BodyRaw](#bodyraw). + +```go title="Signature" +func (c *Ctx) Body() []byte +``` + +```go title="Example" +// echo 'user=john' | gzip | curl -v -i --data-binary @- -H "Content-Encoding: gzip" http://localhost:8080 + +app.Post("/", func(c *fiber.Ctx) error { + // Decompress body from POST request based on the Content-Encoding and return the raw content: return c.Send(c.Body()) // []byte("user=john") }) ``` @@ -216,13 +237,13 @@ Binds the request body to a struct. It is important to specify the correct struct tag based on the content type to be parsed. For example, if you want to parse a JSON body with a field called Pass, you would use a struct field of `json:"pass"`. -| content-type | struct tag | -|---|---| -| `application/x-www-form-urlencoded` | form | -| `multipart/form-data` | form | -| `application/json` | json | -| `application/xml` | xml | -| `text/xml` | xml | +| content-type | struct tag | +| ----------------------------------- | ---------- | +| `application/x-www-form-urlencoded` | form | +| `multipart/form-data` | form | +| `application/json` | json | +| `application/xml` | xml | +| `text/xml` | xml | ```go title="Signature" func (c *Ctx) BodyParser(out interface{}) error @@ -693,6 +714,7 @@ app.Get("/", func(c *fiber.Ctx) error { ## IsFromLocal Returns true if request came from localhost + ```go title="Signature" func (c *Ctx) IsFromLocal() bool { ``` @@ -837,7 +859,7 @@ app.Post("/", func(c *fiber.Ctx) error { c.Location("http://example.com") c.Location("/foo/bar") - + return nil }) ``` @@ -1024,6 +1046,7 @@ app.Get("/user/:id", func(c *fiber.Ctx) error { This method is equivalent of using `atoi` with ctx.Params ## ParamsParser + This method is similar to BodyParser, but for path parameters. It is important to use the struct tag "params". For example, if you want to parse a path parameter with a field called Pass, you would use a struct field of params:"pass" ```go title="Signature" @@ -1034,7 +1057,7 @@ func (c *Ctx) ParamsParser(out interface{}) error // GET http://example.com/user/111 app.Get("/user/:id", func(c *fiber.Ctx) error { param := struct {ID uint `params:"id"`}{} - + c.ParamsParser(¶m) // "{"id": 111}" // ... @@ -1176,7 +1199,6 @@ app.Get("/", func(c *fiber.Ctx) error { This property is an object containing a property for each query boolean parameter in the route, you could pass an optional default value that will be returned if the query key does not exist. - :::caution Please note if that parameter is not in the request, false will be returned. If the parameter is not a boolean, it is still tried to be converted and usually returned as false. @@ -1232,12 +1254,10 @@ app.Get("/", func(c *fiber.Ctx) error { }) ``` - ## QueryInt This property is an object containing a property for each query integer parameter in the route, you could pass an optional default value that will be returned if the query key does not exist. - :::caution Please note if that parameter is not in the request, zero will be returned. If the parameter is not a number, it is still tried to be converted and usually returned as 1. @@ -1522,7 +1542,7 @@ func (c *Ctx) Route() *Route app.Get("/hello/:name", func(c *fiber.Ctx) error { r := c.Route() fmt.Println(r.Method, r.Path, r.Params, r.Handlers) - // GET /hello/:name handler [name] + // GET /hello/:name handler [name] // ... }) @@ -1768,7 +1788,7 @@ var timeConverter = func(value string) reflect.Value { customTime := fiber.ParserType{ Customtype: CustomTime{}, Converter: timeConverter, -} +} // Add setting to the Decoder fiber.SetParserDecoder(fiber.ParserConfig{ @@ -1804,7 +1824,6 @@ app.Get("/query", func(c *fiber.Ctx) error { ``` - ## SetUserContext Sets the user specified implementation for context interface. @@ -2020,7 +2039,7 @@ XML also sets the content header to **application/xml**. ::: ```go title="Signature" -func (c *Ctx) XML(data interface{}) error +func (c *Ctx) XML(data interface{}) error ``` ```go title="Example" diff --git a/helpers.go b/helpers.go index cfe31e0d40..cc36f13e10 100644 --- a/helpers.go +++ b/helpers.go @@ -269,6 +269,41 @@ func acceptsOfferType(spec, offerType string) bool { return false } +// getSplicedStrList function takes a string and a string slice as an argument, divides the string into different +// elements divided by ',' and stores these elements in the string slice. +// It returns the populated string slice as an output. +// +// If the given slice hasn't enough space, it will allocate more and return. +func getSplicedStrList(headerValue string, dst []string) []string { + if headerValue == "" { + return nil + } + + var ( + index int + character rune + lastElementEndsAt uint8 + insertIndex int + ) + for index, character = range headerValue + "$" { + if character == ',' || index == len(headerValue) { + if insertIndex >= len(dst) { + oldSlice := dst + dst = make([]string, len(dst)+(len(dst)>>1)+2) + copy(dst, oldSlice) + } + dst[insertIndex] = utils.TrimLeft(headerValue[lastElementEndsAt:index], ' ') + lastElementEndsAt = uint8(index + 1) + insertIndex++ + } + } + + if len(dst) > insertIndex { + dst = dst[:insertIndex] + } + return dst +} + // getOffer return valid offer for header negotiation func getOffer(header string, isAccepted func(spec, offer string) bool, offers ...string) string { if len(offers) == 0 { diff --git a/helpers_test.go b/helpers_test.go index 5ecab49034..788b7a9a47 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -107,6 +107,53 @@ func Benchmark_Utils_GetOffer(b *testing.B) { } } +func Test_Utils_GetSplicedStrList(t *testing.T) { + testCases := []struct { + description string + headerValue string + expectedList []string + }{ + { + description: "normal case", + headerValue: "gzip, deflate,br", + expectedList: []string{"gzip", "deflate", "br"}, + }, + { + description: "no matter the value", + headerValue: " gzip,deflate, br, zip", + expectedList: []string{"gzip", "deflate", "br", "zip"}, + }, + { + description: "headerValue is empty", + headerValue: "", + expectedList: nil, + }, + { + description: "has a comma without element", + headerValue: "gzip,", + expectedList: []string{"gzip", ""}, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + dst := make([]string, 10) + result := getSplicedStrList(tc.headerValue, dst) + utils.AssertEqual(t, tc.expectedList, result) + }) + } +} + +func Benchmark_Utils_GetSplicedStrList(b *testing.B) { + destination := make([]string, 5) + result := destination + const input = "deflate, gzip,br,brotli" + for n := 0; n < b.N; n++ { + result = getSplicedStrList(input, destination) + } + utils.AssertEqual(b, []string{"deflate", "gzip", "br", "brotli"}, result) +} + func Test_Utils_SortAcceptedTypes(t *testing.T) { t.Parallel() acceptedTypes := []acceptedType{ diff --git a/middleware/session/session_test.go b/middleware/session/session_test.go index 20d683f458..db11cb4a49 100644 --- a/middleware/session/session_test.go +++ b/middleware/session/session_test.go @@ -287,6 +287,7 @@ func Test_Session_Save_Expiration(t *testing.T) { t.Parallel() t.Run("save to cookie", func(t *testing.T) { + const sessionDuration = 5 * time.Second t.Parallel() // session store store := New() @@ -302,7 +303,7 @@ func Test_Session_Save_Expiration(t *testing.T) { sess.Set("name", "john") // expire this session in 5 seconds - sess.SetExpiry(time.Second * 5) + sess.SetExpiry(sessionDuration) // save session err = sess.Save() @@ -314,7 +315,7 @@ func Test_Session_Save_Expiration(t *testing.T) { utils.AssertEqual(t, "john", sess.Get("name")) // just to make sure the session has been expired - time.Sleep(time.Second * 5) + time.Sleep(sessionDuration + (10 * time.Millisecond)) // here you should get a new session sess, err = store.Get(ctx) From 9fbb961adbad2a0f71adbed8f6acade9963950f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Sun, 6 Aug 2023 19:10:44 +0300 Subject: [PATCH 02/84] filesystem: refactor: use `errors.Is` instead of `os.IsNotExist` (#2558) --- internal/gopsutil/net/net_linux.go | 3 ++- internal/gopsutil/process/process_posix.go | 4 +++- middleware/filesystem/filesystem.go | 15 ++++++++------- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/internal/gopsutil/net/net_linux.go b/internal/gopsutil/net/net_linux.go index de8a3a7e80..964b053c73 100644 --- a/internal/gopsutil/net/net_linux.go +++ b/internal/gopsutil/net/net_linux.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "io" + "io/fs" "net" "os" "strconv" @@ -673,7 +674,7 @@ func getProcInodesAll(root string, max int) (map[string][]inodeMap, error) { t, err := getProcInodes(root, pid, max) if err != nil { // skip if permission error or no longer exists - if os.IsPermission(err) || os.IsNotExist(err) || err == io.EOF { + if os.IsPermission(err) || errors.Is(err, fs.ErrNotExist) || err == io.EOF { continue } return ret, err diff --git a/internal/gopsutil/process/process_posix.go b/internal/gopsutil/process/process_posix.go index 1b6c6fc2d7..ee09574c74 100644 --- a/internal/gopsutil/process/process_posix.go +++ b/internal/gopsutil/process/process_posix.go @@ -5,7 +5,9 @@ package process import ( "context" + "errors" "fmt" + "io/fs" "os" "os/user" "path/filepath" @@ -86,7 +88,7 @@ func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { // This covers the case when running inside container with a different process namespace (by default) _, err := os.Stat(common.HostProc(strconv.Itoa(int(pid)))) - if os.IsNotExist(err) { + if errors.Is(err, fs.ErrNotExist) { return false, nil } return err == nil, err diff --git a/middleware/filesystem/filesystem.go b/middleware/filesystem/filesystem.go index 4b5b6c2928..42276a9b5b 100644 --- a/middleware/filesystem/filesystem.go +++ b/middleware/filesystem/filesystem.go @@ -1,9 +1,10 @@ package filesystem import ( + "errors" "fmt" + "io/fs" "net/http" - "os" "strconv" "strings" "sync" @@ -143,11 +144,11 @@ func New(config ...Config) fiber.Handler { path = utils.TrimRight(path, '/') } file, err := cfg.Root.Open(path) - if err != nil && os.IsNotExist(err) && cfg.NotFoundFile != "" { + if err != nil && errors.Is(err, fs.ErrNotExist) && cfg.NotFoundFile != "" { file, err = cfg.Root.Open(cfg.NotFoundFile) } if err != nil { - if os.IsNotExist(err) { + if errors.Is(err, fs.ErrNotExist) { return c.Status(fiber.StatusNotFound).Next() } return fmt.Errorf("failed to open: %w", err) @@ -217,10 +218,10 @@ func New(config ...Config) fiber.Handler { } // SendFile ... -func SendFile(c *fiber.Ctx, fs http.FileSystem, path string) error { - file, err := fs.Open(path) +func SendFile(c *fiber.Ctx, filesystem http.FileSystem, path string) error { + file, err := filesystem.Open(path) if err != nil { - if os.IsNotExist(err) { + if errors.Is(err, fs.ErrNotExist) { return fiber.ErrNotFound } return fmt.Errorf("failed to open: %w", err) @@ -234,7 +235,7 @@ func SendFile(c *fiber.Ctx, fs http.FileSystem, path string) error { // Serve index if path is directory if stat.IsDir() { indexPath := utils.TrimRight(path, '/') + ConfigDefault.Index - index, err := fs.Open(indexPath) + index, err := filesystem.Open(indexPath) if err == nil { indexStat, err := index.Stat() if err == nil { From 1e4e0c3b76bbbea8950256ba5591e0ef4eb021f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Mon, 7 Aug 2023 10:35:50 +0200 Subject: [PATCH 03/84] optimize release drafter config --- .github/release-drafter.yml | 63 ++++++++++++++++++++----------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 134447d7bc..ebc7c6f96c 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,37 +1,44 @@ name-template: 'v$RESOLVED_VERSION' tag-template: 'v$RESOLVED_VERSION' categories: - - title: '🚀 New' - labels: - - '✏️ Feature' - - title: '🧹 Updates' - labels: - - '🧹 Updates' - - '🤖 Dependencies' - - title: '🐛 Fixes' - labels: - - '☢️ Bug' - - title: '📚 Documentation' - labels: - - '📒 Documentation' + - title: '❗ Breaking Changes' + labels: + - '❗ BreakingChange' + - title: '🚀 New' + labels: + - '✏️ Feature' + - title: '🧹 Updates' + labels: + - '🧹 Updates' + - '🤖 Dependencies' + - title: '🐛 Fixes' + labels: + - '☢️ Bug' + - title: '📚 Documentation' + labels: + - '📒 Documentation' change-template: '- $TITLE (#$NUMBER)' change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. +exclude-contributors: + - dependabot + - dependabot[bot] version-resolver: - major: - labels: - - 'major' - minor: - labels: - - 'minor' - - '✏️ Feature' - patch: - labels: - - 'patch' - - '📒 Documentation' - - '☢️ Bug' - - '🤖 Dependencies' - - '🧹 Updates' - default: patch + major: + labels: + - 'major' + - '❗ BreakingChange' + minor: + labels: + - 'minor' + - '✏️ Feature' + patch: + labels: + - 'patch' + - '📒 Documentation' + - '☢️ Bug' + - '🤖 Dependencies' + - '🧹 Updates' + default: patch template: | $CHANGES From e4839eaeba9318526f05223fa8db8c7f4af62380 Mon Sep 17 00:00:00 2001 From: RW Date: Mon, 7 Aug 2023 15:51:16 +0200 Subject: [PATCH 04/84] Update sync_docs.sh optimize sync docs - sort version json --- .github/scripts/sync_docs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/sync_docs.sh b/.github/scripts/sync_docs.sh index 4b58a1e128..ae870a728d 100755 --- a/.github/scripts/sync_docs.sh +++ b/.github/scripts/sync_docs.sh @@ -37,7 +37,7 @@ elif [ "$EVENT" == "release" ]; then # Check if contrib_versions.json exists and modify it if required if [[ -f $VERSION_FILE ]]; then jq --arg new_version "$new_version" 'del(.[] | select(. == $new_version))' $VERSION_FILE >temp.json && mv temp.json $VERSION_FILE - jq -S . ${VERSION_FILE} >temp.json && mv temp.json ${VERSION_FILE} + jq 'sort | reverse' ${VERSION_FILE} >temp.json && mv temp.json ${VERSION_FILE} fi # Run docusaurus versioning command From e6a93808800753d626cd3c3b3a0b75300ed29feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Mon, 7 Aug 2023 16:03:12 +0200 Subject: [PATCH 05/84] sync docs workflow optimization --- .github/scripts/sync_docs.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/scripts/sync_docs.sh b/.github/scripts/sync_docs.sh index ae870a728d..a05e1ab238 100755 --- a/.github/scripts/sync_docs.sh +++ b/.github/scripts/sync_docs.sh @@ -36,12 +36,15 @@ elif [ "$EVENT" == "release" ]; then # Check if contrib_versions.json exists and modify it if required if [[ -f $VERSION_FILE ]]; then - jq --arg new_version "$new_version" 'del(.[] | select(. == $new_version))' $VERSION_FILE >temp.json && mv temp.json $VERSION_FILE - jq 'sort | reverse' ${VERSION_FILE} >temp.json && mv temp.json ${VERSION_FILE} + jq --arg new_version "$new_version" 'del(.[] | select(. == $new_version))' $VERSION_FILE > temp.json && mv temp.json $VERSION_FILE fi # Run docusaurus versioning command $DOCUSAURUS_COMMAND "${new_version}" + + if [[ -f $VERSION_FILE ]]; then + jq 'sort | reverse' ${VERSION_FILE} > temp.json && mv temp.json ${VERSION_FILE} + fi fi # Push changes From 8d8bddf21246cc390ab64cc231b6297bd54ef9c8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:16:16 +0200 Subject: [PATCH 06/84] build(deps): bump golang.org/x/sys from 0.10.0 to 0.11.0 (#2563) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.10.0 to 0.11.0. - [Commits](https://github.com/golang/sys/compare/v0.10.0...v0.11.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 b20325a780..b5e96ceff5 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.48.0 - golang.org/x/sys v0.10.0 + golang.org/x/sys v0.11.0 ) require ( diff --git a/go.sum b/go.sum index 780c01035e..0b6ac4a42d 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.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= From 35a13fb726e7e6506c113d8b0d45f45193225da1 Mon Sep 17 00:00:00 2001 From: Anderson Miranda Date: Wed, 9 Aug 2023 13:05:01 +0200 Subject: [PATCH 07/84] =?UTF-8?q?=F0=9F=93=9A=20Doc:=20Translate=20README?= =?UTF-8?q?=20to=20Portuguese=20(#2567)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 📚 Doc: Translate REAMDE to Portuguese Co-authored-by: Anderson Miranda --- .github/README_pt.md | 103 ++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 51 deletions(-) diff --git a/.github/README_pt.md b/.github/README_pt.md index e08341d749..846da368dc 100644 --- a/.github/README_pt.md +++ b/.github/README_pt.md @@ -152,9 +152,9 @@ Os novos gophers que mudaram do [Node.js](https://nodejs.org/en/about/) para o [ O Fiber é **inspirado** no Express, o framework web mais popular da Internet. Combinamos a **facilidade** do Express e com o **desempenho bruto** do Go. Se você já implementou um aplicativo web com Node.js ( _usando Express.js ou similar_ ), então muitos métodos e princípios parecerão **muito familiares** para você. -## ⚠️ Limitations -* Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. -* Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. +## ⚠️ Limitações +* Devido ao uso de "unsafe" pelo Fiber, a biblioteca pode nem sempre ser compatível com a última versão do Go. Fiber 2.40.0 foi testado com as versões Go de 1.17 a 1.20. +* Fiber não é compatível com as interfaces net/http. Isso significa que você não poderá usar projetos como gqlgen, go-swagger ou quaisquer outros que fazem parte do ecossistema net/http. ## 👀 Exemplos @@ -203,7 +203,7 @@ func main() { ``` -#### 📖 [**Route Naming**](https://docs.gofiber.io/api/app#name) +#### 📖 [**Nome de Rotas**](https://docs.gofiber.io/api/app#name) ```go func main() { @@ -570,53 +570,54 @@ func main() { -## 🧬 Internal Middleware - -Here is a list of middleware that are included within the Fiber framework. - -| Middleware | Description | -| :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Basic auth middleware provides an HTTP basic authentication. It calls the next handler for valid credentials and 401 Unauthorized for missing or invalid credentials. | -| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercept and cache responses | -| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Compression middleware for Fiber, it supports `deflate`, `gzip` and `brotli` by default. | -| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Enable cross-origin resource sharing \(CORS\) with various options. | -| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | Protect from CSRF exploits. | -| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Encrypt middleware which encrypts cookie values. | -| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Expose environment variables with providing an optional config. | -| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | ETag middleware that lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content has not changed. | -| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Expvar middleware that serves via its HTTP server runtime exposed variants in the JSON format. | -| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Ignore favicon from logs or serve from memory if a file path is provided. | -| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | FileSystem middleware for Fiber, special thanks and credits to Alireza Salary | -| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Rate-limiting middleware for Fiber. Use to limit repeated requests to public APIs and/or endpoints such as password reset. | -| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | HTTP request/response logger. | -| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Monitor middleware that reports server metrics, inspired by express-status-monitor | -| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Special thanks to Matthew Lee \(@mthli\) | -| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Allows you to proxy requests to a multiple servers | -| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Recover middleware recovers from panics anywhere in the stack chain and handles the control to the centralized[ ErrorHandler](https://docs.gofiber.io/guide/error-handling). | -| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Adds a requestid to every request. | -| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | -| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | -| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | - -## 🧬 External Middleware - -List of externally hosted middleware modules and maintained by the [Fiber team](https://github.com/orgs/gofiber/people). - -| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | - -## 🕶️ Awesome List - -For more articles, middlewares, examples or tools check our [awesome list](https://github.com/gofiber/awesome-fiber). +## 🧬 Middleware Interno + +Aqui está uma lista de middlewares que estão incluídos no framework Fiber. + +| Middleware | Descrição | +| :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Autenticação básica fornece uma autenticação HTTP básica. Ele chama o próximo manipulador para credenciais válidas e 401 Não Autorizado para credenciais ausentes ou inválidas.| +| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercepta e armazena em cache as respostas | +| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Middleware de compressão para o Fiber, suporta `deflate`, `gzip` e `brotli` por padrão. | +| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Habilita o compartilhamento de recursos de origem cruzada (CORS) com várias opções. | +| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | Protege contra exploits CSRF. | +| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Criptografa valores de cookie. | +| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Expõe variáveis de ambiente fornecendo uma configuração opcional. | +| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | Permite que caches sejam mais eficientes e economizem largura de banda, pois um servidor web não precisa reenviar uma resposta completa se o conteúdo não mudou. | +| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Serve via seu servidor HTTP variantes expostas em tempo de execução no formato JSON. | +| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Ignora favicon dos logs ou serve da memória se um caminho de arquivo for fornecido. | +| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | Sistema de Arquivos para o Fiber, agradecimentos especiais e créditos a Alireza Salary | +| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Limitação de taxa para o Fiber. Use para limitar solicitações repetidas para APIs públicas e/ou endpoints como redefinição de senha. | +| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | Logger de solicitação/resposta HTTP. | +| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Middleware de monitoramento que relata métricas do servidor, inspirado pelo express-status-monitor | +| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Agradecimentos especiais a Matthew Lee (@mthli) | +| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Permite que você faça proxy de solicitações a vários servidores | +| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Recupera de panics em qualquer lugar da cadeia de chamadas e passa o controle para o [ErrorHandler](https://docs.gofiber.io/guide/error-handling) centralizado. | +| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Adiciona um ID de solicitação a cada pedido. | +| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Middleware de sessão. NOTA: Este middleware usa nosso pacote Storage. | +| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Pula um handler envolto se um predicado for verdadeiro. | +| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adiciona um tempo máximo para uma solicitação e encaminha para ErrorHandler se ele for excedido. | +| [keyauth](https://github.com/gofiber/keyauth) | Autenticação por chave fornece uma autenticação baseada em chave. | +| [redirect](https://github.com/gofiber/redirect) | Middleware de redirecionamento | +| [rewrite](https://github.com/gofiber/rewrite) | Reescreve o caminho da URL com base nas regras fornecidas. Pode ser útil para compatibilidade retroativa ou para criar links mais limpos e descritivos. | +| [adaptor](https://github.com/gofiber/adaptor) | Conversor para handlers net/http para/para manipuladores de solicitação Fiber, agradecimentos especiais ao @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Ajuda a proteger seus aplicativos definindo vários cabeçalhos HTTP. | + +## 🧬 Middleware Externo + +Lista de módulos de middleware hospedados externamente e mantidos pela [equipe Fiber](https://github.com/orgs/gofiber/people). + +| Middleware | Descrição | +| :------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT retorna um middleware de autenticação com tokens JWT. | +| [storage](https://github.com/gofiber/storage) | Drivers de armazenamento prontos que implementam a interface Storage, projetados para serem usados com vários middlewares do Fiber. | +| [template](https://github.com/gofiber/template) | Este pacote contém 8 mecanismos de template que podem ser usados com Fiber `v1.10.x`. É necessário Go versão 1.13 ou superior. | +| [websocket](https://github.com/gofiber/websocket) | Baseado no WebSocket do Fasthttp para Fiber com suporte a Locals | + + + +## 🕶️ Lista Incrível +Para mais artigos, middlewares, exemplos ou ferramentas, confira nossa [lista incrível](https://github.com/gofiber/awesome-fiber). ## 👍 Contribuindo From acf427c4bb637d67dbc55cb685294601464e8e93 Mon Sep 17 00:00:00 2001 From: Jason McNeil Date: Thu, 10 Aug 2023 15:27:25 -0300 Subject: [PATCH 08/84] chore: TagLatency match gin-gonic/gin format --- middleware/logger/logger_test.go | 54 ++++++++++++++++++++++++++++++++ middleware/logger/tags.go | 2 +- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/middleware/logger/logger_test.go b/middleware/logger/logger_test.go index d3006c88de..84906c55cd 100644 --- a/middleware/logger/logger_test.go +++ b/middleware/logger/logger_test.go @@ -205,6 +205,60 @@ func Test_Logger_All(t *testing.T) { utils.AssertEqual(t, expected, buf.String()) } +// go test -run Test_Logger_WithLatency +func Test_Logger_WithLatency(t *testing.T) { + t.Parallel() + buff := bytebufferpool.Get() + defer bytebufferpool.Put(buff) + app := fiber.New() + logger := New(Config{ + Output: buff, + Format: "${latency}", + }) + app.Use(logger) + + // Define a list of time units to test + timeUnits := []struct { + unit string + div time.Duration + }{ + // {"ns", time.Nanosecond}, // TODO: Nano seconds are too fast to test + {"µs", time.Microsecond}, + {"ms", time.Millisecond}, + {"s", time.Second}, + } + + // Initialize a new time unit + sleepDuration := 1 * time.Nanosecond + + // Define a test route that sleeps + app.Get("/test", func(c *fiber.Ctx) error { + time.Sleep(sleepDuration) + return c.SendStatus(fiber.StatusOK) + }) + + // Loop through each time unit and assert that the log output contains the expected latency value + for _, tu := range timeUnits { + // Update the sleep duration for the next iteration + sleepDuration = 1 * tu.div + + // Create a new HTTP request to the test route + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), int(2*time.Second)) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) + + fmt.Println("|", buff.String(), "|") + + // Assert that the log output contains the expected latency value in the current time unit + bb := buff.Bytes() + unit := bb[len(bb)-len(tu.unit):] + utils.AssertEqual(t, string(unit), tu.unit) + + // Reset the buffer + buff.Reset() + } +} + // go test -run Test_Query_Params func Test_Query_Params(t *testing.T) { t.Parallel() diff --git a/middleware/logger/tags.go b/middleware/logger/tags.go index 2f746ddd4e..ac2b909002 100644 --- a/middleware/logger/tags.go +++ b/middleware/logger/tags.go @@ -192,7 +192,7 @@ func createTagMap(cfg *Config) map[string]LogFunc { }, TagLatency: func(output Buffer, c *fiber.Ctx, data *Data, extraParam string) (int, error) { latency := data.Stop.Sub(data.Start) - return output.WriteString(fmt.Sprintf("%7v", latency)) + return output.WriteString(fmt.Sprintf("%13v", latency)) }, TagTime: func(output Buffer, c *fiber.Ctx, data *Data, extraParam string) (int, error) { return output.WriteString(data.Timestamp.Load().(string)) //nolint:forcetypeassert // We always store a string in here From 7b1aa8a612a1dc314e7594c200a04e5198c43a99 Mon Sep 17 00:00:00 2001 From: Jason McNeil Date: Thu, 10 Aug 2023 15:35:16 -0300 Subject: [PATCH 09/84] chore: rm debug --- middleware/logger/logger_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/middleware/logger/logger_test.go b/middleware/logger/logger_test.go index 84906c55cd..8638aa75f0 100644 --- a/middleware/logger/logger_test.go +++ b/middleware/logger/logger_test.go @@ -247,8 +247,6 @@ func Test_Logger_WithLatency(t *testing.T) { utils.AssertEqual(t, nil, err) utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) - fmt.Println("|", buff.String(), "|") - // Assert that the log output contains the expected latency value in the current time unit bb := buff.Bytes() unit := bb[len(bb)-len(tu.unit):] From 35da4c6a7510e9a4a73409e85f2b70c632347d89 Mon Sep 17 00:00:00 2001 From: Jason McNeil Date: Thu, 10 Aug 2023 16:04:29 -0300 Subject: [PATCH 10/84] test: fix text --- middleware/logger/logger_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/middleware/logger/logger_test.go b/middleware/logger/logger_test.go index 8638aa75f0..a5764580f9 100644 --- a/middleware/logger/logger_test.go +++ b/middleware/logger/logger_test.go @@ -248,9 +248,7 @@ func Test_Logger_WithLatency(t *testing.T) { utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) // Assert that the log output contains the expected latency value in the current time unit - bb := buff.Bytes() - unit := bb[len(bb)-len(tu.unit):] - utils.AssertEqual(t, string(unit), tu.unit) + utils.AssertEqual(t, bytes.HasSuffix(buff.Bytes(), []byte(tu.unit)), true, "Expected latency to be in %s, got %s", tu.unit, buff.String()) // Reset the buffer buff.Reset() From c3ae06608b68302e91eba2f338efa65a1cac8b13 Mon Sep 17 00:00:00 2001 From: Jason McNeil Date: Thu, 17 Aug 2023 09:33:59 -0300 Subject: [PATCH 11/84] =?UTF-8?q?=F0=9F=90=9B=20fix(middleware/logger):=20?= =?UTF-8?q?default=20latency=20output=20format=20(#2580)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: default logger formater latency * test: add Test_Logger_WithLatency_DefaultFormat * test: rm t.Parallel() from Latency tests Trying to make windows CI pass.... * test: fix windows sleep issue --- middleware/logger/logger.go | 8 ++-- middleware/logger/logger_test.go | 80 ++++++++++++++++++++++++++++---- 2 files changed, 75 insertions(+), 13 deletions(-) diff --git a/middleware/logger/logger.go b/middleware/logger/logger.go index ec4aa3cafc..f33f3562a3 100644 --- a/middleware/logger/logger.go +++ b/middleware/logger/logger.go @@ -146,10 +146,10 @@ func New(config ...Config) fiber.Handler { formatErr = colors.Red + " | " + chainErr.Error() + colors.Reset } _, _ = buf.WriteString( //nolint:errcheck // This will never fail - fmt.Sprintf("%s |%s %3d %s| %7v | %15s |%s %-7s %s| %-"+errPaddingStr+"s %s\n", + fmt.Sprintf("%s |%s %3d %s| %13v | %15s |%s %-7s %s| %-"+errPaddingStr+"s %s\n", timestamp.Load().(string), statusColor(c.Response().StatusCode(), colors), c.Response().StatusCode(), colors.Reset, - data.Stop.Sub(data.Start).Round(time.Millisecond), + data.Stop.Sub(data.Start), c.IP(), methodColor(c.Method(), colors), c.Method(), colors.Reset, c.Path(), @@ -161,10 +161,10 @@ func New(config ...Config) fiber.Handler { formatErr = " | " + chainErr.Error() } _, _ = buf.WriteString( //nolint:errcheck // This will never fail - fmt.Sprintf("%s | %3d | %7v | %15s | %-7s | %-"+errPaddingStr+"s %s\n", + fmt.Sprintf("%s | %3d | %13v | %15s | %-7s | %-"+errPaddingStr+"s %s\n", timestamp.Load().(string), c.Response().StatusCode(), - data.Stop.Sub(data.Start).Round(time.Millisecond), + data.Stop.Sub(data.Start), c.IP(), c.Method(), c.Path(), diff --git a/middleware/logger/logger_test.go b/middleware/logger/logger_test.go index a5764580f9..d563a5ccc6 100644 --- a/middleware/logger/logger_test.go +++ b/middleware/logger/logger_test.go @@ -10,6 +10,7 @@ import ( "net/http" "net/http/httptest" "os" + "runtime" "sync" "testing" "time" @@ -205,6 +206,31 @@ func Test_Logger_All(t *testing.T) { utils.AssertEqual(t, expected, buf.String()) } +func getLatencyTimeUnits() []struct { + unit string + div time.Duration +} { + // windows does not support µs sleep precision + // https://github.com/golang/go/issues/29485 + if runtime.GOOS == "windows" { + return []struct { + unit string + div time.Duration + }{ + {"ms", time.Millisecond}, + {"s", time.Second}, + } + } + return []struct { + unit string + div time.Duration + }{ + {"µs", time.Microsecond}, + {"ms", time.Millisecond}, + {"s", time.Second}, + } +} + // go test -run Test_Logger_WithLatency func Test_Logger_WithLatency(t *testing.T) { t.Parallel() @@ -218,15 +244,48 @@ func Test_Logger_WithLatency(t *testing.T) { app.Use(logger) // Define a list of time units to test - timeUnits := []struct { - unit string - div time.Duration - }{ - // {"ns", time.Nanosecond}, // TODO: Nano seconds are too fast to test - {"µs", time.Microsecond}, - {"ms", time.Millisecond}, - {"s", time.Second}, + timeUnits := getLatencyTimeUnits() + + // Initialize a new time unit + sleepDuration := 1 * time.Nanosecond + + // Define a test route that sleeps + app.Get("/test", func(c *fiber.Ctx) error { + time.Sleep(sleepDuration) + return c.SendStatus(fiber.StatusOK) + }) + + // Loop through each time unit and assert that the log output contains the expected latency value + for _, tu := range timeUnits { + // Update the sleep duration for the next iteration + sleepDuration = 1 * tu.div + + // Create a new HTTP request to the test route + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil), int(2*time.Second)) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) + + // Assert that the log output contains the expected latency value in the current time unit + utils.AssertEqual(t, bytes.HasSuffix(buff.Bytes(), []byte(tu.unit)), true, fmt.Sprintf("Expected latency to be in %s, got %s", tu.unit, buff.String())) + + // Reset the buffer + buff.Reset() } +} + +// go test -run Test_Logger_WithLatency_DefaultFormat +func Test_Logger_WithLatency_DefaultFormat(t *testing.T) { + t.Parallel() + buff := bytebufferpool.Get() + defer bytebufferpool.Put(buff) + app := fiber.New() + logger := New(Config{ + Output: buff, + }) + app.Use(logger) + + // Define a list of time units to test + timeUnits := getLatencyTimeUnits() // Initialize a new time unit sleepDuration := 1 * time.Nanosecond @@ -248,7 +307,10 @@ func Test_Logger_WithLatency(t *testing.T) { utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode) // Assert that the log output contains the expected latency value in the current time unit - utils.AssertEqual(t, bytes.HasSuffix(buff.Bytes(), []byte(tu.unit)), true, "Expected latency to be in %s, got %s", tu.unit, buff.String()) + // parse out the latency value from the log output + latency := bytes.Split(buff.Bytes(), []byte(" | "))[2] + // Assert that the latency value is in the current time unit + utils.AssertEqual(t, bytes.HasSuffix(latency, []byte(tu.unit)), true, fmt.Sprintf("Expected latency to be in %s, got %s", tu.unit, latency)) // Reset the buffer buff.Reset() From bd9c3fc23996897c67d9f3b1df69f3031d66d15b Mon Sep 17 00:00:00 2001 From: Girges Scandar <25529286+scandar@users.noreply.github.com> Date: Thu, 17 Aug 2023 14:35:48 +0200 Subject: [PATCH 12/84] =?UTF-8?q?=F0=9F=93=9D=20Added=20Egyptian=20Arabic?= =?UTF-8?q?=20readme=20file=20(#2565)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adds EG readme * Links EG readme to other readmes * update language count to 19 * add missing translation --- .github/README.md | 5 +- .github/README_az.md | 117 +++---- .github/README_ckb.md | 33 +- .github/README_de.md | 32 +- .github/README_eg.md | 716 ++++++++++++++++++++++++++++++++++++++++ .github/README_es.md | 33 +- .github/README_fa.md | 82 ++--- .github/README_fr.md | 32 +- .github/README_he.md | 30 +- .github/README_id.md | 32 +- .github/README_it.md | 77 ++--- .github/README_ja.md | 27 +- .github/README_ko.md | 32 +- .github/README_nl.md | 32 +- .github/README_pt.md | 8 +- .github/README_ru.md | 36 +- .github/README_sa.md | 32 +- .github/README_tr.md | 74 +++-- .github/README_uk.md | 5 +- .github/README_zh-CN.md | 5 +- .github/README_zh-TW.md | 5 +- 21 files changed, 1116 insertions(+), 329 deletions(-) create mode 100644 .github/README_eg.md diff --git a/.github/README.md b/.github/README.md index b441b4aa48..0dc23586ee 100644 --- a/.github/README.md +++ b/.github/README.md @@ -67,6 +67,9 @@ + + +
@@ -145,7 +148,7 @@ go get -u github.com/gofiber/fiber/v2 - [WebSocket support](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- Translated in [18 languages](https://docs.gofiber.io/) +- Translated in [19 languages](https://docs.gofiber.io/) - And much more, [explore Fiber](https://docs.gofiber.io/) ## 💡 Philosophy diff --git a/.github/README_az.md b/.github/README_az.md index f6486333eb..d6e154b198 100644 --- a/.github/README_az.md +++ b/.github/README_az.md @@ -66,6 +66,9 @@ + + +
@@ -125,7 +128,6 @@ Bu testlər [TechEmpower](https://www.techempower.com/benchmarks/#section=data-r Go dilinin `1.17` və ya daha yuxarı versiyanın [yükləndiyindən](https://go.dev/dl/) əmin olun. - Bir qovluq yaratdıqdan sonra, `go mod init github.com/your/repo` komandasını eyni qovluğun daxilində işə salaraq layihənizi başladın ([go modulları haqqında əlavə bilgilər](https://go.dev/blog/using-go-modules)). Növbəti addım olaraq Fiber-i [`go get`](https://pkg.go.dev/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them) komandasını işlədərək yükləyin: ```bash @@ -145,7 +147,7 @@ go get -u github.com/gofiber/fiber/v2 - [WebSocket dəstəyi](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- [18 dildə](https://docs.gofiber.io/) mövcudluğu +- [19 dildə](https://docs.gofiber.io/) mövcudluğu Daha ətraflı məlumat üçün [rəsmi sənədləşməyə](https://docs.gofiber.io/) baxış keçirə bilərsiniz. @@ -158,8 +160,9 @@ Fiber internet üzərində olan ən məşhur web framework-lərdən biri olan Ex Biz istifadəçilərdən gələn [issue-a](https://github.com/gofiber/fiber/issues), Discord [kanalımıza](https://gofiber.io/discord) və bütün interneti əhatə edən vasitələrdən gələn rəyləri nəzərə alırıq. Bunun nəzdində, biz sürətli və rahat şəkildə hər bir tapşırığın səviyyəsinə uyğun olan — dostcasına bir Go web framework-ü olmağı hədəfləmişik (Express-in JavaScript dünyasında etdiyi kimi). ## ⚠️ Limitlər -* Fiber unsafe prinsiplərə əsaslanaraq çalışdığından, o hər zaman Go-nun son versiyası ilə uyğunlaşmaya bilər. Buna görə də, Fiber 2.40.0 — Go 1.17 və 1.20 versiyaları ilə test edilərək saz vəziyyətə gətirilmişdir. -* Fiber net/http interfeysləri ilə uyğun deyil. Yəni gqlgen, go-swagger kimi net/http ekosisteminin parçası olan layihələri istifadə edə bilməzsiniz. + +- Fiber unsafe prinsiplərə əsaslanaraq çalışdığından, o hər zaman Go-nun son versiyası ilə uyğunlaşmaya bilər. Buna görə də, Fiber 2.40.0 — Go 1.17 və 1.20 versiyaları ilə test edilərək saz vəziyyətə gətirilmişdir. +- Fiber net/http interfeysləri ilə uyğun deyil. Yəni gqlgen, go-swagger kimi net/http ekosisteminin parçası olan layihələri istifadə edə bilməzsiniz. ## 👀 Misallar @@ -604,45 +607,45 @@ func main() { Aşağıda Fiber-in daxilində olan middleware-lər siyahı şəklində göstərilmişdir. -| Middleware | Açıqlama | -|:---------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Sadə bir auth middleware-dir və HTTP Basic Auth yaratmaq üçün istifadə olunur. Keçərli vəsiqə (credentials) bilgiləri üçün sonrakı handler-i, əksik və ya keçərsiz vəsiqə bilgiləri üçün 401 qaytarır. | -| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Response-ı dayandırır və keşə yerləşdirir. | -| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Fiber üçün sıxışdırma (compression) middleware-dir. Default olaraq `deflate`, `gzip` və `brotli` dəstəkləyir. | -| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Çeşidli seçimlərlə başlanğıclar arası mənbə paylaşımı (CORS) aktivləşdirir. | -| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | CSRF exploit-dən qorunmasını təmin edir. | -| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Encrypt middleware-i cookie dəyərlərini şifrələyir. | -| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Environment dəyərlərini göstərilən config-ə görə təyin edir. | -| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | Keşlərin daha səmərəli istifadəsinə və bant genişliyinə qənaət etməyə imkan verən ETag middleware-i; məzmun dəyişməyibsə veb serverin response-nı təkrar göndərməsinin qarşısını alır. | -| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Expvar middleware, HTTP serverlərinin bəzi runtime dəyərlərini JSON formatında göstərir. | -| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Əgər faylın yolu (path) göstərilmişdirsə, artıq loglarda olan favicon-u yox sayıb onu saxlanan depodan götürür. | -| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | Fiber üçün fayl sistem middleware-i. Alireza Salary-ə xüsusi təşəkkürlər. | -| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Fiber üçün rate limitləyən middleware. Açıq API-ə və ya şifrə yeniləmə kimi endpoint-ə yönəlik təkrarlanan request-in qarşısını alır. | -| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | HTTP istək/cavab (request/response) logger-i. | -| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Monitor middleware-i serverin metriklərini report edər ("Express-status-monitor"-dan qaynaqlanıb). | -| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Matthew Lee-yə xüsusi təşəkkürlər \(@mthli\). | -| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Birdən çox server-ə proxy istəyi göndərməyiniz üçündür. | -| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Recover middleware-i stack chain-ni hər hansı bir yerindəki paniklərdən qurtulmasına kömək edir və kontrolu mərkəzləşdirilmiş [ErrorHandler-ə](https://docs.gofiber.io/guide/error-handling) ötürür.| -| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Hər request üçün ayrı request id yaradır. | -| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session üçün middleware. Qeyd: Bu middleware Fiber-in öz storage struktrunu istifadə edir. | -| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware-i verilən şərt true olduğu halda handler-i görməyərək üstündən ötüb keçir. | -| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Bir request üçün maksimum vaxt əlavə edir. Əgər arada fasilə yaranarsa, onda proses məhz ErrorHandler-ə göndərilərək icra edilir. | -| [keyauth](https://github.com/gofiber/keyauth) | Key giriş middleware-i, key əsaslı bir authentication metodudur. | -| [redirect](https://github.com/gofiber/redirect) | Yönləndirmə üçün middleware. | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware-i verilən qanunlara əsasən URL yolunu (path) yenidən yazır. Geri dönüşün icrası üçün uyğunluq təşkil edən təsviri linklərin yaradılması üçün nəzərdə tutulmuşdur. | -| [adaptor](https://github.com/gofiber/adaptor) | Fiber request handler-dən net/http handler-ə çevirici. @arsmn-ə xüsusi təşəkkürlər! | -| [helmet](https://github.com/gofiber/helmet) | Fərqli HTTP header istifadə edərək tətbiqi daha təhlükəsiz saxlamağa kömək edir. | +| Middleware | Açıqlama | +| :------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Sadə bir auth middleware-dir və HTTP Basic Auth yaratmaq üçün istifadə olunur. Keçərli vəsiqə (credentials) bilgiləri üçün sonrakı handler-i, əksik və ya keçərsiz vəsiqə bilgiləri üçün 401 qaytarır. | +| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Response-ı dayandırır və keşə yerləşdirir. | +| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Fiber üçün sıxışdırma (compression) middleware-dir. Default olaraq `deflate`, `gzip` və `brotli` dəstəkləyir. | +| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Çeşidli seçimlərlə başlanğıclar arası mənbə paylaşımı (CORS) aktivləşdirir. | +| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | CSRF exploit-dən qorunmasını təmin edir. | +| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Encrypt middleware-i cookie dəyərlərini şifrələyir. | +| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Environment dəyərlərini göstərilən config-ə görə təyin edir. | +| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | Keşlərin daha səmərəli istifadəsinə və bant genişliyinə qənaət etməyə imkan verən ETag middleware-i; məzmun dəyişməyibsə veb serverin response-nı təkrar göndərməsinin qarşısını alır. | +| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Expvar middleware, HTTP serverlərinin bəzi runtime dəyərlərini JSON formatında göstərir. | +| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Əgər faylın yolu (path) göstərilmişdirsə, artıq loglarda olan favicon-u yox sayıb onu saxlanan depodan götürür. | +| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | Fiber üçün fayl sistem middleware-i. Alireza Salary-ə xüsusi təşəkkürlər. | +| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Fiber üçün rate limitləyən middleware. Açıq API-ə və ya şifrə yeniləmə kimi endpoint-ə yönəlik təkrarlanan request-in qarşısını alır. | +| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | HTTP istək/cavab (request/response) logger-i. | +| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Monitor middleware-i serverin metriklərini report edər ("Express-status-monitor"-dan qaynaqlanıb). | +| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Matthew Lee-yə xüsusi təşəkkürlər \(@mthli\). | +| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Birdən çox server-ə proxy istəyi göndərməyiniz üçündür. | +| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Recover middleware-i stack chain-ni hər hansı bir yerindəki paniklərdən qurtulmasına kömək edir və kontrolu mərkəzləşdirilmiş [ErrorHandler-ə](https://docs.gofiber.io/guide/error-handling) ötürür. | +| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Hər request üçün ayrı request id yaradır. | +| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session üçün middleware. Qeyd: Bu middleware Fiber-in öz storage struktrunu istifadə edir. | +| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware-i verilən şərt true olduğu halda handler-i görməyərək üstündən ötüb keçir. | +| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Bir request üçün maksimum vaxt əlavə edir. Əgər arada fasilə yaranarsa, onda proses məhz ErrorHandler-ə göndərilərək icra edilir. | +| [keyauth](https://github.com/gofiber/keyauth) | Key giriş middleware-i, key əsaslı bir authentication metodudur. | +| [redirect](https://github.com/gofiber/redirect) | Yönləndirmə üçün middleware. | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware-i verilən qanunlara əsasən URL yolunu (path) yenidən yazır. Geri dönüşün icrası üçün uyğunluq təşkil edən təsviri linklərin yaradılması üçün nəzərdə tutulmuşdur. | +| [adaptor](https://github.com/gofiber/adaptor) | Fiber request handler-dən net/http handler-ə çevirici. @arsmn-ə xüsusi təşəkkürlər! | +| [helmet](https://github.com/gofiber/helmet) | Fərqli HTTP header istifadə edərək tətbiqi daha təhlükəsiz saxlamağa kömək edir. | ## 🧬 Xarici Middleware [Fiber komandası](https://github.com/orgs/gofiber/people) tərəfindən dəstəklənən və inkişaf etdirilən middleware-in siyahısı. -| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT, JSON Web Token(JWT) girişi qaytaran bir middleware-dir. | +| Middleware | Description | +| :------------------------------------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT, JSON Web Token(JWT) girişi qaytaran bir middleware-dir. | | [storage](https://github.com/gofiber/storage) | Fiber-in Storage arxitekturasını dəstəkləyən bir sıra storage driver verir. Bu sayədə storage-ə ehtiyac duyan Fiber middleware-də rahatlıqla istifadə oluna bilər. | -| [template](https://github.com/gofiber/template) | Bu paket, Fiber `v1.10.x`, Go versiyası 1.13 və ya daha yuxarı olduqda istifadə oluna bilər. 8 template mühərriki var. | -| [websocket](https://github.com/gofiber/websocket) | Yerlilərin dəstəyi ilə WebSocket-ə əsaslanan Fiber üçün Fasthttp. | +| [template](https://github.com/gofiber/template) | Bu paket, Fiber `v1.10.x`, Go versiyası 1.13 və ya daha yuxarı olduqda istifadə oluna bilər. 8 template mühərriki var. | +| [websocket](https://github.com/gofiber/websocket) | Yerlilərin dəstəyi ilə WebSocket-ə əsaslanan Fiber üçün Fasthttp. | ## 🕶️ Möhtəşəm Siyahı @@ -661,26 +664,26 @@ Aşağıda Fiber-in daxilində olan middleware-lər siyahı şəklində göstər Fiber açıq qaynaqlı bir layihə olduğu üçün, gəlirlərini yalnız ianələr vasitəsilə təmin edir və bu da domain adı, gitbook, netlify, serverless hosting xərcləri üçün istifadə olunur. Belə olduğu halda, Fiber-ə ən yaxşı dəstək elə bizim üçün ☕ [**bir kofe almaqdan gələ bilər**](https://buymeacoff.ee/fenny). -| | İstifadəçi | İanə | -| :--------------------------------------------------------- | :----------------------------------------------- | :------- | -| ![](https://avatars.githubusercontent.com/u/204341?s=25) | [@destari](https://github.com/destari) | ☕ x 10 | -| ![](https://avatars.githubusercontent.com/u/63164982?s=25) | [@dembygenesis](https://github.com/dembygenesis) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/56607882?s=25) | [@thomasvvugt](https://github.com/thomasvvugt) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/27820675?s=25) | [@hendratommy](https://github.com/hendratommy) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/1094221?s=25) | [@ekaputra07](https://github.com/ekaputra07) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/194590?s=25) | [@jorgefuertes](https://github.com/jorgefuertes) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/186637?s=25) | [@candidosales](https://github.com/candidosales) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/29659953?s=25) | [@l0nax](https://github.com/l0nax) | ☕ x 3 | -| ![](https://avatars.githubusercontent.com/u/635852?s=25) | [@bihe](https://github.com/bihe) | ☕ x 3 | -| ![](https://avatars.githubusercontent.com/u/307334?s=25) | [@justdave](https://github.com/justdave) | ☕ x 3 | -| ![](https://avatars.githubusercontent.com/u/11155743?s=25) | [@koddr](https://github.com/koddr) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/29042462?s=25) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/2978730?s=25) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/44171355?s=25) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/5638101?s=25) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/619996?s=25) | [@melkorm](https://github.com/melkorm) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/31022056?s=25) | [@marvinjwendt](https://github.com/marvinjwendt) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/31921460?s=25) | [@toishy](https://github.com/toishy) | ☕ x 1 | +| | İstifadəçi | İanə | +| :--------------------------------------------------------- | :----------------------------------------------- | :------ | +| ![](https://avatars.githubusercontent.com/u/204341?s=25) | [@destari](https://github.com/destari) | ☕ x 10 | +| ![](https://avatars.githubusercontent.com/u/63164982?s=25) | [@dembygenesis](https://github.com/dembygenesis) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/56607882?s=25) | [@thomasvvugt](https://github.com/thomasvvugt) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/27820675?s=25) | [@hendratommy](https://github.com/hendratommy) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/1094221?s=25) | [@ekaputra07](https://github.com/ekaputra07) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/194590?s=25) | [@jorgefuertes](https://github.com/jorgefuertes) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/186637?s=25) | [@candidosales](https://github.com/candidosales) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/29659953?s=25) | [@l0nax](https://github.com/l0nax) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/635852?s=25) | [@bihe](https://github.com/bihe) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/307334?s=25) | [@justdave](https://github.com/justdave) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/11155743?s=25) | [@koddr](https://github.com/koddr) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/29042462?s=25) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/2978730?s=25) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/44171355?s=25) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/5638101?s=25) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/619996?s=25) | [@melkorm](https://github.com/melkorm) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/31022056?s=25) | [@marvinjwendt](https://github.com/marvinjwendt) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/31921460?s=25) | [@toishy](https://github.com/toishy) | ☕ x 1 | ## ‎‍💻 Koda Töhfə Verənlər diff --git a/.github/README_ckb.md b/.github/README_ckb.md index d4508e5945..627be06dda 100644 --- a/.github/README_ckb.md +++ b/.github/README_ckb.md @@ -66,6 +66,9 @@ + + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - پشتگیریی [WebSocket](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- وەرگێڕراوە بۆ [18 زمان](https://docs.gofiber.io/) +- وەرگێڕراوە بۆ [19 زمان](https://docs.gofiber.io/) - زیاتریش، [فایبەر بپشکنە](https://docs.gofiber.io/) ## 💡 فەلسەفە @@ -158,8 +161,8 @@ go get -u github.com/gofiber/fiber/v2 ## ⚠️ سنوورەکان -* تایبەتمەندیی `unsafe` بەکار دەهێنێت کە وای لێ دەکات لەگەڵ هەندێک وەشانی گۆ نەگونجێت. -* لەگەڵ `net/http` ناگونجێت. +- تایبەتمەندیی `unsafe` بەکار دەهێنێت کە وای لێ دەکات لەگەڵ هەندێک وەشانی گۆ نەگونجێت. +- لەگەڵ `net/http` ناگونجێت. ## 👀 نموونەکان @@ -604,7 +607,7 @@ func main() { ئەمە لیستی ئەو کاڵانەیە کە لەناو فایبەر جێگیر کراون. -| کاڵا | دەربارە | +| کاڵا | دەربارە | | :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Basic auth middleware provides an HTTP basic authentication. It calls the next handler for valid credentials and 401 Unauthorized for missing or invalid credentials. | | [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercept and cache responses | @@ -627,22 +630,22 @@ func main() { | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | ## 🧬 کاڵا دەرەکییەکان ئەمە لیستی ئەو کاڵا دەرەکییانەیە کە لەلایەن [تیمی فایبەر](https://github.com/orgs/gofiber/people) بەڕێوە دەبرێن. -| کاڵا | دەربارە | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| کاڵا | دەربارە | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List diff --git a/.github/README_de.md b/.github/README_de.md index 010154e1de..a0b897aacf 100644 --- a/.github/README_de.md +++ b/.github/README_de.md @@ -66,6 +66,9 @@ + + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - [WebSocket support](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- Verfügbar in [18 Sprachen](https://docs.gofiber.io/) +- Verfügbar in [19 Sprachen](https://docs.gofiber.io/) - Und vieles mehr - [erkunde Fiber](https://docs.gofiber.io/) ## 💡 Philosophie @@ -153,8 +156,9 @@ Neue Gopher, welche von [Node.js](https://nodejs.org/en/about/) zu [Go](https:// Fiber ist **inspiriert** von Express.js, dem beliebtesten Web-Framework im Internet. Wir haben die **Leichtigkeit** von Express und die **Rohleistung** von Go kombiniert. Wenn du jemals eine Webanwendung mit Node.js implementiert hast (_mit Express.js oder ähnlichem_), werden dir viele Methoden und Prinzipien **sehr vertraut** vorkommen. ## ⚠️ Limitations -* Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. -* Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. + +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 Beispiele @@ -597,22 +601,22 @@ Hier finden Sie eine Liste der Middleware, die im Fiber-Framework enthalten ist. | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | ## 🧬 External Middleware Liste der extern gehosteten Middleware-Module, die vom [Fiber team](https://github.com/orgs/gofiber/people) gepflegt werden. -| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. || [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | --- | --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | | [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List diff --git a/.github/README_eg.md b/.github/README_eg.md new file mode 100644 index 0000000000..7adef30718 --- /dev/null +++ b/.github/README_eg.md @@ -0,0 +1,716 @@ +

+ + + + Fiber + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +

+

+ فايبر هي ويب فريمورك مستوحاه من اكسبريس ومبنيه على فاست اتش تي تي بي وهي اسرع محركات الويب للغه جو. مصممة عشان تسهل و تسرع التطوير ومابتعملش memory allocation زيادة. وبتهتم بالبيرفورمانس. +

+ +## ⚡️ بداية سريعة + +```go +package main + +import "github.com/gofiber/fiber/v2" + +func main() { + app := fiber.New() + + app.Get("/", func(c *fiber.Ctx) error { + return c.SendString("Hello, World 👋!") + }) + + app.Listen(":3000") +} +``` + +## 🤖 القياسات + +القياسات دي اتعملت عن طريق [TechEmpower](https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext) و [Go Web](https://github.com/smallnest/go-web-framework-benchmark). لو عاوز تشوف كل النتايج زور [الويكي بتاعتنا](https://docs.gofiber.io/extra/benchmarks). + +

+ + +

+ +## ⚙️ التسطيب + +أتأكد انك مسطب جو ([تحميل](https://go.dev/dl/)). الاصدار `1.17` او اعلى. + +ابدأ البروجكت بتاعك بعمل فولدر وبعدين رن الكوماند ده `go mod init github.com/your/repo` ([اعرف اكتر](https://go.dev/blog/using-go-modules)) بعدين سطب فايبر بكوماند [`go get`](https://pkg.go.dev/cmd/go/#hdr-Add_dependencies_to_current_module_and_install_them): + +```bash +go get -u github.com/gofiber/fiber/v2 +``` + +## 🎯 المميزات + +- [راوتنج](https://docs.gofiber.io/guide/routing) متين +- سيرف [فايلات ستاتك](https://docs.gofiber.io/api/app#static) +- [بيرفورمانس](https://docs.gofiber.io/extra/benchmarks) فشيخ +- [استهلاك قليل للميموري](https://docs.gofiber.io/extra/benchmarks) +- [APIs](https://docs.gofiber.io/api/ctx) +- [ميدلويرز](https://docs.gofiber.io/category/-middleware) و بتدعم [Next](https://docs.gofiber.io/api/ctx#next) +- برمجة سيرفر [سريعة](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) +- [تيمبلت اينجنز](https://github.com/gofiber/template) +- [بتدعم الويب سوكتس](https://github.com/gofiber/websocket) +- [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) +- [ريت ليمت](https://docs.gofiber.io/api/middleware/limiter) +- مترجمة [لـ19 لغة](https://docs.gofiber.io/) +- وحاجات اكتر, [تصفح فايبر](https://docs.gofiber.io/) + +## 💡 الفكرة + +الجوفرز الجداد اللي بيسوتشوا من [نود جي اس](https://nodejs.org/en/about/) لـ[جو](https://go.dev/doc/) بيتعاملوا مع مرحلة تعلم قبل ما يبدأوا يبنوا تطبيقاتهم و مايكروسيرفساتهم. فايبر, كـ**ويب فريمورك**, اتعملت بفكرة **البساطة** و بتتبع **طريقة يونكس**, عشان الجوفرز الجداد يقدروا يدخلوا عالم جو بسرعة و بثقة. + +فايبر **مستوحاة** من اكسبريس اللي هي اشهر ويب فريمورك عالانترنت. احنا جمعنا بين **سهولة** اكسبريس و **سرعة** جو. لو انت عملت تطبيق ويب في نود جي اس (_باستخدام اكسبريس او حاجة شبهها_), هتلاقي ان معظم الطرق و المبادئ بتاعت فايبر **مألوفة** جدا. + +احنا **بنسمع** لمستخدمينا في [الايشوز](https://github.com/gofiber/fiber/issues) و [قناة الديسكورد](https://gofiber.io/discord) و _في كل حتة عالنت_ عشان نعمل فريمورك ويب جو **سريع**, **مرن** و **سهل** **لاي تاسك**, **ديدلاين** واي **مستوى** مبرمج! زي اكسبريس في عالم الجافاسكريبت. + +## ⚠️ القيود + +- بسبب استخدام فايبر لـunsafe ممكن انها متتوافقش مع اخر اصدار من جو. فايبر 2.40.0 اتتست بـجو من اصدار 1.17 لـ1.20 +- فايبر مش متوافقة مع واجهات net/http. ده يعني انك مش هتقدر تستخدم مشاريع زي gqlgen, go-swagger, او اي حاجة تانية متعلقة بـnet/http + +## 👀 أمثلة + +دي بعض الامثلة الشائعة. لو عايز تشوف امثلة اكتر, زور [Recipes repository](https://github.com/gofiber/recipes) او زور [API documentation](https://docs.gofiber.io). + +#### 📖 [**الراوتنج البسيط**](https://docs.gofiber.io/#basic-routing) + +```go +func main() { + app := fiber.New() + + // GET /api/register + app.Get("/api/*", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("✋ %s", c.Params("*")) + return c.SendString(msg) // => ✋ register + }) + + // GET /flights/LAX-SFO + app.Get("/flights/:from-:to", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("💸 From: %s, To: %s", c.Params("from"), c.Params("to")) + return c.SendString(msg) // => 💸 From: LAX, To: SFO + }) + + // GET /dictionary.txt + app.Get("/:file.:ext", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("📃 %s.%s", c.Params("file"), c.Params("ext")) + return c.SendString(msg) // => 📃 dictionary.txt + }) + + // GET /john/75 + app.Get("/:name/:age/:gender?", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("👴 %s is %s years old", c.Params("name"), c.Params("age")) + return c.SendString(msg) // => 👴 john is 75 years old + }) + + // GET /john + app.Get("/:name", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("Hello, %s 👋!", c.Params("name")) + return c.SendString(msg) // => Hello john 👋! + }) + + log.Fatal(app.Listen(":3000")) +} + +``` + +#### 📖 [**تسمية الراوتس**](https://docs.gofiber.io/api/app#name) + +```go +func main() { + app := fiber.New() + + // GET /api/register + app.Get("/api/*", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("✋ %s", c.Params("*")) + return c.SendString(msg) // => ✋ register + }).Name("api") + + data, _ := json.MarshalIndent(app.GetRoute("api"), "", " ") + fmt.Print(string(data)) + // Prints: + // { + // "method": "GET", + // "name": "api", + // "path": "/api/*", + // "params": [ + // "*1" + // ] + // } + + + log.Fatal(app.Listen(":3000")) +} + +``` + +#### 📖 [**ازاي تسيرف فايلات ستاتك**](https://docs.gofiber.io/api/app#static) + +```go +func main() { + app := fiber.New() + + app.Static("/", "./public") + // => http://localhost:3000/js/script.js + // => http://localhost:3000/css/style.css + + app.Static("/prefix", "./public") + // => http://localhost:3000/prefix/js/script.js + // => http://localhost:3000/prefix/css/style.css + + app.Static("*", "./public/index.html") + // => http://localhost:3000/any/path/shows/index/html + + log.Fatal(app.Listen(":3000")) +} + +``` + +#### 📖 [**الميدلويرز ونيكست**](https://docs.gofiber.io/api/ctx#next) + +```go +func main() { + app := fiber.New() + + // Match any route + app.Use(func(c *fiber.Ctx) error { + fmt.Println("🥇 First handler") + return c.Next() + }) + + // Match all routes starting with /api + app.Use("/api", func(c *fiber.Ctx) error { + fmt.Println("🥈 Second handler") + return c.Next() + }) + + // GET /api/list + app.Get("/api/list", func(c *fiber.Ctx) error { + fmt.Println("🥉 Last handler") + return c.SendString("Hello, World 👋!") + }) + + log.Fatal(app.Listen(":3000")) +} + +``` + +
+ 📚 اعرض امثلة اكتر + +### محركات الفيوز + +📖 [Config](https://docs.gofiber.io/api/fiber#config) +📖 [Engines](https://github.com/gofiber/template) +📖 [Render](https://docs.gofiber.io/api/ctx#render) + +فايبر بتستخدم [html/template](https://pkg.go.dev/html/template/) لما مايكونش في محرك فيوز متعرف + +لو عاوز تستخدم فيوز جزئية او محرك فيوز تاني زي [amber](https://github.com/eknkc/amber), [handlebars](https://github.com/aymerick/raymond), [mustache](https://github.com/cbroglie/mustache) او [pug](https://github.com/Joker/jade) وغيره.. + +بص على [الباكدج](https://github.com/gofiber/template) بتاعنا اللي بيدعم محركات فيوز متعددة + + +```go +package main + +import ( + "github.com/gofiber/fiber/v2" + "github.com/gofiber/template/pug" +) + +func main() { + // You can setup Views engine before initiation app: + app := fiber.New(fiber.Config{ + Views: pug.New("./views", ".pug"), + }) + + // And now, you can call template `./views/home.pug` like this: + app.Get("/", func(c *fiber.Ctx) error { + return c.Render("home", fiber.Map{ + "title": "Homepage", + "year": 1999, + }) + }) + + log.Fatal(app.Listen(":3000")) +} +``` + +### تجميع الراوتس في سلسلة + +📖 [Group](https://docs.gofiber.io/api/app#group) + +```go +func middleware(c *fiber.Ctx) error { + fmt.Println("Don't mind me!") + return c.Next() +} + +func handler(c *fiber.Ctx) error { + return c.SendString(c.Path()) +} + +func main() { + app := fiber.New() + + // Root API route + api := app.Group("/api", middleware) // /api + + // API v1 routes + v1 := api.Group("/v1", middleware) // /api/v1 + v1.Get("/list", handler) // /api/v1/list + v1.Get("/user", handler) // /api/v1/user + + // API v2 routes + v2 := api.Group("/v2", middleware) // /api/v2 + v2.Get("/list", handler) // /api/v2/list + v2.Get("/user", handler) // /api/v2/user + + // ... +} + +``` + +### ميدل وير لوجر + +📖 [Logger](https://docs.gofiber.io/api/middleware/logger) + +```go +package main + +import ( + "log" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/logger" +) + +func main() { + app := fiber.New() + + app.Use(logger.New()) + + // ... + + log.Fatal(app.Listen(":3000")) +} +``` + +### هيدر الكروس اوريجن (CORS) + +📖 [CORS](https://docs.gofiber.io/api/middleware/cors) + +```go +import ( + "log" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/cors" +) + +func main() { + app := fiber.New() + + app.Use(cors.New()) + + // ... + + log.Fatal(app.Listen(":3000")) +} +``` + +جرب الCORS بانك تبعت اي دومين في هيدر `Origin` وتشوف الرد بتاع السيرفر + + +```bash +curl -H "Origin: http://example.com" --verbose http://localhost:3000 +``` + +### ريسبومس 404 معدل + +📖 [HTTP Methods](https://docs.gofiber.io/api/ctx#status) + +```go +func main() { + app := fiber.New() + + app.Static("/", "./public") + + app.Get("/demo", func(c *fiber.Ctx) error { + return c.SendString("This is a demo!") + }) + + app.Post("/register", func(c *fiber.Ctx) error { + return c.SendString("Welcome!") + }) + + // Last middleware to match anything + app.Use(func(c *fiber.Ctx) error { + return c.SendStatus(404) + // => 404 "Not Found" + }) + + log.Fatal(app.Listen(":3000")) +} +``` + +### JSON ريبسونس + +📖 [JSON](https://docs.gofiber.io/api/ctx#json) + +```go +type User struct { + Name string `json:"name"` + Age int `json:"age"` +} + +func main() { + app := fiber.New() + + app.Get("/user", func(c *fiber.Ctx) error { + return c.JSON(&User{"John", 20}) + // => {"name":"John", "age":20} + }) + + app.Get("/json", func(c *fiber.Ctx) error { + return c.JSON(fiber.Map{ + "success": true, + "message": "Hi John!", + }) + // => {"success":true, "message":"Hi John!"} + }) + + log.Fatal(app.Listen(":3000")) +} +``` + +### اضافة ويبسوكيت + +📖 [Websocket](https://github.com/gofiber/websocket) + +```go +import ( + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/websocket" +) + +func main() { + app := fiber.New() + + app.Get("/ws", websocket.New(func(c *websocket.Conn) { + for { + mt, msg, err := c.ReadMessage() + if err != nil { + log.Println("read:", err) + break + } + log.Printf("recv: %s", msg) + err = c.WriteMessage(mt, msg) + if err != nil { + log.Println("write:", err) + break + } + } + })) + + log.Fatal(app.Listen(":3000")) + // ws://localhost:3000/ws +} +``` + +### Server-Sent Events + +📖 [More Info](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) + +```go +import ( + "github.com/gofiber/fiber/v2" + "github.com/valyala/fasthttp" +) + +func main() { + app := fiber.New() + + app.Get("/sse", func(c *fiber.Ctx) error { + c.Set("Content-Type", "text/event-stream") + c.Set("Cache-Control", "no-cache") + c.Set("Connection", "keep-alive") + c.Set("Transfer-Encoding", "chunked") + + c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) { + fmt.Println("WRITER") + var i int + + for { + i++ + msg := fmt.Sprintf("%d - the time is %v", i, time.Now()) + fmt.Fprintf(w, "data: Message: %s\n\n", msg) + fmt.Println(msg) + + w.Flush() + time.Sleep(5 * time.Second) + } + })) + + return nil + }) + + log.Fatal(app.Listen(":3000")) +} +``` + +### ميدلوير ريكوفر + +📖 [Recover](https://docs.gofiber.io/api/middleware/recover) + +```go +import ( + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/recover" +) + +func main() { + app := fiber.New() + + app.Use(recover.New()) + + app.Get("/", func(c *fiber.Ctx) error { + panic("normally this would crash your app") + }) + + log.Fatal(app.Listen(":3000")) +} +``` + +
+ +### استخدام بروكسي موثوق + +📖 [Config](https://docs.gofiber.io/api/fiber#config) + +```go +import ( + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/recover" +) + +func main() { + app := fiber.New(fiber.Config{ + EnableTrustedProxyCheck: true, + TrustedProxies: []string{"0.0.0.0", "1.1.1.1/30"}, // IP address or IP address range + ProxyHeader: fiber.HeaderXForwardedFor, + }) + + // ... + + log.Fatal(app.Listen(":3000")) +} +``` + + + +## 🧬 ميدلوير داخلي + +Here is a list of middleware that are included within the Fiber framework. +دي ليستة بالميدلوير الموجودة في فايبر + +| Middleware | Description | +|:---------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Basic auth middleware provides an HTTP basic authentication. It calls the next handler for valid credentials and 401 Unauthorized for missing or invalid credentials. | +| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercept and cache responses | +| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Compression middleware for Fiber, it supports `deflate`, `gzip` and `brotli` by default. | +| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Enable cross-origin resource sharing \(CORS\) with various options. | +| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | Protect from CSRF exploits. | +| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Encrypt middleware which encrypts cookie values. | +| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Expose environment variables with providing an optional config. | +| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | ETag middleware that lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content has not changed. | +| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Expvar middleware that serves via its HTTP server runtime exposed variants in the JSON format. | +| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Ignore favicon from logs or serve from memory if a file path is provided. | +| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | FileSystem middleware for Fiber, special thanks and credits to Alireza Salary | +| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Rate-limiting middleware for Fiber. Use to limit repeated requests to public APIs and/or endpoints such as password reset. | +| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | HTTP request/response logger. | +| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Monitor middleware that reports server metrics, inspired by express-status-monitor | +| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Special thanks to Matthew Lee \(@mthli\) | +| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Allows you to proxy requests to a multiple servers | +| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Recover middleware recovers from panics anywhere in the stack chain and handles the control to the centralized[ ErrorHandler](https://docs.gofiber.io/guide/error-handling). | +| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Adds a requestid to every request. | +| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | +| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler if a predicate is true. | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | + +## 🧬 ميدلوير خارجي + +لستة ميدلويرز خارجية بتطور من [تيم فايبر](https://github.com/orgs/gofiber/people). + +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | + +## 🕶️ لستة الجامدين + +لو عاوز تشوف مقالات او ميدل وير او امثلة او ادوات بص على اللستة دي [awesome list](https://github.com/gofiber/awesome-fiber). + +## 👍 شاركنا + +لو عاوز تقول **شكرا** او تدعمنا في تطوير `فايبر`: + +1. اعمل [GitHub Star](https://github.com/gofiber/fiber/stargazers) للبروجكت. +2. تويت عن البروجكت [على تويتر](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +3. اكتب ريفيو او توتوريال على [Medium](https://medium.com/), [Dev.to](https://dev.to/) او البلوج بتاعتك. +4. او ادعم المشروع [بكوباية شاي](https://buymeacoff.ee/fenny). + +## ☕ الداعمين + +فايبر مشروع اوبن سورس وشغال على التبرعات عشان ندفع فواتير الدومين والجيت بوك والنتليفاي والسيرفرات. لو عاوز تدعم فايبر تقدر تشتري كوباية شاي من [هنا](https://buymeacoff.ee/fenny). + +| | User | Donation | +| :--------------------------------------------------------- | :----------------------------------------------- | :------- | +| ![](https://avatars.githubusercontent.com/u/204341?s=25) | [@destari](https://github.com/destari) | ☕ x 10 | +| ![](https://avatars.githubusercontent.com/u/63164982?s=25) | [@dembygenesis](https://github.com/dembygenesis) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/56607882?s=25) | [@thomasvvugt](https://github.com/thomasvvugt) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/27820675?s=25) | [@hendratommy](https://github.com/hendratommy) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/1094221?s=25) | [@ekaputra07](https://github.com/ekaputra07) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/194590?s=25) | [@jorgefuertes](https://github.com/jorgefuertes) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/186637?s=25) | [@candidosales](https://github.com/candidosales) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/29659953?s=25) | [@l0nax](https://github.com/l0nax) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/635852?s=25) | [@bihe](https://github.com/bihe) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/307334?s=25) | [@justdave](https://github.com/justdave) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/11155743?s=25) | [@koddr](https://github.com/koddr) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/29042462?s=25) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/2978730?s=25) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/44171355?s=25) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/5638101?s=25) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/619996?s=25) | [@melkorm](https://github.com/melkorm) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/31022056?s=25) | [@marvinjwendt](https://github.com/marvinjwendt) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/31921460?s=25) | [@toishy](https://github.com/toishy) | ☕ x 1 | + +## ‎‍💻 Code Contributors + +Code Contributors + +## ⭐️ Stargazers + +Stargazers over time + +## ⚠️ License + +Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](https://github.com/gofiber/fiber/graphs/contributors). `Fiber` is free and open-source software licensed under the [MIT License](https://github.com/gofiber/fiber/blob/master/LICENSE). Official logo was created by [Vic Shóstak](https://github.com/koddr) and distributed under [Creative Commons](https://creativecommons.org/licenses/by-sa/4.0/) license (CC BY-SA 4.0 International). + +**Third-party library licenses** + +- [colorable](https://github.com/mattn/go-colorable/blob/master/LICENSE) +- [isatty](https://github.com/mattn/go-isatty/blob/master/LICENSE) +- [runewidth](https://github.com/mattn/go-runewidth/blob/master/LICENSE) +- [fasthttp](https://github.com/valyala/fasthttp/blob/master/LICENSE) +- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE) +- [fwd](https://github.com/philhofer/fwd/blob/master/LICENSE.md) +- [go-ole](https://github.com/go-ole/go-ole/blob/master/LICENSE) +- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE) +- [msgp](https://github.com/tinylib/msgp/blob/master/LICENSE) +- [schema](https://github.com/gorilla/schema/blob/master/LICENSE) +- [uuid](https://github.com/google/uuid/blob/master/LICENSE) +- [wmi](https://github.com/StackExchange/wmi/blob/master/LICENSE) diff --git a/.github/README_es.md b/.github/README_es.md index e723505f82..755bdb3617 100644 --- a/.github/README_es.md +++ b/.github/README_es.md @@ -66,6 +66,9 @@ + + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - [WebSocket support](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- Disponible en [18 idiomas](https://docs.gofiber.io/) +- Disponible en [19 idiomas](https://docs.gofiber.io/) - Y mucho más, [explora Fiber](https://docs.gofiber.io/) ## 💡 Filosofía @@ -153,8 +156,9 @@ Los nuevos gophers que hacen el cambio de [Node.js](https://nodejs.org/en/about/ Fiber está **inspirado** en Expressjs, el framework web más popular en Internet. Combinamos la **facilidad** de Express y **el rendimiento bruto** de Go. Si alguna vez ha implementado una aplicación web en Node.js ( _utilizando Express.js o similar_ ), muchos métodos y principios le parecerán **muy comunes** . ## ⚠️ Limitantes -* Debido a que Fiber utiliza unsafe, la biblioteca no siempre será compatible con la última versión de Go. Fiber 2.40.0 ha sido probado con las versiones de Go 1.17 a 1.20. -* Fiber no es compatible con interfaces net/http. Esto significa que no lo podrá usar en proyectos como qglgen, go-swagger, u otros que son parte del ecosistema net/http. + +- Debido a que Fiber utiliza unsafe, la biblioteca no siempre será compatible con la última versión de Go. Fiber 2.40.0 ha sido probado con las versiones de Go 1.17 a 1.20. +- Fiber no es compatible con interfaces net/http. Esto significa que no lo podrá usar en proyectos como qglgen, go-swagger, u otros que son parte del ecosistema net/http. ## 👀 Ejemplos @@ -597,22 +601,22 @@ Aquí está una lista del middleware incluido en el marco web Fiber. | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | ## 🧬 Middleware Externo Lista de módulos de middleware alojados externamente, y mantenidos por el [equipo de Fiber](https://github.com/orgs/gofiber/people). -| Middleware | Descripción | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Descripción | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List @@ -678,4 +682,3 @@ Copyright (c) 2019-presente [Fenny](https://github.com/fenny) y [contribuyentes] - [schema](https://github.com/gorilla/schema/blob/master/LICENSE) - [uuid](https://github.com/google/uuid/blob/master/LICENSE) - [wmi](https://github.com/StackExchange/wmi/blob/master/LICENSE) - diff --git a/.github/README_fa.md b/.github/README_fa.md index 506466a026..1c331a95bd 100644 --- a/.github/README_fa.md +++ b/.github/README_fa.md @@ -66,6 +66,9 @@ + + +
@@ -172,7 +175,7 @@ go get -u github.com/gofiber/fiber/v2 - [پشتیبانی از وب سوکت](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - قابلیت [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- ترجمه در [18 زبان](https://docs.gofiber.io/) +- ترجمه در [19 زبان](https://docs.gofiber.io/) - و امکانات بیشتر, [دیدن در داکیومنت](https://docs.gofiber.io/)
@@ -193,8 +196,9 @@ Fiber از Express الهام گرفته, که محبوب ترین فری

## ⚠️ محدودیت ها -* به دلیل استفاده ناامن از Fiber, ممکن است کتابخانه همیشه با آخرین نسخه Go سازگار نباشد. Fiber 2.40.0 با زبان گو نسخه 1.17 تا 1.20 تست شده است. -* فریمورک Fiber با پکیج net/http سازگار نیست. این بدان معناست شما نمی توانید از پکیج های مانند go-swagger, gqlgen یا سایر پروژه هایی که بخشی از اکوسیستم net/http هستند استفاده کنید. + +- به دلیل استفاده ناامن از Fiber, ممکن است کتابخانه همیشه با آخرین نسخه Go سازگار نباشد. Fiber 2.40.0 با زبان گو نسخه 1.17 تا 1.20 تست شده است. +- فریمورک Fiber با پکیج net/http سازگار نیست. این بدان معناست شما نمی توانید از پکیج های مانند go-swagger, gqlgen یا سایر پروژه هایی که بخشی از اکوسیستم net/http هستند استفاده کنید.
@@ -286,7 +290,6 @@ func main() { - #### 📖 [**Serving Static Files**](https://docs.gofiber.io/api/app#static)
@@ -696,6 +699,7 @@ func main() { log.Fatal(app.Listen(":3000")) } ``` +
@@ -711,34 +715,34 @@ func main() {
-| Middleware | توضیحات | -| :------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) |یک میدلور پایه که سیستم احراز هویت پایه ای را فراهم میکند. در صورت معتبر بودن درخواست روتر بعدی صدا زده شده و در صورت نامعتبر بودن خطای ۴۰۱ نمایش داده میشود.| -| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) |پاسخ هارا رهگیری کرده و انها را به صورت موقت ذخیره میکند.| -| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | یک میدلور فشرده سازی برای Fiber که به طور پیشفرض از `deflate`, `gzip` و `brotli`. پشتیبانی میکند.| | -| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) |فعال سازی هدر های cross-origin با گزینه های مختلف.| -| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) |در برابر حملات CSRF ایمنی ایجاد میکند.| -| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) |مقادیر کوکی هارا رمزنگاری میکند.| -| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | با ارائه تنظیمات اختیاری، متغیرهای محیط را در معرض دید قرار دهید. | -| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | میدلور ETag به کش ها اجازه میدهد کارآمد تر عمل کرده و در پهنای باند صرفه جویی کنند. به عنوان یک وب سرور نیازی به دادن پاسخ کامل نیست اگر محتوا تغییر نکرده باشد. | -| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | میدلور Expvar میتواند متغیر هایی را تعریف کرده و مقادیر انها را در زمان اجرا با فرمت JSON به شما نشان دهد. | -| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | جلوگیری و یا کش کردن درخواست های favicon در صورتی که مسیر یک فایل را داده باشید.| -| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | میدلور FileSystem به شما اجازه میدهد فایل های یک مسیر را عمومی کنید. | -| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) |میدلور محدود کننده تعداد درخواست برای Fiber.| -| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) |لاگ گرفتن از درخواست و پاسخ های HTTP.| -| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) |وضعیت سرور را مانیتور و گزارش میکند، از express-status-monitor الهام گرفته شده است.| -| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | تشکر ویژه از Matthew Lee \(@mthli\)| -| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | اجازه میدهد درخواست هارا بر روی چند سرور پروکسی کنید. | -| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) |خطا های زمان اجرا را در وب سرور HTTP شما مدیریت میکنند[ ErrorHandler](https://docs.gofiber.io/guide/error-handling). | -| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | به تمامی درخواست ها شناسه ای را اختصاص میدهد.| -| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) |برای ذخیره و مدیریت شناسه کاربری یا session بازدید کنندگان استفاده .میشود| -| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) |این میدلور میتواند با استفاده از شرط های تعیین شده درخواست هایی را نادیده بگیرد.| -| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) |این میدلور محدودیت زمانی ای را برای درخواست ها تنظیم میکند، در صورتی که محدودیت به پایان برسد ErrorHandler صدا زده میشود.| -| [keyauth](https://github.com/gofiber/keyauth) | این میدلور احراز هویت مبتنی بر کلید را فراهم می کند. | -| [redirect](https://github.com/gofiber/redirect) | برای ریدایرکت کردن از این میدلور میتوانید استفاده کنید. | -| [rewrite](https://github.com/gofiber/rewrite) | مسیر URL را براساس قوانین مشخص شده بازنویسی می کند. این میتواند برای سازگاری با ورژن های قبلی یا برای ساخت لینک های تمیز تر و توصیفی تر مفید باشد. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | با استفاده از HTTP هدر های مختلف به ایمن سازی برنامه شما کمک می کند. | +| Middleware | توضیحات | +| :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | +| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | یک میدلور پایه که سیستم احراز هویت پایه ای را فراهم میکند. در صورت معتبر بودن درخواست روتر بعدی صدا زده شده و در صورت نامعتبر بودن خطای ۴۰۱ نمایش داده میشود. | +| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | پاسخ هارا رهگیری کرده و انها را به صورت موقت ذخیره میکند. | +| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | یک میدلور فشرده سازی برای Fiber که به طور پیشفرض از `deflate`, `gzip` و `brotli`. پشتیبانی میکند. | | +| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | فعال سازی هدر های cross-origin با گزینه های مختلف. | +| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | در برابر حملات CSRF ایمنی ایجاد میکند. | +| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | مقادیر کوکی هارا رمزنگاری میکند. | +| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | با ارائه تنظیمات اختیاری، متغیرهای محیط را در معرض دید قرار دهید. | +| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | میدلور ETag به کش ها اجازه میدهد کارآمد تر عمل کرده و در پهنای باند صرفه جویی کنند. به عنوان یک وب سرور نیازی به دادن پاسخ کامل نیست اگر محتوا تغییر نکرده باشد. | +| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | میدلور Expvar میتواند متغیر هایی را تعریف کرده و مقادیر انها را در زمان اجرا با فرمت JSON به شما نشان دهد. | +| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | جلوگیری و یا کش کردن درخواست های favicon در صورتی که مسیر یک فایل را داده باشید. | +| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | میدلور FileSystem به شما اجازه میدهد فایل های یک مسیر را عمومی کنید. | +| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | میدلور محدود کننده تعداد درخواست برای Fiber. | +| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | لاگ گرفتن از درخواست و پاسخ های HTTP. | +| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | وضعیت سرور را مانیتور و گزارش میکند، از express-status-monitor الهام گرفته شده است. | +| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | تشکر ویژه از Matthew Lee \(@mthli\) | +| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | اجازه میدهد درخواست هارا بر روی چند سرور پروکسی کنید. | +| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | خطا های زمان اجرا را در وب سرور HTTP شما مدیریت میکنند[ ErrorHandler](https://docs.gofiber.io/guide/error-handling). | +| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | به تمامی درخواست ها شناسه ای را اختصاص میدهد. | +| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | برای ذخیره و مدیریت شناسه کاربری یا session بازدید کنندگان استفاده .میشود | +| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | این میدلور میتواند با استفاده از شرط های تعیین شده درخواست هایی را نادیده بگیرد. | +| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | این میدلور محدودیت زمانی ای را برای درخواست ها تنظیم میکند، در صورتی که محدودیت به پایان برسد ErrorHandler صدا زده میشود. | +| [keyauth](https://github.com/gofiber/keyauth) | این میدلور احراز هویت مبتنی بر کلید را فراهم می کند. | +| [redirect](https://github.com/gofiber/redirect) | برای ریدایرکت کردن از این میدلور میتوانید استفاده کنید. | +| [rewrite](https://github.com/gofiber/rewrite) | مسیر URL را براساس قوانین مشخص شده بازنویسی می کند. این میتواند برای سازگاری با ورژن های قبلی یا برای ساخت لینک های تمیز تر و توصیفی تر مفید باشد. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | با استفاده از HTTP هدر های مختلف به ایمن سازی برنامه شما کمک می کند. |


@@ -753,16 +757,16 @@ func main() {
-| Middleware | توضیحات | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | توضیحات | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List - [awesome list](https://github.com/gofiber/awesome-fiber) برای مقاله، میدلور، مثال ها و ابزار های بیشتر لطفا از این لینک بازدید کنید +[awesome list](https://github.com/gofiber/awesome-fiber) برای مقاله، میدلور، مثال ها و ابزار های بیشتر لطفا از این لینک بازدید کنید
diff --git a/.github/README_fr.md b/.github/README_fr.md index 374642409c..b24aa632b8 100644 --- a/.github/README_fr.md +++ b/.github/README_fr.md @@ -66,6 +66,9 @@
+ + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - [WebSocket support](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- Available in [18 languages](https://docs.gofiber.io/) +- Available in [19 languages](https://docs.gofiber.io/) - Et plus encore, [explorez Fiber](https://docs.gofiber.io/) ## 💡 Philosophie @@ -153,8 +156,9 @@ Les nouveaux gophers qui passent de [Node.js](https://nodejs.org/en/about/) à [ Fiber est **inspiré** par Express, le framework web le plus populaire d'Internet. Nous avons combiné la **facilité** d'Express, et la **performance brute** de Go. Si vous avez déja développé une application web en Node.js (_en utilisant Express ou équivalent_), alors de nombreuses méthodes et principes vous sembleront **familiers**. ## ⚠️ Limitations -* Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. -* Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. + +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 Exemples @@ -599,22 +603,22 @@ Here is a list of middleware that are included within the Fiber framework. | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | ## 🧬 External Middleware List of externally hosted middleware modules and maintained by the [Fiber team](https://github.com/orgs/gofiber/people). -| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List diff --git a/.github/README_he.md b/.github/README_he.md index 39a97fde0e..838f94c75d 100644 --- a/.github/README_he.md +++ b/.github/README_he.md @@ -66,6 +66,9 @@ + + +
@@ -198,8 +201,9 @@ Fiber נוצרה **בהשראת** Express, ה-web framework הפופולרית
## ⚠️ Limitations -* Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. -* Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. + +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 דוגמאות @@ -715,11 +719,11 @@ Here is a list of middleware that are included within the Fiber framework. | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. |
@@ -737,12 +741,12 @@ Here is a list of middleware that are included within the Fiber framework.
-| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! |
diff --git a/.github/README_id.md b/.github/README_id.md index 1bbdf1725c..013a59e4b6 100644 --- a/.github/README_id.md +++ b/.github/README_id.md @@ -66,6 +66,9 @@
+ + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - [Mendukung WebSocket](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- Tersedia dalam [18 bahasa](https://docs.gofiber.io/) +- Tersedia dalam [19 bahasa](https://docs.gofiber.io/) - Dan masih banyak lagi, [kunjungi Fiber](https://docs.gofiber.io/) ## 💡 Filosofi @@ -156,8 +159,8 @@ Kami **mendengarkan** para pengguna di [GitHub Issues](https://github.com/gofibe ## ⚠️ Limitasi -* Karena penggunaan Fiber yang tidak aman, perpustakaan mungkin tidak selalu kompatibel dengan versi Go terbaru. Fiber 2.40.0 telah diuji dengan Go versi 1.17 hingga 1.20. -* Fiber tidak kompatibel dengan antarmuka net/http. Ini berarti kamu tidak akan dapat menggunakan proyek seperti gqlgen, go-swagger, atau lainnya yang merupakan bagian dari ekosistem net/http. +- Karena penggunaan Fiber yang tidak aman, perpustakaan mungkin tidak selalu kompatibel dengan versi Go terbaru. Fiber 2.40.0 telah diuji dengan Go versi 1.17 hingga 1.20. +- Fiber tidak kompatibel dengan antarmuka net/http. Ini berarti kamu tidak akan dapat menggunakan proyek seperti gqlgen, go-swagger, atau lainnya yang merupakan bagian dari ekosistem net/http. ## 👀 Contoh @@ -600,22 +603,22 @@ Kumpulan `middleware` yang ada didalam kerangka kerja Fiber. | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | ## 🧬 Middleware External Kumpulan `middleware` yang dihost external dan diurus oleh [Tim Fiber](https://github.com/orgs/gofiber/people). -| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List @@ -681,4 +684,3 @@ Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors]( - [schema](https://github.com/gorilla/schema/blob/master/LICENSE) - [uuid](https://github.com/google/uuid/blob/master/LICENSE) - [wmi](https://github.com/StackExchange/wmi/blob/master/LICENSE) - diff --git a/.github/README_it.md b/.github/README_it.md index 567d4b4a24..0124cddcb0 100644 --- a/.github/README_it.md +++ b/.github/README_it.md @@ -66,6 +66,9 @@ + + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - [Supporto WebSocket](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- Disponible in [18 lingue](https://docs.gofiber.io/) +- Disponible in [19 lingue](https://docs.gofiber.io/) - E molto altro ancora, [esplora Fiber](https://docs.gofiber.io/) ## 💡 Filosofia @@ -154,8 +157,8 @@ Fiber è **ispirato** da Express, il web framework più popolare su internet. Ab ## ⚠️ Limitazioni -* Dato che Fiber utilizza unsafe, la libreria non sempre potrebbe essere compatibile con l'ultima versione di Go. Fiber 2.40.0 è stato testato con la versioni 1.17 alla 1.20 di Go. -* Fiber non è compatibile con le interfacce net/http. Questo significa che non è possibile utilizzare progetti come qglgen, go-swagger, o altri che fanno parte dell'ecosistema net/http. +- Dato che Fiber utilizza unsafe, la libreria non sempre potrebbe essere compatibile con l'ultima versione di Go. Fiber 2.40.0 è stato testato con la versioni 1.17 alla 1.20 di Go. +- Fiber non è compatibile con le interfacce net/http. Questo significa che non è possibile utilizzare progetti come qglgen, go-swagger, o altri che fanno parte dell'ecosistema net/http. ## 👀 Esempi @@ -600,45 +603,45 @@ func main() { Qui una lista dei middleware inclusi con Fiber. -| Middleware | Descrizione | -| :------------------------------------------------------------------------------------- |:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Middleware basico di autenticazione usando http. Chiama il suo handler se le credenziali sono giuste e il codice 401 Unauthorized per credenziali mancanti o invalide. | -| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercetta e mette nella cache la risposta | -| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Middleware di compressione per Fiber, supporta `deflate`, `gzip` e `brotli` di default. | -| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Ti permette di usare cross-origin resource sharing \(CORS\) con tante opzioni. | -| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | Ti protegge da attachi CSRF. | -| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Middleware che encrypta i valori dei cookie. | -| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Esporre le variabili di ambiente fornendo una configurazione facoltativa. | -| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | Middleware che permette alle cache di essere più efficienti e salvare banda, come un web server che non deve rimandare il messagio pieno se il contenuto non è cambiato. | -| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Middleware che serve via il suo runtime server HTTP varianti esposte in formato JSON. | -| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Ignora favicon dai logs o serve dalla memoria se un filepath è specificato. | -| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | Middleware per il FileSystem per Fiber, grazie tante e crediti a Alireza Salary | -| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Middleware per Rate-limiting per Fiber. Usato per limitare richieste continue agli APIs publici e/o endpoints come un password reset. | -| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | Logger HTTP per richiesta/risposta. | -| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Middleware per monitorare che riporta metriche server, ispirato da express-status-monitor | -| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Grazie tante a Matthew Lee \(@mthli\) | -| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Ti permette di fare richieste proxy a multipli server. | -| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Middleware per recuperare dagli attachi di panico da tutte le parti nella stack chain e affida il controllo al [ ErrorHandler](https://docs.gofiber.io/guide/error-handling) centralizzato. | -| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Aggiunge un requestid a ogni richiesta. | -| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Middleware per sessioni. NOTA: Questo middleware usa il nostro Storage package. | -| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Middleware che salta un wrapped handler se un predicate è vero. | -| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Aggiunge un tempo massimo per una richiesta e lo manda a ErrorHandler se si supera. | -| [keyauth](https://github.com/gofiber/keyauth) | Usa auth basato su chiavi. | -| [redirect](https://github.com/gofiber/redirect) | Middleware per reinderizzare | -| [rewrite](https://github.com/gofiber/rewrite) | Riscrive la path all URL con le regole date. Può essere di aiuto per compatibilità o per creare link puliti e più descrittivi. | -| [adaptor](https://github.com/gofiber/adaptor) | Converte gli handler net/http a/da i request handlers di Fiber, grazie tante a @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Aiuta a mettere sicurezza alla tua app usando vari header HTTP. | +| Middleware | Descrizione | +| :------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Middleware basico di autenticazione usando http. Chiama il suo handler se le credenziali sono giuste e il codice 401 Unauthorized per credenziali mancanti o invalide. | +| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercetta e mette nella cache la risposta | +| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Middleware di compressione per Fiber, supporta `deflate`, `gzip` e `brotli` di default. | +| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Ti permette di usare cross-origin resource sharing \(CORS\) con tante opzioni. | +| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | Ti protegge da attachi CSRF. | +| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Middleware che encrypta i valori dei cookie. | +| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Esporre le variabili di ambiente fornendo una configurazione facoltativa. | +| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | Middleware che permette alle cache di essere più efficienti e salvare banda, come un web server che non deve rimandare il messagio pieno se il contenuto non è cambiato. | +| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Middleware che serve via il suo runtime server HTTP varianti esposte in formato JSON. | +| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Ignora favicon dai logs o serve dalla memoria se un filepath è specificato. | +| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | Middleware per il FileSystem per Fiber, grazie tante e crediti a Alireza Salary | +| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Middleware per Rate-limiting per Fiber. Usato per limitare richieste continue agli APIs publici e/o endpoints come un password reset. | +| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | Logger HTTP per richiesta/risposta. | +| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Middleware per monitorare che riporta metriche server, ispirato da express-status-monitor | +| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Grazie tante a Matthew Lee \(@mthli\) | +| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Ti permette di fare richieste proxy a multipli server. | +| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Middleware per recuperare dagli attachi di panico da tutte le parti nella stack chain e affida il controllo al [ ErrorHandler](https://docs.gofiber.io/guide/error-handling) centralizzato. | +| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Aggiunge un requestid a ogni richiesta. | +| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Middleware per sessioni. NOTA: Questo middleware usa il nostro Storage package. | +| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Middleware che salta un wrapped handler se un predicate è vero. | +| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Aggiunge un tempo massimo per una richiesta e lo manda a ErrorHandler se si supera. | +| [keyauth](https://github.com/gofiber/keyauth) | Usa auth basato su chiavi. | +| [redirect](https://github.com/gofiber/redirect) | Middleware per reinderizzare | +| [rewrite](https://github.com/gofiber/rewrite) | Riscrive la path all URL con le regole date. Può essere di aiuto per compatibilità o per creare link puliti e più descrittivi. | +| [adaptor](https://github.com/gofiber/adaptor) | Converte gli handler net/http a/da i request handlers di Fiber, grazie tante a @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Aiuta a mettere sicurezza alla tua app usando vari header HTTP. | ## 🧬 Middleware Esterni La lista dei moduli middleware hostati esternamente e mantenuti dal [team di Fiber](https://github.com/orgs/gofiber/people). -| Middleware | Descrizione | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | Usa JSON Web Token \(JWT\) auth. | -| [storage](https://github.com/gofiber/storage) | Dirver di storage che implementa la interfaccia Storage, fatto per essere usato con vari Fiber middleware. | -| [template](https://github.com/gofiber/template) | Questo pachetto contiene 8 motori template che possono essere usati con Fiber `v1.10.x`. Versione di go neccesaria: 1.13+. | -| [websocket](https://github.com/gofiber/websocket) | Basato su Fasthttp WebSocket per Fiber con supporto per Locals! | +| Middleware | Descrizione | +| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | Usa JSON Web Token \(JWT\) auth. | +| [storage](https://github.com/gofiber/storage) | Dirver di storage che implementa la interfaccia Storage, fatto per essere usato con vari Fiber middleware. | +| [template](https://github.com/gofiber/template) | Questo pachetto contiene 8 motori template che possono essere usati con Fiber `v1.10.x`. Versione di go neccesaria: 1.13+. | +| [websocket](https://github.com/gofiber/websocket) | Basato su Fasthttp WebSocket per Fiber con supporto per Locals! | ## 🕶️ Awesome List diff --git a/.github/README_ja.md b/.github/README_ja.md index 8006c60b8b..719d7a9167 100644 --- a/.github/README_ja.md +++ b/.github/README_ja.md @@ -66,6 +66,9 @@ + + +
@@ -144,7 +147,7 @@ go get -u github.com/gofiber/fiber/v2 - [WebSocket support](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- [18 ヶ国語](https://docs.gofiber.io/)に翻訳 +- [19 ヶ国語](https://docs.gofiber.io/)に翻訳 - [Fiber](https://docs.gofiber.io/)をもっと知る ## 💡 哲学 @@ -602,22 +605,22 @@ func main() { | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | ## 🧬 外部ミドルウェア [Fiber team](https://github.com/orgs/gofiber/people) により管理・運用されているミドルウェアの一覧です。 -| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List diff --git a/.github/README_ko.md b/.github/README_ko.md index 037605c3cc..7dea503a14 100644 --- a/.github/README_ko.md +++ b/.github/README_ko.md @@ -66,6 +66,9 @@ + + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - [WebSocket support](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- Available in [18 languages](https://docs.gofiber.io/) +- Available in [19 languages](https://docs.gofiber.io/) - 더 알고 싶다면, [Fiber 둘러보기](https://docs.gofiber.io/) ## 💡 철학 @@ -155,8 +158,9 @@ Fiber는 인터넷에서 가장 인기있는 웹 프레임워크인 Express에 우리는 **어떤한** 작업, **마감일정**, 개발자의 **기술**이던간에 **빠르고**, **유연하고**, **익숙한** Go 웹 프레임워크를 만들기 위해 사용자들의 [이슈들](https://github.com/gofiber/fiber/issues)을(그리고 모든 인터넷을 통해) **듣고 있습니다**! Express가 자바스크립트 세계에서 하는 것 처럼요. ## ⚠️ 한계점 -* Fiber는 unsafe 패키지를 사용하기 때문에 최신 Go버전과 호환되지 않을 수 있습니다.Fiber 2.40.0은 Go 버전 1.17에서 1.20로 테스트되고 있습니다. -* Fiber는 net/http 인터페이스와 호환되지 않습니다.즉, gqlgen이나 go-swagger 등 net/http 생태계의 일부인 프로젝트를 사용할 수 없습니다. + +- Fiber는 unsafe 패키지를 사용하기 때문에 최신 Go버전과 호환되지 않을 수 있습니다.Fiber 2.40.0은 Go 버전 1.17에서 1.20로 테스트되고 있습니다. +- Fiber는 net/http 인터페이스와 호환되지 않습니다.즉, gqlgen이나 go-swagger 등 net/http 생태계의 일부인 프로젝트를 사용할 수 없습니다. ## 👀 예제 @@ -603,22 +607,22 @@ Fiber 프레임워크에 포함되는 미들웨어 목록입니다. | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | ## 🧬 External Middleware [Fiber team](https://github.com/orgs/gofiber/people)에 의해 관리 및 운용되고 있는 미들웨어 목록입니다. -| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List diff --git a/.github/README_nl.md b/.github/README_nl.md index 45711c8807..e3e8205de9 100644 --- a/.github/README_nl.md +++ b/.github/README_nl.md @@ -66,6 +66,9 @@ + + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - [WebSocket ondersteuning](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/category/-middleware/limiter) -- Vertaald in [18 talen](https://docs.gofiber.io/) +- Vertaald in [19 talen](https://docs.gofiber.io/) - En nog veel meer, [ontdek Fiber](https://docs.gofiber.io/) ## 💡 Filosofie @@ -155,8 +158,9 @@ Fiber is **geïnspireerd** door Express, het populairste webframework op interne We **luisteren** naar onze gebruikers in [issues](https://github.com/gofiber/fiber/issues) (_en overal op het internet_) om een **snelle**, **flexibele** en **vriendelijk** Go web framework te maken voor **elke** taak, **deadline** en ontwikkelaar **vaardigheid**! Net zoals Express dat doet in de JavaScript-wereld. ## ⚠️ Limitations -* Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. -* Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. + +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 Voorbeelden @@ -603,22 +607,22 @@ Here is a list of middleware that are included within the Fiber framework. | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | ## 🧬 External Middleware List of externally hosted middleware modules and maintained by the [Fiber team](https://github.com/orgs/gofiber/people). -| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List diff --git a/.github/README_pt.md b/.github/README_pt.md index 846da368dc..f6e5ac9335 100644 --- a/.github/README_pt.md +++ b/.github/README_pt.md @@ -66,6 +66,9 @@ + + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - [Suporte à WebSockets](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Limitador de requisições](https://docs.gofiber.io/api/middleware/limiter) -- Disponível em [18 línguas](https://docs.gofiber.io/) +- Disponível em [19 línguas](https://docs.gofiber.io/) - E muito mais, [explore o Fiber](https://docs.gofiber.io/) ## 💡 Filosofia @@ -152,10 +155,12 @@ Os novos gophers que mudaram do [Node.js](https://nodejs.org/en/about/) para o [ O Fiber é **inspirado** no Express, o framework web mais popular da Internet. Combinamos a **facilidade** do Express e com o **desempenho bruto** do Go. Se você já implementou um aplicativo web com Node.js ( _usando Express.js ou similar_ ), então muitos métodos e princípios parecerão **muito familiares** para você. + ## ⚠️ Limitações * Devido ao uso de "unsafe" pelo Fiber, a biblioteca pode nem sempre ser compatível com a última versão do Go. Fiber 2.40.0 foi testado com as versões Go de 1.17 a 1.20. * Fiber não é compatível com as interfaces net/http. Isso significa que você não poderá usar projetos como gqlgen, go-swagger ou quaisquer outros que fazem parte do ecossistema net/http. + ## 👀 Exemplos Listados abaixo estão alguns exemplos comuns. Se você quiser ver mais exemplos de código, @@ -570,6 +575,7 @@ func main() { + ## 🧬 Middleware Interno Aqui está uma lista de middlewares que estão incluídos no framework Fiber. diff --git a/.github/README_ru.md b/.github/README_ru.md index 9ebbb1d224..3776644c9c 100644 --- a/.github/README_ru.md +++ b/.github/README_ru.md @@ -66,6 +66,9 @@ + + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - [Поддержка WebSocket](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- Документация доступна на [18 языках](https://docs.gofiber.io/) +- Документация доступна на [19 языках](https://docs.gofiber.io/) - И многое другое, [посетите наш Wiki](https://docs.gofiber.io/) ## 💡 Философия @@ -155,8 +158,9 @@ Fiber **вдохновлен** Express, самым популярным веб Мы **прислушиваемся** к нашим пользователям в [issues](https://github.com/gofiber/fiber/issues), Discord [канале](https://gofiber.io/discord) _и в остальном Интернете_, чтобы создать **быстрый**, **гибкий** и **дружелюбный** веб фреймворк на Go для **любых** задач, **дедлайнов** и **уровней** разработчиков! Как это делает Express в мире JavaScript. ## ⚠️ Ограничения -* Из-за того, что Fiber использует пакет unsafe, библиотека не всегда может быть совместима с последней версией Go. Fiber 2.40.0 был протестирован с версиями Go от 1.17 до 1.20. -* Fiber не совместим с интерфейсами net/http. Это означает, что вы не сможете использовать такие проекты, как gqlgen, go-swagger или любые другие, которые являются частью экосистемы net/http. + +- Из-за того, что Fiber использует пакет unsafe, библиотека не всегда может быть совместима с последней версией Go. Fiber 2.40.0 был протестирован с версиями Go от 1.17 до 1.20. +- Fiber не совместим с интерфейсами net/http. Это означает, что вы не сможете использовать такие проекты, как gqlgen, go-swagger или любые другие, которые являются частью экосистемы net/http. ## 👀 Примеры @@ -581,7 +585,7 @@ func main() { Вот список middleware, входящих в состав фреймворка Fiber. -| Middleware | Описание | +| Middleware | Описание | | :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Basic auth middleware provides an HTTP basic authentication. It calls the next handler for valid credentials and 401 Unauthorized for missing or invalid credentials. | | [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercept and cache responses | @@ -604,22 +608,22 @@ func main() { | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | ## 🧬 Внешние Middleware Список модулей middleware, размещенных на внешнем хостинге от [Fiber team](https://github.com/orgs/gofiber/people). -| Middleware | Описание | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Описание | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Полезный список @@ -671,7 +675,7 @@ Fiber — это проект с открытым исходным кодом, ## ⚠️ Лицензия -Copyright (c) 2019-настоящее время [Fenny](https://github.com/fenny) и [Контрибьютеры](https://github.com/gofiber/fiber/graphs/contributors). `Fiber` - это свободное программное обсепечение с открытым исходным кодом лицензированное под [MIT License](https://github.com/gofiber/fiber/blob/master/LICENSE). Официальный логотип создан [Vic Shóstak](https://github.com/koddr) и распространяется под [Creative Commons](https://creativecommons.org/licenses/by-sa/4.0/) лицензией (CC BY-SA 4.0 International). +Copyright (c) 2019-настоящее время [Fenny](https://github.com/fenny) и [Контрибьютеры](https://github.com/gofiber/fiber/graphs/contributors). `Fiber` - это свободное программное обсепечение с открытым исходным кодом лицензированное под [MIT License](https://github.com/gofiber/fiber/blob/master/LICENSE). Официальный логотип создан [Vic Shóstak](https://github.com/koddr) и распространяется под [Creative Commons](https://creativecommons.org/licenses/by-sa/4.0/) лицензией (CC BY-SA 4.0 International). **Third-party library licenses** diff --git a/.github/README_sa.md b/.github/README_sa.md index b3f77d6198..25e01906a2 100644 --- a/.github/README_sa.md +++ b/.github/README_sa.md @@ -66,6 +66,9 @@ + + +
@@ -156,7 +159,7 @@ go get -u github.com/gofiber/fiber/v2 - [WebSocket دعم](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- ترجم الى [18 لغة أخرى](https://docs.gofiber.io/) +- ترجم الى [19 لغة أخرى](https://docs.gofiber.io/) - وأكثر بكثير, [استكشف Fiber](https://docs.gofiber.io/) ## 💡 فلسفة @@ -169,8 +172,9 @@ Fiber هو **مستوحى** من Express, إطار الويب الأكثر شع ** و تطوير **مهارات**! فقط مثل Express تفعل لـ JavaScript عالم. ## ⚠️ Limitations -* Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. -* Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. + +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 أمثلة @@ -668,22 +672,22 @@ Here is a list of middleware that are included within the Fiber framework. | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler is a predicate is true. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | ## 🧬 External Middleware List of externally hosted middleware modules and maintained by the [Fiber team](https://github.com/orgs/gofiber/people). -| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List diff --git a/.github/README_tr.md b/.github/README_tr.md index 496c2797a2..326c2fa973 100644 --- a/.github/README_tr.md +++ b/.github/README_tr.md @@ -63,6 +63,9 @@ + + +
@@ -143,7 +146,7 @@ go get -u github.com/gofiber/fiber/v2 - [WebSocket desteği](https://github.com/gofiber/websocket) - [Server-Sent eventler](https://github.com/gofiber/recipes/tree/master/sse) - [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) -- [18 dilde](https://docs.gofiber.io/) mevcut +- [19 dilde](https://docs.gofiber.io/) mevcut - Ve daha fazlası, [Fiber'ı keşfet](https://docs.gofiber.io/) ## 💡 Felsefe @@ -574,47 +577,48 @@ func main() { Fiber'a dahil edilen middlewareların bir listesi aşağıda verilmiştir. -| Middleware | Açıklama | -| :------------------------------------------------------------------------------------- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Basic auth middleware'ı, bir HTTP Basic auth sağlar. Geçerli kimlik bilgileri için sonraki handlerı ve eksik veya geçersiz kimlik bilgileri için 401 döndürür. | -| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Reponseları durdur ve önbelleğe al. | -| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Fiber için sıkıştırma middleware, varsayılan olarak `deflate`, `gzip` ve `brotli`yi destekler. | -| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Çeşitli seçeneklerle başlangıçlar arası kaynak paylaşımını \(CORS\) etkinleştirin. | -| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | CSRF exploitlerinden korunun. | -| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Encrypt middleware'ı cookie değerlerini şifreler. | -| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Environment değişkenlerini belirtilen ayarlara göre dışarıya açar. | -| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | ETag middleware'ı sayfa içeriği değişmediyse bant genişliğini daha verimli kullanmak için tam sayfa içeriğini tekrar göndermez. | -| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Expvar middleware, HTTP serverinin bazı runtime değişkenlerini JSON formatında sunar. | -| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Bir dosya yolu sağlanmışsa, loglardaki favicon'u yoksayar veya bellekten sunar. | -| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | Fiber için FileSystem middleware, Alireza Salary'e özel teşekkürler. | -| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Fiber için hız sınırlayıcı middleware'i. Açık API'lere ve/veya parola sıfırlama gibi endpointlere yönelik tekrarlanan istekleri sınırlamak için kullanın. | -| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | HTTP istek/yanıt logger'ı. | -| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Monitor middleware'ı sunucu metriklerini rapor eder, express-status-monitor'den esinlenildi. | -| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Matthew Lee'ye özel teşekkürler \(@mthli\). | -| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Birden çok sunucuya proxy istekleri yapmanızı sağlar. | -| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Recover middleware'i, stack chain'ini herhangi bir yerindeki paniklerden kurtulur ve kontrolü merkezileştirilmiş [ErrorHandler'e](https://docs.gofiber.io/guide/error-handling) verir. | -| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Her requeste id verir. | -| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session için middleware. NOTE: Bu middleware Fiber'in Storage yapısını kullanır. | -| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware'ı verilen koşul `true` olduğunda handler'ı atlar ve işlemez. | -| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Bir request için maksimum süre ekler ve aşılırsa ErrorHandler'a iletir. | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware, key tabanlı bir authentication sağlar. | -| [redirect](https://github.com/gofiber/redirect) | Yönlendirme middleware 'ı. | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware, sağlanan kurallara göre URL yolunu yeniden yazar. Geriye dönük uyumluluk için veya yalnızca daha temiz ve daha açıklayıcı bağlantılar oluşturmak için yardımcı olabilir. | -| [adaptor](https://github.com/gofiber/adaptor) | Fiber request handlerdan net/http handlerları için dönüştürücü, @arsmn'a özel teşekkürler! | -| [helmet](https://github.com/gofiber/helmet) | Çeşitli HTTP headerları ayarlayarak uygulamalarınızın güvenliğini sağlamaya yardımcı olur. | +| Middleware | Açıklama | +| :------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Basic auth middleware'ı, bir HTTP Basic auth sağlar. Geçerli kimlik bilgileri için sonraki handlerı ve eksik veya geçersiz kimlik bilgileri için 401 döndürür. | +| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Reponseları durdur ve önbelleğe al. | +| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Fiber için sıkıştırma middleware, varsayılan olarak `deflate`, `gzip` ve `brotli`yi destekler. | +| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Çeşitli seçeneklerle başlangıçlar arası kaynak paylaşımını \(CORS\) etkinleştirin. | +| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | CSRF exploitlerinden korunun. | +| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Encrypt middleware'ı cookie değerlerini şifreler. | +| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Environment değişkenlerini belirtilen ayarlara göre dışarıya açar. | +| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | ETag middleware'ı sayfa içeriği değişmediyse bant genişliğini daha verimli kullanmak için tam sayfa içeriğini tekrar göndermez. | +| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Expvar middleware, HTTP serverinin bazı runtime değişkenlerini JSON formatında sunar. | +| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Bir dosya yolu sağlanmışsa, loglardaki favicon'u yoksayar veya bellekten sunar. | +| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | Fiber için FileSystem middleware, Alireza Salary'e özel teşekkürler. | +| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Fiber için hız sınırlayıcı middleware'i. Açık API'lere ve/veya parola sıfırlama gibi endpointlere yönelik tekrarlanan istekleri sınırlamak için kullanın. | +| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | HTTP istek/yanıt logger'ı. | +| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Monitor middleware'ı sunucu metriklerini rapor eder, express-status-monitor'den esinlenildi. | +| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Matthew Lee'ye özel teşekkürler \(@mthli\). | +| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Birden çok sunucuya proxy istekleri yapmanızı sağlar. | +| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Recover middleware'i, stack chain'ini herhangi bir yerindeki paniklerden kurtulur ve kontrolü merkezileştirilmiş [ErrorHandler'e](https://docs.gofiber.io/guide/error-handling) verir. | +| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Her requeste id verir. | +| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session için middleware. NOTE: Bu middleware Fiber'in Storage yapısını kullanır. | +| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware'ı verilen koşul `true` olduğunda handler'ı atlar ve işlemez. | +| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Bir request için maksimum süre ekler ve aşılırsa ErrorHandler'a iletir. | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware, key tabanlı bir authentication sağlar. | +| [redirect](https://github.com/gofiber/redirect) | Yönlendirme middleware 'ı. | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware, sağlanan kurallara göre URL yolunu yeniden yazar. Geriye dönük uyumluluk için veya yalnızca daha temiz ve daha açıklayıcı bağlantılar oluşturmak için yardımcı olabilir. | +| [adaptor](https://github.com/gofiber/adaptor) | Fiber request handlerdan net/http handlerları için dönüştürücü, @arsmn'a özel teşekkürler! | +| [helmet](https://github.com/gofiber/helmet) | Çeşitli HTTP headerları ayarlayarak uygulamalarınızın güvenliğini sağlamaya yardımcı olur. | ## 🧬 Harici Middlewarelar Harici olarak barındırılan middlewareların modüllerinin listesi. Bu middlewarelar, [Fiber ekibi](https://github.com/orgs/gofiber/people) tarafından geliştirilir. -| Middleware | Açıklama | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [jwt](https://github.com/gofiber/jwt) | JWT, bir JSON Web Token \(JWT\) yetkilendirmesi döndüren middleware. | -| [storage](https://github.com/gofiber/storage) | Fiber'in Storage yapısını destekleyen birçok storage driver'ı verir. Bu sayede depolama gerektiren Fiber middlewarelarında kolaylıkla kullanılabilir. | -| [template](https://github.com/gofiber/template) | Bu paket, Fiber `v2.x.x`, Go sürüm 1.17 veya üzeri gerekli olduğunda kullanılabilecek 9 template motoru içerir. | -| [websocket](https://github.com/gofiber/websocket) | Yereller desteğiyle Fiber için Fasthttp WebSocket'a dayalıdır! | +| Middleware | Açıklama | +| :------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT, bir JSON Web Token \(JWT\) yetkilendirmesi döndüren middleware. | +| [storage](https://github.com/gofiber/storage) | Fiber'in Storage yapısını destekleyen birçok storage driver'ı verir. Bu sayede depolama gerektiren Fiber middlewarelarında kolaylıkla kullanılabilir. | +| [template](https://github.com/gofiber/template) | Bu paket, Fiber `v2.x.x`, Go sürüm 1.17 veya üzeri gerekli olduğunda kullanılabilecek 9 template motoru içerir. | +| [websocket](https://github.com/gofiber/websocket) | Yereller desteğiyle Fiber için Fasthttp WebSocket'a dayalıdır! | ## 🕶️ Awesome Listesi + Daha fazla yazı, middleware, örnek veya araç için [awesome list](https://github.com/gofiber/awesome-fiber) reposunu kontrol etmeyi unutmayın. ## 👍 Destek diff --git a/.github/README_uk.md b/.github/README_uk.md index 9556e924e1..fe18dfdf52 100644 --- a/.github/README_uk.md +++ b/.github/README_uk.md @@ -68,6 +68,9 @@ + + +
@@ -155,7 +158,7 @@ go get -u github.com/gofiber/fiber/v2 - [Підтримка WebSocket](https://github.com/gofiber/websocket) - [Server-Sent Events](https://github.com/gofiber/recipes/tree/master/sse) - [Обмежувач швидкості](https://docs.gofiber.io/api/middleware/limiter) -- Документація доступна [18 мовами](https://docs.gofiber.io/) +- Документація доступна [19 мовами](https://docs.gofiber.io/) - І багато іншого, [відвідайте наш Wiki](https://docs.gofiber.io/) ## 💡 Філософія diff --git a/.github/README_zh-CN.md b/.github/README_zh-CN.md index bcc5c8a066..7ff9c55567 100644 --- a/.github/README_zh-CN.md +++ b/.github/README_zh-CN.md @@ -66,6 +66,9 @@ + + +
@@ -145,7 +148,7 @@ go get -u github.com/gofiber/fiber/v2 - [支持 WebSocket](https://github.com/gofiber/websocket) - [Server-Sent events](https://github.com/gofiber/recipes/tree/master/sse) - [频率限制](https://docs.gofiber.io/api/middleware/limiter) -- [被翻译成 18 种语言](https://docs.gofiber.io/) +- [被翻译成 19 种语言](https://docs.gofiber.io/) - 更多请[探索文档](https://docs.gofiber.io/) ## 💡 哲学 diff --git a/.github/README_zh-TW.md b/.github/README_zh-TW.md index 3a22be4654..87f8908de7 100644 --- a/.github/README_zh-TW.md +++ b/.github/README_zh-TW.md @@ -69,6 +69,9 @@ + + +
@@ -154,7 +157,7 @@ go get -u github.com/gofiber/fiber/v2 - [支援 WebSocket](https://github.com/gofiber/websocket) - [Server-Sent Events](https://github.com/gofiber/recipes/tree/master/sse) - 支援[速率限制](https://docs.gofiber.io/api/middleware/limiter) -- 有 [18 門語言](https://docs.gofiber.io/)的翻譯 +- 有 [19 門語言](https://docs.gofiber.io/)的翻譯 - 還有很多功能,[開始探索 Fiber](https://docs.gofiber.io/) ## 💡 設計哲學 From 892b23bd461279580b69c08a3897f3355b703abc Mon Sep 17 00:00:00 2001 From: Jacob <16949253+PassTheMayo@users.noreply.github.com> Date: Thu, 17 Aug 2023 08:04:53 -0500 Subject: [PATCH 13/84] :sparkles: Add custom data property to favicon middleware config (#2579) * Add custom data property to favicon middleware * Update favicon middleware docs * Fix formatting --- docs/api/middleware/favicon.md | 1 + middleware/favicon/favicon.go | 11 ++++++++++- middleware/favicon/favicon_test.go | 24 ++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/api/middleware/favicon.md b/docs/api/middleware/favicon.md index 3fea8b129a..b1a9b0df6c 100644 --- a/docs/api/middleware/favicon.md +++ b/docs/api/middleware/favicon.md @@ -45,6 +45,7 @@ app.Use(favicon.New(favicon.Config{ | Property | Type | Description | Default | |:-------------|:------------------------|:---------------------------------------------------------------------------------|:---------------------------| | Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | +| Data | `[]byte` | Raw data of the favicon file. This can be used instead of `File`. | `nil` | | File | `string` | File holds the path to an actual favicon that will be cached. | "" | | URL | `string` | URL for favicon handler. | "/favicon.ico" | | FileSystem | `http.FileSystem` | FileSystem is an optional alternate filesystem to search for the favicon in. | `nil` | diff --git a/middleware/favicon/favicon.go b/middleware/favicon/favicon.go index 84572b6d0f..457528916f 100644 --- a/middleware/favicon/favicon.go +++ b/middleware/favicon/favicon.go @@ -16,6 +16,11 @@ type Config struct { // Optional. Default: nil Next func(c *fiber.Ctx) bool + // Raw data of the favicon file + // + // Optional. Default: nil + Data []byte `json:"-"` + // File holds the path to an actual favicon that will be cached // // Optional. Default: "" @@ -83,7 +88,11 @@ func New(config ...Config) fiber.Handler { icon []byte iconLen string ) - if cfg.File != "" { + if cfg.Data != nil { + // use the provided favicon data + icon = cfg.Data + iconLen = strconv.Itoa(len(cfg.Data)) + } else if cfg.File != "" { // read from configured filesystem if present if cfg.FileSystem != nil { f, err := cfg.FileSystem.Open(cfg.File) diff --git a/middleware/favicon/favicon_test.go b/middleware/favicon/favicon_test.go index 9e628cf73e..6c8c9db723 100644 --- a/middleware/favicon/favicon_test.go +++ b/middleware/favicon/favicon_test.go @@ -99,6 +99,30 @@ func Test_Custom_Favicon_Url(t *testing.T) { utils.AssertEqual(t, "image/x-icon", resp.Header.Get(fiber.HeaderContentType)) } +// go test -run Test_Custom_Favicon_Data +func Test_Custom_Favicon_Data(t *testing.T) { + data, err := os.ReadFile("../../.github/testdata/favicon.ico") + if err != nil { + t.Fatal(err) + } + + app := fiber.New() + + app.Use(New(Config{ + Data: data, + })) + + app.Get("/", func(c *fiber.Ctx) error { + return nil + }) + + resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/favicon.ico", nil)) + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode, "Status code") + utils.AssertEqual(t, "image/x-icon", resp.Header.Get(fiber.HeaderContentType)) + utils.AssertEqual(t, "public, max-age=31536000", resp.Header.Get(fiber.HeaderCacheControl), "CacheControl Control") +} + // mockFS wraps local filesystem for the purposes of // Test_Middleware_Favicon_FileSystem located below // TODO use os.Dir if fiber upgrades to 1.16 From 85d1f6895aa86170f53250b88661ad05e8366a5f Mon Sep 17 00:00:00 2001 From: RW Date: Thu, 17 Aug 2023 16:24:38 +0200 Subject: [PATCH 14/84] Update README.md correct EG flag --- .github/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/README.md b/.github/README.md index 0dc23586ee..a82902ab8a 100644 --- a/.github/README.md +++ b/.github/README.md @@ -68,7 +68,7 @@ - +
From 242ff945050146e2865134185ff2d81ee73b1581 Mon Sep 17 00:00:00 2001 From: Eng Zer Jun Date: Fri, 18 Aug 2023 02:49:53 +0800 Subject: [PATCH 15/84] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20Remove?= =?UTF-8?q?=20redundant=20nil=20check=20(#2584)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the Go docs: "If the map is nil, the number of iterations is 0." [1] Therefore, an additional nil check for before the loop is unnecessary. [1]: https://go.dev/ref/spec#For_range Signed-off-by: Eng Zer Jun --- middleware/cache/cache.go | 6 ++---- middleware/logger/tags.go | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/middleware/cache/cache.go b/middleware/cache/cache.go index a4bfc4ddaf..f7149d1e8b 100644 --- a/middleware/cache/cache.go +++ b/middleware/cache/cache.go @@ -141,10 +141,8 @@ func New(config ...Config) fiber.Handler { if len(e.cencoding) > 0 { c.Response().Header.SetBytesV(fiber.HeaderContentEncoding, e.cencoding) } - if e.headers != nil { - for k, v := range e.headers { - c.Response().Header.SetBytesV(k, v) - } + for k, v := range e.headers { + c.Response().Header.SetBytesV(k, v) } // Set Cache-Control header if enabled if cfg.CacheControl { diff --git a/middleware/logger/tags.go b/middleware/logger/tags.go index ac2b909002..af114a5777 100644 --- a/middleware/logger/tags.go +++ b/middleware/logger/tags.go @@ -199,10 +199,8 @@ func createTagMap(cfg *Config) map[string]LogFunc { }, } // merge with custom tags from user - if cfg.CustomTags != nil { - for k, v := range cfg.CustomTags { - tagFunctions[k] = v - } + for k, v := range cfg.CustomTags { + tagFunctions[k] = v } return tagFunctions From 5fd3f20de8e2e745e1760d921e56ae6796b619ed Mon Sep 17 00:00:00 2001 From: Girges Scandar <25529286+scandar@users.noreply.github.com> Date: Fri, 18 Aug 2023 08:57:52 +0200 Subject: [PATCH 16/84] =?UTF-8?q?=F0=9F=93=9D=20Replace=20EG=20flag=20with?= =?UTF-8?q?=20the=20proper=20and=20smaller=20SVG=20=20(#2585)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit replace the EG flag with the proper smaller svg --- .github/README.md | 31 ++++++------ .github/README_az.md | 2 +- .github/README_ckb.md | 4 +- .github/README_de.md | 2 +- .github/README_eg.md | 22 ++++---- .github/README_es.md | 2 +- .github/README_fa.md | 2 +- .github/README_fr.md | 2 +- .github/README_he.md | 2 +- .github/README_id.md | 2 +- .github/README_it.md | 2 +- .github/README_ja.md | 2 +- .github/README_ko.md | 2 +- .github/README_nl.md | 2 +- .github/README_pt.md | 77 ++++++++++++++-------------- .github/README_ru.md | 2 +- .github/README_sa.md | 2 +- .github/README_tr.md | 2 +- .github/README_uk.md | 108 ++++++++++++++++++++-------------------- .github/README_zh-CN.md | 2 +- .github/README_zh-TW.md | 24 ++++----- 21 files changed, 145 insertions(+), 151 deletions(-) diff --git a/.github/README.md b/.github/README.md index a82902ab8a..01a38e9d29 100644 --- a/.github/README.md +++ b/.github/README.md @@ -68,7 +68,7 @@ - +
@@ -160,8 +160,9 @@ Fiber is **inspired** by Express, the most popular web framework on the Internet We **listen** to our users in [issues](https://github.com/gofiber/fiber/issues), Discord [channel](https://gofiber.io/discord) _and all over the Internet_ to create a **fast**, **flexible** and **friendly** Go web framework for **any** task, **deadline** and developer **skill**! Just like Express does in the JavaScript world. ## ⚠️ Limitations -* Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. -* Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. + +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 Examples @@ -607,7 +608,7 @@ func main() { Here is a list of middleware that are included within the Fiber framework. | Middleware | Description | -|:---------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Basic auth middleware provides an HTTP basic authentication. It calls the next handler for valid credentials and 401 Unauthorized for missing or invalid credentials. | | [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercept and cache responses | | [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Compression middleware for Fiber, it supports `deflate`, `gzip` and `brotli` by default. | @@ -628,23 +629,23 @@ Here is a list of middleware that are included within the Fiber framework. | [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Adds a requestid to every request. | | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler if a predicate is true. | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | ## 🧬 External Middleware List of externally hosted middleware modules and maintained by the [Fiber team](https://github.com/orgs/gofiber/people). -| Middleware | Description | -| :------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | -| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | -| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | -| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | ## 🕶️ Awesome List diff --git a/.github/README_az.md b/.github/README_az.md index d6e154b198..fcc2dee2f3 100644 --- a/.github/README_az.md +++ b/.github/README_az.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_ckb.md b/.github/README_ckb.md index 627be06dda..11d445be7d 100644 --- a/.github/README_ckb.md +++ b/.github/README_ckb.md @@ -66,9 +66,7 @@ - - - +
diff --git a/.github/README_de.md b/.github/README_de.md index a0b897aacf..cc422ed9ca 100644 --- a/.github/README_de.md +++ b/.github/README_de.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_eg.md b/.github/README_eg.md index 7adef30718..2a39f607f3 100644 --- a/.github/README_eg.md +++ b/.github/README_eg.md @@ -68,7 +68,7 @@ - +
@@ -161,8 +161,8 @@ go get -u github.com/gofiber/fiber/v2 ## ⚠️ القيود -- بسبب استخدام فايبر لـunsafe ممكن انها متتوافقش مع اخر اصدار من جو. فايبر 2.40.0 اتتست بـجو من اصدار 1.17 لـ1.20 -- فايبر مش متوافقة مع واجهات net/http. ده يعني انك مش هتقدر تستخدم مشاريع زي gqlgen, go-swagger, او اي حاجة تانية متعلقة بـnet/http +- بسبب استخدام فايبر لـunsafe ممكن انها متتوافقش مع اخر اصدار من جو. فايبر 2.40.0 اتتست بـجو من اصدار 1.17 لـ1.20 +- فايبر مش متوافقة مع واجهات net/http. ده يعني انك مش هتقدر تستخدم مشاريع زي gqlgen, go-swagger, او اي حاجة تانية متعلقة بـnet/http ## 👀 أمثلة @@ -303,8 +303,7 @@ func main() { لو عاوز تستخدم فيوز جزئية او محرك فيوز تاني زي [amber](https://github.com/eknkc/amber), [handlebars](https://github.com/aymerick/raymond), [mustache](https://github.com/cbroglie/mustache) او [pug](https://github.com/Joker/jade) وغيره.. -بص على [الباكدج](https://github.com/gofiber/template) بتاعنا اللي بيدعم محركات فيوز متعددة - +بص على [الباكدج](https://github.com/gofiber/template) بتاعنا اللي بيدعم محركات فيوز متعددة ```go package main @@ -417,7 +416,6 @@ func main() { جرب الCORS بانك تبعت اي دومين في هيدر `Origin` وتشوف الرد بتاع السيرفر - ```bash curl -H "Origin: http://example.com" --verbose http://localhost:3000 ``` @@ -611,7 +609,7 @@ Here is a list of middleware that are included within the Fiber framework. دي ليستة بالميدلوير الموجودة في فايبر | Middleware | Description | -|:---------------------------------------------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Basic auth middleware provides an HTTP basic authentication. It calls the next handler for valid credentials and 401 Unauthorized for missing or invalid credentials. | | [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercept and cache responses | | [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Compression middleware for Fiber, it supports `deflate`, `gzip` and `brotli` by default. | @@ -632,12 +630,12 @@ Here is a list of middleware that are included within the Fiber framework. | [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Adds a requestid to every request. | | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Session middleware. NOTE: This middleware uses our Storage package. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Skip middleware that skips a wrapped handler if a predicate is true. | -| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | +| [rewrite](https://github.com/gofiber/rewrite) | Rewrite middleware rewrites the URL path based on provided rules. It can be helpful for backward compatibility or just creating cleaner and more descriptive links. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adds a max time for a request and forwards to ErrorHandler if it is exceeded. | -| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | -| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | +| [adaptor](https://github.com/gofiber/adaptor) | Converter for net/http handlers to/from Fiber request handlers, special thanks to @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Helps secure your apps by setting various HTTP headers. | +| [redirect](https://github.com/gofiber/redirect) | Redirect middleware | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth middleware provides a key based authentication. | ## 🧬 ميدلوير خارجي diff --git a/.github/README_es.md b/.github/README_es.md index 755bdb3617..16adf2775b 100644 --- a/.github/README_es.md +++ b/.github/README_es.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_fa.md b/.github/README_fa.md index 1c331a95bd..d09cc7dd70 100644 --- a/.github/README_fa.md +++ b/.github/README_fa.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_fr.md b/.github/README_fr.md index b24aa632b8..1891ca8891 100644 --- a/.github/README_fr.md +++ b/.github/README_fr.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_he.md b/.github/README_he.md index 838f94c75d..d97ad2f7a9 100644 --- a/.github/README_he.md +++ b/.github/README_he.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_id.md b/.github/README_id.md index 013a59e4b6..4384b67d77 100644 --- a/.github/README_id.md +++ b/.github/README_id.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_it.md b/.github/README_it.md index 0124cddcb0..12049a6d91 100644 --- a/.github/README_it.md +++ b/.github/README_it.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_ja.md b/.github/README_ja.md index 719d7a9167..7840cf7244 100644 --- a/.github/README_ja.md +++ b/.github/README_ja.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_ko.md b/.github/README_ko.md index 7dea503a14..ebc08072b2 100644 --- a/.github/README_ko.md +++ b/.github/README_ko.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_nl.md b/.github/README_nl.md index e3e8205de9..9c2a7d99e4 100644 --- a/.github/README_nl.md +++ b/.github/README_nl.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_pt.md b/.github/README_pt.md index f6e5ac9335..dbbf3a842c 100644 --- a/.github/README_pt.md +++ b/.github/README_pt.md @@ -67,7 +67,7 @@ - +
@@ -155,11 +155,10 @@ Os novos gophers que mudaram do [Node.js](https://nodejs.org/en/about/) para o [ O Fiber é **inspirado** no Express, o framework web mais popular da Internet. Combinamos a **facilidade** do Express e com o **desempenho bruto** do Go. Se você já implementou um aplicativo web com Node.js ( _usando Express.js ou similar_ ), então muitos métodos e princípios parecerão **muito familiares** para você. - ## ⚠️ Limitações -* Devido ao uso de "unsafe" pelo Fiber, a biblioteca pode nem sempre ser compatível com a última versão do Go. Fiber 2.40.0 foi testado com as versões Go de 1.17 a 1.20. -* Fiber não é compatível com as interfaces net/http. Isso significa que você não poderá usar projetos como gqlgen, go-swagger ou quaisquer outros que fazem parte do ecossistema net/http. +- Devido ao uso de "unsafe" pelo Fiber, a biblioteca pode nem sempre ser compatível com a última versão do Go. Fiber 2.40.0 foi testado com as versões Go de 1.17 a 1.20. +- Fiber não é compatível com as interfaces net/http. Isso significa que você não poderá usar projetos como gqlgen, go-swagger ou quaisquer outros que fazem parte do ecossistema net/http. ## 👀 Exemplos @@ -575,54 +574,52 @@ func main() { - ## 🧬 Middleware Interno Aqui está uma lista de middlewares que estão incluídos no framework Fiber. -| Middleware | Descrição | -| :------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Autenticação básica fornece uma autenticação HTTP básica. Ele chama o próximo manipulador para credenciais válidas e 401 Não Autorizado para credenciais ausentes ou inválidas.| -| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercepta e armazena em cache as respostas | -| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Middleware de compressão para o Fiber, suporta `deflate`, `gzip` e `brotli` por padrão. | -| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Habilita o compartilhamento de recursos de origem cruzada (CORS) com várias opções. | -| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | Protege contra exploits CSRF. | -| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Criptografa valores de cookie. | -| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Expõe variáveis de ambiente fornecendo uma configuração opcional. | -| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | Permite que caches sejam mais eficientes e economizem largura de banda, pois um servidor web não precisa reenviar uma resposta completa se o conteúdo não mudou. | -| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Serve via seu servidor HTTP variantes expostas em tempo de execução no formato JSON. | -| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Ignora favicon dos logs ou serve da memória se um caminho de arquivo for fornecido. | -| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | Sistema de Arquivos para o Fiber, agradecimentos especiais e créditos a Alireza Salary | -| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Limitação de taxa para o Fiber. Use para limitar solicitações repetidas para APIs públicas e/ou endpoints como redefinição de senha. | -| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | Logger de solicitação/resposta HTTP. | -| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Middleware de monitoramento que relata métricas do servidor, inspirado pelo express-status-monitor | +| Middleware | Descrição | +| :------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Autenticação básica fornece uma autenticação HTTP básica. Ele chama o próximo manipulador para credenciais válidas e 401 Não Autorizado para credenciais ausentes ou inválidas. | +| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Intercepta e armazena em cache as respostas | +| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Middleware de compressão para o Fiber, suporta `deflate`, `gzip` e `brotli` por padrão. | +| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Habilita o compartilhamento de recursos de origem cruzada (CORS) com várias opções. | +| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | Protege contra exploits CSRF. | +| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Criptografa valores de cookie. | +| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Expõe variáveis de ambiente fornecendo uma configuração opcional. | +| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | Permite que caches sejam mais eficientes e economizem largura de banda, pois um servidor web não precisa reenviar uma resposta completa se o conteúdo não mudou. | +| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Serve via seu servidor HTTP variantes expostas em tempo de execução no formato JSON. | +| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Ignora favicon dos logs ou serve da memória se um caminho de arquivo for fornecido. | +| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | Sistema de Arquivos para o Fiber, agradecimentos especiais e créditos a Alireza Salary | +| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Limitação de taxa para o Fiber. Use para limitar solicitações repetidas para APIs públicas e/ou endpoints como redefinição de senha. | +| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | Logger de solicitação/resposta HTTP. | +| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Middleware de monitoramento que relata métricas do servidor, inspirado pelo express-status-monitor | | [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Agradecimentos especiais a Matthew Lee (@mthli) | -| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Permite que você faça proxy de solicitações a vários servidores | -| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Recupera de panics em qualquer lugar da cadeia de chamadas e passa o controle para o [ErrorHandler](https://docs.gofiber.io/guide/error-handling) centralizado. | -| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Adiciona um ID de solicitação a cada pedido. | -| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Middleware de sessão. NOTA: Este middleware usa nosso pacote Storage. | -| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Pula um handler envolto se um predicado for verdadeiro. | -| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adiciona um tempo máximo para uma solicitação e encaminha para ErrorHandler se ele for excedido. | -| [keyauth](https://github.com/gofiber/keyauth) | Autenticação por chave fornece uma autenticação baseada em chave. | -| [redirect](https://github.com/gofiber/redirect) | Middleware de redirecionamento | -| [rewrite](https://github.com/gofiber/rewrite) | Reescreve o caminho da URL com base nas regras fornecidas. Pode ser útil para compatibilidade retroativa ou para criar links mais limpos e descritivos. | -| [adaptor](https://github.com/gofiber/adaptor) | Conversor para handlers net/http para/para manipuladores de solicitação Fiber, agradecimentos especiais ao @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Ajuda a proteger seus aplicativos definindo vários cabeçalhos HTTP. | +| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Permite que você faça proxy de solicitações a vários servidores | +| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Recupera de panics em qualquer lugar da cadeia de chamadas e passa o controle para o [ErrorHandler](https://docs.gofiber.io/guide/error-handling) centralizado. | +| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Adiciona um ID de solicitação a cada pedido. | +| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Middleware de sessão. NOTA: Este middleware usa nosso pacote Storage. | +| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Pula um handler envolto se um predicado for verdadeiro. | +| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Adiciona um tempo máximo para uma solicitação e encaminha para ErrorHandler se ele for excedido. | +| [keyauth](https://github.com/gofiber/keyauth) | Autenticação por chave fornece uma autenticação baseada em chave. | +| [redirect](https://github.com/gofiber/redirect) | Middleware de redirecionamento | +| [rewrite](https://github.com/gofiber/rewrite) | Reescreve o caminho da URL com base nas regras fornecidas. Pode ser útil para compatibilidade retroativa ou para criar links mais limpos e descritivos. | +| [adaptor](https://github.com/gofiber/adaptor) | Conversor para handlers net/http para/para manipuladores de solicitação Fiber, agradecimentos especiais ao @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Ajuda a proteger seus aplicativos definindo vários cabeçalhos HTTP. | ## 🧬 Middleware Externo Lista de módulos de middleware hospedados externamente e mantidos pela [equipe Fiber](https://github.com/orgs/gofiber/people). -| Middleware | Descrição | -| :------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [jwt](https://github.com/gofiber/jwt) | JWT retorna um middleware de autenticação com tokens JWT. | -| [storage](https://github.com/gofiber/storage) | Drivers de armazenamento prontos que implementam a interface Storage, projetados para serem usados com vários middlewares do Fiber. | -| [template](https://github.com/gofiber/template) | Este pacote contém 8 mecanismos de template que podem ser usados com Fiber `v1.10.x`. É necessário Go versão 1.13 ou superior. | -| [websocket](https://github.com/gofiber/websocket) | Baseado no WebSocket do Fasthttp para Fiber com suporte a Locals | - - +| Middleware | Descrição | +| :------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT retorna um middleware de autenticação com tokens JWT. | +| [storage](https://github.com/gofiber/storage) | Drivers de armazenamento prontos que implementam a interface Storage, projetados para serem usados com vários middlewares do Fiber. | +| [template](https://github.com/gofiber/template) | Este pacote contém 8 mecanismos de template que podem ser usados com Fiber `v1.10.x`. É necessário Go versão 1.13 ou superior. | +| [websocket](https://github.com/gofiber/websocket) | Baseado no WebSocket do Fasthttp para Fiber com suporte a Locals | ## 🕶️ Lista Incrível + Para mais artigos, middlewares, exemplos ou ferramentas, confira nossa [lista incrível](https://github.com/gofiber/awesome-fiber). ## 👍 Contribuindo diff --git a/.github/README_ru.md b/.github/README_ru.md index 3776644c9c..4c4b63688f 100644 --- a/.github/README_ru.md +++ b/.github/README_ru.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_sa.md b/.github/README_sa.md index 25e01906a2..99e6c265b2 100644 --- a/.github/README_sa.md +++ b/.github/README_sa.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_tr.md b/.github/README_tr.md index 326c2fa973..9c76ad9c36 100644 --- a/.github/README_tr.md +++ b/.github/README_tr.md @@ -64,7 +64,7 @@ - +
diff --git a/.github/README_uk.md b/.github/README_uk.md index fe18dfdf52..1751bbdc6c 100644 --- a/.github/README_uk.md +++ b/.github/README_uk.md @@ -68,9 +68,9 @@ - - + +
@@ -147,19 +147,19 @@ go get -u github.com/gofiber/fiber/v2 ## 🎯 Особливості -- Надійна [маршрутизація](https://docs.gofiber.io/routing) -- Доступ до [статичних файлів](https://docs.gofiber.io/api/app#static) -- Екстремальна [продуктивність](https://docs.gofiber.io/extra/benchmarks) -- [Низький обсяг споживання пам'яті](https://docs.gofiber.io/extra/benchmarks) -- [Кінцеві точки API](https://docs.gofiber.io/api/ctx) -- [Middleware](https://docs.gofiber.io/middleware) та підтримка [Next](https://docs.gofiber.io/api/ctx#next) -- [Швидке](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) програмування на стороні сервера -- [Двигуни шаблонів](https://github.com/gofiber/template) -- [Підтримка WebSocket](https://github.com/gofiber/websocket) -- [Server-Sent Events](https://github.com/gofiber/recipes/tree/master/sse) -- [Обмежувач швидкості](https://docs.gofiber.io/api/middleware/limiter) -- Документація доступна [19 мовами](https://docs.gofiber.io/) -- І багато іншого, [відвідайте наш Wiki](https://docs.gofiber.io/) +- Надійна [маршрутизація](https://docs.gofiber.io/routing) +- Доступ до [статичних файлів](https://docs.gofiber.io/api/app#static) +- Екстремальна [продуктивність](https://docs.gofiber.io/extra/benchmarks) +- [Низький обсяг споживання пам'яті](https://docs.gofiber.io/extra/benchmarks) +- [Кінцеві точки API](https://docs.gofiber.io/api/ctx) +- [Middleware](https://docs.gofiber.io/middleware) та підтримка [Next](https://docs.gofiber.io/api/ctx#next) +- [Швидке](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) програмування на стороні сервера +- [Двигуни шаблонів](https://github.com/gofiber/template) +- [Підтримка WebSocket](https://github.com/gofiber/websocket) +- [Server-Sent Events](https://github.com/gofiber/recipes/tree/master/sse) +- [Обмежувач швидкості](https://docs.gofiber.io/api/middleware/limiter) +- Документація доступна [19 мовами](https://docs.gofiber.io/) +- І багато іншого, [відвідайте наш Wiki](https://docs.gofiber.io/) ## 💡 Філософія @@ -171,8 +171,8 @@ Fiber **натхненний** Express, найпопулярнішим веб-ф ## ⚠️ Обмеження -- Через те, що Fiber використовує unsafe, бібліотека не завжди може бути сумісною з останньою версією Go. Fiber 2.40.0 було протестовано з Go версій 1.17 до 1.20. -- Fiber не сумісний з інтерфейсами net/http. Це означає, що ви не зможете використовувати такі проекти, як gqlgen, go-swagger або будь-які інші, які є частиною екосистеми net/http. +- Через те, що Fiber використовує unsafe, бібліотека не завжди може бути сумісною з останньою версією Go. Fiber 2.40.0 було протестовано з Go версій 1.17 до 1.20. +- Fiber не сумісний з інтерфейсами net/http. Це означає, що ви не зможете використовувати такі проекти, як gqlgen, go-swagger або будь-які інші, які є частиною екосистеми net/http. ## 👀 Приклади @@ -307,7 +307,7 @@ func main() { Fiber за умовчанням використовує [html/template](https://pkg.go.dev/html/template/), якщо жодного двигуна не було вказано. -Якщо ви хочете виконати частково або використовувати інший двигун, наприклад [amber](https://github.com/eknkc/amber), [handlebars](https://github.com/aymerick/raymond), [mustache]( https://github.com/cbroglie/mustache) або [jade](https://github.com/Joker/jade), тощо. +Якщо ви хочете виконати частково або використовувати інший двигун, наприклад [amber](https://github.com/eknkc/amber), [handlebars](https://github.com/aymerick/raymond), [mustache](https://github.com/cbroglie/mustache) або [jade](https://github.com/Joker/jade), тощо. Перегляньте наш пакет [Шаблон](https://github.com/gofiber/template), який підтримує кілька двигунів перегляду. @@ -613,7 +613,7 @@ func main() { Ось список middleware, яке входить до складу Fiber фреймворку. | Middleware | Опис | -|:---------------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| :------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Middleware який забезпечує базову автентифікацію по HTTP. | | [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Middleware який перехоплює та кешує відповіді | | [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | стиснення для Fiber, воно за замовчуванням підтримує `deflate`, `gzip` і `brotli`. | @@ -635,11 +635,11 @@ func main() { | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Middleware для сеансів. ПРИМІТКА: Цей middleware використовує наш пакет зберігання. | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Middleware який пропускає упакований обробник, якщо предикат є істинним. | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Додає максимальний час для запиту та пересилає до ErrorHandler, якщо його перевищено. | -| [keyauth](https://github.com/gofiber/keyauth) | Middleware для автентифікації по ключам. | -| [redirect](https://github.com/gofiber/redirect) | Middleware для перенаправлення. | -| [rewrite](https://github.com/gofiber/rewrite) | Middleware для перезапису URL-адреси на основі наданих правил. | -| [adaptor](https://github.com/gofiber/adaptor) | Конвентор для обробників net/http до/з обробників запитів Fiber, особлива подяка @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | Допомагає захистити ваші програми, встановлюючи різні заголовки HTTP. | +| [keyauth](https://github.com/gofiber/keyauth) | Middleware для автентифікації по ключам. | +| [redirect](https://github.com/gofiber/redirect) | Middleware для перенаправлення. | +| [rewrite](https://github.com/gofiber/rewrite) | Middleware для перезапису URL-адреси на основі наданих правил. | +| [adaptor](https://github.com/gofiber/adaptor) | Конвентор для обробників net/http до/з обробників запитів Fiber, особлива подяка @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Допомагає захистити ваші програми, встановлюючи різні заголовки HTTP. | ## 🧬 Зовнішні Middleware @@ -671,24 +671,24 @@ Fiber – це проект із відкритим вихідним кодом, | | Користувач | Пожертвування | | :--------------------------------------------------------- | :----------------------------------------------- | :------------ | -| ![](https://avatars.githubusercontent.com/u/204341?s=25) | [@destari](https://github.com/destari) | ☕ x 10 | -| ![](https://avatars.githubusercontent.com/u/63164982?s=25) | [@dembygenesis](https://github.com/dembygenesis) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/56607882?s=25) | [@thomasvvugt](https://github.com/thomasvvugt) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/27820675?s=25) | [@hendratommy](https://github.com/hendratommy) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/1094221?s=25) | [@ekaputra07](https://github.com/ekaputra07) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/194590?s=25) | [@jorgefuertes](https://github.com/jorgefuertes) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/186637?s=25) | [@candidosales](https://github.com/candidosales) | ☕ x 5 | -| ![](https://avatars.githubusercontent.com/u/29659953?s=25) | [@l0nax](https://github.com/l0nax) | ☕ x 3 | -| ![](https://avatars.githubusercontent.com/u/635852?s=25) | [@bihe](https://github.com/bihe) | ☕ x 3 | -| ![](https://avatars.githubusercontent.com/u/307334?s=25) | [@justdave](https://github.com/justdave) | ☕ x 3 | -| ![](https://avatars.githubusercontent.com/u/11155743?s=25) | [@koddr](https://github.com/koddr) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/29042462?s=25) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/2978730?s=25) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/44171355?s=25) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/5638101?s=25) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/619996?s=25) | [@melkorm](https://github.com/melkorm) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/31022056?s=25) | [@marvinjwendt](https://github.com/marvinjwendt) | ☕ x 1 | -| ![](https://avatars.githubusercontent.com/u/31921460?s=25) | [@toishy](https://github.com/toishy) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/204341?s=25) | [@destari](https://github.com/destari) | ☕ x 10 | +| ![](https://avatars.githubusercontent.com/u/63164982?s=25) | [@dembygenesis](https://github.com/dembygenesis) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/56607882?s=25) | [@thomasvvugt](https://github.com/thomasvvugt) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/27820675?s=25) | [@hendratommy](https://github.com/hendratommy) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/1094221?s=25) | [@ekaputra07](https://github.com/ekaputra07) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/194590?s=25) | [@jorgefuertes](https://github.com/jorgefuertes) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/186637?s=25) | [@candidosales](https://github.com/candidosales) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/29659953?s=25) | [@l0nax](https://github.com/l0nax) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/635852?s=25) | [@bihe](https://github.com/bihe) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/307334?s=25) | [@justdave](https://github.com/justdave) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/11155743?s=25) | [@koddr](https://github.com/koddr) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/29042462?s=25) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/2978730?s=25) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/44171355?s=25) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/5638101?s=25) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/619996?s=25) | [@melkorm](https://github.com/melkorm) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/31022056?s=25) | [@marvinjwendt](https://github.com/marvinjwendt) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/31921460?s=25) | [@toishy](https://github.com/toishy) | ☕ x 1 | ## ‎‍💻 Автори коду @@ -704,15 +704,15 @@ Fiber – це проект із відкритим вихідним кодом, **Ліцензії сторонніх бібліотек** -- [colorable](https://github.com/mattn/go-colorable/blob/master/LICENSE) -- [isatty](https://github.com/mattn/go-isatty/blob/master/LICENSE) -- [runewidth](https://github.com/mattn/go-runewidth/blob/master/LICENSE) -- [fasthttp](https://github.com/valyala/fasthttp/blob/master/LICENSE) -- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE) -- [fwd](https://github.com/philhofer/fwd/blob/master/LICENSE.md) -- [go-ole](https://github.com/go-ole/go-ole/blob/master/LICENSE) -- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE) -- [msgp](https://github.com/tinylib/msgp/blob/master/LICENSE) -- [schema](https://github.com/gorilla/schema/blob/master/LICENSE) -- [uuid](https://github.com/google/uuid/blob/master/LICENSE) -- [wmi](https://github.com/StackExchange/wmi/blob/master/LICENSE) +- [colorable](https://github.com/mattn/go-colorable/blob/master/LICENSE) +- [isatty](https://github.com/mattn/go-isatty/blob/master/LICENSE) +- [runewidth](https://github.com/mattn/go-runewidth/blob/master/LICENSE) +- [fasthttp](https://github.com/valyala/fasthttp/blob/master/LICENSE) +- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE) +- [fwd](https://github.com/philhofer/fwd/blob/master/LICENSE.md) +- [go-ole](https://github.com/go-ole/go-ole/blob/master/LICENSE) +- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE) +- [msgp](https://github.com/tinylib/msgp/blob/master/LICENSE) +- [schema](https://github.com/gorilla/schema/blob/master/LICENSE) +- [uuid](https://github.com/google/uuid/blob/master/LICENSE) +- [wmi](https://github.com/StackExchange/wmi/blob/master/LICENSE) diff --git a/.github/README_zh-CN.md b/.github/README_zh-CN.md index 7ff9c55567..4494deec4d 100644 --- a/.github/README_zh-CN.md +++ b/.github/README_zh-CN.md @@ -67,7 +67,7 @@ - +
diff --git a/.github/README_zh-TW.md b/.github/README_zh-TW.md index 87f8908de7..f1f0b8bee0 100644 --- a/.github/README_zh-TW.md +++ b/.github/README_zh-TW.md @@ -70,7 +70,7 @@ - +
@@ -639,22 +639,22 @@ func main() { | [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | 連線階段中介模組。注意:這個中介模組有用到我們的 Storage 套件。 | | [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | 略過中介模組,會在條件成立時略過封裝過的處理常式。 | | [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | 為請求加上最長時限,並在逾時後轉送至錯誤處理常式 (ErrorHandler)。 | -| [keyauth](https://github.com/gofiber/keyauth) | Key auth 中介模組提供以金鑰為基礎的認證模式。 | -| [redirect](https://github.com/gofiber/redirect) | 用來重新導向的中介模組。 | -| [rewrite](https://github.com/gofiber/rewrite) | 重寫 (Rewrite) 中介模組:根據提供規則重寫 URL 路徑,適合用來向後相容,或者是製作更乾淨且更好懂的連結。 | -| [adaptor](https://github.com/gofiber/adaptor) | 將 net/http 處理常式轉換至 Fiber 處理常式,或者是反著做。特別感謝 @arsmn! | -| [helmet](https://github.com/gofiber/helmet) | 透過設定多種 HTTP 標頭,協助保護您應用程式的安全。 | +| [keyauth](https://github.com/gofiber/keyauth) | Key auth 中介模組提供以金鑰為基礎的認證模式。 | +| [redirect](https://github.com/gofiber/redirect) | 用來重新導向的中介模組。 | +| [rewrite](https://github.com/gofiber/rewrite) | 重寫 (Rewrite) 中介模組:根據提供規則重寫 URL 路徑,適合用來向後相容,或者是製作更乾淨且更好懂的連結。 | +| [adaptor](https://github.com/gofiber/adaptor) | 將 net/http 處理常式轉換至 Fiber 處理常式,或者是反著做。特別感謝 @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | 透過設定多種 HTTP 標頭,協助保護您應用程式的安全。 | ## 🧬 外掛中介模組 這裡列出由 [Fiber 團隊](https://github.com/orgs/gofiber/people) 維護、存放在外部的中介模組。 -| 中介模組 | 描述 | -| :------------------------------------------------ | :----------------------------------------------------------------------------------------------------- | -| [jwt](https://github.com/gofiber/jwt) | JWT 回傳 JSON Web Token \(JWT\) 認證中介模組。 | -| [storage](https://github.com/gofiber/storage) | 已經做好,實作 Storage 介面的儲存區驅動模組,設計用來與各種 Fiber 中介模組搭配使用。 | -| [template](https://github.com/gofiber/template) | 本套件包含 8 種樣板引擎,可以和 Fiber `v1.10.x` 一起使用。需要 Go 1.13 或更新版本。 | -| [websocket](https://github.com/gofiber/websocket) | 適用於 Fiber,建基於 Fasthttp 的 WebSocket。支援本機空間 (Locals)! | +| 中介模組 | 描述 | +| :------------------------------------------------ | :----------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT 回傳 JSON Web Token \(JWT\) 認證中介模組。 | +| [storage](https://github.com/gofiber/storage) | 已經做好,實作 Storage 介面的儲存區驅動模組,設計用來與各種 Fiber 中介模組搭配使用。 | +| [template](https://github.com/gofiber/template) | 本套件包含 8 種樣板引擎,可以和 Fiber `v1.10.x` 一起使用。需要 Go 1.13 或更新版本。 | +| [websocket](https://github.com/gofiber/websocket) | 適用於 Fiber,建基於 Fasthttp 的 WebSocket。支援本機空間 (Locals)! | ## 🕶️ Awesome List From e2f7457d4de166214e17ec9f7a233fcbfc2d28e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Sat, 19 Aug 2023 19:31:38 +0300 Subject: [PATCH 17/84] :broom: chore: add go 1.21 to ci and readmes (#2588) --- .github/README.md | 2 +- .github/README_az.md | 2 +- .github/README_de.md | 2 +- .github/README_eg.md | 2 +- .github/README_es.md | 2 +- .github/README_fa.md | 2 +- .github/README_fr.md | 2 +- .github/README_he.md | 2 +- .github/README_id.md | 2 +- .github/README_it.md | 2 +- .github/README_ja.md | 2 +- .github/README_ko.md | 2 +- .github/README_nl.md | 2 +- .github/README_pt.md | 2 +- .github/README_ru.md | 2 +- .github/README_sa.md | 2 +- .github/README_tr.md | 2 +- .github/README_uk.md | 2 +- .github/README_zh-CN.md | 2 +- .github/README_zh-TW.md | 2 +- .github/workflows/benchmark.yml | 2 +- .github/workflows/linter.yml | 2 +- .github/workflows/test.yml | 2 +- go.mod | 4 ++-- go.sum | 4 ++++ 25 files changed, 29 insertions(+), 25 deletions(-) diff --git a/.github/README.md b/.github/README.md index 01a38e9d29..31d376c1a4 100644 --- a/.github/README.md +++ b/.github/README.md @@ -161,7 +161,7 @@ We **listen** to our users in [issues](https://github.com/gofiber/fiber/issues), ## ⚠️ Limitations -- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.21. - Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 Examples diff --git a/.github/README_az.md b/.github/README_az.md index fcc2dee2f3..df0e71b677 100644 --- a/.github/README_az.md +++ b/.github/README_az.md @@ -161,7 +161,7 @@ Biz istifadəçilərdən gələn [issue-a](https://github.com/gofiber/fiber/issu ## ⚠️ Limitlər -- Fiber unsafe prinsiplərə əsaslanaraq çalışdığından, o hər zaman Go-nun son versiyası ilə uyğunlaşmaya bilər. Buna görə də, Fiber 2.40.0 — Go 1.17 və 1.20 versiyaları ilə test edilərək saz vəziyyətə gətirilmişdir. +- Fiber unsafe prinsiplərə əsaslanaraq çalışdığından, o hər zaman Go-nun son versiyası ilə uyğunlaşmaya bilər. Buna görə də, Fiber 2.40.0 — Go 1.17 və 1.21 versiyaları ilə test edilərək saz vəziyyətə gətirilmişdir. - Fiber net/http interfeysləri ilə uyğun deyil. Yəni gqlgen, go-swagger kimi net/http ekosisteminin parçası olan layihələri istifadə edə bilməzsiniz. ## 👀 Misallar diff --git a/.github/README_de.md b/.github/README_de.md index cc422ed9ca..a74c75aecc 100644 --- a/.github/README_de.md +++ b/.github/README_de.md @@ -157,7 +157,7 @@ Fiber ist **inspiriert** von Express.js, dem beliebtesten Web-Framework im Inter ## ⚠️ Limitations -- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.21. - Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 Beispiele diff --git a/.github/README_eg.md b/.github/README_eg.md index 2a39f607f3..62d84c624f 100644 --- a/.github/README_eg.md +++ b/.github/README_eg.md @@ -161,7 +161,7 @@ go get -u github.com/gofiber/fiber/v2 ## ⚠️ القيود -- بسبب استخدام فايبر لـunsafe ممكن انها متتوافقش مع اخر اصدار من جو. فايبر 2.40.0 اتتست بـجو من اصدار 1.17 لـ1.20 +- بسبب استخدام فايبر لـunsafe ممكن انها متتوافقش مع اخر اصدار من جو. فايبر 2.40.0 اتتست بـجو من اصدار 1.17 لـ1.21 - فايبر مش متوافقة مع واجهات net/http. ده يعني انك مش هتقدر تستخدم مشاريع زي gqlgen, go-swagger, او اي حاجة تانية متعلقة بـnet/http ## 👀 أمثلة diff --git a/.github/README_es.md b/.github/README_es.md index 16adf2775b..fad1b16bbc 100644 --- a/.github/README_es.md +++ b/.github/README_es.md @@ -157,7 +157,7 @@ Fiber está **inspirado** en Expressjs, el framework web más popular en Interne ## ⚠️ Limitantes -- Debido a que Fiber utiliza unsafe, la biblioteca no siempre será compatible con la última versión de Go. Fiber 2.40.0 ha sido probado con las versiones de Go 1.17 a 1.20. +- Debido a que Fiber utiliza unsafe, la biblioteca no siempre será compatible con la última versión de Go. Fiber 2.40.0 ha sido probado con las versiones de Go 1.17 a 1.21. - Fiber no es compatible con interfaces net/http. Esto significa que no lo podrá usar en proyectos como qglgen, go-swagger, u otros que son parte del ecosistema net/http. ## 👀 Ejemplos diff --git a/.github/README_fa.md b/.github/README_fa.md index d09cc7dd70..b32ee40eaf 100644 --- a/.github/README_fa.md +++ b/.github/README_fa.md @@ -197,7 +197,7 @@ Fiber از Express الهام گرفته, که محبوب ترین فری ## ⚠️ محدودیت ها -- به دلیل استفاده ناامن از Fiber, ممکن است کتابخانه همیشه با آخرین نسخه Go سازگار نباشد. Fiber 2.40.0 با زبان گو نسخه 1.17 تا 1.20 تست شده است. +- به دلیل استفاده ناامن از Fiber, ممکن است کتابخانه همیشه با آخرین نسخه Go سازگار نباشد. Fiber 2.40.0 با زبان گو نسخه 1.17 تا 1.21 تست شده است. - فریمورک Fiber با پکیج net/http سازگار نیست. این بدان معناست شما نمی توانید از پکیج های مانند go-swagger, gqlgen یا سایر پروژه هایی که بخشی از اکوسیستم net/http هستند استفاده کنید.
diff --git a/.github/README_fr.md b/.github/README_fr.md index 1891ca8891..66e2ec27a8 100644 --- a/.github/README_fr.md +++ b/.github/README_fr.md @@ -157,7 +157,7 @@ Fiber est **inspiré** par Express, le framework web le plus populaire d'Interne ## ⚠️ Limitations -- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.21. - Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 Exemples diff --git a/.github/README_he.md b/.github/README_he.md index d97ad2f7a9..4a95476340 100644 --- a/.github/README_he.md +++ b/.github/README_he.md @@ -202,7 +202,7 @@ Fiber נוצרה **בהשראת** Express, ה-web framework הפופולרית ## ⚠️ Limitations -- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.21. - Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 דוגמאות diff --git a/.github/README_id.md b/.github/README_id.md index 4384b67d77..8de22107ee 100644 --- a/.github/README_id.md +++ b/.github/README_id.md @@ -159,7 +159,7 @@ Kami **mendengarkan** para pengguna di [GitHub Issues](https://github.com/gofibe ## ⚠️ Limitasi -- Karena penggunaan Fiber yang tidak aman, perpustakaan mungkin tidak selalu kompatibel dengan versi Go terbaru. Fiber 2.40.0 telah diuji dengan Go versi 1.17 hingga 1.20. +- Karena penggunaan Fiber yang tidak aman, perpustakaan mungkin tidak selalu kompatibel dengan versi Go terbaru. Fiber 2.40.0 telah diuji dengan Go versi 1.17 hingga 1.21. - Fiber tidak kompatibel dengan antarmuka net/http. Ini berarti kamu tidak akan dapat menggunakan proyek seperti gqlgen, go-swagger, atau lainnya yang merupakan bagian dari ekosistem net/http. ## 👀 Contoh diff --git a/.github/README_it.md b/.github/README_it.md index 12049a6d91..3fb854ede5 100644 --- a/.github/README_it.md +++ b/.github/README_it.md @@ -157,7 +157,7 @@ Fiber è **ispirato** da Express, il web framework più popolare su internet. Ab ## ⚠️ Limitazioni -- Dato che Fiber utilizza unsafe, la libreria non sempre potrebbe essere compatibile con l'ultima versione di Go. Fiber 2.40.0 è stato testato con la versioni 1.17 alla 1.20 di Go. +- Dato che Fiber utilizza unsafe, la libreria non sempre potrebbe essere compatibile con l'ultima versione di Go. Fiber 2.40.0 è stato testato con la versioni 1.17 alla 1.21 di Go. - Fiber non è compatibile con le interfacce net/http. Questo significa che non è possibile utilizzare progetti come qglgen, go-swagger, o altri che fanno parte dell'ecosistema net/http. ## 👀 Esempi diff --git a/.github/README_ja.md b/.github/README_ja.md index 7840cf7244..07a5f18b60 100644 --- a/.github/README_ja.md +++ b/.github/README_ja.md @@ -161,7 +161,7 @@ Fiber は人気の高い Web フレームワークである Expressjs に**イ ## ⚠️ 制限事項 -- Fiber は unsafe パッケージを使用しているため、最新の Go バージョンと互換性がない場合があります。Fiber 2.40.0 は、Go のバージョン 1.17 から 1.20 でテストされています。 +- Fiber は unsafe パッケージを使用しているため、最新の Go バージョンと互換性がない場合があります。Fiber 2.40.0 は、Go のバージョン 1.17 から 1.21 でテストされています。 - Fiber は net/http インターフェースと互換性がありません。つまり、gqlgen や go-swagger など、net/http のエコシステムの一部であるプロジェクトを使用することができません。 ## 👀 例 diff --git a/.github/README_ko.md b/.github/README_ko.md index ebc08072b2..2b40d2c58a 100644 --- a/.github/README_ko.md +++ b/.github/README_ko.md @@ -159,7 +159,7 @@ Fiber는 인터넷에서 가장 인기있는 웹 프레임워크인 Express에 ## ⚠️ 한계점 -- Fiber는 unsafe 패키지를 사용하기 때문에 최신 Go버전과 호환되지 않을 수 있습니다.Fiber 2.40.0은 Go 버전 1.17에서 1.20로 테스트되고 있습니다. +- Fiber는 unsafe 패키지를 사용하기 때문에 최신 Go버전과 호환되지 않을 수 있습니다.Fiber 2.40.0은 Go 버전 1.17에서 1.21로 테스트되고 있습니다. - Fiber는 net/http 인터페이스와 호환되지 않습니다.즉, gqlgen이나 go-swagger 등 net/http 생태계의 일부인 프로젝트를 사용할 수 없습니다. ## 👀 예제 diff --git a/.github/README_nl.md b/.github/README_nl.md index 9c2a7d99e4..932c4790c2 100644 --- a/.github/README_nl.md +++ b/.github/README_nl.md @@ -159,7 +159,7 @@ We **luisteren** naar onze gebruikers in [issues](https://github.com/gofiber/fib ## ⚠️ Limitations -- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.21. - Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 Voorbeelden diff --git a/.github/README_pt.md b/.github/README_pt.md index dbbf3a842c..5cdd408414 100644 --- a/.github/README_pt.md +++ b/.github/README_pt.md @@ -157,7 +157,7 @@ O Fiber é **inspirado** no Express, o framework web mais popular da Internet. C ## ⚠️ Limitações -- Devido ao uso de "unsafe" pelo Fiber, a biblioteca pode nem sempre ser compatível com a última versão do Go. Fiber 2.40.0 foi testado com as versões Go de 1.17 a 1.20. +- Devido ao uso de "unsafe" pelo Fiber, a biblioteca pode nem sempre ser compatível com a última versão do Go. Fiber 2.40.0 foi testado com as versões Go de 1.17 a 1.21. - Fiber não é compatível com as interfaces net/http. Isso significa que você não poderá usar projetos como gqlgen, go-swagger ou quaisquer outros que fazem parte do ecossistema net/http. ## 👀 Exemplos diff --git a/.github/README_ru.md b/.github/README_ru.md index 4c4b63688f..338e7cb960 100644 --- a/.github/README_ru.md +++ b/.github/README_ru.md @@ -159,7 +159,7 @@ Fiber **вдохновлен** Express, самым популярным веб ## ⚠️ Ограничения -- Из-за того, что Fiber использует пакет unsafe, библиотека не всегда может быть совместима с последней версией Go. Fiber 2.40.0 был протестирован с версиями Go от 1.17 до 1.20. +- Из-за того, что Fiber использует пакет unsafe, библиотека не всегда может быть совместима с последней версией Go. Fiber 2.40.0 был протестирован с версиями Go от 1.17 до 1.21. - Fiber не совместим с интерфейсами net/http. Это означает, что вы не сможете использовать такие проекты, как gqlgen, go-swagger или любые другие, которые являются частью экосистемы net/http. ## 👀 Примеры diff --git a/.github/README_sa.md b/.github/README_sa.md index 99e6c265b2..3a2e1fa81f 100644 --- a/.github/README_sa.md +++ b/.github/README_sa.md @@ -173,7 +173,7 @@ Fiber هو **مستوحى** من Express, إطار الويب الأكثر شع ## ⚠️ Limitations -- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.20. +- Due to Fiber's usage of unsafe, the library may not always be compatible with the latest Go version. Fiber 2.40.0 has been tested with Go versions 1.17 to 1.21. - Fiber is not compatible with net/http interfaces. This means you will not be able to use projects like gqlgen, go-swagger, or any others which are part of the net/http ecosystem. ## 👀 أمثلة diff --git a/.github/README_tr.md b/.github/README_tr.md index 9c76ad9c36..1138b3346e 100644 --- a/.github/README_tr.md +++ b/.github/README_tr.md @@ -157,7 +157,7 @@ Fiber, internet üzerinde en popüler web framework'ü olan Express'ten **esinle ## ⚠️ Sınırlamalar -- Fiber unsafe kullanımı sebebiyle Go'nun son sürümüyle her zaman uyumlu olmayabilir. Fiber 2.40.0, Go 1.17 ile 1.20 sürümleriyle test edildi. +- Fiber unsafe kullanımı sebebiyle Go'nun son sürümüyle her zaman uyumlu olmayabilir. Fiber 2.40.0, Go 1.17 ile 1.21 sürümleriyle test edildi. - Fiber net/http arabirimiyle uyumlu değildir. Yani gqlgen veya go-swagger gibi net/http ekosisteminin parçası olan projeleri kullanamazsınız. ## 👀 Örnekler diff --git a/.github/README_uk.md b/.github/README_uk.md index 1751bbdc6c..d2ed7ecd5b 100644 --- a/.github/README_uk.md +++ b/.github/README_uk.md @@ -171,7 +171,7 @@ Fiber **натхненний** Express, найпопулярнішим веб-ф ## ⚠️ Обмеження -- Через те, що Fiber використовує unsafe, бібліотека не завжди може бути сумісною з останньою версією Go. Fiber 2.40.0 було протестовано з Go версій 1.17 до 1.20. +- Через те, що Fiber використовує unsafe, бібліотека не завжди може бути сумісною з останньою версією Go. Fiber 2.40.0 було протестовано з Go версій 1.17 до 1.21. - Fiber не сумісний з інтерфейсами net/http. Це означає, що ви не зможете використовувати такі проекти, як gqlgen, go-swagger або будь-які інші, які є частиною екосистеми net/http. ## 👀 Приклади diff --git a/.github/README_zh-CN.md b/.github/README_zh-CN.md index 4494deec4d..95d49b0dfa 100644 --- a/.github/README_zh-CN.md +++ b/.github/README_zh-CN.md @@ -163,7 +163,7 @@ go get -u github.com/gofiber/fiber/v2 以及在互联网上的所有诉求,为了创建一个能让有着任何技术栈的开发者都能在 deadline 前完成任务的**迅速**,**灵活**以及**友好**的 `Go web` 框架,就像 `Express` 在 `JavaScript` 世界中一样。 ## ⚠️ 限制 -* 由于 Fiber 使用了 unsafe 特性,导致其可能与最新的 Go 版本不兼容。Fiber 2.40.0 已经在 Go 1.17 到 1.20 上测试过。 +* 由于 Fiber 使用了 unsafe 特性,导致其可能与最新的 Go 版本不兼容。Fiber 2.40.0 已经在 Go 1.17 到 1.21 上测试过。 * Fiber 与 net/http 接口不兼容。也就是说你无法直接使用例如 gqlen,go-swagger 或者任何其他属于 net/http 生态的项目。 ## 👀 示例 diff --git a/.github/README_zh-TW.md b/.github/README_zh-TW.md index f1f0b8bee0..d9ad3cfe83 100644 --- a/.github/README_zh-TW.md +++ b/.github/README_zh-TW.md @@ -170,7 +170,7 @@ Fiber **啟發自** Express——網際網路上最知名的 Web 框架,我們 ## ⚠️ 限制 -- 由於 Fiber 有用到 Unsafe,本函式庫有時可能無法相容最新版的 Go 語言。Fiber 2.40.0 已在 Go 1.17 至 1.20 的版本測試過。 +- 由於 Fiber 有用到 Unsafe,本函式庫有時可能無法相容最新版的 Go 語言。Fiber 2.40.0 已在 Go 1.17 至 1.21 的版本測試過。 - Fiber 不相容 net/http 的介面,意味著您無法使用像是 gqlgen、go-swagger 或其他任何屬於 net/http 生態系統的專案。 ## 👀 範例 diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 96750a2eaa..add4ed5d28 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -20,7 +20,7 @@ jobs: - name: Install Go uses: actions/setup-go@v4 with: - go-version: 1.20.x + go-version: 1.21.x - name: Fetch Repository uses: actions/checkout@v3 - name: Run Benchmark diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 2b8e893e4c..5eccb9efa4 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -18,7 +18,7 @@ jobs: - uses: actions/setup-go@v4 with: # NOTE: Keep this in sync with the version from go.mod - go-version: 1.20.x + go-version: 1.21.x - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0206df5841..7efb0bddc5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,7 +17,7 @@ jobs: Build: strategy: matrix: - go-version: [1.17.x, 1.18.x, 1.19.x, 1.20.x] + go-version: [1.17.x, 1.18.x, 1.19.x, 1.20.x, 1.21.x] platform: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.platform }} steps: diff --git a/go.mod b/go.mod index b5e96ceff5..0d40fcae06 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/gofiber/fiber/v2 -go 1.20 +go 1.21 require ( github.com/google/uuid v1.3.0 @@ -15,7 +15,7 @@ require ( require ( github.com/andybalholm/brotli v1.0.5 // indirect - github.com/klauspost/compress v1.16.3 // indirect + github.com/klauspost/compress v1.16.7 // 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 0b6ac4a42d..16373c6b63 100644 --- a/go.sum +++ b/go.sum @@ -4,6 +4,8 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/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= @@ -15,6 +17,8 @@ github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 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= From 1dea615ddf636a7ffb786d1225a929e357e986d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Mon, 21 Aug 2023 10:44:02 +0300 Subject: [PATCH 18/84] :fire: add config to enable splitting by comma in parsers (#2560) * :fire: add config to enable splitting by comma in parsers :fire: add config to enable splitting by comma in parsers * optimize if statements, remove escape char support optimize if statements, remove escape char support * update --- app.go | 7 ++++++ ctx.go | 6 ++--- ctx_test.go | 59 +++++++++++++++++++++++++++++++++++++++++++---- docs/api/fiber.md | 7 +++--- path_test.go | 11 +++++++++ 5 files changed, 80 insertions(+), 10 deletions(-) diff --git a/app.go b/app.go index e15383a63e..ca598fce9e 100644 --- a/app.go +++ b/app.go @@ -390,6 +390,13 @@ type Config struct { // // Optional. Default: DefaultMethods RequestMethods []string + + // EnableSplittingOnParsers splits the query/body/header parameters by comma when it's true. + // For example, you can use it to parse multiple values from a query parameter like this: + // /api?foo=bar,baz == foo[]=bar&foo[]=baz + // + // Optional. Default: false + EnableSplittingOnParsers bool `json:"enable_splitting_on_parsers"` } // Static defines configuration options when defining static assets. diff --git a/ctx.go b/ctx.go index 86fae50dde..4f0e94812d 100644 --- a/ctx.go +++ b/ctx.go @@ -396,7 +396,7 @@ func (c *Ctx) BodyParser(out interface{}) error { k, err = parseParamSquareBrackets(k) } - if strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) { + if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) { values := strings.Split(v, ",") for i := 0; i < len(values); i++ { data[k] = append(data[k], values[i]) @@ -1220,7 +1220,7 @@ func (c *Ctx) QueryParser(out interface{}) error { k, err = parseParamSquareBrackets(k) } - if strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) { + if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) { values := strings.Split(v, ",") for i := 0; i < len(values); i++ { data[k] = append(data[k], values[i]) @@ -1269,7 +1269,7 @@ func (c *Ctx) ReqHeaderParser(out interface{}) error { k := c.app.getString(key) v := c.app.getString(val) - if strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) { + if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) { values := strings.Split(v, ",") for i := 0; i < len(values); i++ { data[k] = append(data[k], values[i]) diff --git a/ctx_test.go b/ctx_test.go index e092fcd322..4ea1e877ae 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -4082,7 +4082,7 @@ func Benchmark_Ctx_Queries(b *testing.B) { // go test -run Test_Ctx_QueryParser -v func Test_Ctx_QueryParser(t *testing.T) { t.Parallel() - app := New() + app := New(Config{EnableSplittingOnParsers: true}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) type Query struct { @@ -4153,6 +4153,29 @@ func Test_Ctx_QueryParser(t *testing.T) { utils.AssertEqual(t, 2, len(aq.Data)) } +// go test -run Test_Ctx_QueryParser -v +func Test_Ctx_QueryParser_WithoutSplitting(t *testing.T) { + t.Parallel() + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + type Query struct { + ID int + Name string + Hobby []string + } + + c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football") + q := new(Query) + utils.AssertEqual(t, nil, c.QueryParser(q)) + utils.AssertEqual(t, 1, len(q.Hobby)) + + c.Request().URI().SetQueryString("id=1&name=tom&hobby=scoccer&hobby=basketball,football") + q = new(Query) + utils.AssertEqual(t, nil, c.QueryParser(q)) + utils.AssertEqual(t, 2, len(q.Hobby)) +} + // go test -run Test_Ctx_QueryParser_WithSetParserDecoder -v func Test_Ctx_QueryParser_WithSetParserDecoder(t *testing.T) { t.Parallel() @@ -4311,7 +4334,7 @@ func Test_Ctx_QueryParser_Schema(t *testing.T) { // go test -run Test_Ctx_ReqHeaderParser -v func Test_Ctx_ReqHeaderParser(t *testing.T) { t.Parallel() - app := New() + app := New(Config{EnableSplittingOnParsers: true}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) type Header struct { @@ -4380,6 +4403,34 @@ func Test_Ctx_ReqHeaderParser(t *testing.T) { utils.AssertEqual(t, "failed to decode: name is empty", c.ReqHeaderParser(rh).Error()) } +// go test -run Test_Ctx_ReqHeaderParser -v +func Test_Ctx_ReqHeaderParser_WithoutSplitting(t *testing.T) { + t.Parallel() + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + type Header struct { + ID int + Name string + Hobby []string + } + c.Request().SetBody([]byte(``)) + c.Request().Header.SetContentType("") + + c.Request().Header.Add("id", "1") + c.Request().Header.Add("Name", "John Doe") + c.Request().Header.Add("Hobby", "golang,fiber") + q := new(Header) + utils.AssertEqual(t, nil, c.ReqHeaderParser(q)) + utils.AssertEqual(t, 1, len(q.Hobby)) + + c.Request().Header.Del("hobby") + c.Request().Header.Add("Hobby", "golang,fiber,go") + q = new(Header) + utils.AssertEqual(t, nil, c.ReqHeaderParser(q)) + utils.AssertEqual(t, 1, len(q.Hobby)) +} + // go test -run Test_Ctx_ReqHeaderParser_WithSetParserDecoder -v func Test_Ctx_ReqHeaderParser_WithSetParserDecoder(t *testing.T) { t.Parallel() @@ -4604,7 +4655,7 @@ func Benchmark_Ctx_parseQuery(b *testing.B) { // go test -v -run=^$ -bench=Benchmark_Ctx_QueryParser_Comma -benchmem -count=4 func Benchmark_Ctx_QueryParser_Comma(b *testing.B) { - app := New() + app := New(Config{EnableSplittingOnParsers: true}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) type Query struct { @@ -4630,7 +4681,7 @@ func Benchmark_Ctx_QueryParser_Comma(b *testing.B) { // go test -v -run=^$ -bench=Benchmark_Ctx_ReqHeaderParser -benchmem -count=4 func Benchmark_Ctx_ReqHeaderParser(b *testing.B) { - app := New() + app := New(Config{EnableSplittingOnParsers: true}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) type ReqHeader struct { diff --git a/docs/api/fiber.md b/docs/api/fiber.md index fa0ad2412d..1f9a91b8bf 100644 --- a/docs/api/fiber.md +++ b/docs/api/fiber.md @@ -40,7 +40,7 @@ app := fiber.New(fiber.Config{ **Config fields** | Property | Type | Description | Default | -| ---------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------- | +| ---------------------------- | --------------------- |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| --------------------- | | AppName | `string` | This allows to setup app name for the app | `""` | | BodyLimit | `int` | Sets the maximum allowed size for a request body, if the size exceeds the configured limit, it sends `413 - Request Entity Too Large` response. | `4 * 1024 * 1024` | | CaseSensitive | `bool` | When enabled, `/Foo` and `/foo` are different routes. When disabled, `/Foo`and `/foo` are treated the same. | `false` | @@ -56,6 +56,7 @@ app := fiber.New(fiber.Config{ | ETag | `bool` | Enable or disable ETag header generation, since both weak and strong etags are generated using the same hashing method \(CRC-32\). Weak ETags are the default when enabled. | `false` | | EnableIPValidation | `bool` | If set to true, `c.IP()` and `c.IPs()` will validate IP addresses before returning them. Also, `c.IP()` will return only the first valid IP rather than just the raw header value that may be a comma seperated string.

**WARNING:** There is a small performance cost to doing this validation. Keep disabled if speed is your only concern and your application is behind a trusted proxy that already validates this header. | `false` | | EnablePrintRoutes | `bool` | EnablePrintRoutes enables print all routes with their method, path, name and handler.. | `false` | +| EnableSplittingOnParsers | `bool` | EnableSplittingOnParsers splits the query/body/header parameters by comma when it's true.

For example, you can use it to parse multiple values from a query parameter like this: `/api?foo=bar,baz == foo[]=bar&foo[]=baz` | `false` | | EnableTrustedProxyCheck | `bool` | When set to true, fiber will check whether proxy is trusted, using TrustedProxies list.

By default `c.Protocol()` will get value from X-Forwarded-Proto, X-Forwarded-Protocol, X-Forwarded-Ssl or X-Url-Scheme header, `c.IP()` will get value from `ProxyHeader` header, `c.Hostname()` will get value from X-Forwarded-Host header.
If `EnableTrustedProxyCheck` is true, and `RemoteIP` is in the list of `TrustedProxies` `c.Protocol()`, `c.IP()`, and `c.Hostname()` will have the same behaviour when `EnableTrustedProxyCheck` disabled, if `RemoteIP` isn't in the list, `c.Protocol()` will return https in case when tls connection is handled by the app, or http otherwise, `c.IP()` will return RemoteIP() from fasthttp context, `c.Hostname()` will return `fasthttp.Request.URI().Host()` | `false` | | ErrorHandler | `ErrorHandler` | ErrorHandler is executed when an error is returned from fiber.Handler. Mounted fiber error handlers are retained by the top-level app and applied on prefix associated requests. | `DefaultErrorHandler` | | GETOnly | `bool` | Rejects all non-GET requests if set to true. This option is useful as anti-DoS protection for servers accepting only GET requests. The request size is limited by ReadBufferSize if GETOnly is set. | `false` | @@ -63,13 +64,13 @@ app := fiber.New(fiber.Config{ | Immutable | `bool` | When enabled, all values returned by context methods are immutable. By default, they are valid until you return from the handler; see issue [\#185](https://github.com/gofiber/fiber/issues/185). | `false` | | JSONDecoder | `utils.JSONUnmarshal` | Allowing for flexibility in using another json library for decoding. | `json.Unmarshal` | | JSONEncoder | `utils.JSONMarshal` | Allowing for flexibility in using another json library for encoding. | `json.Marshal` | -| Network | `string` | Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only)

**WARNING:** When prefork is set to true, only "tcp4" and "tcp6" can be chosen. | `NetworkTCP4` | +| Network | `string` | Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only)

**WARNING:** When prefork is set to true, only "tcp4" and "tcp6" can be chosen. | `NetworkTCP4` | | PassLocalsToViews | `bool` | PassLocalsToViews Enables passing of the locals set on a fiber.Ctx to the template engine. See our **Template Middleware** for supported engines. | `false` | | Prefork | `bool` | Enables use of the[`SO_REUSEPORT`](https://lwn.net/Articles/542629/)socket option. This will spawn multiple Go processes listening on the same port. learn more about [socket sharding](https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/). **NOTE: if enabled, the application will need to be ran through a shell because prefork mode sets environment variables. If you're using Docker, make sure the app is ran with `CMD ./app` or `CMD ["sh", "-c", "/app"]`. For more info, see** [**this**](https://github.com/gofiber/fiber/issues/1021#issuecomment-730537971) **issue comment.** | `false` | | ProxyHeader | `string` | This will enable `c.IP()` to return the value of the given header key. By default `c.IP()`will return the Remote IP from the TCP connection, this property can be useful if you are behind a load balancer e.g. _X-Forwarded-\*_. | `""` | | ReadBufferSize | `int` | per-connection buffer size for requests' reading. This also limits the maximum header size. Increase this buffer if your clients send multi-KB RequestURIs and/or multi-KB headers \(for example, BIG cookies\). | `4096` | | ReadTimeout | `time.Duration` | The amount of time allowed to read the full request, including the body. The default timeout is unlimited. | `nil` | -| RequestMethods | `[]string` | RequestMethods provides customizibility for HTTP methods. You can add/remove methods as you wish. | `DefaultMethods` | +| RequestMethods | `[]string` | RequestMethods provides customizibility for HTTP methods. You can add/remove methods as you wish. | `DefaultMethods` | | ServerHeader | `string` | Enables the `Server` HTTP header with the given value. | `""` | | StreamRequestBody | `bool` | StreamRequestBody enables request body streaming, and calls the handler sooner when given body is larger then the current limit. | `false` | | StrictRouting | `bool` | When enabled, the router treats `/foo` and `/foo/` as different. Otherwise, the router treats `/foo` and `/foo/` as the same. | `false` | diff --git a/path_test.go b/path_test.go index 65dfdd6f72..d0d11d07a2 100644 --- a/path_test.go +++ b/path_test.go @@ -195,6 +195,17 @@ func Test_Utils_RemoveEscapeChar(t *testing.T) { utils.AssertEqual(t, "noEscapeChar", res) } +func Benchmark_Utils_RemoveEscapeChar(b *testing.B) { + b.ReportAllocs() + b.ResetTimer() + var res string + for n := 0; n < b.N; n++ { + res = RemoveEscapeChar(":test\\:bla") + } + + utils.AssertEqual(b, ":test:bla", res) +} + // go test -race -run Test_Path_matchParams func Benchmark_Path_matchParams(t *testing.B) { var ctxParams [maxParams]string From 35797e6639d40de4baae88847c82b5711184acbf Mon Sep 17 00:00:00 2001 From: Jian Lim <85569173+LimJiAn@users.noreply.github.com> Date: Tue, 22 Aug 2023 15:57:00 +0900 Subject: [PATCH 19/84] =?UTF-8?q?=F0=9F=93=9D=20Docs:=20update=20io/ioutil?= =?UTF-8?q?=20package=20to=20io=20package=20(#2589)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deprecation of io/ioutil --- docs/api/app.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/app.md b/docs/api/app.md index 5f788ca356..93dae1bc64 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -643,7 +643,7 @@ resp, _ := app.Test(req) // Do something with results: if resp.StatusCode == fiber.StatusOK { - body, _ := ioutil.ReadAll(resp.Body) + body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) // => Hello, World! } ``` From 7850cde541d187862539d43bae079dedc064ac6f Mon Sep 17 00:00:00 2001 From: RW Date: Tue, 22 Aug 2023 12:35:26 +0200 Subject: [PATCH 20/84] Update CONTRIBUTING.md --- .github/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 7a84e21e40..ae1a1a6057 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contributing -When contributing to this repository, please first discuss the change you wish to make via our [Discord](https://gofiber.io/discord) server, by creating an [issue](https://github.com/gofiber/fiber/issues) or any other method with the owners of this repository before making a change. +Before making any changes to this repository, we kindly request you to initiate discussions for proposed changes that do not yet have an associated [issue](https://github.com/gofiber/fiber/issues). Please use our [Discord](https://gofiber.io/discord) server to initiate these discussions. For [issue](https://github.com/gofiber/fiber/issues) that already exist, you may proceed with discussions using our [issue](https://github.com/gofiber/fiber/issues) tracker or any other suitable method, in consultation with the repository owners. Your collaboration is greatly appreciated. Please note: we have a [code of conduct](https://github.com/gofiber/fiber/blob/master/.github/CODE_OF_CONDUCT.md), please follow it in all your interactions with the `Fiber` project. From 408501434af7c538d7f9dc3b8225c5fa7afe50e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Aug 2023 08:35:52 +0300 Subject: [PATCH 21/84] build(deps): bump github.com/google/uuid from 1.3.0 to 1.3.1 (#2592) Bumps [github.com/google/uuid](https://github.com/google/uuid) from 1.3.0 to 1.3.1. - [Release notes](https://github.com/google/uuid/releases) - [Changelog](https://github.com/google/uuid/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/uuid/compare/v1.3.0...v1.3.1) --- updated-dependencies: - dependency-name: github.com/google/uuid dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 0d40fcae06..a35de3e1e5 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/gofiber/fiber/v2 go 1.21 require ( - github.com/google/uuid v1.3.0 + github.com/google/uuid v1.3.1 github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.19 github.com/mattn/go-runewidth v0.0.15 diff --git a/go.sum b/go.sum index 16373c6b63..9a980c090f 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/klauspost/compress v1.16.3 h1:XuJt9zzcnaz6a16/OU53ZjWp/v7/42WcR5t2a0PcNQY= -github.com/klauspost/compress v1.16.3/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= +github.com/google/uuid v1.3.1/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/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -17,8 +15,6 @@ github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= github.com/philhofer/fwd v1.1.2/go.mod h1:qkPdfjR2SIEbspLqpe1tO4n5yICnr2DY7mqEx2tUTP0= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= -github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 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= From 8ec7cec43522bc7fe2a035d42458d656e58b667f Mon Sep 17 00:00:00 2001 From: Jian Lim <85569173+LimJiAn@users.noreply.github.com> Date: Wed, 23 Aug 2023 19:19:22 +0900 Subject: [PATCH 22/84] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor:=20Use=20Gl?= =?UTF-8?q?obal=20vars=20instead=20of=20local=20vars=20for=20isLocalHost?= =?UTF-8?q?=20=20(#2595)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ♻️ Refactor: Use Global vars instead of local vars for isLocalHost --- ctx.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ctx.go b/ctx.go index 4f0e94812d..ddb1e61db2 100644 --- a/ctx.go +++ b/ctx.go @@ -1887,9 +1887,10 @@ func (c *Ctx) IsProxyTrusted() bool { return false } +var localHosts = [...]string{"127.0.0.1", "0.0.0.0", "::1"} + // IsLocalHost will return true if address is a localhost address. func (*Ctx) isLocalHost(address string) bool { - localHosts := []string{"127.0.0.1", "0.0.0.0", "::1"} for _, h := range localHosts { if strings.Contains(address, h) { return true From 15129972357dc1fc75fe03db2723c9e10bed20e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Sun, 27 Aug 2023 12:35:30 +0200 Subject: [PATCH 23/84] improve not found error --- router.go | 3 ++- router_test.go | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/router.go b/router.go index 2823bbc704..e80bc57d1e 100644 --- a/router.go +++ b/router.go @@ -6,6 +6,7 @@ package fiber import ( "fmt" + "html" "sort" "strconv" "strings" @@ -147,7 +148,7 @@ func (app *App) next(c *Ctx) (bool, error) { } // If c.Next() does not match, return 404 - err := NewError(StatusNotFound, "Cannot "+c.method+" "+c.pathOriginal) + err := NewError(StatusNotFound, "Cannot "+c.method+" "+html.EscapeString(c.pathOriginal)) if !c.matched && app.methodExist(c) { // If no match, scan stack again if other methods match the request // Moved from app.handler because middleware may break the route chain diff --git a/router_test.go b/router_test.go index 0cc8e766ea..6a43db5937 100644 --- a/router_test.go +++ b/router_test.go @@ -473,6 +473,40 @@ func Test_Route_Static_HasPrefix(t *testing.T) { utils.AssertEqual(t, true, strings.Contains(app.getString(body), "color")) } +func Test_Router_NotFound(t *testing.T) { + app := New() + app.Use(func(c *Ctx) error { + return c.Next() + }) + appHandler := app.Handler() + c := &fasthttp.RequestCtx{} + + c.Request.Header.SetMethod("DELETE") + c.URI().SetPath("/this/route/does/not/exist") + + appHandler(c) + + utils.AssertEqual(t, 404, c.Response.StatusCode()) + utils.AssertEqual(t, "Cannot DELETE /this/route/does/not/exist", string(c.Response.Body())) +} + +func Test_Router_NotFound_HTML_Inject(t *testing.T) { + app := New() + app.Use(func(c *Ctx) error { + return c.Next() + }) + appHandler := app.Handler() + c := &fasthttp.RequestCtx{} + + c.Request.Header.SetMethod("DELETE") + c.URI().SetPath("/does/not/exist") + + appHandler(c) + + utils.AssertEqual(t, 404, c.Response.StatusCode()) + utils.AssertEqual(t, "Cannot DELETE /does/not/exist<script>alert('foo');</script>", string(c.Response.Body())) +} + ////////////////////////////////////////////// ///////////////// BENCHMARKS ///////////////// ////////////////////////////////////////////// From b84f8a64e3b795bb9c8407d9a36cb3989f0216f1 Mon Sep 17 00:00:00 2001 From: RW Date: Sun, 27 Aug 2023 12:53:07 +0200 Subject: [PATCH 24/84] Update app.go prepare release v2.49.0 --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index ca598fce9e..f49a1a7cb8 100644 --- a/app.go +++ b/app.go @@ -30,7 +30,7 @@ import ( ) // Version of current fiber package -const Version = "2.48.0" +const Version = "2.49.0" // Handler defines a function to serve HTTP requests. type Handler = func(*Ctx) error From 57aef091c4d0b171082ff590ec630e2cec9284e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Sun, 27 Aug 2023 14:27:40 +0200 Subject: [PATCH 25/84] add docs for dynamic routing --- docs/guide/routing.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/guide/routing.md b/docs/guide/routing.md index 615d1aa2f2..9c7b4166f6 100644 --- a/docs/guide/routing.md +++ b/docs/guide/routing.md @@ -262,6 +262,13 @@ app.Get("/", func(c *fiber.Ctx) error { `Use` method path is a **mount**, or **prefix** path, and limits middleware to only apply to any paths requested that begin with it. +### Constraints on Adding Routes Dynamically + +:::warning +Adding routes dynamically after the application has started is not supported due to design and performance considerations. Make sure to define all your routes before the application starts. +::: + + ## Grouping If you have many endpoints, you can organize your routes using `Group`. From 5745dfe1ac4b4b02abe92b7e66f2c6ed51c86487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Sun, 27 Aug 2023 14:29:17 +0200 Subject: [PATCH 26/84] add docs for dynamic routing --- docs/guide/routing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/routing.md b/docs/guide/routing.md index 9c7b4166f6..2d97ede4c8 100644 --- a/docs/guide/routing.md +++ b/docs/guide/routing.md @@ -264,7 +264,7 @@ app.Get("/", func(c *fiber.Ctx) error { ### Constraints on Adding Routes Dynamically -:::warning +:::caution Adding routes dynamically after the application has started is not supported due to design and performance considerations. Make sure to define all your routes before the application starts. ::: From d44b03e60a68f8414f47e60127371267b8d60719 Mon Sep 17 00:00:00 2001 From: Jian Lim <85569173+LimJiAn@users.noreply.github.com> Date: Mon, 28 Aug 2023 15:00:12 +0900 Subject: [PATCH 27/84] =?UTF-8?q?=F0=9F=93=9D=20docs:=20update=20README=5F?= =?UTF-8?q?ko.md=20(#2605)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modifying sentences that are awkward to translate Translating an untranslated sentence --- .github/README_ko.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/README_ko.md b/.github/README_ko.md index 2b40d2c58a..e8b7a79abc 100644 --- a/.github/README_ko.md +++ b/.github/README_ko.md @@ -159,7 +159,7 @@ Fiber는 인터넷에서 가장 인기있는 웹 프레임워크인 Express에 ## ⚠️ 한계점 -- Fiber는 unsafe 패키지를 사용하기 때문에 최신 Go버전과 호환되지 않을 수 있습니다.Fiber 2.40.0은 Go 버전 1.17에서 1.21로 테스트되고 있습니다. +- Fiber는 unsafe 패키지를 사용하기 때문에 최신 Go버전과 호환되지 않을 수 있습니다. Fiber 2.40.0은 Go 버전 1.17부터 1.21까지 테스트되고 있습니다. - Fiber는 net/http 인터페이스와 호환되지 않습니다.즉, gqlgen이나 go-swagger 등 net/http 생태계의 일부인 프로젝트를 사용할 수 없습니다. ## 👀 예제 @@ -637,9 +637,9 @@ For more articles, middlewares, examples or tools check our [awesome list](https 3. [Medium](https://medium.com/), [Dev.to](https://dev.to/) 또는 개인 블로그에 리뷰 또는 튜토리얼을 작성하세요. 4. Support the project by donating a [cup of coffee](https://buymeacoff.ee/fenny). -## ☕ Supporters +## ☕ 후원자 -Fiber is an open source project that runs on donations to pay the bills e.g. our domain name, gitbook, netlify and serverless hosting. If you want to support Fiber, you can ☕ [**buy a coffee here**](https://buymeacoff.ee/fenny). +Fiber는 오픈소스 프로젝트로, 기부를 통해 도메인 이름, gitbook, netlify, 서버리스 호스팅 등의 비용을 충당하고 있습니다. Fiber를 후원하고 싶다면 ☕ [**여기서 커피를 사주세요**](https://buymeacoff.ee/fenny). | | User | Donation | | :--------------------------------------------------------- | :----------------------------------------------- | :------- | From 8761d948ba5f492ecc40c060298f7db04fecbd9e Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Sat, 2 Sep 2023 01:41:54 -0400 Subject: [PATCH 28/84] Rollback changes to go.mod file (#2614) * Rollback changes to go.mod file * Format workflow files with prettier, use go1.20 for go.mod file --- .github/workflows/auto-labeler.yml | 26 ++++---- .github/workflows/benchmark.yml | 70 +++++++++++---------- .github/workflows/codeql-analysis.yml | 88 +++++++++++++-------------- .github/workflows/linter.yml | 5 +- .github/workflows/release-drafter.yml | 40 ++++++------ .github/workflows/sync-docs.yml | 12 ++-- .github/workflows/test.yml | 39 ++++++------ .github/workflows/vulncheck.yml | 53 ++++++++-------- go.mod | 2 +- 9 files changed, 175 insertions(+), 160 deletions(-) diff --git a/.github/workflows/auto-labeler.yml b/.github/workflows/auto-labeler.yml index ef7299117e..3a18ed8aaa 100644 --- a/.github/workflows/auto-labeler.yml +++ b/.github/workflows/auto-labeler.yml @@ -1,21 +1,23 @@ name: Auto labeler + on: - issues: - types: [ opened, edited, milestoned ] - pull_request_target: - types: [ opened ] + issues: + types: [opened, edited, milestoned] + pull_request_target: + types: [opened] permissions: contents: read issues: write pull-requests: write statuses: write checks: write + jobs: - labeler: - runs-on: ubuntu-latest - steps: - - name: Check Labels - id: labeler - uses: fuxingloh/multi-labeler@v2 - with: - github-token: ${{secrets.GITHUB_TOKEN}} + labeler: + runs-on: ubuntu-latest + steps: + - name: Check Labels + id: labeler + uses: fuxingloh/multi-labeler@v2 + with: + github-token: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index add4ed5d28..bfe625a86e 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -4,42 +4,48 @@ on: - master - main paths: - - '**' - - '!docs/**' - - '!**.md' + - "**" + - "!docs/**" + - "!**.md" pull_request: paths: - - '**' - - '!docs/**' - - '!**.md' + - "**" + - "!docs/**" + - "!**.md" + name: Benchmark jobs: Compare: runs-on: ubuntu-latest steps: - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: 1.21.x - - name: Fetch Repository - uses: actions/checkout@v3 - - name: Run Benchmark - run: set -o pipefail; go test ./... -benchmem -run=^$ -bench . | tee output.txt - - name: Get Previous Benchmark Results - uses: actions/cache@v3 - with: - path: ./cache - key: ${{ runner.os }}-benchmark - - name: Save Benchmark Results - uses: benchmark-action/github-action-benchmark@v1.16.2 - with: - tool: 'go' - output-file-path: output.txt - github-token: ${{ secrets.BENCHMARK_TOKEN }} - benchmark-data-dir-path: 'benchmarks' - fail-on-alert: true - comment-on-alert: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} - # Enable Job Summary for PRs - deactivated because of issues - #summary-always: ${{ github.event_name != 'push' && github.event_name != 'workflow_dispatch' }} - auto-push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} - save-data-file: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} + - name: Fetch Repository + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v4 + with: + # NOTE: Keep this in sync with the version from go.mod + go-version: "1.20.x" + + - name: Run Benchmark + run: set -o pipefail; go test ./... -benchmem -run=^$ -bench . | tee output.txt + + - name: Get Previous Benchmark Results + uses: actions/cache@v3 + with: + path: ./cache + key: ${{ runner.os }}-benchmark + + - name: Save Benchmark Results + uses: benchmark-action/github-action-benchmark@v1.16.2 + with: + tool: "go" + output-file-path: output.txt + github-token: ${{ secrets.BENCHMARK_TOKEN }} + benchmark-data-dir-path: "benchmarks" + fail-on-alert: true + comment-on-alert: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} + # Enable Job Summary for PRs - deactivated because of issues + #summary-always: ${{ github.event_name != 'push' && github.event_name != 'workflow_dispatch' }} + auto-push: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} + save-data-file: ${{ github.event_name == 'push' || github.event_name == 'workflow_dispatch' }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b2a35a1ac6..d48c53bff5 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -6,16 +6,16 @@ on: - master - main paths: - - '**' - - '!docs/**' - - '!**.md' + - "**" + - "!docs/**" + - "!**.md" pull_request: paths: - - '**' - - '!docs/**' - - '!**.md' + - "**" + - "!docs/**" + - "!**.md" schedule: - - cron: '0 3 * * 6' + - cron: "0 3 * * 6" jobs: analyse: @@ -23,40 +23,40 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v2 - # Override language selection by uncommenting this and choosing your languages - with: - languages: go - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v2 - - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v2 + - name: Checkout repository + uses: actions/checkout@v3 + with: + # We must fetch at least the immediate parents so that if this is + # a pull request then we can checkout the head. + fetch-depth: 2 + + # If this run was triggered by a pull request event, then checkout + # the head of the pull request instead of the merge commit. + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + # Override language selection by uncommenting this and choosing your languages + with: + languages: go + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 5eccb9efa4..f9a7d0e3f0 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -9,16 +9,19 @@ on: pull_request: permissions: contents: read + jobs: golangci: name: lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 + - uses: actions/setup-go@v4 with: # NOTE: Keep this in sync with the version from go.mod - go-version: 1.21.x + go-version: "1.20.x" + - name: golangci-lint uses: golangci/golangci-lint-action@v3 with: diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index f4a5cea982..cedaab432f 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -1,26 +1,26 @@ name: Release Drafter on: - push: - # branches to consider in the event; optional, defaults to all - branches: - - master - - main + push: + # branches to consider in the event; optional, defaults to all + branches: + - master + - main jobs: - update_release_draft: - runs-on: ubuntu-latest - steps: - # (Optional) GitHub Enterprise requires GHE_HOST variable set - #- name: Set GHE_HOST - # run: | - # echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV + update_release_draft: + runs-on: ubuntu-latest + steps: + # (Optional) GitHub Enterprise requires GHE_HOST variable set + #- name: Set GHE_HOST + # run: | + # echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV - # Drafts your next Release notes as Pull Requests are merged into "master" - - uses: release-drafter/release-drafter@v5 - # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml - # with: - # config-name: my-config.yml - # disable-autolabeler: true - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # Drafts your next Release notes as Pull Requests are merged into "master" + - uses: release-drafter/release-drafter@v5 + # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml + # with: + # config-name: my-config.yml + # disable-autolabeler: true + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sync-docs.yml b/.github/workflows/sync-docs.yml index c7f895de6a..c662956754 100644 --- a/.github/workflows/sync-docs.yml +++ b/.github/workflows/sync-docs.yml @@ -1,4 +1,4 @@ -name: 'Sync docs' +name: "Sync docs" on: push: @@ -6,9 +6,9 @@ on: - master - main paths: - - 'docs/**' + - "docs/**" release: - types: [ published ] + types: [published] jobs: sync-docs: @@ -19,13 +19,11 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 2 + - name: Setup Node.js environment uses: actions/setup-node@v3 with: - node-version: '18' - - - name: Install JQ - run: sudo apt-get install jq + node-version: "18" - name: Sync docs run: ./.github/scripts/sync_docs.sh diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7efb0bddc5..5ad7a7c20b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,14 +4,15 @@ on: - master - main paths: - - '**' - - '!docs/**' - - '!**.md' + - "**" + - "!docs/**" + - "!**.md" pull_request: paths: - - '**' - - '!docs/**' - - '!**.md' + - "**" + - "!docs/**" + - "!**.md" + name: Test jobs: Build: @@ -21,15 +22,17 @@ jobs: platform: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.platform }} steps: - - name: Fetch Repository - uses: actions/checkout@v3 - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: ${{ matrix.go-version }} - - name: Run Test - uses: nick-fields/retry@v2 - with: - max_attempts: 3 - timeout_minutes: 15 - command: go test ./... -v -race -count=1 + - name: Fetch Repository + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v4 + with: + go-version: ${{ matrix.go-version }} + + - name: Run Test + uses: nick-fields/retry@v2 + with: + max_attempts: 3 + timeout_minutes: 15 + command: go test ./... -v -race -count=1 diff --git a/.github/workflows/vulncheck.yml b/.github/workflows/vulncheck.yml index 4c13423020..99dc59e499 100644 --- a/.github/workflows/vulncheck.yml +++ b/.github/workflows/vulncheck.yml @@ -1,19 +1,19 @@ name: Run govulncheck on: - push: - branches: - - master - - main - paths: - - '**' - - '!docs/**' - - '!**.md' - pull_request: - paths: - - '**' - - '!docs/**' - - '!**.md' + push: + branches: + - master + - main + paths: + - "**" + - "!docs/**" + - "!**.md" + pull_request: + paths: + - "**" + - "!docs/**" + - "!**.md" jobs: govulncheck-check: @@ -21,15 +21,18 @@ jobs: env: GO111MODULE: on steps: - - name: Fetch Repository - uses: actions/checkout@v3 - - name: Install Go - uses: actions/setup-go@v4 - with: - go-version: 'stable' - check-latest: true - cache: false - - name: Install Govulncheck - run: go install golang.org/x/vuln/cmd/govulncheck@latest - - name: Run Govulncheck - run: govulncheck ./... \ No newline at end of file + - name: Fetch Repository + uses: actions/checkout@v3 + + - name: Install Go + uses: actions/setup-go@v4 + with: + go-version: "stable" + check-latest: true + cache: false + + - name: Install Govulncheck + run: go install golang.org/x/vuln/cmd/govulncheck@latest + + - name: Run Govulncheck + run: govulncheck ./... diff --git a/go.mod b/go.mod index a35de3e1e5..90b0a0321e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/gofiber/fiber/v2 -go 1.21 +go 1.20 require ( github.com/google/uuid v1.3.1 From 8bb5e21e39cf011b1125bbf4e8b84e93b4852a4e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 2 Sep 2023 18:26:21 +0200 Subject: [PATCH 29/84] build(deps): bump github.com/valyala/fasthttp from 1.48.0 to 1.49.0 (#2615) Bumps [github.com/valyala/fasthttp](https://github.com/valyala/fasthttp) from 1.48.0 to 1.49.0. - [Release notes](https://github.com/valyala/fasthttp/releases) - [Commits](https://github.com/valyala/fasthttp/compare/v1.48.0...v1.49.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 | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 90b0a0321e..e8ae6cf987 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ 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.48.0 + github.com/valyala/fasthttp v1.49.0 golang.org/x/sys v0.11.0 ) diff --git a/go.sum b/go.sum index 9a980c090f..b05cb41e6e 100644 --- a/go.sum +++ b/go.sum @@ -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.48.0 h1:oJWvHb9BIZToTQS3MuQ2R3bJZiNSa2KiNdeI8A+79Tc= -github.com/valyala/fasthttp v1.48.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE= +github.com/valyala/fasthttp v1.49.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= 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 e85ceda9998cf4e20426f7a5a8f632b886e0b877 Mon Sep 17 00:00:00 2001 From: Kacper Soczko <58148956+KompocikDot@users.noreply.github.com> Date: Sat, 2 Sep 2023 18:26:34 +0200 Subject: [PATCH 30/84] =?UTF-8?q?=F0=9F=93=9AAdd=20Polish=20translation=20?= =?UTF-8?q?-=20README=5Fpl.md=20(#2613)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add polish translation of github readme Co-authored-by: Kacper Soczko --- .github/README.md | 3 + .github/README_az.md | 3 + .github/README_ckb.md | 3 + .github/README_de.md | 3 + .github/README_eg.md | 3 + .github/README_es.md | 3 + .github/README_fa.md | 3 + .github/README_fr.md | 3 + .github/README_he.md | 3 + .github/README_id.md | 3 + .github/README_it.md | 3 + .github/README_ja.md | 3 + .github/README_ko.md | 3 + .github/README_nl.md | 3 + .github/README_pl.md | 715 ++++++++++++++++++++++++++++++++++++++++ .github/README_pt.md | 3 + .github/README_ru.md | 3 + .github/README_sa.md | 3 + .github/README_tr.md | 3 + .github/README_uk.md | 3 + .github/README_zh-CN.md | 3 + .github/README_zh-TW.md | 3 + 22 files changed, 778 insertions(+) create mode 100644 .github/README_pl.md diff --git a/.github/README.md b/.github/README.md index 31d376c1a4..bf397b96a3 100644 --- a/.github/README.md +++ b/.github/README.md @@ -70,6 +70,9 @@
+ + +
diff --git a/.github/README_az.md b/.github/README_az.md index df0e71b677..ade4fa8857 100644 --- a/.github/README_az.md +++ b/.github/README_az.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_ckb.md b/.github/README_ckb.md index 11d445be7d..9c1704a7af 100644 --- a/.github/README_ckb.md +++ b/.github/README_ckb.md @@ -67,6 +67,9 @@ + + +
diff --git a/.github/README_de.md b/.github/README_de.md index a74c75aecc..72b4d02f0a 100644 --- a/.github/README_de.md +++ b/.github/README_de.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_eg.md b/.github/README_eg.md index 62d84c624f..7b337b567a 100644 --- a/.github/README_eg.md +++ b/.github/README_eg.md @@ -70,6 +70,9 @@ + + +
diff --git a/.github/README_es.md b/.github/README_es.md index fad1b16bbc..73af515002 100644 --- a/.github/README_es.md +++ b/.github/README_es.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_fa.md b/.github/README_fa.md index b32ee40eaf..cafbf5e526 100644 --- a/.github/README_fa.md +++ b/.github/README_fa.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_fr.md b/.github/README_fr.md index 66e2ec27a8..8691e59d5f 100644 --- a/.github/README_fr.md +++ b/.github/README_fr.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_he.md b/.github/README_he.md index 4a95476340..44ed8c4627 100644 --- a/.github/README_he.md +++ b/.github/README_he.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_id.md b/.github/README_id.md index 8de22107ee..69ada3f3e5 100644 --- a/.github/README_id.md +++ b/.github/README_id.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_it.md b/.github/README_it.md index 3fb854ede5..56e9c5b411 100644 --- a/.github/README_it.md +++ b/.github/README_it.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_ja.md b/.github/README_ja.md index 07a5f18b60..08a794d9de 100644 --- a/.github/README_ja.md +++ b/.github/README_ja.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_ko.md b/.github/README_ko.md index e8b7a79abc..50f1afd943 100644 --- a/.github/README_ko.md +++ b/.github/README_ko.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_nl.md b/.github/README_nl.md index 932c4790c2..33528c6185 100644 --- a/.github/README_nl.md +++ b/.github/README_nl.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_pl.md b/.github/README_pl.md new file mode 100644 index 0000000000..3bb94e8c8b --- /dev/null +++ b/.github/README_pl.md @@ -0,0 +1,715 @@ +

+ + + + Fiber + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +

+

+ Fiber jest frameworkiem webowym inspirowanym javascriptowym frameworkiem Express. Został zbudowany na podstawie Fasthttp, najszybszym silniku HTTP powstałym w Go. Został zaprojektowany tak, aby ułatwić szybkie programowanie +z myślą o wydajności oraz zerowej alokacji pamięci. +

+ +## ⚡️ Szybki start + +```go +package main + +import "github.com/gofiber/fiber/v2" + +func main() { + app := fiber.New() + + app.Get("/", func(c *fiber.Ctx) error { + return c.SendString("Hello, World 👋!") + }) + + app.Listen(":3000") +} +``` + +## 🤖 Testy wydajności +Testy te zostały przeprowadzone przez [TechEmpower](https://www.techempower.com/benchmarks/#section=data-r19&hw=ph&test=plaintext) oraz [Go Web](https://github.com/smallnest/go-web-framework-benchmark). Jeżeli chcesz zobaczyć wszystkie wyniki, proszę, odwiedź naszą [Wiki](https://docs.gofiber.io/extra/benchmarks). + + +

+ + +

+ +## ⚙️ Instalacja + +Upewnij się, że masz zainstalowane Go ([pobierz](https://go.dev/dl/)). Wymagana jest wersja `1.17` lub wyższa. + +Zainicjalizuj swój projekt poprzez stworzenie folderu i użycie komendy `go mod init github.com/your/repo` ([zobacz więcej](https://go.dev/blog/using-go-modules)) w tym folderze. Następnie zainstaluj Fiber'a przy użyciu komendy `go get`: + +```bash +go get -u github.com/gofiber/fiber/v2 +``` + +## 🎯 Funkcjonalności + +- Stabilny [routing](https://docs.gofiber.io/guide/routing) +- Serwowanie [pliki statyczne](https://docs.gofiber.io/api/app#static) +- Ekstremalna [wydajność](https://docs.gofiber.io/extra/benchmarks) +- [Niskie zużycie](https://docs.gofiber.io/extra/benchmarks) pamięci +- [Endpointy API](https://docs.gofiber.io/api/ctx) +- Wsparcie [Middleware](https://docs.gofiber.io/category/-middleware) oraz [Next](https://docs.gofiber.io/api/ctx#next) +- [Szybkie](https://dev.to/koddr/welcome-to-fiber-an-express-js-styled-fastest-web-framework-written-with-on-golang-497) programowanie po stronie servera +- [Silniki szablonów HTML](https://github.com/gofiber/template) +- [Wsparcie WebSocket](https://github.com/gofiber/websocket) +- [Wydarzenia wysyłane przez serwer](https://github.com/gofiber/recipes/tree/master/sse) +- [Rate Limiter](https://docs.gofiber.io/api/middleware/limiter) +- Tłumaczenia w [20 językach](https://docs.gofiber.io/) +- Oraz wiele więcej, [odkryj Fiber'a](https://docs.gofiber.io/) + +## 💡 Nasza filozofia +Nowi gophersi, którzy przenoszą się z [Node.js](https://nodejs.org/en/about/) na [Go](https://go.dev/doc/), mierzą się z problemami nauczania, zanim będą mogli rozpocząć budowanie swoich aplikacji internetowych lub mikroserwisów. Fiber, jako framework, został stworzony z myślą o minimalizmie i podąża za filozofią UNIX, aby nowi programiści w Go mogli szybko wkroczyć do świata Go, ciesząc się serdecznym i godnym zaufania przyjęciem. + +Fiber jest **inspirowany** javascriptowym frameworkiem Express, najpopularniejszym frameworkiem webowym w internecie. Połączyliśmy **łatwość** Express'a z **czystą wydajnością** Go. Jeżeli kiedykolwiek tworzyłeś aplikację webową w Node.js (_korzystając z Express'a lub podobnych_), wtedy wiele metod i zasad będzie dla ciebie **bardzo znajomych**. + + +**Słuchamy** naszych użytkowników w [issues](https://github.com/gofiber/fiber/issues), na kanale [Discord](https://gofiber.io/discord) _i wszędzie w Internecie_, aby stworzyć **szybki**, **elastyczny** i **przyjazny** framework webowy dla Go, który nadaje się do **wszelkich** zadań, **terminów** i **umiejętności** programistów! Tak jak Express w świecie JavaScript. + +## ⚠️ Ograniczenia + +- Z uwagi na użycie unsafe przez Fiber'a, biblioteka nie zawsze będzie kompatybilna z najnowszą wersją Go. Fiber 2.40.0 został przetestowany z Go w wersjach 1.17 i 1.21. +- Fiber nie jest kompatybilny z interfejsami net/http. To oznacza, że nie będziesz w stanie korzystać (bezpośrednio) z projektów takich jak gqlgen, go-swagger lub innych, które są częścią ekosystemu net/http. + + +## 👀 Przykłady + + +Poniżej znajdują się niektóre przykłady. Jeśli chcesz zobaczyć więcej przykładów kodu, odwiedź nasze [repozytorium Recipes](https://github.com/gofiber/recipes) lub odwiedź naszą [dokumentację API](https://docs.gofiber.io). + +#### 📖 [**Podstawowy Routing**](https://docs.gofiber.io/#basic-routing) + +```go +func main() { + app := fiber.New() + + // GET /api/register + app.Get("/api/*", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("✋ %s", c.Params("*")) + return c.SendString(msg) // => ✋ register + }) + + // GET /flights/LAX-SFO + app.Get("/flights/:from-:to", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("💸 From: %s, To: %s", c.Params("from"), c.Params("to")) + return c.SendString(msg) // => 💸 From: LAX, To: SFO + }) + + // GET /dictionary.txt + app.Get("/:file.:ext", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("📃 %s.%s", c.Params("file"), c.Params("ext")) + return c.SendString(msg) // => 📃 dictionary.txt + }) + + // GET /john/75 + app.Get("/:name/:age/:gender?", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("👴 %s is %s years old", c.Params("name"), c.Params("age")) + return c.SendString(msg) // => 👴 john is 75 years old + }) + + // GET /john + app.Get("/:name", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("Hello, %s 👋!", c.Params("name")) + return c.SendString(msg) // => Hello john 👋! + }) + + log.Fatal(app.Listen(":3000")) +} + +``` + +#### 📖 [**Nazywanie Route'ów**](https://docs.gofiber.io/api/app#name) + +```go +func main() { + app := fiber.New() + + // GET /api/register + app.Get("/api/*", func(c *fiber.Ctx) error { + msg := fmt.Sprintf("✋ %s", c.Params("*")) + return c.SendString(msg) // => ✋ register + }).Name("api") + + data, _ := json.MarshalIndent(app.GetRoute("api"), "", " ") + fmt.Print(string(data)) + // Prints: + // { + // "method": "GET", + // "name": "api", + // "path": "/api/*", + // "params": [ + // "*1" + // ] + // } + + + log.Fatal(app.Listen(":3000")) +} + +``` + +#### 📖 [**Serwowanie plików statycznych**](https://docs.gofiber.io/api/app#static) + +```go +func main() { + app := fiber.New() + + app.Static("/", "./public") + // => http://localhost:3000/js/script.js + // => http://localhost:3000/css/style.css + + app.Static("/prefix", "./public") + // => http://localhost:3000/prefix/js/script.js + // => http://localhost:3000/prefix/css/style.css + + app.Static("*", "./public/index.html") + // => http://localhost:3000/any/path/shows/index/html + + log.Fatal(app.Listen(":3000")) +} + +``` + +#### 📖 [**Middleware i Next**](https://docs.gofiber.io/api/ctx#next) + +```go +func main() { + app := fiber.New() + + // Match any route + app.Use(func(c *fiber.Ctx) error { + fmt.Println("🥇 First handler") + return c.Next() + }) + + // Match all routes starting with /api + app.Use("/api", func(c *fiber.Ctx) error { + fmt.Println("🥈 Second handler") + return c.Next() + }) + + // GET /api/list + app.Get("/api/list", func(c *fiber.Ctx) error { + fmt.Println("🥉 Last handler") + return c.SendString("Hello, World 👋!") + }) + + log.Fatal(app.Listen(":3000")) +} + +``` + +
+ 📚 Pokaż więcej przykładów + +### Silniki widoków + +📖 [Config](https://docs.gofiber.io/api/fiber#config) +📖 [Silniki](https://github.com/gofiber/template) +📖 [Render](https://docs.gofiber.io/api/ctx#render) + +Fiber domyślnie korzysta z [html/template](https://pkg.go.dev/html/template/), kiedy nie wybrano żadnego silnika. + +Jeżeli chcesz wykonywać lub korzystać z innego silnika jak [amber](https://github.com/eknkc/amber), [handlebars](https://github.com/aymerick/raymond), [mustache](https://github.com/cbroglie/mustache), [pug](https://github.com/Joker/jade) itd. sprawdź naszą paczkę [Template](https://github.com/gofiber/template), która wspiera wiele silników widoków. + +```go +package main + +import ( + "github.com/gofiber/fiber/v2" + "github.com/gofiber/template/pug" +) + +func main() { + // You can setup Views engine before initiation app: + app := fiber.New(fiber.Config{ + Views: pug.New("./views", ".pug"), + }) + + // And now, you can call template `./views/home.pug` like this: + app.Get("/", func(c *fiber.Ctx) error { + return c.Render("home", fiber.Map{ + "title": "Homepage", + "year": 1999, + }) + }) + + log.Fatal(app.Listen(":3000")) +} +``` + +### Grupowanie route'ów w łańcuchy + +📖 [Group](https://docs.gofiber.io/api/app#group) + +```go +func middleware(c *fiber.Ctx) error { + fmt.Println("Don't mind me!") + return c.Next() +} + +func handler(c *fiber.Ctx) error { + return c.SendString(c.Path()) +} + +func main() { + app := fiber.New() + + // Root API route + api := app.Group("/api", middleware) // /api + + // API v1 routes + v1 := api.Group("/v1", middleware) // /api/v1 + v1.Get("/list", handler) // /api/v1/list + v1.Get("/user", handler) // /api/v1/user + + // API v2 routes + v2 := api.Group("/v2", middleware) // /api/v2 + v2.Get("/list", handler) // /api/v2/list + v2.Get("/user", handler) // /api/v2/user + + // ... +} + +``` + +### Middleware Logger + +📖 [Logger](https://docs.gofiber.io/api/middleware/logger) + +```go +package main + +import ( + "log" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/logger" +) + +func main() { + app := fiber.New() + + app.Use(logger.New()) + + // ... + + log.Fatal(app.Listen(":3000")) +} +``` + +### Cross-Origin Resource Sharing (CORS) + +📖 [CORS](https://docs.gofiber.io/api/middleware/cors) + +```go +import ( + "log" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/cors" +) + +func main() { + app := fiber.New() + + app.Use(cors.New()) + + // ... + + log.Fatal(app.Listen(":3000")) +} +``` +Sprawdź CORS poprzez przesłanie jakiejkolwiek domeny w nagłówku `Origin`: + +```bash +curl -H "Origin: http://example.com" --verbose http://localhost:3000 +``` + +### Niestandardowa odpowiedź 404 + +📖 [Metody HTTP](https://docs.gofiber.io/api/ctx#status) + +```go +func main() { + app := fiber.New() + + app.Static("/", "./public") + + app.Get("/demo", func(c *fiber.Ctx) error { + return c.SendString("This is a demo!") + }) + + app.Post("/register", func(c *fiber.Ctx) error { + return c.SendString("Welcome!") + }) + + // Last middleware to match anything + app.Use(func(c *fiber.Ctx) error { + return c.SendStatus(404) + // => 404 "Not Found" + }) + + log.Fatal(app.Listen(":3000")) +} +``` + +### Odpowiedź JSON + +📖 [JSON](https://docs.gofiber.io/api/ctx#json) + +```go +type User struct { + Name string `json:"name"` + Age int `json:"age"` +} + +func main() { + app := fiber.New() + + app.Get("/user", func(c *fiber.Ctx) error { + return c.JSON(&User{"John", 20}) + // => {"name":"John", "age":20} + }) + + app.Get("/json", func(c *fiber.Ctx) error { + return c.JSON(fiber.Map{ + "success": true, + "message": "Hi John!", + }) + // => {"success":true, "message":"Hi John!"} + }) + + log.Fatal(app.Listen(":3000")) +} +``` + +### Dodanie WebSocket + +📖 [Websocket](https://github.com/gofiber/websocket) + +```go +import ( + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/websocket" +) + +func main() { + app := fiber.New() + + app.Get("/ws", websocket.New(func(c *websocket.Conn) { + for { + mt, msg, err := c.ReadMessage() + if err != nil { + log.Println("read:", err) + break + } + log.Printf("recv: %s", msg) + err = c.WriteMessage(mt, msg) + if err != nil { + log.Println("write:", err) + break + } + } + })) + + log.Fatal(app.Listen(":3000")) + // ws://localhost:3000/ws +} +``` + +### Wydarzenia wysyłane przez serwer + +📖 [More Info](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events) + +```go +import ( + "github.com/gofiber/fiber/v2" + "github.com/valyala/fasthttp" +) + +func main() { + app := fiber.New() + + app.Get("/sse", func(c *fiber.Ctx) error { + c.Set("Content-Type", "text/event-stream") + c.Set("Cache-Control", "no-cache") + c.Set("Connection", "keep-alive") + c.Set("Transfer-Encoding", "chunked") + + c.Context().SetBodyStreamWriter(fasthttp.StreamWriter(func(w *bufio.Writer) { + fmt.Println("WRITER") + var i int + + for { + i++ + msg := fmt.Sprintf("%d - the time is %v", i, time.Now()) + fmt.Fprintf(w, "data: Message: %s\n\n", msg) + fmt.Println(msg) + + w.Flush() + time.Sleep(5 * time.Second) + } + })) + + return nil + }) + + log.Fatal(app.Listen(":3000")) +} +``` + +### Middleware Recover + +📖 [Recover](https://docs.gofiber.io/api/middleware/recover) + +```go +import ( + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/recover" +) + +func main() { + app := fiber.New() + + app.Use(recover.New()) + + app.Get("/", func(c *fiber.Ctx) error { + panic("normally this would crash your app") + }) + + log.Fatal(app.Listen(":3000")) +} +``` + +
+ +### Używanie zaufanego proxy + +📖 [Config](https://docs.gofiber.io/api/fiber#config) + +```go +import ( + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/recover" +) + +func main() { + app := fiber.New(fiber.Config{ + EnableTrustedProxyCheck: true, + TrustedProxies: []string{"0.0.0.0", "1.1.1.1/30"}, // IP address or IP address range + ProxyHeader: fiber.HeaderXForwardedFor, + }) + + // ... + + log.Fatal(app.Listen(":3000")) +} +``` + + + +## 🧬 Wbudowane Middleware + +Poniżej znajduje się lista middleware, które są zawarte wraz z frameworkiem Fiber. + +| Middleware | Opis | +| :------------------------------------------------------------------------------------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [basicauth](https://github.com/gofiber/fiber/tree/master/middleware/basicauth) | Podstawowe middleware zapewniające podstawowe uwierzytelnienie HTTP. Wywołuje ono handler Next dla poprawnych danych uwierzytelniających oraz 401 Unauthorized dla niepoprawnych lub brakujacych danych. | +| [cache](https://github.com/gofiber/fiber/tree/master/middleware/cache) | Przechwytuje i cache'uje odpowiedzi | +| [compress](https://github.com/gofiber/fiber/tree/master/middleware/compress) | Middleware kompresji dla Fiber'a, podstawowo wspiera `deflate`, `gzip` i `brotli`. | +| [cors](https://github.com/gofiber/fiber/tree/master/middleware/cors) | Zezwala na cross-origin resource sharing \(CORS\) z wieloma opcjami konfiguracji. | +| [csrf](https://github.com/gofiber/fiber/tree/master/middleware/csrf) | Chroni przed exploitami CSRF. | +| [encryptcookie](https://github.com/gofiber/fiber/tree/master/middleware/encryptcookie) | Middleware szyfrujące wartości ciasteczek. | +| [envvar](https://github.com/gofiber/fiber/tree/master/middleware/envvar) | Odsłania zmienne środowiskowe oraz zapewnia dodatkową konfigurację. | +| [etag](https://github.com/gofiber/fiber/tree/master/middleware/etag) | Middleware ETag, które pozwala cache być bardziej wydajnym i oszczędzać transfer danych, jako, że serwer web nie musi wysyłać pełnej odpowiedzi, jeżeli dane się nie zmieniły. | +| [expvar](https://github.com/gofiber/fiber/tree/master/middleware/expvar) | Middleware Expvar, które udostępnia warianty uruchomieniowe przez swój serwer HTTP, w formacie JSON | +| [favicon](https://github.com/gofiber/fiber/tree/master/middleware/favicon) | Ignoruje favicony z logów lub serwuje je z pamięci, gdy ścieżka do pliku została podana | +| [filesystem](https://github.com/gofiber/fiber/tree/master/middleware/filesystem) | FileSystem middleware for Fiber, special thanks and credits to Alireza Salary | +| [limiter](https://github.com/gofiber/fiber/tree/master/middleware/limiter) | Rate-limiting middleware for Fiber. Use to limit repeated requests to public APIs and/or endpoints such as password reset. | +| [logger](https://github.com/gofiber/fiber/tree/master/middleware/logger) | Logger zapytań/odpowiedzi HTTP. | +| [monitor](https://github.com/gofiber/fiber/tree/master/middleware/monitor) | Middleware Monitor, które reportuje metryki serwera, inspirowane express-status-monitor | +| [pprof](https://github.com/gofiber/fiber/tree/master/middleware/pprof) | Specjalne podziękowania dla Matthew Lee \(@mthli\) | +| [proxy](https://github.com/gofiber/fiber/tree/master/middleware/proxy) | Pozwala ci przesyłać zapytania dalej do wielu serwerów | +| [recover](https://github.com/gofiber/fiber/tree/master/middleware/recover) | Middleware Recover przywraca działanie po wystąpieniu awarii w dowolnym miejscu w programie i przekazuje kontrolę do scentralizowanego typu [ ErrorHandler](https://docs.gofiber.io/guide/error-handling). | +| [requestid](https://github.com/gofiber/fiber/tree/master/middleware/requestid) | Dodaje requestid do każdego zapytania. | +| [session](https://github.com/gofiber/fiber/tree/master/middleware/session) | Middleware sesji. UWAGA: To middleware korzysta z naszej paczki Storage | +| [skip](https://github.com/gofiber/fiber/tree/master/middleware/skip) | Middleware skip, które pomija opakowany handler, jeżeli założona zasada jest spełniona | +| [rewrite](https://github.com/gofiber/rewrite) | Middleware Rewrite przepisuje scieżkę URL bazując na podanych zasadach. Może być przydatne w przypadku potrzeby kompatybilności wstecznej lub po prostu tworzeniu czystszych i bardziej przejrzystych linków. | +| [timeout](https://github.com/gofiber/fiber/tree/master/middleware/timeout) | Dodaje maksymalny czas dla zapytania i podaje go dalej do ErrorHandler, gdy limit został przekroczony. | +| [adaptor](https://github.com/gofiber/adaptor) | Konwertuje handlery net/http do/z zapytania Fiber'a, specjalne podziękowania dla @arsmn! | +| [helmet](https://github.com/gofiber/helmet) | Pomaga zabezpieczyć twoją aplikację poprzez ustawianie wielu nagłówków HTTP. | +| [redirect](https://github.com/gofiber/redirect) | Middleware przekierowywujące | +| [keyauth](https://github.com/gofiber/keyauth) | Middleware Key auth zapewnia uwierzytelnienie na podstawie klucza. | + +## 🧬 Zewnętrzne middleware +Lista zewnętrznie hostowanych modułów middleware i utrzymywanych przez [zpesół Fiber'a](https://github.com/orgs/gofiber/people). + +| Middleware | Description | +| :------------------------------------------------ | :-------------------------------------------------------------------------------------------------------------------- | +| [jwt](https://github.com/gofiber/jwt) | JWT returns a JSON Web Token \(JWT\) auth middleware. | +| [storage](https://github.com/gofiber/storage) | Premade storage drivers that implement the Storage interface, designed to be used with various Fiber middlewares. | +| [template](https://github.com/gofiber/template) | This package contains 8 template engines that can be used with Fiber `v1.10.x` Go version 1.13 or higher is required. | +| [websocket](https://github.com/gofiber/websocket) | Based on Fasthttp WebSocket for Fiber with Locals support! | + +## 🕶️ Awesome List + +Po więcej artykułów, middleware, przykładów lub narzędzi sprawdź naszą [awesome list](https://github.com/gofiber/awesome-fiber). + +## 👍 Wspomaganie + +Jeżeli chcesz podziękować i/lub wesprzeć aktywny rozwój `Fiber'a`: + +1. Dodaj [Gwiazdkę GitHub](https://github.com/gofiber/fiber/stargazers) dla tego projektu. +2. Zatweetuj o tym projekcie [na twoim Twitterze](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +3. Napisz recenzję lub tutorial na [Medium](https://medium.com/), [Dev.to](https://dev.to/) lub personalnym blogu. +4. Wesprzyj projekt, przekazując darowiznę w postaci [filiżanki kawy](https://buymeacoff.ee/fenny). + +## ☕ Wspierający + +Fiber to projekt open source, który działa dzięki darowiznom, aby pokryć koszty, takie jak nasza nazwa domeny, GitBook, Netlify oraz hosting serverless. Jeśli chcesz wesprzeć Fiber, możesz ☕ [**tutaj kupić kawę**](https://buymeacoff.ee/fenny). + +| | Użytkownik | Dotacja | +| :--------------------------------------------------------- |:-------------------------------------------------|:--------| +| ![](https://avatars.githubusercontent.com/u/204341?s=25) | [@destari](https://github.com/destari) | ☕ x 10 | +| ![](https://avatars.githubusercontent.com/u/63164982?s=25) | [@dembygenesis](https://github.com/dembygenesis) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/56607882?s=25) | [@thomasvvugt](https://github.com/thomasvvugt) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/27820675?s=25) | [@hendratommy](https://github.com/hendratommy) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/1094221?s=25) | [@ekaputra07](https://github.com/ekaputra07) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/194590?s=25) | [@jorgefuertes](https://github.com/jorgefuertes) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/186637?s=25) | [@candidosales](https://github.com/candidosales) | ☕ x 5 | +| ![](https://avatars.githubusercontent.com/u/29659953?s=25) | [@l0nax](https://github.com/l0nax) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/635852?s=25) | [@bihe](https://github.com/bihe) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/307334?s=25) | [@justdave](https://github.com/justdave) | ☕ x 3 | +| ![](https://avatars.githubusercontent.com/u/11155743?s=25) | [@koddr](https://github.com/koddr) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/29042462?s=25) | [@lapolinar](https://github.com/lapolinar) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/2978730?s=25) | [@diegowifi](https://github.com/diegowifi) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/44171355?s=25) | [@ssimk0](https://github.com/ssimk0) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/5638101?s=25) | [@raymayemir](https://github.com/raymayemir) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/619996?s=25) | [@melkorm](https://github.com/melkorm) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/31022056?s=25) | [@marvinjwendt](https://github.com/marvinjwendt) | ☕ x 1 | +| ![](https://avatars.githubusercontent.com/u/31921460?s=25) | [@toishy](https://github.com/toishy) | ☕ x 1 | + +## ‎‍💻 Współtwórcy projektu + +Code Contributors + +## ⭐️ Obserwujący projekt + +Stargazers over time + +## ⚠️ Licencja + +Copyright (c) 2019-present [Fenny](https://github.com/fenny) and [Contributors](https://github.com/gofiber/fiber/graphs/contributors). `Fiber` is free and open-source software licensed under the [MIT License](https://github.com/gofiber/fiber/blob/master/LICENSE). Official logo was created by [Vic Shóstak](https://github.com/koddr) and distributed under [Creative Commons](https://creativecommons.org/licenses/by-sa/4.0/) license (CC BY-SA 4.0 International). + +**Licencje bibliotek od innych twórców** + +- [colorable](https://github.com/mattn/go-colorable/blob/master/LICENSE) +- [isatty](https://github.com/mattn/go-isatty/blob/master/LICENSE) +- [runewidth](https://github.com/mattn/go-runewidth/blob/master/LICENSE) +- [fasthttp](https://github.com/valyala/fasthttp/blob/master/LICENSE) +- [bytebufferpool](https://github.com/valyala/bytebufferpool/blob/master/LICENSE) +- [fwd](https://github.com/philhofer/fwd/blob/master/LICENSE.md) +- [go-ole](https://github.com/go-ole/go-ole/blob/master/LICENSE) +- [gopsutil](https://github.com/shirou/gopsutil/blob/master/LICENSE) +- [msgp](https://github.com/tinylib/msgp/blob/master/LICENSE) +- [schema](https://github.com/gorilla/schema/blob/master/LICENSE) +- [uuid](https://github.com/google/uuid/blob/master/LICENSE) +- [wmi](https://github.com/StackExchange/wmi/blob/master/LICENSE) diff --git a/.github/README_pt.md b/.github/README_pt.md index 5cdd408414..3f18533b2e 100644 --- a/.github/README_pt.md +++ b/.github/README_pt.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_ru.md b/.github/README_ru.md index 338e7cb960..534f6c6734 100644 --- a/.github/README_ru.md +++ b/.github/README_ru.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_sa.md b/.github/README_sa.md index 3a2e1fa81f..c36b4ba495 100644 --- a/.github/README_sa.md +++ b/.github/README_sa.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_tr.md b/.github/README_tr.md index 1138b3346e..8053f4e846 100644 --- a/.github/README_tr.md +++ b/.github/README_tr.md @@ -66,6 +66,9 @@ + + +
diff --git a/.github/README_uk.md b/.github/README_uk.md index d2ed7ecd5b..d87c23c210 100644 --- a/.github/README_uk.md +++ b/.github/README_uk.md @@ -72,6 +72,9 @@ + + +
diff --git a/.github/README_zh-CN.md b/.github/README_zh-CN.md index 95d49b0dfa..ee9d098476 100644 --- a/.github/README_zh-CN.md +++ b/.github/README_zh-CN.md @@ -69,6 +69,9 @@ + + +
diff --git a/.github/README_zh-TW.md b/.github/README_zh-TW.md index d9ad3cfe83..1b2bc055fc 100644 --- a/.github/README_zh-TW.md +++ b/.github/README_zh-TW.md @@ -72,6 +72,9 @@ + + +
From b932bf12fc1265d73988e3aa817d9a3621a792d5 Mon Sep 17 00:00:00 2001 From: RW Date: Sat, 2 Sep 2023 18:27:18 +0200 Subject: [PATCH 31/84] Update app.go prepare release v2.49.1 --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index f49a1a7cb8..814294bdb2 100644 --- a/app.go +++ b/app.go @@ -30,7 +30,7 @@ import ( ) // Version of current fiber package -const Version = "2.49.0" +const Version = "2.49.1" // Handler defines a function to serve HTTP requests. type Handler = func(*Ctx) error From 328411a06b674371bc2a732250f5ac5409446979 Mon Sep 17 00:00:00 2001 From: ")`(-@_.+_^*__*^" <55359898+11-aryan@users.noreply.github.com> Date: Mon, 4 Sep 2023 09:10:44 +0530 Subject: [PATCH 32/84] Replaced double quotes with backticks in all route parameter strings (#2591) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 11-aryan * Removed the backticks where no special characters is used * added backticks to path parameters where special characters are escaped * Replaced double quotes with backticks in all route parameter strings #2591 * Replaced double quotes with backticks in all route parameter strings #2591 --------- Co-authored-by: René Werner --- docs/guide/routing.md | 6 +++--- path_testcases_test.go | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/guide/routing.md b/docs/guide/routing.md index 2d97ede4c8..7b092461ce 100644 --- a/docs/guide/routing.md +++ b/docs/guide/routing.md @@ -80,7 +80,7 @@ app.Get("/user/*", func(c *fiber.Ctx) error { }) // This route path will match requests to "/v1/some/resource/name:customVerb", since the parameter character is escaped -app.Get("/v1/some/resource/name\\:customVerb", func(c *fiber.Ctx) error { +app.Get(`/v1/some/resource/name\:customVerb`, func(c *fiber.Ctx) error { return c.SendString("Hello, Community") }) ``` @@ -90,7 +90,7 @@ Since the hyphen \(`-`\) and the dot \(`.`\) are interpreted literally, they can ::: :::info -All special parameter characters can also be escaped with `"\\"` and lose their value, so you can use them in the route if you want, like in the custom methods of the [google api design guide](https://cloud.google.com/apis/design/custom_methods). +All special parameter characters can also be escaped with `"\\"` and lose their value, so you can use them in the route if you want, like in the custom methods of the [google api design guide](https://cloud.google.com/apis/design/custom_methods). It's recommended to use backticks `` ` `` because in go's regex documentation, they always use backticks to make sure it is unambiguous and the escape character doesn't interfere with regex patterns in an unexpected way. ::: ```go @@ -203,7 +203,7 @@ app.Get("/:test", func(c *fiber.Ctx) error { Fiber precompiles regex query when to register routes. So there're no performance overhead for regex constraint. ```go -app.Get("/:date", func(c *fiber.Ctx) error { +app.Get(`/:date`, func(c *fiber.Ctx) error { return c.SendString(c.Params("date")) }) diff --git a/path_testcases_test.go b/path_testcases_test.go index 5602a0284d..26ec5b748e 100644 --- a/path_testcases_test.go +++ b/path_testcases_test.go @@ -85,21 +85,21 @@ func init() { }, }, { - pattern: "/v1/some/resource/name\\:customVerb", + pattern: `/v1/some/resource/name\:customVerb`, testCases: []routeTestCase{ {url: "/v1/some/resource/name:customVerb", params: nil, match: true}, {url: "/v1/some/resource/name:test", params: nil, match: false}, }, }, { - pattern: "/v1/some/resource/:name\\:customVerb", + pattern: `/v1/some/resource/:name\:customVerb`, testCases: []routeTestCase{ {url: "/v1/some/resource/test:customVerb", params: []string{"test"}, match: true}, {url: "/v1/some/resource/test:test", params: nil, match: false}, }, }, { - pattern: "/v1/some/resource/name\\\\:customVerb?\\?/:param/*", + pattern: `/v1/some/resource/name\\:customVerb?\?/:param/*`, testCases: []routeTestCase{ {url: "/v1/some/resource/name:customVerb??/test/optionalWildCard/character", params: []string{"test", "optionalWildCard/character"}, match: true}, {url: "/v1/some/resource/name:customVerb??/test", params: []string{"test", ""}, match: true}, @@ -572,7 +572,7 @@ func init() { }, }, { - pattern: "/api/v1/:param", + pattern: `/api/v1/:param`, testCases: []routeTestCase{ {url: "/api/v1/entity", params: nil, match: false}, {url: "/api/v1/8728382", params: nil, match: false}, @@ -598,7 +598,7 @@ func init() { }, }, { - pattern: "/api/v1/:param", + pattern: `/api/v1/:param`, testCases: []routeTestCase{ {url: "/api/v1/ent", params: nil, match: false}, {url: "/api/v1/15", params: nil, match: false}, @@ -642,7 +642,7 @@ func init() { }, }, { - pattern: "/api/v1/:param", + pattern: `/api/v1/:param`, testCases: []routeTestCase{ {url: "/api/v1/entity", params: []string{"entity"}, match: true}, {url: "/api/v1/87283827683", params: []string{"87283827683"}, match: true}, @@ -651,7 +651,7 @@ func init() { }, }, { - pattern: "/api/v1/:param", + pattern: `/api/v1/:param`, testCases: []routeTestCase{ {url: "/api/v1/entity", params: nil, match: false}, {url: "/api/v1/87283827683", params: nil, match: false}, @@ -697,7 +697,7 @@ func init() { }, }, { - pattern: "/api/v1/:date/:regex", + pattern: `/api/v1/:date/:regex`, testCases: []routeTestCase{ {url: "/api/v1/2005-11-01/a", params: nil, match: false}, {url: "/api/v1/2005-1101/paach", params: nil, match: false}, From d570d95e844252d390a7209c5e7a67dddb85e016 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Sep 2023 15:40:10 +0300 Subject: [PATCH 33/84] build(deps): bump golang.org/x/sys from 0.11.0 to 0.12.0 (#2617) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.11.0 to 0.12.0. - [Commits](https://github.com/golang/sys/compare/v0.11.0...v0.12.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 e8ae6cf987..79a6b84457 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.49.0 - golang.org/x/sys v0.11.0 + golang.org/x/sys v0.12.0 ) require ( diff --git a/go.sum b/go.sum index b05cb41e6e..16b1c74853 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.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= From b8c9ede6efa231116c4bd8bb9d5e03eac1cb76dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Wed, 6 Sep 2023 13:20:33 +0200 Subject: [PATCH 34/84] IsFromLocal corrected --- ctx.go | 10 ++--- ctx_test.go | 112 ++++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 94 insertions(+), 28 deletions(-) diff --git a/ctx.go b/ctx.go index ddb1e61db2..f409250aad 100644 --- a/ctx.go +++ b/ctx.go @@ -1887,12 +1887,12 @@ func (c *Ctx) IsProxyTrusted() bool { return false } -var localHosts = [...]string{"127.0.0.1", "0.0.0.0", "::1"} +var localHosts = [...]string{"127.0.0.1", "::1"} // IsLocalHost will return true if address is a localhost address. func (*Ctx) isLocalHost(address string) bool { for _, h := range localHosts { - if strings.Contains(address, h) { + if address == h { return true } } @@ -1901,9 +1901,5 @@ func (*Ctx) isLocalHost(address string) bool { // IsFromLocal will return true if request came from local. func (c *Ctx) IsFromLocal() bool { - ips := c.IPs() - if len(ips) == 0 { - ips = append(ips, c.IP()) - } - return c.isLocalHost(ips[0]) + return c.isLocalHost(c.fasthttp.RemoteIP().String()) } diff --git a/ctx_test.go b/ctx_test.go index 4ea1e877ae..52c62fe510 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -17,6 +17,7 @@ import ( "fmt" "io" "mime/multipart" + "net" "net/http/httptest" "net/url" "os" @@ -4918,57 +4919,126 @@ func Test_Ctx_GetReqHeaders(t *testing.T) { }) } -// go test -run Test_Ctx_IsFromLocal -func Test_Ctx_IsFromLocal(t *testing.T) { +// go test -run Test_Ctx_IsFromLocal_X_Forwarded +func Test_Ctx_IsFromLocal_X_Forwarded(t *testing.T) { t.Parallel() - // Test "0.0.0.0", "127.0.0.1" and "::1". + // Test unset X-Forwarded-For header. { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) - utils.AssertEqual(t, true, c.IsFromLocal()) + // fasthttp returns "0.0.0.0" as IP as there is no remote address. + utils.AssertEqual(t, "0.0.0.0", c.IP()) + utils.AssertEqual(t, false, c.IsFromLocal()) } - // This is a test for "0.0.0.0" + // Test when setting X-Forwarded-For header to localhost "127.0.0.1" { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "0.0.0.0") + c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1") defer app.ReleaseCtx(c) - utils.AssertEqual(t, true, c.IsFromLocal()) + utils.AssertEqual(t, false, c.IsFromLocal()) } - - // This is a test for "127.0.0.1" + // Test when setting X-Forwarded-For header to localhost "::1" { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1") + c.Request().Header.Set(HeaderXForwardedFor, "::1") defer app.ReleaseCtx(c) - utils.AssertEqual(t, true, c.IsFromLocal()) + utils.AssertEqual(t, false, c.IsFromLocal()) } - - // This is a test for "localhost" + // Test when setting X-Forwarded-For to full localhost IPv6 address "0:0:0:0:0:0:0:1" { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) + c.Request().Header.Set(HeaderXForwardedFor, "0:0:0:0:0:0:0:1") defer app.ReleaseCtx(c) - utils.AssertEqual(t, true, c.IsFromLocal()) + utils.AssertEqual(t, false, c.IsFromLocal()) } - - // This is testing "::1", it is the compressed format IPV6 loopback address 0:0:0:0:0:0:0:1. - // It is the equivalent of the IPV4 address 127.0.0.1. + // Test for a random IP address. { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "::1") + c.Request().Header.Set(HeaderXForwardedFor, "93.46.8.90") defer app.ReleaseCtx(c) - utils.AssertEqual(t, true, c.IsFromLocal()) + utils.AssertEqual(t, false, c.IsFromLocal()) } +} +// go test -run Test_Ctx_IsFromLocal_RemoteAddr +func Test_Ctx_IsFromLocal_RemoteAddr(t *testing.T) { + t.Parallel() + + localIPv4 := net.Addr(&net.TCPAddr{IP: net.ParseIP("127.0.0.1")}) + localIPv6 := net.Addr(&net.TCPAddr{IP: net.ParseIP("::1")}) + localIPv6long := net.Addr(&net.TCPAddr{IP: net.ParseIP("0:0:0:0:0:0:0:1")}) + + zeroIPv4 := net.Addr(&net.TCPAddr{IP: net.IPv4zero}) + + someIPv4 := net.Addr(&net.TCPAddr{IP: net.ParseIP("93.46.8.90")}) + someIPv6 := net.Addr(&net.TCPAddr{IP: net.ParseIP("2001:0db8:85a3:0000:0000:8a2e:0370:7334")}) + + // Test for the case fasthttp remoteAddr is set to "127.0.0.1". { app := New() - c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "93.46.8.90") + fastCtx := &fasthttp.RequestCtx{} + fastCtx.SetRemoteAddr(localIPv4) + c := app.AcquireCtx(fastCtx) + defer app.ReleaseCtx(c) + + utils.AssertEqual(t, "127.0.0.1", c.IP()) + utils.AssertEqual(t, true, c.IsFromLocal()) + } + // Test for the case fasthttp remoteAddr is set to "::1". + { + app := New() + fastCtx := &fasthttp.RequestCtx{} + fastCtx.SetRemoteAddr(localIPv6) + c := app.AcquireCtx(fastCtx) + defer app.ReleaseCtx(c) + utils.AssertEqual(t, "::1", c.IP()) + utils.AssertEqual(t, true, c.IsFromLocal()) + } + // Test for the case fasthttp remoteAddr is set to "0:0:0:0:0:0:0:1". + { + app := New() + fastCtx := &fasthttp.RequestCtx{} + fastCtx.SetRemoteAddr(localIPv6long) + c := app.AcquireCtx(fastCtx) + defer app.ReleaseCtx(c) + // fasthttp should return "::1" for "0:0:0:0:0:0:0:1". + // otherwise IsFromLocal() will break. + utils.AssertEqual(t, "::1", c.IP()) + utils.AssertEqual(t, true, c.IsFromLocal()) + } + // Test for the case fasthttp remoteAddr is set to "0.0.0.0". + { + app := New() + fastCtx := &fasthttp.RequestCtx{} + fastCtx.SetRemoteAddr(zeroIPv4) + c := app.AcquireCtx(fastCtx) + defer app.ReleaseCtx(c) + utils.AssertEqual(t, "0.0.0.0", c.IP()) + utils.AssertEqual(t, false, c.IsFromLocal()) + } + // Test for the case fasthttp remoteAddr is set to "93.46.8.90". + { + app := New() + fastCtx := &fasthttp.RequestCtx{} + fastCtx.SetRemoteAddr(someIPv4) + c := app.AcquireCtx(fastCtx) + defer app.ReleaseCtx(c) + utils.AssertEqual(t, "93.46.8.90", c.IP()) + utils.AssertEqual(t, false, c.IsFromLocal()) + } + // Test for the case fasthttp remoteAddr is set to "2001:0db8:85a3:0000:0000:8a2e:0370:7334". + { + app := New() + fastCtx := &fasthttp.RequestCtx{} + fastCtx.SetRemoteAddr(someIPv6) + c := app.AcquireCtx(fastCtx) defer app.ReleaseCtx(c) + utils.AssertEqual(t, "2001:db8:85a3::8a2e:370:7334", c.IP()) utils.AssertEqual(t, false, c.IsFromLocal()) } } From fe65ff8dff718db4dfb6921108371c9e248ee208 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Sep 2023 13:24:24 +0200 Subject: [PATCH 35/84] build(deps): bump actions/checkout from 3 to 4 (#2618) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/benchmark.yml | 2 +- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/linter.yml | 2 +- .github/workflows/sync-docs.yml | 2 +- .github/workflows/test.yml | 2 +- .github/workflows/vulncheck.yml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index bfe625a86e..cbef15c3b3 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Fetch Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Go uses: actions/setup-go@v4 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d48c53bff5..bedc27fe61 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index f9a7d0e3f0..37c53168a5 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -15,7 +15,7 @@ jobs: name: lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: diff --git a/.github/workflows/sync-docs.yml b/.github/workflows/sync-docs.yml index c662956754..a92449e35c 100644 --- a/.github/workflows/sync-docs.yml +++ b/.github/workflows/sync-docs.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 2 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5ad7a7c20b..c11960f478 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,7 +23,7 @@ jobs: runs-on: ${{ matrix.platform }} steps: - name: Fetch Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Go uses: actions/setup-go@v4 diff --git a/.github/workflows/vulncheck.yml b/.github/workflows/vulncheck.yml index 99dc59e499..85e96fdd00 100644 --- a/.github/workflows/vulncheck.yml +++ b/.github/workflows/vulncheck.yml @@ -22,7 +22,7 @@ jobs: GO111MODULE: on steps: - name: Fetch Repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Go uses: actions/setup-go@v4 From 6d34e23815eb6cf8cb4d0a1748a1c033e592df32 Mon Sep 17 00:00:00 2001 From: Akarshit Joshi <46246540+AKARSHITJOSHI@users.noreply.github.com> Date: Mon, 11 Sep 2023 12:15:00 +0530 Subject: [PATCH 36/84] [Bug]: Logger Middleware: Enabling color changes padding for some fields #2604 (#2616) :bug: Removes extra padding for response code, method --- middleware/logger/tags.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/middleware/logger/tags.go b/middleware/logger/tags.go index af114a5777..87b9a9b228 100644 --- a/middleware/logger/tags.go +++ b/middleware/logger/tags.go @@ -176,14 +176,14 @@ func createTagMap(cfg *Config) map[string]LogFunc { TagStatus: func(output Buffer, c *fiber.Ctx, data *Data, extraParam string) (int, error) { if cfg.enableColors { colors := c.App().Config().ColorScheme - return output.WriteString(fmt.Sprintf("%s %3d %s", statusColor(c.Response().StatusCode(), colors), c.Response().StatusCode(), colors.Reset)) + return output.WriteString(fmt.Sprintf("%s%3d%s", statusColor(c.Response().StatusCode(), colors), c.Response().StatusCode(), colors.Reset)) } return appendInt(output, c.Response().StatusCode()) }, TagMethod: func(output Buffer, c *fiber.Ctx, data *Data, extraParam string) (int, error) { if cfg.enableColors { colors := c.App().Config().ColorScheme - return output.WriteString(fmt.Sprintf("%s %-7s %s", methodColor(c.Method(), colors), c.Method(), colors.Reset)) + return output.WriteString(fmt.Sprintf("%s%s%s", methodColor(c.Method(), colors), c.Method(), colors.Reset)) } return output.WriteString(c.Method()) }, From 2af907d98d949f710553ebed3d3f9da37bd94966 Mon Sep 17 00:00:00 2001 From: RW Date: Thu, 14 Sep 2023 08:00:10 +0200 Subject: [PATCH 37/84] Update app.go prepare release v2.49.2 --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index 814294bdb2..5ec5d0dbc7 100644 --- a/app.go +++ b/app.go @@ -30,7 +30,7 @@ import ( ) // Version of current fiber package -const Version = "2.49.1" +const Version = "2.49.2" // Handler defines a function to serve HTTP requests. type Handler = func(*Ctx) error From d0d5e9ee995a9ae84dc44d931bc8e4d4f2849484 Mon Sep 17 00:00:00 2001 From: CuiPeiyu Date: Thu, 14 Sep 2023 20:46:34 +0800 Subject: [PATCH 38/84] [middleware/filesystem]: Set response code (#2632) Specified response code --- middleware/filesystem/filesystem.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/middleware/filesystem/filesystem.go b/middleware/filesystem/filesystem.go index 42276a9b5b..ea23ab05cf 100644 --- a/middleware/filesystem/filesystem.go +++ b/middleware/filesystem/filesystem.go @@ -180,6 +180,8 @@ func New(config ...Config) fiber.Handler { return fiber.ErrForbidden } + c.Status(fiber.StatusOK) + modTime := stat.ModTime() contentLength := int(stat.Size()) From 52f1eb9ddfa7bba9c36f6bc764ab6b5d48470003 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Sep 2023 14:53:16 +0200 Subject: [PATCH 39/84] build(deps): bump github.com/valyala/fasthttp from 1.49.0 to 1.50.0 (#2634) Bumps [github.com/valyala/fasthttp](https://github.com/valyala/fasthttp) from 1.49.0 to 1.50.0. - [Release notes](https://github.com/valyala/fasthttp/releases) - [Commits](https://github.com/valyala/fasthttp/compare/v1.49.0...v1.50.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 | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 79a6b84457..235d44af0e 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ 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.49.0 + github.com/valyala/fasthttp v1.50.0 golang.org/x/sys v0.12.0 ) diff --git a/go.sum b/go.sum index 16b1c74853..c26d486a85 100644 --- a/go.sum +++ b/go.sum @@ -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.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE= -github.com/valyala/fasthttp v1.49.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA= +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/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 5d6552e42d211ee251533b76e2eb8f779f230bc4 Mon Sep 17 00:00:00 2001 From: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Date: Tue, 19 Sep 2023 02:08:51 -0400 Subject: [PATCH 40/84] =?UTF-8?q?=F0=9F=90=9B=20fix(middleware/adaptor):?= =?UTF-8?q?=20Reduce=20memory=20usage=20by=20replacing=20io.ReadAll()=20wi?= =?UTF-8?q?th=20io.Copy()=20(#2637)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Replace io.ReadAll with io.Copy for Adaptor Middleware * Add nolint to Close() during benchmark --- middleware/adaptor/adaptor.go | 9 +--- middleware/adaptor/adaptor_test.go | 86 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 7 deletions(-) diff --git a/middleware/adaptor/adaptor.go b/middleware/adaptor/adaptor.go index a137bc03eb..84cc866aa8 100644 --- a/middleware/adaptor/adaptor.go +++ b/middleware/adaptor/adaptor.go @@ -116,14 +116,9 @@ func handlerFunc(app *fiber.App, h ...fiber.Handler) http.HandlerFunc { defer fasthttp.ReleaseRequest(req) // Convert net/http -> fasthttp request if r.Body != nil { - body, err := io.ReadAll(r.Body) - if err != nil { - http.Error(w, utils.StatusMessage(fiber.StatusInternalServerError), fiber.StatusInternalServerError) - return - } + n, err := io.Copy(req.BodyWriter(), r.Body) + req.Header.SetContentLength(int(n)) - req.Header.SetContentLength(len(body)) - _, err = req.BodyWriter().Write(body) if err != nil { http.Error(w, utils.StatusMessage(fiber.StatusInternalServerError), fiber.StatusInternalServerError) return diff --git a/middleware/adaptor/adaptor_test.go b/middleware/adaptor/adaptor_test.go index d04aab9fe1..4e2c1c7584 100644 --- a/middleware/adaptor/adaptor_test.go +++ b/middleware/adaptor/adaptor_test.go @@ -2,6 +2,7 @@ package adaptor import ( + "bytes" "context" "fmt" "io" @@ -485,3 +486,88 @@ func Test_ConvertRequest(t *testing.T) { utils.AssertEqual(t, nil, err) utils.AssertEqual(t, "Request URL: /test?hello=world&another=test", string(body)) } + +// Benchmark for FiberHandlerFunc +func Benchmark_FiberHandlerFunc_1MB(b *testing.B) { + fiberH := func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + } + handlerFunc := FiberHandlerFunc(fiberH) + + // Create body content + bodyContent := make([]byte, 1*1024*1024) + bodyBuffer := bytes.NewBuffer(bodyContent) + + r := http.Request{ + Method: http.MethodPost, + Body: http.NoBody, + } + + // Replace the empty Body with our buffer + r.Body = io.NopCloser(bodyBuffer) + defer r.Body.Close() //nolint:errcheck // not needed + + // Create recorder + w := httptest.NewRecorder() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + handlerFunc.ServeHTTP(w, &r) + } +} + +func Benchmark_FiberHandlerFunc_10MB(b *testing.B) { + fiberH := func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + } + handlerFunc := FiberHandlerFunc(fiberH) + + // Create body content + bodyContent := make([]byte, 10*1024*1024) + bodyBuffer := bytes.NewBuffer(bodyContent) + + r := http.Request{ + Method: http.MethodPost, + Body: http.NoBody, + } + + // Replace the empty Body with our buffer + r.Body = io.NopCloser(bodyBuffer) + defer r.Body.Close() //nolint:errcheck // not needed + + // Create recorder + w := httptest.NewRecorder() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + handlerFunc.ServeHTTP(w, &r) + } +} + +func Benchmark_FiberHandlerFunc_50MB(b *testing.B) { + fiberH := func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + } + handlerFunc := FiberHandlerFunc(fiberH) + + // Create body content + bodyContent := make([]byte, 50*1024*1024) + bodyBuffer := bytes.NewBuffer(bodyContent) + + r := http.Request{ + Method: http.MethodPost, + Body: http.NoBody, + } + + // Replace the empty Body with our buffer + r.Body = io.NopCloser(bodyBuffer) + defer r.Body.Close() //nolint:errcheck // not needed + + // Create recorder + w := httptest.NewRecorder() + + b.ResetTimer() + for i := 0; i < b.N; i++ { + handlerFunc.ServeHTTP(w, &r) + } +} From 59d3eb0762cb44f40897f6b061d11221c499cfc1 Mon Sep 17 00:00:00 2001 From: huykn Date: Tue, 19 Sep 2023 23:00:26 +0700 Subject: [PATCH 41/84] :bug: fix bug parse custom header (#2638) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :bug: fix bug parse custom header * :rotating_light: fix lint when request merge https://github.com/gofiber/fiber/pull/2638 --------- Co-authored-by: Khúc Ngọc Huy --- ctx.go | 10 +-- ctx_test.go | 249 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 242 insertions(+), 17 deletions(-) diff --git a/ctx.go b/ctx.go index f409250aad..4fd114c42b 100644 --- a/ctx.go +++ b/ctx.go @@ -396,7 +396,7 @@ func (c *Ctx) BodyParser(out interface{}) error { k, err = parseParamSquareBrackets(k) } - if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) { + if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k, bodyTag) { values := strings.Split(v, ",") for i := 0; i < len(values); i++ { data[k] = append(data[k], values[i]) @@ -1220,7 +1220,7 @@ func (c *Ctx) QueryParser(out interface{}) error { k, err = parseParamSquareBrackets(k) } - if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) { + if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k, queryTag) { values := strings.Split(v, ",") for i := 0; i < len(values); i++ { data[k] = append(data[k], values[i]) @@ -1269,7 +1269,7 @@ func (c *Ctx) ReqHeaderParser(out interface{}) error { k := c.app.getString(key) v := c.app.getString(val) - if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k) { + if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k, reqHeaderTag) { values := strings.Split(v, ",") for i := 0; i < len(values); i++ { data[k] = append(data[k], values[i]) @@ -1300,7 +1300,7 @@ func (*Ctx) parseToStruct(aliasTag string, out interface{}, data map[string][]st return nil } -func equalFieldType(out interface{}, kind reflect.Kind, key string) bool { +func equalFieldType(out interface{}, kind reflect.Kind, key, tag string) bool { // Get type of interface outTyp := reflect.TypeOf(out).Elem() key = utils.ToLower(key) @@ -1327,7 +1327,7 @@ func equalFieldType(out interface{}, kind reflect.Kind, key string) bool { continue } // Get tag from field if exist - inputFieldName := typeField.Tag.Get(queryTag) + inputFieldName := typeField.Tag.Get(tag) if inputFieldName == "" { inputFieldName = typeField.Name } else { diff --git a/ctx_test.go b/ctx_test.go index 52c62fe510..fb6cda79a6 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -4127,7 +4127,81 @@ func Test_Ctx_QueryParser(t *testing.T) { c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1") q2 := new(Query2) q2.Bool = true - q2.Name = "hello world" + q2.Name = "hello world 1" + utils.AssertEqual(t, nil, c.QueryParser(q2)) + utils.AssertEqual(t, "basketball,football", q2.Hobby) + utils.AssertEqual(t, true, q2.Bool) + utils.AssertEqual(t, "tom", q2.Name) // check value get overwritten + utils.AssertEqual(t, []string{"milo", "coke", "pepsi"}, q2.FavouriteDrinks) + var nilSlice []string + utils.AssertEqual(t, nilSlice, q2.Empty) + utils.AssertEqual(t, []string{""}, q2.Alloc) + utils.AssertEqual(t, []int64{1}, q2.No) + + type RequiredQuery struct { + Name string `query:"name,required"` + } + rq := new(RequiredQuery) + c.Request().URI().SetQueryString("") + utils.AssertEqual(t, "failed to decode: name is empty", c.QueryParser(rq).Error()) + + type ArrayQuery struct { + Data []string + } + aq := new(ArrayQuery) + c.Request().URI().SetQueryString("data[]=john&data[]=doe") + utils.AssertEqual(t, nil, c.QueryParser(aq)) + utils.AssertEqual(t, 2, len(aq.Data)) +} + +// go test -run Test_Ctx_QueryParserUsingTag -v +func Test_Ctx_QueryParserUsingTag(t *testing.T) { + t.Parallel() + app := New(Config{EnableSplittingOnParsers: true}) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + type Query struct { + ID int `query:"id"` + Name string `query:"name"` + Hobby []string `query:"hobby"` + } + c.Request().SetBody([]byte(``)) + c.Request().Header.SetContentType("") + c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football") + q := new(Query) + utils.AssertEqual(t, nil, c.QueryParser(q)) + utils.AssertEqual(t, 2, len(q.Hobby)) + + c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football") + q = new(Query) + utils.AssertEqual(t, nil, c.QueryParser(q)) + utils.AssertEqual(t, 2, len(q.Hobby)) + + c.Request().URI().SetQueryString("id=1&name=tom&hobby=scoccer&hobby=basketball,football") + q = new(Query) + utils.AssertEqual(t, nil, c.QueryParser(q)) + utils.AssertEqual(t, 3, len(q.Hobby)) + + empty := new(Query) + c.Request().URI().SetQueryString("") + utils.AssertEqual(t, nil, c.QueryParser(empty)) + utils.AssertEqual(t, 0, len(empty.Hobby)) + + type Query2 struct { + Bool bool `query:"bool"` + ID int `query:"id"` + Name string `query:"name"` + Hobby string `query:"hobby"` + FavouriteDrinks []string `query:"favouriteDrinks"` + Empty []string `query:"empty"` + Alloc []string `query:"alloc"` + No []int64 `query:"no"` + } + + c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1") + q2 := new(Query2) + q2.Bool = true + q2.Name = "hello world 2" utils.AssertEqual(t, nil, c.QueryParser(q2)) utils.AssertEqual(t, "basketball,football", q2.Hobby) utils.AssertEqual(t, true, q2.Bool) @@ -4385,7 +4459,82 @@ func Test_Ctx_ReqHeaderParser(t *testing.T) { h2 := new(Header2) h2.Bool = true - h2.Name = "hello world" + h2.Name = "hello world 3" + utils.AssertEqual(t, nil, c.ReqHeaderParser(h2)) + utils.AssertEqual(t, "go,fiber", h2.Hobby) + utils.AssertEqual(t, true, h2.Bool) + utils.AssertEqual(t, "Jane Doe", h2.Name) // check value get overwritten + utils.AssertEqual(t, []string{"milo", "coke", "pepsi"}, h2.FavouriteDrinks) + var nilSlice []string + utils.AssertEqual(t, nilSlice, h2.Empty) + utils.AssertEqual(t, []string{""}, h2.Alloc) + utils.AssertEqual(t, []int64{1}, h2.No) + + type RequiredHeader struct { + Name string `reqHeader:"name,required"` + } + rh := new(RequiredHeader) + c.Request().Header.Del("name") + utils.AssertEqual(t, "failed to decode: name is empty", c.ReqHeaderParser(rh).Error()) +} + +// go test -run Test_Ctx_ReqHeaderParserUsingTag -v +func Test_Ctx_ReqHeaderParserUsingTag(t *testing.T) { + t.Parallel() + app := New(Config{EnableSplittingOnParsers: true}) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + type Header struct { + ID int `reqHeader:"id"` + Name string `reqHeader:"name"` + Hobby []string `reqHeader:"hobby"` + Address []string `reqHeader:"x-secure-address"` + } + c.Request().SetBody([]byte(``)) + c.Request().Header.SetContentType("") + + c.Request().Header.Add("id", "1") + c.Request().Header.Add("Name", "John Doe") + c.Request().Header.Add("Hobby", "golang,fiber") + c.Request().Header.Add("x-secure-address", "1st,2st") + q := new(Header) + utils.AssertEqual(t, nil, c.ReqHeaderParser(q)) + utils.AssertEqual(t, 2, len(q.Hobby)) + utils.AssertEqual(t, 2, len(q.Address)) + + c.Request().Header.Del("hobby") + c.Request().Header.Add("Hobby", "golang,fiber,go") + q = new(Header) + utils.AssertEqual(t, nil, c.ReqHeaderParser(q)) + utils.AssertEqual(t, 3, len(q.Hobby)) + + empty := new(Header) + c.Request().Header.Del("hobby") + utils.AssertEqual(t, nil, c.QueryParser(empty)) + utils.AssertEqual(t, 0, len(empty.Hobby)) + + type Header2 struct { + Bool bool `reqHeader:"bool"` + ID int `reqHeader:"id"` + Name string `reqHeader:"name"` + Hobby string `reqHeader:"hobby"` + FavouriteDrinks []string `reqHeader:"favouriteDrinks"` + Empty []string `reqHeader:"empty"` + Alloc []string `reqHeader:"alloc"` + No []int64 `reqHeader:"no"` + } + + c.Request().Header.Add("id", "2") + c.Request().Header.Add("Name", "Jane Doe") + c.Request().Header.Del("hobby") + c.Request().Header.Add("Hobby", "go,fiber") + c.Request().Header.Add("favouriteDrinks", "milo,coke,pepsi") + c.Request().Header.Add("alloc", "") + c.Request().Header.Add("no", "1") + + h2 := new(Header2) + h2.Bool = true + h2.Name = "hello world 4" utils.AssertEqual(t, nil, c.ReqHeaderParser(h2)) utils.AssertEqual(t, "go,fiber", h2.Hobby) utils.AssertEqual(t, true, h2.Bool) @@ -4574,28 +4723,104 @@ func Test_Ctx_ReqHeaderParser_Schema(t *testing.T) { utils.AssertEqual(t, 0, n.Next.Value) } -func Test_Ctx_EqualFieldType(t *testing.T) { +// go test -run Test_Ctx_EqualFieldTypeOfRequestQuery +func Test_Ctx_EqualFieldTypeOfRequestQuery(t *testing.T) { t.Parallel() var out int - utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key")) + utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key", queryTag)) var dummy struct{ f string } - utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key")) + utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key", queryTag)) var dummy2 struct{ f string } - utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f")) + utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f", queryTag)) var user struct { Name string Address string `query:"address"` Age int `query:"AGE"` } - utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name")) - utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name")) - utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address")) - utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address")) - utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE")) - utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age")) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name", queryTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name", queryTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address", queryTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address", queryTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE", queryTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age", queryTag)) +} + +// go test -run Test_Ctx_EqualFieldTypeOfRequestHeader +func Test_Ctx_EqualFieldTypeOfRequestHeader(t *testing.T) { + t.Parallel() + var out int + utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key", reqHeaderTag)) + + var dummy struct{ f string } + utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key", reqHeaderTag)) + + var dummy2 struct{ f string } + utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f", reqHeaderTag)) + + var user struct { + Name string + Address string `reqHeader:"address"` + Age int `reqHeader:"AGE"` + } + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name", reqHeaderTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name", reqHeaderTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address", reqHeaderTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address", reqHeaderTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE", reqHeaderTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age", reqHeaderTag)) +} + +// go test -run Test_Ctx_EqualFieldTypeOfRequestBody +func Test_Ctx_EqualFieldTypeOfRequestBody(t *testing.T) { + t.Parallel() + var out int + utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key", bodyTag)) + + var dummy struct{ f string } + utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key", bodyTag)) + + var dummy2 struct{ f string } + utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f", bodyTag)) + + var user struct { + Name string + Address string `form:"address"` + Age int `form:"AGE"` + } + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name", bodyTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name", bodyTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address", bodyTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address", bodyTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE", bodyTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age", bodyTag)) +} + +// go test -run Test_Ctx_EqualFieldTypeOfRequestParams +func Test_Ctx_EqualFieldTypeOfRequestParams(t *testing.T) { + t.Parallel() + var out int + utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key", paramsTag)) + + var dummy struct{ f string } + utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key", paramsTag)) + + var dummy2 struct{ f string } + utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f", paramsTag)) + + var user struct { + Name string + Address string `params:"address"` + Age int `params:"AGE"` + } + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name", paramsTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name", paramsTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address", paramsTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address", paramsTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE", paramsTag)) + utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age", paramsTag)) } // go test -v -run=^$ -bench=Benchmark_Ctx_QueryParser -benchmem -count=4 From e547bea49e19984fddd1131332d43db092b1f58e Mon Sep 17 00:00:00 2001 From: RW Date: Wed, 20 Sep 2023 09:14:58 +0200 Subject: [PATCH 42/84] Update cache.md --- docs/api/middleware/cache.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/api/middleware/cache.md b/docs/api/middleware/cache.md index 3a87306d3b..e014694103 100644 --- a/docs/api/middleware/cache.md +++ b/docs/api/middleware/cache.md @@ -36,7 +36,7 @@ app.Use(cache.New()) // Or extend your config for customization app.Use(cache.New(cache.Config{ Next: func(c *fiber.Ctx) bool { - return c.Query("refresh") == "true" + return c.Query("noCache") == "true" }, Expiration: 30 * time.Minute, CacheControl: true, @@ -64,20 +64,20 @@ app.Get("/", func(c *fiber.Ctx) error { ## Config -| Property | Type | Description | Default | -|:---------------------|:------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------| -| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | -| Expiration | `time.Duration` | Expiration is the time that a cached response will live. | `1 * time.Minute` | -| CacheHeader | `string` | CacheHeader is the header on the response header that indicates the cache status, with the possible return values "hit," "miss," or "unreachable." | `X-Cache` | -| CacheControl | `bool` | CacheControl enables client-side caching if set to true. | `false` | -| KeyGenerator | `func(*fiber.Ctx) string` | Key allows you to generate custom keys. | `func(c *fiber.Ctx) string { return utils.CopyString(c.Path()) }` | -| ExpirationGenerator | `func(*fiber.Ctx, *cache.Config) time.Duration` | ExpirationGenerator allows you to generate custom expiration keys based on the request. | `nil` | -| Storage | `fiber.Storage` | Store is used to store the state of the middleware. | In-memory store | -| Store (Deprecated) | `fiber.Storage` | Deprecated: Use Storage instead. | In-memory store | -| Key (Deprecated) | `func(*fiber.Ctx) string` | Deprecated: Use KeyGenerator instead. | `nil` | -| StoreResponseHeaders | `bool` | StoreResponseHeaders allows you to store additional headers generated by next middlewares & handler. | `false` | -| MaxBytes | `uint` | MaxBytes is the maximum number of bytes of response bodies simultaneously stored in cache. | `0` (No limit) | -| Methods | `[]string` | Methods specifies the HTTP methods to cache. | `[]string{fiber.MethodGet, fiber.MethodHead}` | +| Property | Type | Description | Default | +|:---------------------|:------------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------| +| Next | `func(*fiber.Ctx) bool` | Next defines a function that is executed before creating the cache entry and can be used to execute the request without cache creation. If an entry already exists, it will be used. If you want to completely bypass the cache functionality in certain cases, you should use the [skip middleware](./skip.md). | `nil` | +| Expiration | `time.Duration` | Expiration is the time that a cached response will live. | `1 * time.Minute` | +| CacheHeader | `string` | CacheHeader is the header on the response header that indicates the cache status, with the possible return values "hit," "miss," or "unreachable." | `X-Cache` | +| CacheControl | `bool` | CacheControl enables client-side caching if set to true. | `false` | +| KeyGenerator | `func(*fiber.Ctx) string` | Key allows you to generate custom keys. | `func(c *fiber.Ctx) string { return utils.CopyString(c.Path()) }` | +| ExpirationGenerator | `func(*fiber.Ctx, *cache.Config) time.Duration` | ExpirationGenerator allows you to generate custom expiration keys based on the request. | `nil` | +| Storage | `fiber.Storage` | Store is used to store the state of the middleware. | In-memory store | +| Store (Deprecated) | `fiber.Storage` | Deprecated: Use Storage instead. | In-memory store | +| Key (Deprecated) | `func(*fiber.Ctx) string` | Deprecated: Use KeyGenerator instead. | `nil` | +| StoreResponseHeaders | `bool` | StoreResponseHeaders allows you to store additional headers generated by next middlewares & handler. | `false` | +| MaxBytes | `uint` | MaxBytes is the maximum number of bytes of response bodies simultaneously stored in cache. | `0` (No limit) | +| Methods | `[]string` | Methods specifies the HTTP methods to cache. | `[]string{fiber.MethodGet, fiber.MethodHead}` | ## Default Config From 640fd1f7c7555e9cad20782369c6ab00aba7bc55 Mon Sep 17 00:00:00 2001 From: huykn Date: Thu, 21 Sep 2023 16:06:02 +0700 Subject: [PATCH 43/84] :bug: fix parse ips return invalid in abnormal case (#2642) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :bug: fix parse ips return invalid in abnormal case * :recycle: change benchmark to test cases --------- Co-authored-by: Khúc Ngọc Huy --- ctx.go | 2 +- ctx_test.go | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/ctx.go b/ctx.go index 4fd114c42b..2a09576dc0 100644 --- a/ctx.go +++ b/ctx.go @@ -749,7 +749,7 @@ iploop: j++ } - for i < j && headerValue[i] == ' ' { + for i < j && (headerValue[i] == ' ' || headerValue[i] == ',') { i++ } diff --git a/ctx_test.go b/ctx_test.go index fb6cda79a6..7e89327ff8 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -5317,3 +5317,26 @@ func Test_Ctx_RepeatParserWithSameStruct(t *testing.T) { testDecodeParser(MIMEApplicationForm, "body_param=body_param") testDecodeParser(MIMEMultipartForm+`;boundary="b"`, "--b\r\nContent-Disposition: form-data; name=\"body_param\"\r\n\r\nbody_param\r\n--b--") } + +// go test -run Test_Ctx_extractIPsFromHeader -v +func Test_Ctx_extractIPsFromHeader(t *testing.T) { + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + c.Request().Header.Set("x-forwarded-for", "1.1.1.1,8.8.8.8 , /n, \n,1.1, a.c, 6.,6., , a,,42.118.81.169,10.0.137.108") + ips := c.IPs() + res := ips[len(ips)-2] + utils.AssertEqual(t, "42.118.81.169", res) +} + +// go test -run Test_Ctx_extractIPsFromHeader -v +func Test_Ctx_extractIPsFromHeader_EnableValidateIp(t *testing.T) { + app := New() + app.config.EnableIPValidation = true + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + c.Request().Header.Set("x-forwarded-for", "1.1.1.1,8.8.8.8 , /n, \n,1.1, a.c, 6.,6., , a,,42.118.81.169,10.0.137.108") + ips := c.IPs() + res := ips[len(ips)-2] + utils.AssertEqual(t, "42.118.81.169", res) +} From c89184c155fbaa2bbb6589bb8d20332e4dddd5b0 Mon Sep 17 00:00:00 2001 From: dairlair <51401608+dairlair@users.noreply.github.com> Date: Tue, 26 Sep 2023 09:15:33 +0300 Subject: [PATCH 44/84] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20Refactor=20Ctx.Metho?= =?UTF-8?q?d=20func=20to=20improve=20code=20readability=20(#2647)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactor Ctx.Method func to improve code readability * Fix the lint issue with extra tab on blank line --- ctx.go | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/ctx.go b/ctx.go index 2a09576dc0..8e568e2576 100644 --- a/ctx.go +++ b/ctx.go @@ -927,17 +927,24 @@ func (c *Ctx) Location(path string) { c.setCanonical(HeaderLocation, path) } -// Method contains a string corresponding to the HTTP method of the request: GET, POST, PUT and so on. +// Method returns the HTTP request method for the context, optionally overridden by the provided argument. +// If no override is given or if the provided override is not a valid HTTP method, it returns the current method from the context. +// Otherwise, it updates the context's method and returns the overridden method as a string. func (c *Ctx) Method(override ...string) string { - if len(override) > 0 { - method := utils.ToUpper(override[0]) - mINT := c.app.methodInt(method) - if mINT == -1 { - return c.method - } - c.method = method - c.methodINT = mINT + if len(override) == 0 { + // Nothing to override, just return current method from context + return c.method + } + + method := utils.ToUpper(override[0]) + mINT := c.app.methodInt(method) + if mINT == -1 { + // Provided override does not valid HTTP method, no override, return current method + return c.method } + + c.method = method + c.methodINT = mINT return c.method } From e6d6fbe5a83262d4a7262f03a1bbceca9105a80d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Wed, 27 Sep 2023 16:06:24 +0300 Subject: [PATCH 45/84] :sparkles: middleware: cors: allow disabling caching in preflight requests (#2649) --- docs/api/middleware/cors.md | 20 ++++++++++---------- middleware/cors/cors.go | 5 +++++ middleware/cors/cors_test.go | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/docs/api/middleware/cors.md b/docs/api/middleware/cors.md index af9b8c5f2b..d688c7f5cf 100644 --- a/docs/api/middleware/cors.md +++ b/docs/api/middleware/cors.md @@ -54,16 +54,16 @@ app.Use(cors.New(cors.Config{ ## Config -| Property | Type | Description | Default | -|:-----------------|:---------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------| -| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | -| AllowOriginsFunc | `func(origin string) bool` | AllowOriginsFunc defines a function that will set the 'access-control-allow-origin' response header to the 'origin' request header when returned true. | `nil` | -| AllowOrigins | `string` | AllowOrigin defines a list of origins that may access the resource. | `"*"` | -| AllowMethods | `string` | AllowMethods defines a list methods allowed when accessing the resource. This is used in response to a preflight request. | `"GET,POST,HEAD,PUT,DELETE,PATCH"` | -| AllowHeaders | `string` | AllowHeaders defines a list of request headers that can be used when making the actual request. This is in response to a preflight request. | `""` | -| AllowCredentials | `bool` | AllowCredentials indicates whether or not the response to the request can be exposed when the credentials flag is true. | `false` | -| ExposeHeaders | `string` | ExposeHeaders defines a whitelist headers that clients are allowed to access. | `""` | -| MaxAge | `int` | MaxAge indicates how long (in seconds) the results of a preflight request can be cached. | `0` | +| Property | Type | Description | Default | +|:-----------------|:---------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------| +| Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | +| AllowOriginsFunc | `func(origin string) bool` | AllowOriginsFunc defines a function that will set the 'access-control-allow-origin' response header to the 'origin' request header when returned true. | `nil` | +| AllowOrigins | `string` | AllowOrigin defines a list of origins that may access the resource. | `"*"` | +| AllowMethods | `string` | AllowMethods defines a list methods allowed when accessing the resource. This is used in response to a preflight request. | `"GET,POST,HEAD,PUT,DELETE,PATCH"` | +| AllowHeaders | `string` | AllowHeaders defines a list of request headers that can be used when making the actual request. This is in response to a preflight request. | `""` | +| AllowCredentials | `bool` | AllowCredentials indicates whether or not the response to the request can be exposed when the credentials flag is true. | `false` | +| ExposeHeaders | `string` | ExposeHeaders defines a whitelist headers that clients are allowed to access. | `""` | +| MaxAge | `int` | MaxAge indicates how long (in seconds) the results of a preflight request can be cached. If you pass MaxAge 0, Access-Control-Max-Age header will not be added and browser will use 5 seconds by default. To disable caching completely, pass MaxAge value negative. It will set the Access-Control-Max-Age header 0. | `0` | ## Default Config diff --git a/middleware/cors/cors.go b/middleware/cors/cors.go index 281b2b4571..c347e43525 100644 --- a/middleware/cors/cors.go +++ b/middleware/cors/cors.go @@ -54,6 +54,9 @@ type Config struct { // MaxAge indicates how long (in seconds) the results of a preflight request // can be cached. + // If you pass MaxAge 0, Access-Control-Max-Age header will not be added and + // browser will use 5 seconds by default. + // To disable caching completely, pass MaxAge value negative. It will set the Access-Control-Max-Age header 0. // // Optional. Default value 0. MaxAge int @@ -187,6 +190,8 @@ func New(config ...Config) fiber.Handler { // Set MaxAge is set if cfg.MaxAge > 0 { c.Set(fiber.HeaderAccessControlMaxAge, maxAge) + } else if cfg.MaxAge < 0 { + c.Set(fiber.HeaderAccessControlMaxAge, "0") } // Send 204 No Content diff --git a/middleware/cors/cors_test.go b/middleware/cors/cors_test.go index 15b51a954e..692a24bfcc 100644 --- a/middleware/cors/cors_test.go +++ b/middleware/cors/cors_test.go @@ -27,6 +27,20 @@ func Test_CORS_Empty_Config(t *testing.T) { testDefaultOrEmptyConfig(t, app) } +func Test_CORS_Negative_MaxAge(t *testing.T) { + t.Parallel() + + app := fiber.New() + app.Use(New(Config{MaxAge: -1})) + + ctx := &fasthttp.RequestCtx{} + ctx.Request.Header.SetMethod(fiber.MethodOptions) + ctx.Request.Header.Set(fiber.HeaderOrigin, "localhost") + app.Handler()(ctx) + + utils.AssertEqual(t, "0", string(ctx.Response.Header.Peek(fiber.HeaderAccessControlMaxAge))) +} + func testDefaultOrEmptyConfig(t *testing.T, app *fiber.App) { t.Helper() From c0988de91ea21074b6c56c9851eddfc4e31e5538 Mon Sep 17 00:00:00 2001 From: Jimmy Li Date: Wed, 27 Sep 2023 23:28:35 -0700 Subject: [PATCH 46/84] :memo: middleware: cors: update docs to better explain AllowOriginsFunc (#2652) --- docs/api/middleware/cors.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/api/middleware/cors.md b/docs/api/middleware/cors.md index d688c7f5cf..9a28342fd3 100644 --- a/docs/api/middleware/cors.md +++ b/docs/api/middleware/cors.md @@ -6,6 +6,10 @@ id: cors CORS middleware for [Fiber](https://github.com/gofiber/fiber) that can be used to enable [Cross-Origin Resource Sharing](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) with various options. +The middleware conforms to the `access-control-allow-origin` specification by parsing `AllowOrigins`. First, the middleware checks if there is a matching allowed origin for the requesting 'origin' header. If there is a match, it returns exactly one matching domain from the list of allowed origins. + +For more control, `AllowOriginsFunc` can be used to programatically determine if an origin is allowed. If no match was found in `AllowOrigins` and if `AllowOriginsFunc` returns true then the 'access-control-allow-origin' response header is set to the 'origin' request header. + ## Signatures ```go @@ -58,8 +62,8 @@ app.Use(cors.New(cors.Config{ |:-----------------|:---------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------| | Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | | AllowOriginsFunc | `func(origin string) bool` | AllowOriginsFunc defines a function that will set the 'access-control-allow-origin' response header to the 'origin' request header when returned true. | `nil` | -| AllowOrigins | `string` | AllowOrigin defines a list of origins that may access the resource. | `"*"` | -| AllowMethods | `string` | AllowMethods defines a list methods allowed when accessing the resource. This is used in response to a preflight request. | `"GET,POST,HEAD,PUT,DELETE,PATCH"` | +| AllowOrigins | `string` | AllowOrigin defines a comma separated list of origins that may access the resource. | `"*"` | +| AllowMethods | `string` | AllowMethods defines a list of methods allowed when accessing the resource. This is used in response to a preflight request. | `"GET,POST,HEAD,PUT,DELETE,PATCH"` | | AllowHeaders | `string` | AllowHeaders defines a list of request headers that can be used when making the actual request. This is in response to a preflight request. | `""` | | AllowCredentials | `bool` | AllowCredentials indicates whether or not the response to the request can be exposed when the credentials flag is true. | `false` | | ExposeHeaders | `string` | ExposeHeaders defines a whitelist headers that clients are allowed to access. | `""` | From a9447a5b49fce63e77370ccfe65f50ffe8921a4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Thu, 28 Sep 2023 09:31:31 +0300 Subject: [PATCH 47/84] ctx: change signatures of GetReqHeaders and GetRespHeaders (#2650) * ctx: change signatures of GetReqHeaders and GetRespHeaders * fix middlewares --- ctx.go | 14 ++--- ctx_test.go | 70 ++++++++++++++++++++++--- docs/api/ctx.md | 4 +- middleware/idempotency/idempotency.go | 8 +-- middleware/idempotency/response.go | 2 +- middleware/idempotency/response_msgp.go | 29 ++++++++-- middleware/logger/tags.go | 2 +- 7 files changed, 103 insertions(+), 26 deletions(-) diff --git a/ctx.go b/ctx.go index 8e568e2576..880113d5f2 100644 --- a/ctx.go +++ b/ctx.go @@ -651,10 +651,11 @@ func (c *Ctx) GetRespHeader(key string, defaultValue ...string) string { // GetReqHeaders returns the HTTP request headers. // Returned value is only valid within the handler. Do not store any references. // Make copies or use the Immutable setting instead. -func (c *Ctx) GetReqHeaders() map[string]string { - headers := make(map[string]string) +func (c *Ctx) GetReqHeaders() map[string][]string { + headers := make(map[string][]string) c.Request().Header.VisitAll(func(k, v []byte) { - headers[c.app.getString(k)] = c.app.getString(v) + key := c.app.getString(k) + headers[key] = append(headers[key], c.app.getString(v)) }) return headers @@ -663,10 +664,11 @@ func (c *Ctx) GetReqHeaders() map[string]string { // GetRespHeaders returns the HTTP response headers. // Returned value is only valid within the handler. Do not store any references. // Make copies or use the Immutable setting instead. -func (c *Ctx) GetRespHeaders() map[string]string { - headers := make(map[string]string) +func (c *Ctx) GetRespHeaders() map[string][]string { + headers := make(map[string][]string) c.Response().Header.VisitAll(func(k, v []byte) { - headers[c.app.getString(k)] = c.app.getString(v) + key := c.app.getString(k) + headers[key] = append(headers[key], c.app.getString(v)) }) return headers diff --git a/ctx_test.go b/ctx_test.go index 7e89327ff8..ae15febef9 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -5117,12 +5117,39 @@ func Test_Ctx_GetRespHeaders(t *testing.T) { c.Set("test", "Hello, World 👋!") c.Set("foo", "bar") + c.Response().Header.Set("multi", "one") + c.Response().Header.Add("multi", "two") c.Response().Header.Set(HeaderContentType, "application/json") - utils.AssertEqual(t, c.GetRespHeaders(), map[string]string{ - "Content-Type": "application/json", - "Foo": "bar", - "Test": "Hello, World 👋!", + utils.AssertEqual(t, c.GetRespHeaders(), map[string][]string{ + "Content-Type": {"application/json"}, + "Foo": {"bar"}, + "Multi": {"one", "two"}, + "Test": {"Hello, World 👋!"}, + }) +} + +func Benchmark_Ctx_GetRespHeaders(b *testing.B) { + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + + c.Response().Header.Set("test", "Hello, World 👋!") + c.Response().Header.Set("foo", "bar") + c.Response().Header.Set(HeaderContentType, "application/json") + + b.ReportAllocs() + b.ResetTimer() + + var headers map[string][]string + for n := 0; n < b.N; n++ { + headers = c.GetRespHeaders() + } + + utils.AssertEqual(b, headers, map[string][]string{ + "Content-Type": {"application/json"}, + "Foo": {"bar"}, + "Test": {"Hello, World 👋!"}, }) } @@ -5133,14 +5160,41 @@ func Test_Ctx_GetReqHeaders(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) + c.Request().Header.Set("test", "Hello, World 👋!") + c.Request().Header.Set("foo", "bar") + c.Request().Header.Set("multi", "one") + c.Request().Header.Add("multi", "two") + c.Request().Header.Set(HeaderContentType, "application/json") + + utils.AssertEqual(t, c.GetReqHeaders(), map[string][]string{ + "Content-Type": {"application/json"}, + "Foo": {"bar"}, + "Test": {"Hello, World 👋!"}, + "Multi": {"one", "two"}, + }) +} + +func Benchmark_Ctx_GetReqHeaders(b *testing.B) { + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + c.Request().Header.Set("test", "Hello, World 👋!") c.Request().Header.Set("foo", "bar") c.Request().Header.Set(HeaderContentType, "application/json") - utils.AssertEqual(t, c.GetReqHeaders(), map[string]string{ - "Content-Type": "application/json", - "Foo": "bar", - "Test": "Hello, World 👋!", + b.ReportAllocs() + b.ResetTimer() + + var headers map[string][]string + for n := 0; n < b.N; n++ { + headers = c.GetReqHeaders() + } + + utils.AssertEqual(b, headers, map[string][]string{ + "Content-Type": {"application/json"}, + "Foo": {"bar"}, + "Test": {"Hello, World 👋!"}, }) } diff --git a/docs/api/ctx.md b/docs/api/ctx.md index 1da3db9795..fdd473aacc 100644 --- a/docs/api/ctx.md +++ b/docs/api/ctx.md @@ -554,7 +554,7 @@ app.Get("/", func(c *fiber.Ctx) error { Returns the HTTP request headers. ```go title="Signature" -func (c *Ctx) GetReqHeaders() map[string]string +func (c *Ctx) GetReqHeaders() map[string][]string ``` > _Returned value is only valid within the handler. Do not store any references. @@ -589,7 +589,7 @@ app.Get("/", func(c *fiber.Ctx) error { Returns the HTTP response headers. ```go title="Signature" -func (c *Ctx) GetRespHeaders() map[string]string +func (c *Ctx) GetRespHeaders() map[string][]string ``` > _Returned value is only valid within the handler. Do not store any references. diff --git a/middleware/idempotency/idempotency.go b/middleware/idempotency/idempotency.go index ae4097ae9d..604f867c76 100644 --- a/middleware/idempotency/idempotency.go +++ b/middleware/idempotency/idempotency.go @@ -45,8 +45,10 @@ func New(config ...Config) fiber.Handler { _ = c.Status(res.StatusCode) - for header, val := range res.Headers { - c.Set(header, val) + for header, vals := range res.Headers { + for _, val := range vals { + c.Context().Response.Header.Add(header, val) + } } if len(res.Body) != 0 { @@ -122,7 +124,7 @@ func New(config ...Config) fiber.Handler { res.Headers = headers } else { // Filter - res.Headers = make(map[string]string) + res.Headers = make(map[string][]string) for h := range headers { if _, ok := keepResponseHeadersMap[utils.ToLower(h)]; ok { res.Headers[h] = headers[h] diff --git a/middleware/idempotency/response.go b/middleware/idempotency/response.go index ca06bcb452..f42d1a3311 100644 --- a/middleware/idempotency/response.go +++ b/middleware/idempotency/response.go @@ -4,7 +4,7 @@ package idempotency type response struct { StatusCode int `msg:"sc"` - Headers map[string]string `msg:"hs"` + Headers map[string][]string `msg:"hs"` Body []byte `msg:"b"` } diff --git a/middleware/idempotency/response_msgp.go b/middleware/idempotency/response_msgp.go index 4eb4d7fcb0..410d118ca0 100644 --- a/middleware/idempotency/response_msgp.go +++ b/middleware/idempotency/response_msgp.go @@ -18,7 +18,10 @@ func (z *response) MarshalMsg(b []byte) (o []byte, err error) { o = msgp.AppendMapHeader(o, uint32(len(z.Headers))) for za0001, za0002 := range z.Headers { o = msgp.AppendString(o, za0001) - o = msgp.AppendString(o, za0002) + o = msgp.AppendArrayHeader(o, uint32(len(za0002))) + for za0003 := range za0002 { + o = msgp.AppendString(o, za0002[za0003]) + } } // string "b" o = append(o, 0xa1, 0x62) @@ -58,7 +61,7 @@ func (z *response) UnmarshalMsg(bts []byte) (o []byte, err error) { return } if z.Headers == nil { - z.Headers = make(map[string]string, zb0002) + z.Headers = make(map[string][]string, zb0002) } else if len(z.Headers) > 0 { for key := range z.Headers { delete(z.Headers, key) @@ -66,18 +69,31 @@ func (z *response) UnmarshalMsg(bts []byte) (o []byte, err error) { } for zb0002 > 0 { var za0001 string - var za0002 string + var za0002 []string zb0002-- za0001, bts, err = msgp.ReadStringBytes(bts) if err != nil { err = msgp.WrapError(err, "Headers") return } - za0002, bts, err = msgp.ReadStringBytes(bts) + var zb0003 uint32 + zb0003, bts, err = msgp.ReadArrayHeaderBytes(bts) if err != nil { err = msgp.WrapError(err, "Headers", za0001) return } + if cap(za0002) >= int(zb0003) { + za0002 = (za0002)[:zb0003] + } else { + za0002 = make([]string, zb0003) + } + for za0003 := range za0002 { + za0002[za0003], bts, err = msgp.ReadStringBytes(bts) + if err != nil { + err = msgp.WrapError(err, "Headers", za0001, za0003) + return + } + } z.Headers[za0001] = za0002 } case "b": @@ -104,7 +120,10 @@ func (z *response) Msgsize() (s int) { if z.Headers != nil { for za0001, za0002 := range z.Headers { _ = za0002 - s += msgp.StringPrefixSize + len(za0001) + msgp.StringPrefixSize + len(za0002) + s += msgp.StringPrefixSize + len(za0001) + msgp.ArrayHeaderSize + for za0003 := range za0002 { + s += msgp.StringPrefixSize + len(za0002[za0003]) + } } } s += 2 + msgp.BytesPrefixSize + len(z.Body) diff --git a/middleware/logger/tags.go b/middleware/logger/tags.go index 87b9a9b228..67ccbb83a2 100644 --- a/middleware/logger/tags.go +++ b/middleware/logger/tags.go @@ -102,7 +102,7 @@ func createTagMap(cfg *Config) map[string]LogFunc { TagReqHeaders: func(output Buffer, c *fiber.Ctx, data *Data, extraParam string) (int, error) { reqHeaders := make([]string, 0) for k, v := range c.GetReqHeaders() { - reqHeaders = append(reqHeaders, k+"="+v) + reqHeaders = append(reqHeaders, k+"="+strings.Join(v, ",")) } return output.Write([]byte(strings.Join(reqHeaders, "&"))) }, From 6e443f60267108577ef5e191b3e60fa964d5c8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Thu, 28 Sep 2023 15:40:42 +0300 Subject: [PATCH 48/84] refactor: use utils.AssertEqual instead of t.Fatal on some tests (#2653) --- app_test.go | 4 +- ctx_test.go | 68 ++++------ middleware/adaptor/adaptor_test.go | 197 ++++++++--------------------- middleware/favicon/favicon_test.go | 4 +- middleware/session/session_test.go | 5 +- middleware/session/store_test.go | 4 +- 6 files changed, 82 insertions(+), 200 deletions(-) diff --git a/app_test.go b/app_test.go index 09600b72be..9e0e617049 100644 --- a/app_test.go +++ b/app_test.go @@ -755,9 +755,7 @@ func Test_App_Shutdown(t *testing.T) { t.Parallel() app := &App{} if err := app.Shutdown(); err != nil { - if err.Error() != "shutdown: server is not running" { - t.Fatal() - } + utils.AssertEqual(t, "shutdown: server is not running", err.Error()) } }) } diff --git a/ctx_test.go b/ctx_test.go index ae15febef9..10fcc4f5ad 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -386,16 +386,15 @@ func Test_Ctx_Body_With_Compression(t *testing.T) { if strings.Contains(tCase.contentEncoding, "gzip") { var b bytes.Buffer gz := gzip.NewWriter(&b) + _, err := gz.Write(tCase.body) - if err != nil { - t.Fatal(err) - } - if err = gz.Flush(); err != nil { - t.Fatal(err) - } - if err = gz.Close(); err != nil { - t.Fatal(err) - } + utils.AssertEqual(t, nil, err) + + err = gz.Flush() + utils.AssertEqual(t, nil, err) + + err = gz.Close() + utils.AssertEqual(t, nil, err) tCase.body = b.Bytes() } @@ -619,9 +618,8 @@ func Test_Ctx_ParamParser(t *testing.T) { RoleID uint `params:"roleId"` } d := new(Demo) - if err := ctx.ParamsParser(d); err != nil { - t.Fatal(err) - } + + utils.AssertEqual(t, nil, ctx.ParamsParser(d)) utils.AssertEqual(t, uint(111), d.UserID) utils.AssertEqual(t, uint(222), d.RoleID) return nil @@ -4946,21 +4944,17 @@ func Test_Ctx_BodyStreamWriter(t *testing.T) { } fmt.Fprintf(w, "body writer line 2\n") }) - if !ctx.IsBodyStream() { - t.Fatal("IsBodyStream must return true") - } + + utils.AssertEqual(t, true, ctx.IsBodyStream()) s := ctx.Response.String() br := bufio.NewReader(bytes.NewBufferString(s)) var resp fasthttp.Response - if err := resp.Read(br); err != nil { - t.Fatalf("Error when reading response: %s", err) - } + utils.AssertEqual(t, nil, resp.Read(br)) + body := string(resp.Body()) expectedBody := "body writer line 1\nbody writer line 2\n" - if body != expectedBody { - t.Fatalf("unexpected body: %q. Expecting %q", body, expectedBody) - } + utils.AssertEqual(t, expectedBody, body) } // go test -v -run=^$ -bench=Benchmark_Ctx_BodyStreamWriter -benchmem -count=4 @@ -5010,14 +5004,10 @@ func TestCtx_ParamsInt(t *testing.T) { num, err := c.ParamsInt("user") // Check the number matches - if num != 1111 { - t.Fatalf("Expected number 1111 from the path, got %d", num) - } + utils.AssertEqual(t, 1111, num) // Check no errors are returned, because we want NO errors in this one - if err != nil { - t.Fatalf("Expected nil error for 1111 test, got " + err.Error()) - } + utils.AssertEqual(t, nil, err) return nil }) @@ -5030,14 +5020,10 @@ func TestCtx_ParamsInt(t *testing.T) { num, err := c.ParamsInt("user") // Check the number matches - if num != 0 { - t.Fatalf("Expected number 0 from the path, got %d", num) - } + utils.AssertEqual(t, 0, num) // Check an error is returned, because we want NO errors in this one - if err == nil { - t.Fatal("Expected non nil error for bad req test, got nil") - } + utils.AssertEqual(t, true, err != nil) return nil }) @@ -5050,14 +5036,10 @@ func TestCtx_ParamsInt(t *testing.T) { num, err := c.ParamsInt("user", 1111) // Check the number matches - if num != 2222 { - t.Fatalf("Expected number 2222 from the path, got %d", num) - } + utils.AssertEqual(t, 2222, num) // Check no errors are returned, because we want NO errors in this one - if err != nil { - t.Fatalf("Expected nil error for 2222 test, got " + err.Error()) - } + utils.AssertEqual(t, nil, err) return nil }) @@ -5070,14 +5052,10 @@ func TestCtx_ParamsInt(t *testing.T) { num, err := c.ParamsInt("user", 1111) // Check the number matches - if num != 1111 { - t.Fatalf("Expected number 1111 from the path, got %d", num) - } + utils.AssertEqual(t, 1111, num) // Check an error is returned, because we want NO errors in this one - if err != nil { - t.Fatalf("Expected nil error for 1111 test, got " + err.Error()) - } + utils.AssertEqual(t, nil, err) return nil }) diff --git a/middleware/adaptor/adaptor_test.go b/middleware/adaptor/adaptor_test.go index 4e2c1c7584..8187baefb9 100644 --- a/middleware/adaptor/adaptor_test.go +++ b/middleware/adaptor/adaptor_test.go @@ -10,7 +10,6 @@ import ( "net/http" "net/http/httptest" "net/url" - "reflect" "testing" "github.com/gofiber/fiber/v2" @@ -34,61 +33,33 @@ func Test_HTTPHandler(t *testing.T) { "XXX-Remote-Addr": "123.43.4543.345", } expectedURL, err := url.ParseRequestURI(expectedRequestURI) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + utils.AssertEqual(t, nil, err) + expectedContextKey := "contextKey" expectedContextValue := "contextValue" callsCount := 0 nethttpH := func(w http.ResponseWriter, r *http.Request) { callsCount++ - if r.Method != expectedMethod { - t.Fatalf("unexpected method %q. Expecting %q", r.Method, expectedMethod) - } - if r.Proto != expectedProto { - t.Fatalf("unexpected proto %q. Expecting %q", r.Proto, expectedProto) - } - if r.ProtoMajor != expectedProtoMajor { - t.Fatalf("unexpected protoMajor %d. Expecting %d", r.ProtoMajor, expectedProtoMajor) - } - if r.ProtoMinor != expectedProtoMinor { - t.Fatalf("unexpected protoMinor %d. Expecting %d", r.ProtoMinor, expectedProtoMinor) - } - if r.RequestURI != expectedRequestURI { - t.Fatalf("unexpected requestURI %q. Expecting %q", r.RequestURI, expectedRequestURI) - } - if r.ContentLength != int64(expectedContentLength) { - t.Fatalf("unexpected contentLength %d. Expecting %d", r.ContentLength, expectedContentLength) - } - if len(r.TransferEncoding) != 0 { - t.Fatalf("unexpected transferEncoding %q. Expecting []", r.TransferEncoding) - } - if r.Host != expectedHost { - t.Fatalf("unexpected host %q. Expecting %q", r.Host, expectedHost) - } - if r.RemoteAddr != expectedRemoteAddr { - t.Fatalf("unexpected remoteAddr %q. Expecting %q", r.RemoteAddr, expectedRemoteAddr) - } + utils.AssertEqual(t, expectedMethod, r.Method, "Method") + utils.AssertEqual(t, expectedProto, r.Proto, "Proto") + utils.AssertEqual(t, expectedProtoMajor, r.ProtoMajor, "ProtoMajor") + utils.AssertEqual(t, expectedProtoMinor, r.ProtoMinor, "ProtoMinor") + utils.AssertEqual(t, expectedRequestURI, r.RequestURI, "RequestURI") + utils.AssertEqual(t, expectedContentLength, int(r.ContentLength), "ContentLength") + utils.AssertEqual(t, 0, len(r.TransferEncoding), "TransferEncoding") + utils.AssertEqual(t, expectedHost, r.Host, "Host") + utils.AssertEqual(t, expectedRemoteAddr, r.RemoteAddr, "RemoteAddr") + body, err := io.ReadAll(r.Body) - if err != nil { - t.Fatalf("unexpected error when reading request body: %s", err) - } - if string(body) != expectedBody { - t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody) - } - if !reflect.DeepEqual(r.URL, expectedURL) { - t.Fatalf("unexpected URL: %#v. Expecting %#v", r.URL, expectedURL) - } - if r.Context().Value(expectedContextKey) != expectedContextValue { - t.Fatalf("unexpected context value for key %q. Expecting %q", expectedContextKey, expectedContextValue) - } + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, expectedBody, string(body), "Body") + utils.AssertEqual(t, expectedURL, r.URL, "URL") + utils.AssertEqual(t, expectedContextValue, r.Context().Value(expectedContextKey), "Context") for k, expectedV := range expectedHeader { v := r.Header.Get(k) - if v != expectedV { - t.Fatalf("unexpected header value %q for key %q. Expecting %q", v, k, expectedV) - } + utils.AssertEqual(t, expectedV, v, "Header") } w.Header().Set("Header1", "value1") @@ -111,37 +82,24 @@ func Test_HTTPHandler(t *testing.T) { } remoteAddr, err := net.ResolveTCPAddr("tcp", expectedRemoteAddr) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + utils.AssertEqual(t, nil, err) + fctx.Init(&req, remoteAddr, nil) app := fiber.New() ctx := app.AcquireCtx(&fctx) defer app.ReleaseCtx(ctx) err = fiberH(ctx) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } - - if callsCount != 1 { - t.Fatalf("unexpected callsCount: %d. Expecting 1", callsCount) - } + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, 1, callsCount, "callsCount") resp := &fctx.Response - if resp.StatusCode() != fiber.StatusBadRequest { - t.Fatalf("unexpected statusCode: %d. Expecting %d", resp.StatusCode(), fiber.StatusBadRequest) - } - if string(resp.Header.Peek("Header1")) != "value1" { - t.Fatalf("unexpected header value: %q. Expecting %q", resp.Header.Peek("Header1"), "value1") - } - if string(resp.Header.Peek("Header2")) != "value2" { - t.Fatalf("unexpected header value: %q. Expecting %q", resp.Header.Peek("Header2"), "value2") - } + utils.AssertEqual(t, http.StatusBadRequest, resp.StatusCode(), "StatusCode") + utils.AssertEqual(t, "value1", string(resp.Header.Peek("Header1")), "Header1") + utils.AssertEqual(t, "value2", string(resp.Header.Peek("Header2")), "Header2") + expectedResponseBody := fmt.Sprintf("request body is %q", expectedBody) - if string(resp.Body()) != expectedResponseBody { - t.Fatalf("unexpected response body %q. Expecting %q", resp.Body(), expectedResponseBody) - } + utils.AssertEqual(t, expectedResponseBody, string(resp.Body()), "Body") } type contextKey string @@ -220,32 +178,20 @@ func Test_HTTPMiddleware(t *testing.T) { for _, tt := range tests { req, err := http.NewRequestWithContext(context.Background(), tt.method, tt.url, nil) - if err != nil { - t.Fatalf(`%s: %s`, t.Name(), err) - } + utils.AssertEqual(t, nil, err) + resp, err := app.Test(req) - if err != nil { - t.Fatalf(`%s: %s`, t.Name(), err) - } - if resp.StatusCode != tt.statusCode { - t.Fatalf(`%s: StatusCode: got %v - expected %v`, t.Name(), resp.StatusCode, tt.statusCode) - } + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, tt.statusCode, resp.StatusCode, "StatusCode") } req, err := http.NewRequestWithContext(context.Background(), fiber.MethodPost, "/", nil) - if err != nil { - t.Fatalf(`%s: %s`, t.Name(), err) - } + utils.AssertEqual(t, nil, err) + resp, err := app.Test(req) - if err != nil { - t.Fatalf(`%s: %s`, t.Name(), err) - } - if resp.Header.Get("context_okay") != "okay" { - t.Fatalf(`%s: Header context_okay: got %v - expected %v`, t.Name(), resp.Header.Get("context_okay"), "okay") - } - if resp.Header.Get("context_second_okay") != "okay" { - t.Fatalf(`%s: Header context_second_okay: got %v - expected %v`, t.Name(), resp.Header.Get("context_second_okay"), "okay") - } + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, resp.Header.Get("context_okay"), "okay") + utils.AssertEqual(t, resp.Header.Get("context_second_okay"), "okay") } func Test_FiberHandler(t *testing.T) { @@ -282,43 +228,24 @@ func testFiberToHandlerFunc(t *testing.T, checkDefaultPort bool, app ...*fiber.A "XXX-Remote-Addr": "123.43.4543.345", } expectedURL, err := url.ParseRequestURI(expectedRequestURI) - if err != nil { - t.Fatalf("unexpected error: %s", err) - } + utils.AssertEqual(t, nil, err) callsCount := 0 fiberH := func(c *fiber.Ctx) error { callsCount++ - if c.Method() != expectedMethod { - t.Fatalf("unexpected method %q. Expecting %q", c.Method(), expectedMethod) - } - if string(c.Context().RequestURI()) != expectedRequestURI { - t.Fatalf("unexpected requestURI %q. Expecting %q", string(c.Context().RequestURI()), expectedRequestURI) - } - contentLength := c.Context().Request.Header.ContentLength() - if contentLength != expectedContentLength { - t.Fatalf("unexpected contentLength %d. Expecting %d", contentLength, expectedContentLength) - } - if c.Hostname() != expectedHost { - t.Fatalf("unexpected host %q. Expecting %q", c.Hostname(), expectedHost) - } - remoteAddr := c.Context().RemoteAddr().String() - if remoteAddr != expectedRemoteAddr { - t.Fatalf("unexpected remoteAddr %q. Expecting %q", remoteAddr, expectedRemoteAddr) - } + utils.AssertEqual(t, expectedMethod, c.Method(), "Method") + utils.AssertEqual(t, expectedRequestURI, string(c.Context().RequestURI()), "RequestURI") + utils.AssertEqual(t, expectedContentLength, c.Context().Request.Header.ContentLength(), "ContentLength") + utils.AssertEqual(t, expectedHost, c.Hostname(), "Host") + utils.AssertEqual(t, expectedRemoteAddr, c.Context().RemoteAddr().String(), "RemoteAddr") + body := string(c.Body()) - if body != expectedBody { - t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody) - } - if c.OriginalURL() != expectedURL.String() { - t.Fatalf("unexpected URL: %#v. Expecting %#v", c.OriginalURL(), expectedURL) - } + utils.AssertEqual(t, expectedBody, body, "Body") + utils.AssertEqual(t, expectedURL.String(), c.OriginalURL(), "URL") for k, expectedV := range expectedHeader { v := c.Get(k) - if v != expectedV { - t.Fatalf("unexpected header value %q for key %q. Expecting %q", v, k, expectedV) - } + utils.AssertEqual(t, expectedV, v, "Header") } c.Set("Header1", "value1") @@ -357,19 +284,12 @@ func testFiberToHandlerFunc(t *testing.T, checkDefaultPort bool, app ...*fiber.A var w netHTTPResponseWriter handlerFunc.ServeHTTP(&w, &r) - if w.StatusCode() != http.StatusBadRequest { - t.Fatalf("unexpected statusCode: %d. Expecting %d", w.StatusCode(), http.StatusBadRequest) - } - if w.Header().Get("Header1") != "value1" { - t.Fatalf("unexpected header value: %q. Expecting %q", w.Header().Get("Header1"), "value1") - } - if w.Header().Get("Header2") != "value2" { - t.Fatalf("unexpected header value: %q. Expecting %q", w.Header().Get("Header2"), "value2") - } + utils.AssertEqual(t, http.StatusBadRequest, w.StatusCode(), "StatusCode") + utils.AssertEqual(t, "value1", w.Header().Get("Header1"), "Header1") + utils.AssertEqual(t, "value2", w.Header().Get("Header2"), "Header2") + expectedResponseBody := fmt.Sprintf("request body is %q", expectedBody) - if string(w.body) != expectedResponseBody { - t.Fatalf("unexpected response body %q. Expecting %q", string(w.body), expectedResponseBody) - } + utils.AssertEqual(t, expectedResponseBody, string(w.body), "Body") } func setFiberContextValueMiddleware(next fiber.Handler, key string, value interface{}) fiber.Handler { @@ -387,16 +307,9 @@ func Test_FiberHandler_RequestNilBody(t *testing.T) { callsCount := 0 fiberH := func(c *fiber.Ctx) error { callsCount++ - if c.Method() != expectedMethod { - t.Fatalf("unexpected method %q. Expecting %q", c.Method(), expectedMethod) - } - if string(c.Request().RequestURI()) != expectedRequestURI { - t.Fatalf("unexpected requestURI %q. Expecting %q", string(c.Request().RequestURI()), expectedRequestURI) - } - contentLength := c.Request().Header.ContentLength() - if contentLength != expectedContentLength { - t.Fatalf("unexpected contentLength %d. Expecting %d", contentLength, expectedContentLength) - } + utils.AssertEqual(t, expectedMethod, c.Method(), "Method") + utils.AssertEqual(t, expectedRequestURI, string(c.Context().RequestURI()), "RequestURI") + utils.AssertEqual(t, expectedContentLength, c.Context().Request.Header.ContentLength(), "ContentLength") _, err := c.Write([]byte("request body is nil")) return err @@ -412,9 +325,7 @@ func Test_FiberHandler_RequestNilBody(t *testing.T) { nethttpH.ServeHTTP(&w, &r) expectedResponseBody := "request body is nil" - if string(w.body) != expectedResponseBody { - t.Fatalf("unexpected response body %q. Expecting %q", string(w.body), expectedResponseBody) - } + utils.AssertEqual(t, expectedResponseBody, string(w.body), "Body") } type netHTTPBody struct { diff --git a/middleware/favicon/favicon_test.go b/middleware/favicon/favicon_test.go index 6c8c9db723..f7837e3daa 100644 --- a/middleware/favicon/favicon_test.go +++ b/middleware/favicon/favicon_test.go @@ -102,9 +102,7 @@ func Test_Custom_Favicon_Url(t *testing.T) { // go test -run Test_Custom_Favicon_Data func Test_Custom_Favicon_Data(t *testing.T) { data, err := os.ReadFile("../../.github/testdata/favicon.ico") - if err != nil { - t.Fatal(err) - } + utils.AssertEqual(t, nil, err) app := fiber.New() diff --git a/middleware/session/session_test.go b/middleware/session/session_test.go index db11cb4a49..fd1c686ace 100644 --- a/middleware/session/session_test.go +++ b/middleware/session/session_test.go @@ -496,9 +496,8 @@ func Test_Session_Regenerate(t *testing.T) { err = acquiredSession.Regenerate() utils.AssertEqual(t, nil, err) - if acquiredSession.ID() == originalSessionUUIDString { - t.Fatal("regenerate should generate another different id") - } + utils.AssertEqual(t, false, acquiredSession.ID() == originalSessionUUIDString) + // acquiredSession.fresh should be true after regenerating utils.AssertEqual(t, true, acquiredSession.Fresh()) }) diff --git a/middleware/session/store_test.go b/middleware/session/store_test.go index c7e435f6ae..06c45f9b10 100644 --- a/middleware/session/store_test.go +++ b/middleware/session/store_test.go @@ -82,8 +82,6 @@ func TestStore_Get(t *testing.T) { acquiredSession, err := store.Get(ctx) utils.AssertEqual(t, err, nil) - if acquiredSession.ID() != unexpectedID { - t.Fatal("server should not accept the unexpectedID which is not in the store") - } + utils.AssertEqual(t, unexpectedID, acquiredSession.ID()) }) } From fa887332189ea9dc0bec8c33be5cefe9e7c817ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Thu, 28 Sep 2023 15:40:59 +0300 Subject: [PATCH 49/84] :bug: bug: fix PassLocalsToView when bind parameter is nil (#2651) * :bug: bug: fix PassLocalsToView when bind parameter is nil * fix linter --- ctx.go | 5 +++++ ctx_test.go | 40 +++++++++++++++++++++------------------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/ctx.go b/ctx.go index 880113d5f2..e03b240699 100644 --- a/ctx.go +++ b/ctx.go @@ -1505,6 +1505,11 @@ func (c *Ctx) Render(name string, bind interface{}, layouts ...string) error { buf := bytebufferpool.Get() defer bytebufferpool.Put(buf) + // Initialize empty bind map if bind is nil + if bind == nil { + bind = make(Map) + } + // Pass-locals-to-views, bind, appListKeys c.renderExtensions(bind) diff --git a/ctx_test.go b/ctx_test.go index 10fcc4f5ad..3eaaaf6091 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -3136,10 +3136,6 @@ func Test_Ctx_Render(t *testing.T) { }) utils.AssertEqual(t, nil, err) - buf := bytebufferpool.Get() - _, _ = buf.WriteString("overwrite") //nolint:errcheck // This will never fail - defer bytebufferpool.Put(buf) - utils.AssertEqual(t, "

Hello, World!

", string(c.Response().Body())) err = c.Render("./.github/testdata/template-non-exists.html", nil) @@ -3155,16 +3151,12 @@ func Test_Ctx_RenderWithoutLocals(t *testing.T) { PassLocalsToViews: false, }) c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) c.Locals("Title", "Hello, World!") - defer app.ReleaseCtx(c) + err := c.Render("./.github/testdata/index.tmpl", Map{}) utils.AssertEqual(t, nil, err) - - buf := bytebufferpool.Get() - _, _ = buf.WriteString("overwrite") //nolint:errcheck // This will never fail - defer bytebufferpool.Put(buf) - utils.AssertEqual(t, "

", string(c.Response().Body())) } @@ -3173,18 +3165,28 @@ func Test_Ctx_RenderWithLocals(t *testing.T) { app := New(Config{ PassLocalsToViews: true, }) - c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Locals("Title", "Hello, World!") - defer app.ReleaseCtx(c) - err := c.Render("./.github/testdata/index.tmpl", Map{}) - utils.AssertEqual(t, nil, err) + t.Run("EmptyBind", func(t *testing.T) { + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) - buf := bytebufferpool.Get() - _, _ = buf.WriteString("overwrite") //nolint:errcheck // This will never fail - defer bytebufferpool.Put(buf) + c.Locals("Title", "Hello, World!") + err := c.Render("./.github/testdata/index.tmpl", Map{}) - utils.AssertEqual(t, "

Hello, World!

", string(c.Response().Body())) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, "

Hello, World!

", string(c.Response().Body())) + }) + + t.Run("NilBind", func(t *testing.T) { + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + + c.Locals("Title", "Hello, World!") + err := c.Render("./.github/testdata/index.tmpl", nil) + + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, "

Hello, World!

", string(c.Response().Body())) + }) } func Test_Ctx_RenderWithBind(t *testing.T) { From d86c257c89fc320fdb95e4e2d0b9f35842106dda Mon Sep 17 00:00:00 2001 From: KaptinLin Date: Mon, 2 Oct 2023 21:19:18 +0800 Subject: [PATCH 50/84] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20Delete=20method?= =?UTF-8?q?=20to=20Store=20struct=20in=20session=20middleware=20(#2655)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ feat: add Delete method to Store struct in session middleware * ♻ refactor: enhance Delete method and test cases in session middleware --- docs/api/middleware/session.md | 1 + middleware/session/store.go | 12 ++++++++++++ middleware/session/store_test.go | 31 +++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/docs/api/middleware/session.md b/docs/api/middleware/session.md index 65d23681e7..08b115cb75 100644 --- a/docs/api/middleware/session.md +++ b/docs/api/middleware/session.md @@ -16,6 +16,7 @@ This middleware uses our [Storage](https://github.com/gofiber/storage) package t func New(config ...Config) *Store func (s *Store) RegisterType(i interface{}) func (s *Store) Get(c *fiber.Ctx) (*Session, error) +func (s *Store) Delete(id string) error func (s *Store) Reset() error func (s *Session) Get(key string) interface{} diff --git a/middleware/session/store.go b/middleware/session/store.go index bda5db7f45..f0c84f0653 100644 --- a/middleware/session/store.go +++ b/middleware/session/store.go @@ -2,6 +2,7 @@ package session import ( "encoding/gob" + "errors" "fmt" "sync" @@ -12,6 +13,9 @@ import ( "github.com/valyala/fasthttp" ) +// ErrEmptySessionID is an error that occurs when the session ID is empty. +var ErrEmptySessionID = errors.New("session id cannot be empty") + type Store struct { Config } @@ -140,3 +144,11 @@ func (s *Store) responseCookies(c *fiber.Ctx) (string, error) { func (s *Store) Reset() error { return s.Storage.Reset() } + +// Delete deletes a session by its id. +func (s *Store) Delete(id string) error { + if id == "" { + return ErrEmptySessionID + } + return s.Storage.Delete(id) +} diff --git a/middleware/session/store_test.go b/middleware/session/store_test.go index 06c45f9b10..fbc6e846b0 100644 --- a/middleware/session/store_test.go +++ b/middleware/session/store_test.go @@ -85,3 +85,34 @@ func TestStore_Get(t *testing.T) { utils.AssertEqual(t, unexpectedID, acquiredSession.ID()) }) } + +// go test -run TestStore_DeleteSession +func TestStore_DeleteSession(t *testing.T) { + t.Parallel() + // fiber instance + app := fiber.New() + // session store + store := New() + + // fiber context + ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(ctx) + + // Create a new session + session, err := store.Get(ctx) + utils.AssertEqual(t, err, nil) + + // Save the session ID + sessionID := session.ID() + + // Delete the session + err = store.Delete(sessionID) + utils.AssertEqual(t, err, nil) + + // Try to get the session again + session, err = store.Get(ctx) + utils.AssertEqual(t, err, nil) + + // The session ID should be different now, because the old session was deleted + utils.AssertEqual(t, session.ID() == sessionID, false) +} From d00f0b834830f7d57f194e59519f3604201e5068 Mon Sep 17 00:00:00 2001 From: KaptinLin Date: Mon, 2 Oct 2023 21:19:35 +0800 Subject: [PATCH 51/84] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20Reset=20method?= =?UTF-8?q?=20to=20Session=20struct=20in=20session=20middleware=20(#2654)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/api/middleware/session.md | 1 + middleware/session/session.go | 27 +++++++++++ middleware/session/session_test.go | 77 ++++++++++++++++++++++++++++-- 3 files changed, 101 insertions(+), 4 deletions(-) diff --git a/docs/api/middleware/session.md b/docs/api/middleware/session.md index 08b115cb75..631599598c 100644 --- a/docs/api/middleware/session.md +++ b/docs/api/middleware/session.md @@ -23,6 +23,7 @@ func (s *Session) Get(key string) interface{} func (s *Session) Set(key string, val interface{}) func (s *Session) Delete(key string) func (s *Session) Destroy() error +func (s *Session) Reset() error func (s *Session) Regenerate() error func (s *Session) Save() error func (s *Session) Fresh() bool diff --git a/middleware/session/session.go b/middleware/session/session.go index fab7e4867b..ebe00f6057 100644 --- a/middleware/session/session.go +++ b/middleware/session/session.go @@ -125,6 +125,33 @@ func (s *Session) Regenerate() error { return nil } +// Reset generates a new session id, deletes the old one from storage, and resets the associated data +func (s *Session) Reset() error { + // Reset local data + if s.data != nil { + s.data.Reset() + } + // Reset byte buffer + if s.byteBuffer != nil { + s.byteBuffer.Reset() + } + // Reset expiration + s.exp = 0 + + // Delete old id from storage + if err := s.config.Storage.Delete(s.id); err != nil { + return err + } + + // Expire session + s.delSession() + + // Generate a new session, and set session.fresh to true + s.refresh() + + return nil +} + // refresh generates a new session, and set session.fresh to be true func (s *Session) refresh() { // Create a new id diff --git a/middleware/session/session_test.go b/middleware/session/session_test.go index fd1c686ace..5fdad00472 100644 --- a/middleware/session/session_test.go +++ b/middleware/session/session_test.go @@ -324,11 +324,11 @@ func Test_Session_Save_Expiration(t *testing.T) { }) } -// go test -run Test_Session_Reset -func Test_Session_Reset(t *testing.T) { +// go test -run Test_Session_Destroy +func Test_Session_Destroy(t *testing.T) { t.Parallel() - t.Run("reset from cookie", func(t *testing.T) { + t.Run("destroy from cookie", func(t *testing.T) { t.Parallel() // session store store := New() @@ -347,7 +347,7 @@ func Test_Session_Reset(t *testing.T) { utils.AssertEqual(t, nil, name) }) - t.Run("reset from header", func(t *testing.T) { + t.Run("destroy from header", func(t *testing.T) { t.Parallel() // session store store := New(Config{ @@ -461,6 +461,75 @@ func Test_Session_Deletes_Single_Key(t *testing.T) { utils.AssertEqual(t, nil, sess.Get("id")) } +// go test -run Test_Session_Reset +func Test_Session_Reset(t *testing.T) { + t.Parallel() + // fiber instance + app := fiber.New() + + // session store + store := New() + + // fiber context + ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(ctx) + + t.Run("reset session data and id, and set fresh to be true", func(t *testing.T) { + // a random session uuid + originalSessionUUIDString := "" + + // now the session is in the storage + freshSession, err := store.Get(ctx) + utils.AssertEqual(t, nil, err) + + originalSessionUUIDString = freshSession.ID() + + // set a value + freshSession.Set("name", "fenny") + freshSession.Set("email", "fenny@example.com") + + err = freshSession.Save() + utils.AssertEqual(t, nil, err) + + // set cookie + ctx.Request().Header.SetCookie(store.sessionName, originalSessionUUIDString) + + // as the session is in the storage, session.fresh should be false + acquiredSession, err := store.Get(ctx) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, false, acquiredSession.Fresh()) + + err = acquiredSession.Reset() + utils.AssertEqual(t, nil, err) + + utils.AssertEqual(t, false, acquiredSession.ID() == originalSessionUUIDString) + + // acquiredSession.fresh should be true after resetting + utils.AssertEqual(t, true, acquiredSession.Fresh()) + + // Check that the session data has been reset + keys := acquiredSession.Keys() + utils.AssertEqual(t, []string{}, keys) + + // Set a new value for 'name' and check that it's updated + acquiredSession.Set("name", "john") + utils.AssertEqual(t, "john", acquiredSession.Get("name")) + utils.AssertEqual(t, nil, acquiredSession.Get("email")) + + // Save after resetting + err = acquiredSession.Save() + utils.AssertEqual(t, nil, err) + + // 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))) + }) +} + // go test -run Test_Session_Regenerate // Regression: https://github.com/gofiber/fiber/issues/1395 func Test_Session_Regenerate(t *testing.T) { From 5171f6b5057a92ceec46db93f11723c7f6b8857a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Thu, 5 Oct 2023 09:00:11 +0200 Subject: [PATCH 52/84] improve compress middleware documentation --- docs/api/middleware/compress.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api/middleware/compress.md b/docs/api/middleware/compress.md index f284f5e92c..472f9d9804 100644 --- a/docs/api/middleware/compress.md +++ b/docs/api/middleware/compress.md @@ -6,6 +6,10 @@ id: compress Compression middleware for [Fiber](https://github.com/gofiber/fiber) that will compress the response using `gzip`, `deflate` and `brotli` compression depending on the [Accept-Encoding](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding) header. +:::note +The compression middleware refrains from compressing bodies that are smaller than 200 bytes. This decision is based on the observation that, in such cases, the compressed size is likely to exceed the original size, making compression inefficient. [more](https://github.com/valyala/fasthttp/blob/497922a21ef4b314f393887e9c6147b8c3e3eda4/http.go#L1713-L1715) +::: + ## Signatures ```go From 9230be3649d0e0c8612cf907b92901541467a1a4 Mon Sep 17 00:00:00 2001 From: Tiago Peczenyj Date: Thu, 5 Oct 2023 10:09:29 +0200 Subject: [PATCH 53/84] Fix jsonp ignoring custom json encoder (#2658) * add unit test to trigger the bug #2675 * implement solution --- ctx.go | 5 ++-- ctx_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/ctx.go b/ctx.go index e03b240699..3d19a45fbf 100644 --- a/ctx.go +++ b/ctx.go @@ -8,7 +8,6 @@ import ( "bytes" "context" "crypto/tls" - "encoding/json" "encoding/xml" "errors" "fmt" @@ -863,9 +862,9 @@ func (c *Ctx) JSON(data interface{}) error { // This method is identical to JSON, except that it opts-in to JSONP callback support. // By default, the callback name is simply callback. func (c *Ctx) JSONP(data interface{}, callback ...string) error { - raw, err := json.Marshal(data) + raw, err := c.app.config.JSONEncoder(data) if err != nil { - return fmt.Errorf("failed to marshal: %w", err) + return err } var result, cb string diff --git a/ctx_test.go b/ctx_test.go index 3eaaaf6091..d8edea0e9e 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -2771,6 +2771,26 @@ func Test_Ctx_JSON(t *testing.T) { testEmpty("", `""`) testEmpty(0, "0") testEmpty([]int{}, "[]") + + t.Run("custom json encoder", func(t *testing.T) { + t.Parallel() + + app := New(Config{ + JSONEncoder: func(v interface{}) ([]byte, error) { + return []byte(`["custom","json"]`), nil + }, + }) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + + err := c.JSON(Map{ // map has no order + "Name": "Grame", + "Age": 20, + }) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, `["custom","json"]`, string(c.Response().Body())) + utils.AssertEqual(t, "application/json", string(c.Response().Header.Peek("content-type"))) + }) } // go test -run=^$ -bench=Benchmark_Ctx_JSON -benchmem -count=4 @@ -2820,6 +2840,26 @@ func Test_Ctx_JSONP(t *testing.T) { utils.AssertEqual(t, nil, err) utils.AssertEqual(t, `john({"Age":20,"Name":"Grame"});`, string(c.Response().Body())) utils.AssertEqual(t, "text/javascript; charset=utf-8", string(c.Response().Header.Peek("content-type"))) + + t.Run("custom json encoder", func(t *testing.T) { + t.Parallel() + + app := New(Config{ + JSONEncoder: func(v interface{}) ([]byte, error) { + return []byte(`["custom","json"]`), nil + }, + }) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + + err := c.JSONP(Map{ // map has no order + "Name": "Grame", + "Age": 20, + }) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, `callback(["custom","json"]);`, string(c.Response().Body())) + utils.AssertEqual(t, "text/javascript; charset=utf-8", string(c.Response().Header.Peek("content-type"))) + }) } // go test -v -run=^$ -bench=Benchmark_Ctx_JSONP -benchmem -count=4 @@ -2879,6 +2919,33 @@ func Test_Ctx_XML(t *testing.T) { testEmpty("", ``) testEmpty(0, "0") testEmpty([]int{}, "") + + t.Run("custom xml encoder", func(t *testing.T) { + t.Parallel() + + app := New(Config{ + XMLEncoder: func(v interface{}) ([]byte, error) { + return []byte(`xml`), nil + }, + }) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + + type xmlResult struct { + XMLName xml.Name `xml:"Users"` + Names []string `xml:"Names"` + Ages []int `xml:"Ages"` + } + + err := c.XML(xmlResult{ + Names: []string{"Grame", "John"}, + Ages: []int{1, 12, 20}, + }) + + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, `xml`, string(c.Response().Body())) + utils.AssertEqual(t, "application/xml", string(c.Response().Header.Peek("content-type"))) + }) } // go test -run=^$ -bench=Benchmark_Ctx_XML -benchmem -count=4 From d25dfa4ce7ff547da20cba4c8fe12dcf0e68f93d Mon Sep 17 00:00:00 2001 From: Tiago Peczenyj Date: Thu, 5 Oct 2023 12:24:59 +0200 Subject: [PATCH 54/84] apply go fix ./... with latest version of go in repository (#2661) apply go fix ./... --- internal/go-ole/com.go | 1 - internal/go-ole/com_func.go | 1 - internal/go-ole/error_func.go | 1 - internal/go-ole/error_windows.go | 1 - internal/go-ole/iconnectionpoint_func.go | 1 - internal/go-ole/iconnectionpoint_windows.go | 1 - internal/go-ole/iconnectionpointcontainer_func.go | 1 - internal/go-ole/iconnectionpointcontainer_windows.go | 1 - internal/go-ole/idispatch_func.go | 1 - internal/go-ole/idispatch_windows.go | 1 - internal/go-ole/ienumvariant_func.go | 1 - internal/go-ole/ienumvariant_windows.go | 1 - internal/go-ole/iinspectable_func.go | 1 - internal/go-ole/iinspectable_windows.go | 1 - internal/go-ole/iprovideclassinfo_func.go | 1 - internal/go-ole/iprovideclassinfo_windows.go | 1 - internal/go-ole/itypeinfo_func.go | 1 - internal/go-ole/itypeinfo_windows.go | 1 - internal/go-ole/iunknown_func.go | 1 - internal/go-ole/iunknown_windows.go | 1 - internal/go-ole/oleutil/connection.go | 1 - internal/go-ole/oleutil/connection_func.go | 1 - internal/go-ole/oleutil/connection_windows.go | 1 - internal/go-ole/oleutil/go-get.go | 1 - internal/go-ole/safearray_func.go | 1 - internal/go-ole/safearray_windows.go | 1 - internal/go-ole/safearrayslices.go | 1 - internal/go-ole/variables.go | 1 - internal/go-ole/variant32.go | 1 - internal/go-ole/variant64.go | 1 - internal/go-ole/variant_date_386.go | 1 - internal/go-ole/variant_date_amd64.go | 1 - internal/go-ole/winrt.go | 1 - internal/go-ole/winrt_doc.go | 1 - internal/gopsutil/common/common_darwin.go | 1 - internal/gopsutil/common/common_freebsd.go | 1 - internal/gopsutil/common/common_linux.go | 1 - internal/gopsutil/common/common_openbsd.go | 1 - internal/gopsutil/common/common_unix.go | 1 - internal/gopsutil/common/common_windows.go | 1 - internal/gopsutil/cpu/cpu_darwin.go | 1 - internal/gopsutil/cpu/cpu_darwin_cgo.go | 1 - internal/gopsutil/cpu/cpu_darwin_nocgo.go | 1 - internal/gopsutil/cpu/cpu_fallback.go | 1 - internal/gopsutil/cpu/cpu_linux.go | 1 - internal/gopsutil/cpu/cpu_openbsd.go | 1 - internal/gopsutil/cpu/cpu_windows.go | 1 - internal/gopsutil/load/load_bsd.go | 1 - internal/gopsutil/load/load_darwin.go | 1 - internal/gopsutil/load/load_fallback.go | 1 - internal/gopsutil/load/load_freebsd.go | 1 - internal/gopsutil/load/load_linux.go | 1 - internal/gopsutil/load/load_openbsd.go | 1 - internal/gopsutil/load/load_solaris.go | 1 - internal/gopsutil/load/load_windows.go | 1 - internal/gopsutil/mem/mem_darwin.go | 1 - internal/gopsutil/mem/mem_darwin_cgo.go | 1 - internal/gopsutil/mem/mem_darwin_nocgo.go | 1 - internal/gopsutil/mem/mem_fallback.go | 1 - internal/gopsutil/mem/mem_freebsd.go | 1 - internal/gopsutil/mem/mem_linux.go | 1 - internal/gopsutil/mem/mem_openbsd.go | 1 - internal/gopsutil/mem/mem_openbsd_386.go | 1 - internal/gopsutil/mem/mem_windows.go | 1 - internal/gopsutil/mem/types_openbsd.go | 1 - internal/gopsutil/net/net_aix.go | 1 - internal/gopsutil/net/net_darwin.go | 1 - internal/gopsutil/net/net_fallback.go | 1 - internal/gopsutil/net/net_freebsd.go | 1 - internal/gopsutil/net/net_linux.go | 1 - internal/gopsutil/net/net_openbsd.go | 1 - internal/gopsutil/net/net_unix.go | 1 - internal/gopsutil/net/net_windows.go | 1 - internal/gopsutil/process/process_darwin.go | 1 - internal/gopsutil/process/process_darwin_arm64.go | 1 - internal/gopsutil/process/process_darwin_cgo.go | 1 - internal/gopsutil/process/process_darwin_nocgo.go | 1 - internal/gopsutil/process/process_fallback.go | 1 - internal/gopsutil/process/process_freebsd.go | 1 - internal/gopsutil/process/process_freebsd_arm64.go | 1 - internal/gopsutil/process/process_linux.go | 1 - internal/gopsutil/process/process_openbsd.go | 1 - internal/gopsutil/process/process_openbsd_386.go | 1 - internal/gopsutil/process/process_posix.go | 1 - internal/gopsutil/process/process_windows.go | 1 - internal/gopsutil/process/process_windows_386.go | 1 - internal/gopsutil/process/process_windows_amd64.go | 1 - internal/gopsutil/process/types_darwin.go | 1 - internal/gopsutil/process/types_freebsd.go | 1 - internal/gopsutil/process/types_openbsd.go | 1 - utils/convert_b2s_new.go | 1 - utils/convert_b2s_old.go | 1 - utils/convert_s2b_new.go | 1 - utils/convert_s2b_old.go | 1 - 94 files changed, 94 deletions(-) diff --git a/internal/go-ole/com.go b/internal/go-ole/com.go index 6333441f91..34ba4ae6c4 100644 --- a/internal/go-ole/com.go +++ b/internal/go-ole/com.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/com_func.go b/internal/go-ole/com_func.go index 7b9fa67f3b..d6518bd49f 100644 --- a/internal/go-ole/com_func.go +++ b/internal/go-ole/com_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/error_func.go b/internal/go-ole/error_func.go index 6478b3390b..f7ef6a1ef0 100644 --- a/internal/go-ole/error_func.go +++ b/internal/go-ole/error_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/error_windows.go b/internal/go-ole/error_windows.go index 8da277c05d..19a9dbe458 100644 --- a/internal/go-ole/error_windows.go +++ b/internal/go-ole/error_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/iconnectionpoint_func.go b/internal/go-ole/iconnectionpoint_func.go index 999720a0d4..f71b9057a8 100644 --- a/internal/go-ole/iconnectionpoint_func.go +++ b/internal/go-ole/iconnectionpoint_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/iconnectionpoint_windows.go b/internal/go-ole/iconnectionpoint_windows.go index c7325ad0b1..5e0a01c3c7 100644 --- a/internal/go-ole/iconnectionpoint_windows.go +++ b/internal/go-ole/iconnectionpoint_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/iconnectionpointcontainer_func.go b/internal/go-ole/iconnectionpointcontainer_func.go index 26e264d1b6..83f086491f 100644 --- a/internal/go-ole/iconnectionpointcontainer_func.go +++ b/internal/go-ole/iconnectionpointcontainer_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/iconnectionpointcontainer_windows.go b/internal/go-ole/iconnectionpointcontainer_windows.go index 8b090f49e3..9e21dbe756 100644 --- a/internal/go-ole/iconnectionpointcontainer_windows.go +++ b/internal/go-ole/iconnectionpointcontainer_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/idispatch_func.go b/internal/go-ole/idispatch_func.go index 5315505ae4..c082074c06 100644 --- a/internal/go-ole/idispatch_func.go +++ b/internal/go-ole/idispatch_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/idispatch_windows.go b/internal/go-ole/idispatch_windows.go index 827275db1e..d4f5058bd0 100644 --- a/internal/go-ole/idispatch_windows.go +++ b/internal/go-ole/idispatch_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/ienumvariant_func.go b/internal/go-ole/ienumvariant_func.go index f332e439b7..b487d0f156 100644 --- a/internal/go-ole/ienumvariant_func.go +++ b/internal/go-ole/ienumvariant_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/ienumvariant_windows.go b/internal/go-ole/ienumvariant_windows.go index 72e5f31d6e..3dc273ef91 100644 --- a/internal/go-ole/ienumvariant_windows.go +++ b/internal/go-ole/ienumvariant_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/iinspectable_func.go b/internal/go-ole/iinspectable_func.go index cf0fba0dcb..49718ac97d 100644 --- a/internal/go-ole/iinspectable_func.go +++ b/internal/go-ole/iinspectable_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/iinspectable_windows.go b/internal/go-ole/iinspectable_windows.go index 9a686d256c..bf98a36bc9 100644 --- a/internal/go-ole/iinspectable_windows.go +++ b/internal/go-ole/iinspectable_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/iprovideclassinfo_func.go b/internal/go-ole/iprovideclassinfo_func.go index 90109f5576..6f94dd8c73 100644 --- a/internal/go-ole/iprovideclassinfo_func.go +++ b/internal/go-ole/iprovideclassinfo_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/iprovideclassinfo_windows.go b/internal/go-ole/iprovideclassinfo_windows.go index c758acd9bd..aab9c5f676 100644 --- a/internal/go-ole/iprovideclassinfo_windows.go +++ b/internal/go-ole/iprovideclassinfo_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/itypeinfo_func.go b/internal/go-ole/itypeinfo_func.go index 31c0677c6d..c82cdb9a8b 100644 --- a/internal/go-ole/itypeinfo_func.go +++ b/internal/go-ole/itypeinfo_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/itypeinfo_windows.go b/internal/go-ole/itypeinfo_windows.go index 2abab82140..b7ac77268d 100644 --- a/internal/go-ole/itypeinfo_windows.go +++ b/internal/go-ole/itypeinfo_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/iunknown_func.go b/internal/go-ole/iunknown_func.go index 247fccb3c9..875263013d 100644 --- a/internal/go-ole/iunknown_func.go +++ b/internal/go-ole/iunknown_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/iunknown_windows.go b/internal/go-ole/iunknown_windows.go index faf9c4c7fd..e948d60629 100644 --- a/internal/go-ole/iunknown_windows.go +++ b/internal/go-ole/iunknown_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/oleutil/connection.go b/internal/go-ole/oleutil/connection.go index a3e3b3619d..ef2f42aa0f 100644 --- a/internal/go-ole/oleutil/connection.go +++ b/internal/go-ole/oleutil/connection.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package oleutil diff --git a/internal/go-ole/oleutil/connection_func.go b/internal/go-ole/oleutil/connection_func.go index 43990ecd72..612a5830f4 100644 --- a/internal/go-ole/oleutil/connection_func.go +++ b/internal/go-ole/oleutil/connection_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package oleutil diff --git a/internal/go-ole/oleutil/connection_windows.go b/internal/go-ole/oleutil/connection_windows.go index 41d7cf6141..0f93ba3c33 100644 --- a/internal/go-ole/oleutil/connection_windows.go +++ b/internal/go-ole/oleutil/connection_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package oleutil diff --git a/internal/go-ole/oleutil/go-get.go b/internal/go-ole/oleutil/go-get.go index 40bd9ff61b..af6a903efc 100644 --- a/internal/go-ole/oleutil/go-get.go +++ b/internal/go-ole/oleutil/go-get.go @@ -2,6 +2,5 @@ // no buildable Go source files in ... // //go:build !windows -// +build !windows package oleutil diff --git a/internal/go-ole/safearray_func.go b/internal/go-ole/safearray_func.go index afb1d02d5e..1bbe4ab80a 100644 --- a/internal/go-ole/safearray_func.go +++ b/internal/go-ole/safearray_func.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/go-ole/safearray_windows.go b/internal/go-ole/safearray_windows.go index 0a322f5da5..f3292d7bd4 100644 --- a/internal/go-ole/safearray_windows.go +++ b/internal/go-ole/safearray_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/safearrayslices.go b/internal/go-ole/safearrayslices.go index 063dbbfec6..0307587475 100644 --- a/internal/go-ole/safearrayslices.go +++ b/internal/go-ole/safearrayslices.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/variables.go b/internal/go-ole/variables.go index 056f844d9a..fe7a9a2771 100644 --- a/internal/go-ole/variables.go +++ b/internal/go-ole/variables.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/variant32.go b/internal/go-ole/variant32.go index 9d17d1f09e..2628428321 100644 --- a/internal/go-ole/variant32.go +++ b/internal/go-ole/variant32.go @@ -1,5 +1,4 @@ //go:build 386 || arm -// +build 386 arm package ole diff --git a/internal/go-ole/variant64.go b/internal/go-ole/variant64.go index 474adaad8e..9a0c248b61 100644 --- a/internal/go-ole/variant64.go +++ b/internal/go-ole/variant64.go @@ -1,5 +1,4 @@ //go:build amd64 || arm64 || ppc64le || s390x -// +build amd64 arm64 ppc64le s390x package ole diff --git a/internal/go-ole/variant_date_386.go b/internal/go-ole/variant_date_386.go index 8c3d3085fe..e5d1004084 100644 --- a/internal/go-ole/variant_date_386.go +++ b/internal/go-ole/variant_date_386.go @@ -1,5 +1,4 @@ //go:build windows && 386 -// +build windows,386 package ole diff --git a/internal/go-ole/variant_date_amd64.go b/internal/go-ole/variant_date_amd64.go index 8554d38d91..a6c279bc3d 100644 --- a/internal/go-ole/variant_date_amd64.go +++ b/internal/go-ole/variant_date_amd64.go @@ -1,5 +1,4 @@ //go:build windows && amd64 -// +build windows,amd64 package ole diff --git a/internal/go-ole/winrt.go b/internal/go-ole/winrt.go index f503d685f5..5aa33c29be 100644 --- a/internal/go-ole/winrt.go +++ b/internal/go-ole/winrt.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package ole diff --git a/internal/go-ole/winrt_doc.go b/internal/go-ole/winrt_doc.go index a392928d21..ec74e75dfd 100644 --- a/internal/go-ole/winrt_doc.go +++ b/internal/go-ole/winrt_doc.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package ole diff --git a/internal/gopsutil/common/common_darwin.go b/internal/gopsutil/common/common_darwin.go index 3b2b8e0f40..ffc7576f12 100644 --- a/internal/gopsutil/common/common_darwin.go +++ b/internal/gopsutil/common/common_darwin.go @@ -1,5 +1,4 @@ //go:build darwin -// +build darwin package common diff --git a/internal/gopsutil/common/common_freebsd.go b/internal/gopsutil/common/common_freebsd.go index 2510f9deff..3364e34395 100644 --- a/internal/gopsutil/common/common_freebsd.go +++ b/internal/gopsutil/common/common_freebsd.go @@ -1,5 +1,4 @@ //go:build freebsd || openbsd -// +build freebsd openbsd package common diff --git a/internal/gopsutil/common/common_linux.go b/internal/gopsutil/common/common_linux.go index a89c8e28ac..6c0bb2bdaf 100644 --- a/internal/gopsutil/common/common_linux.go +++ b/internal/gopsutil/common/common_linux.go @@ -1,5 +1,4 @@ //go:build linux -// +build linux package common diff --git a/internal/gopsutil/common/common_openbsd.go b/internal/gopsutil/common/common_openbsd.go index cbd3d28f6b..262d430ee2 100644 --- a/internal/gopsutil/common/common_openbsd.go +++ b/internal/gopsutil/common/common_openbsd.go @@ -1,5 +1,4 @@ //go:build openbsd -// +build openbsd package common diff --git a/internal/gopsutil/common/common_unix.go b/internal/gopsutil/common/common_unix.go index a4a953a2f5..cbe32ef866 100644 --- a/internal/gopsutil/common/common_unix.go +++ b/internal/gopsutil/common/common_unix.go @@ -1,5 +1,4 @@ //go:build linux || freebsd || darwin || openbsd -// +build linux freebsd darwin openbsd package common diff --git a/internal/gopsutil/common/common_windows.go b/internal/gopsutil/common/common_windows.go index 5b450d3192..00db4c3d20 100644 --- a/internal/gopsutil/common/common_windows.go +++ b/internal/gopsutil/common/common_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package common diff --git a/internal/gopsutil/cpu/cpu_darwin.go b/internal/gopsutil/cpu/cpu_darwin.go index 455857d536..936f26fbda 100644 --- a/internal/gopsutil/cpu/cpu_darwin.go +++ b/internal/gopsutil/cpu/cpu_darwin.go @@ -1,5 +1,4 @@ //go:build darwin -// +build darwin package cpu diff --git a/internal/gopsutil/cpu/cpu_darwin_cgo.go b/internal/gopsutil/cpu/cpu_darwin_cgo.go index a71c7352ba..43c61c5417 100644 --- a/internal/gopsutil/cpu/cpu_darwin_cgo.go +++ b/internal/gopsutil/cpu/cpu_darwin_cgo.go @@ -1,5 +1,4 @@ //go:build darwin && cgo -// +build darwin,cgo package cpu diff --git a/internal/gopsutil/cpu/cpu_darwin_nocgo.go b/internal/gopsutil/cpu/cpu_darwin_nocgo.go index c93b45a257..b2eedef534 100644 --- a/internal/gopsutil/cpu/cpu_darwin_nocgo.go +++ b/internal/gopsutil/cpu/cpu_darwin_nocgo.go @@ -1,5 +1,4 @@ //go:build darwin && !cgo -// +build darwin,!cgo package cpu diff --git a/internal/gopsutil/cpu/cpu_fallback.go b/internal/gopsutil/cpu/cpu_fallback.go index e8e3750ab2..b4bd5f58ef 100644 --- a/internal/gopsutil/cpu/cpu_fallback.go +++ b/internal/gopsutil/cpu/cpu_fallback.go @@ -1,5 +1,4 @@ //go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows && !dragonfly -// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows,!dragonfly package cpu diff --git a/internal/gopsutil/cpu/cpu_linux.go b/internal/gopsutil/cpu/cpu_linux.go index 1a8120c257..e3f45641a4 100644 --- a/internal/gopsutil/cpu/cpu_linux.go +++ b/internal/gopsutil/cpu/cpu_linux.go @@ -1,5 +1,4 @@ //go:build linux -// +build linux package cpu diff --git a/internal/gopsutil/cpu/cpu_openbsd.go b/internal/gopsutil/cpu/cpu_openbsd.go index e373cf39b7..b924fb392e 100644 --- a/internal/gopsutil/cpu/cpu_openbsd.go +++ b/internal/gopsutil/cpu/cpu_openbsd.go @@ -1,5 +1,4 @@ //go:build openbsd -// +build openbsd package cpu diff --git a/internal/gopsutil/cpu/cpu_windows.go b/internal/gopsutil/cpu/cpu_windows.go index 2544ad4822..3a22fe1c9b 100644 --- a/internal/gopsutil/cpu/cpu_windows.go +++ b/internal/gopsutil/cpu/cpu_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package cpu diff --git a/internal/gopsutil/load/load_bsd.go b/internal/gopsutil/load/load_bsd.go index 20d00a5739..bdf979f6b3 100644 --- a/internal/gopsutil/load/load_bsd.go +++ b/internal/gopsutil/load/load_bsd.go @@ -1,5 +1,4 @@ //go:build freebsd || openbsd -// +build freebsd openbsd package load diff --git a/internal/gopsutil/load/load_darwin.go b/internal/gopsutil/load/load_darwin.go index 612d601019..959d861d53 100644 --- a/internal/gopsutil/load/load_darwin.go +++ b/internal/gopsutil/load/load_darwin.go @@ -1,5 +1,4 @@ //go:build darwin -// +build darwin package load diff --git a/internal/gopsutil/load/load_fallback.go b/internal/gopsutil/load/load_fallback.go index f8b1f72d01..d643d1f887 100644 --- a/internal/gopsutil/load/load_fallback.go +++ b/internal/gopsutil/load/load_fallback.go @@ -1,5 +1,4 @@ //go:build !darwin && !linux && !freebsd && !openbsd && !windows && !solaris -// +build !darwin,!linux,!freebsd,!openbsd,!windows,!solaris package load diff --git a/internal/gopsutil/load/load_freebsd.go b/internal/gopsutil/load/load_freebsd.go index 406980506f..a7011bad33 100644 --- a/internal/gopsutil/load/load_freebsd.go +++ b/internal/gopsutil/load/load_freebsd.go @@ -1,5 +1,4 @@ //go:build freebsd -// +build freebsd package load diff --git a/internal/gopsutil/load/load_linux.go b/internal/gopsutil/load/load_linux.go index 422e20075f..e9d95a9351 100644 --- a/internal/gopsutil/load/load_linux.go +++ b/internal/gopsutil/load/load_linux.go @@ -1,5 +1,4 @@ //go:build linux -// +build linux package load diff --git a/internal/gopsutil/load/load_openbsd.go b/internal/gopsutil/load/load_openbsd.go index 1d5d611f37..07353575b3 100644 --- a/internal/gopsutil/load/load_openbsd.go +++ b/internal/gopsutil/load/load_openbsd.go @@ -1,5 +1,4 @@ //go:build openbsd -// +build openbsd package load diff --git a/internal/gopsutil/load/load_solaris.go b/internal/gopsutil/load/load_solaris.go index 0db983fbcd..3dff4396e8 100644 --- a/internal/gopsutil/load/load_solaris.go +++ b/internal/gopsutil/load/load_solaris.go @@ -1,5 +1,4 @@ //go:build solaris -// +build solaris package load diff --git a/internal/gopsutil/load/load_windows.go b/internal/gopsutil/load/load_windows.go index 7c70bdbc0f..a51e507e47 100644 --- a/internal/gopsutil/load/load_windows.go +++ b/internal/gopsutil/load/load_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package load diff --git a/internal/gopsutil/mem/mem_darwin.go b/internal/gopsutil/mem/mem_darwin.go index ec2f58236b..f96030dec0 100644 --- a/internal/gopsutil/mem/mem_darwin.go +++ b/internal/gopsutil/mem/mem_darwin.go @@ -1,5 +1,4 @@ //go:build darwin -// +build darwin package mem diff --git a/internal/gopsutil/mem/mem_darwin_cgo.go b/internal/gopsutil/mem/mem_darwin_cgo.go index 82c38245b4..b2d53212c1 100644 --- a/internal/gopsutil/mem/mem_darwin_cgo.go +++ b/internal/gopsutil/mem/mem_darwin_cgo.go @@ -1,5 +1,4 @@ //go:build darwin && cgo -// +build darwin,cgo package mem diff --git a/internal/gopsutil/mem/mem_darwin_nocgo.go b/internal/gopsutil/mem/mem_darwin_nocgo.go index be926f291b..67d28d3d24 100644 --- a/internal/gopsutil/mem/mem_darwin_nocgo.go +++ b/internal/gopsutil/mem/mem_darwin_nocgo.go @@ -1,5 +1,4 @@ //go:build darwin && !cgo -// +build darwin,!cgo package mem diff --git a/internal/gopsutil/mem/mem_fallback.go b/internal/gopsutil/mem/mem_fallback.go index c1f7ae603a..b2b5856c14 100644 --- a/internal/gopsutil/mem/mem_fallback.go +++ b/internal/gopsutil/mem/mem_fallback.go @@ -1,5 +1,4 @@ //go:build !darwin && !linux && !freebsd && !openbsd && !solaris && !windows -// +build !darwin,!linux,!freebsd,!openbsd,!solaris,!windows package mem diff --git a/internal/gopsutil/mem/mem_freebsd.go b/internal/gopsutil/mem/mem_freebsd.go index 0682edb7cf..253bf9d594 100644 --- a/internal/gopsutil/mem/mem_freebsd.go +++ b/internal/gopsutil/mem/mem_freebsd.go @@ -1,5 +1,4 @@ //go:build freebsd -// +build freebsd package mem diff --git a/internal/gopsutil/mem/mem_linux.go b/internal/gopsutil/mem/mem_linux.go index a0fc7fd44c..fc994efb0f 100644 --- a/internal/gopsutil/mem/mem_linux.go +++ b/internal/gopsutil/mem/mem_linux.go @@ -1,5 +1,4 @@ //go:build linux -// +build linux package mem diff --git a/internal/gopsutil/mem/mem_openbsd.go b/internal/gopsutil/mem/mem_openbsd.go index 36858cb700..74414d81c0 100644 --- a/internal/gopsutil/mem/mem_openbsd.go +++ b/internal/gopsutil/mem/mem_openbsd.go @@ -1,5 +1,4 @@ //go:build openbsd -// +build openbsd package mem diff --git a/internal/gopsutil/mem/mem_openbsd_386.go b/internal/gopsutil/mem/mem_openbsd_386.go index de2b26ca40..77272f35d3 100644 --- a/internal/gopsutil/mem/mem_openbsd_386.go +++ b/internal/gopsutil/mem/mem_openbsd_386.go @@ -1,5 +1,4 @@ //go:build openbsd && 386 -// +build openbsd,386 // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs mem/types_openbsd.go diff --git a/internal/gopsutil/mem/mem_windows.go b/internal/gopsutil/mem/mem_windows.go index 42180c450d..bd126d3643 100644 --- a/internal/gopsutil/mem/mem_windows.go +++ b/internal/gopsutil/mem/mem_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package mem diff --git a/internal/gopsutil/mem/types_openbsd.go b/internal/gopsutil/mem/types_openbsd.go index 8e0e412af4..07ccbb2d58 100644 --- a/internal/gopsutil/mem/types_openbsd.go +++ b/internal/gopsutil/mem/types_openbsd.go @@ -1,5 +1,4 @@ //go:build ignore -// +build ignore /* Input to cgo -godefs. diff --git a/internal/gopsutil/net/net_aix.go b/internal/gopsutil/net/net_aix.go index cda6dc72ef..e7eabe716d 100644 --- a/internal/gopsutil/net/net_aix.go +++ b/internal/gopsutil/net/net_aix.go @@ -1,5 +1,4 @@ //go:build aix -// +build aix package net diff --git a/internal/gopsutil/net/net_darwin.go b/internal/gopsutil/net/net_darwin.go index a7e382dcbb..a4071594a0 100644 --- a/internal/gopsutil/net/net_darwin.go +++ b/internal/gopsutil/net/net_darwin.go @@ -1,5 +1,4 @@ //go:build darwin -// +build darwin package net diff --git a/internal/gopsutil/net/net_fallback.go b/internal/gopsutil/net/net_fallback.go index 03d151c752..e73295cc8e 100644 --- a/internal/gopsutil/net/net_fallback.go +++ b/internal/gopsutil/net/net_fallback.go @@ -1,5 +1,4 @@ //go:build !aix && !darwin && !linux && !freebsd && !openbsd && !windows -// +build !aix,!darwin,!linux,!freebsd,!openbsd,!windows package net diff --git a/internal/gopsutil/net/net_freebsd.go b/internal/gopsutil/net/net_freebsd.go index 3399597148..1c7430b585 100644 --- a/internal/gopsutil/net/net_freebsd.go +++ b/internal/gopsutil/net/net_freebsd.go @@ -1,5 +1,4 @@ //go:build freebsd -// +build freebsd package net diff --git a/internal/gopsutil/net/net_linux.go b/internal/gopsutil/net/net_linux.go index 964b053c73..ebc0b53b17 100644 --- a/internal/gopsutil/net/net_linux.go +++ b/internal/gopsutil/net/net_linux.go @@ -1,5 +1,4 @@ //go:build linux -// +build linux package net diff --git a/internal/gopsutil/net/net_openbsd.go b/internal/gopsutil/net/net_openbsd.go index 7e29f2ab9e..8a62a70b1d 100644 --- a/internal/gopsutil/net/net_openbsd.go +++ b/internal/gopsutil/net/net_openbsd.go @@ -1,5 +1,4 @@ //go:build openbsd -// +build openbsd package net diff --git a/internal/gopsutil/net/net_unix.go b/internal/gopsutil/net/net_unix.go index c912025e39..16085966b8 100644 --- a/internal/gopsutil/net/net_unix.go +++ b/internal/gopsutil/net/net_unix.go @@ -1,5 +1,4 @@ //go:build freebsd || darwin -// +build freebsd darwin package net diff --git a/internal/gopsutil/net/net_windows.go b/internal/gopsutil/net/net_windows.go index 947bf58232..c3883f66e2 100644 --- a/internal/gopsutil/net/net_windows.go +++ b/internal/gopsutil/net/net_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package net diff --git a/internal/gopsutil/process/process_darwin.go b/internal/gopsutil/process/process_darwin.go index 432b5175d9..fb795820e6 100644 --- a/internal/gopsutil/process/process_darwin.go +++ b/internal/gopsutil/process/process_darwin.go @@ -1,5 +1,4 @@ //go:build darwin -// +build darwin package process diff --git a/internal/gopsutil/process/process_darwin_arm64.go b/internal/gopsutil/process/process_darwin_arm64.go index 9696322ffa..8c13a22c0c 100644 --- a/internal/gopsutil/process/process_darwin_arm64.go +++ b/internal/gopsutil/process/process_darwin_arm64.go @@ -1,5 +1,4 @@ //go:build darwin && arm64 -// +build darwin,arm64 // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs process/types_darwin.go diff --git a/internal/gopsutil/process/process_darwin_cgo.go b/internal/gopsutil/process/process_darwin_cgo.go index 4033c282f1..10a743608d 100644 --- a/internal/gopsutil/process/process_darwin_cgo.go +++ b/internal/gopsutil/process/process_darwin_cgo.go @@ -1,5 +1,4 @@ //go:build darwin && cgo -// +build darwin,cgo package process diff --git a/internal/gopsutil/process/process_darwin_nocgo.go b/internal/gopsutil/process/process_darwin_nocgo.go index 94f12ced8b..1df55229a3 100644 --- a/internal/gopsutil/process/process_darwin_nocgo.go +++ b/internal/gopsutil/process/process_darwin_nocgo.go @@ -1,5 +1,4 @@ //go:build darwin && !cgo -// +build darwin,!cgo package process diff --git a/internal/gopsutil/process/process_fallback.go b/internal/gopsutil/process/process_fallback.go index 4db3394ba6..78455ca2b6 100644 --- a/internal/gopsutil/process/process_fallback.go +++ b/internal/gopsutil/process/process_fallback.go @@ -1,5 +1,4 @@ //go:build !darwin && !linux && !freebsd && !openbsd && !windows -// +build !darwin,!linux,!freebsd,!openbsd,!windows package process diff --git a/internal/gopsutil/process/process_freebsd.go b/internal/gopsutil/process/process_freebsd.go index 827165d531..49690cdd72 100644 --- a/internal/gopsutil/process/process_freebsd.go +++ b/internal/gopsutil/process/process_freebsd.go @@ -1,5 +1,4 @@ //go:build freebsd -// +build freebsd package process diff --git a/internal/gopsutil/process/process_freebsd_arm64.go b/internal/gopsutil/process/process_freebsd_arm64.go index effd470a0c..c83fa7c274 100644 --- a/internal/gopsutil/process/process_freebsd_arm64.go +++ b/internal/gopsutil/process/process_freebsd_arm64.go @@ -1,5 +1,4 @@ //go:build freebsd && arm64 -// +build freebsd,arm64 // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs process/types_freebsd.go diff --git a/internal/gopsutil/process/process_linux.go b/internal/gopsutil/process/process_linux.go index 05d3e7ab26..67ca0f7b43 100644 --- a/internal/gopsutil/process/process_linux.go +++ b/internal/gopsutil/process/process_linux.go @@ -1,5 +1,4 @@ //go:build linux -// +build linux package process diff --git a/internal/gopsutil/process/process_openbsd.go b/internal/gopsutil/process/process_openbsd.go index a985416c21..e65fea687c 100644 --- a/internal/gopsutil/process/process_openbsd.go +++ b/internal/gopsutil/process/process_openbsd.go @@ -1,5 +1,4 @@ //go:build openbsd -// +build openbsd package process diff --git a/internal/gopsutil/process/process_openbsd_386.go b/internal/gopsutil/process/process_openbsd_386.go index f4ed024917..7ac9067e97 100644 --- a/internal/gopsutil/process/process_openbsd_386.go +++ b/internal/gopsutil/process/process_openbsd_386.go @@ -1,5 +1,4 @@ //go:build openbsd && 386 -// +build openbsd,386 // Code generated by cmd/cgo -godefs; DO NOT EDIT. // cgo -godefs process/types_openbsd.go diff --git a/internal/gopsutil/process/process_posix.go b/internal/gopsutil/process/process_posix.go index ee09574c74..c319649df0 100644 --- a/internal/gopsutil/process/process_posix.go +++ b/internal/gopsutil/process/process_posix.go @@ -1,5 +1,4 @@ //go:build linux || freebsd || openbsd || darwin -// +build linux freebsd openbsd darwin package process diff --git a/internal/gopsutil/process/process_windows.go b/internal/gopsutil/process/process_windows.go index de576ec2a7..591c598f0a 100644 --- a/internal/gopsutil/process/process_windows.go +++ b/internal/gopsutil/process/process_windows.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package process diff --git a/internal/gopsutil/process/process_windows_386.go b/internal/gopsutil/process/process_windows_386.go index 8727ca2467..b9ef3c4b51 100644 --- a/internal/gopsutil/process/process_windows_386.go +++ b/internal/gopsutil/process/process_windows_386.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package process diff --git a/internal/gopsutil/process/process_windows_amd64.go b/internal/gopsutil/process/process_windows_amd64.go index 2ed97db94a..e7dd6c56e9 100644 --- a/internal/gopsutil/process/process_windows_amd64.go +++ b/internal/gopsutil/process/process_windows_amd64.go @@ -1,5 +1,4 @@ //go:build windows -// +build windows package process diff --git a/internal/gopsutil/process/types_darwin.go b/internal/gopsutil/process/types_darwin.go index 947dab44ad..0782b476d4 100644 --- a/internal/gopsutil/process/types_darwin.go +++ b/internal/gopsutil/process/types_darwin.go @@ -6,7 +6,6 @@ // - all pointer in ExternProc to uint64 //go:build ignore -// +build ignore /* Input to cgo -godefs. diff --git a/internal/gopsutil/process/types_freebsd.go b/internal/gopsutil/process/types_freebsd.go index 658d46166e..5ae6d01dc4 100644 --- a/internal/gopsutil/process/types_freebsd.go +++ b/internal/gopsutil/process/types_freebsd.go @@ -1,5 +1,4 @@ //go:build ignore -// +build ignore // We still need editing by hands. // go tool cgo -godefs types_freebsd.go | sed 's/\*int64/int64/' | sed 's/\*byte/int64/' > process_freebsd_amd64.go diff --git a/internal/gopsutil/process/types_openbsd.go b/internal/gopsutil/process/types_openbsd.go index 75f2344a9a..d55eec6b73 100644 --- a/internal/gopsutil/process/types_openbsd.go +++ b/internal/gopsutil/process/types_openbsd.go @@ -1,5 +1,4 @@ //go:build ignore -// +build ignore // We still need editing by hands. // go tool cgo -godefs types_openbsd.go | sed 's/\*int64/int64/' | sed 's/\*byte/int64/' > process_openbsd_amd64.go diff --git a/utils/convert_b2s_new.go b/utils/convert_b2s_new.go index 2a5b394cc9..3fcf7d5afa 100644 --- a/utils/convert_b2s_new.go +++ b/utils/convert_b2s_new.go @@ -1,5 +1,4 @@ //go:build go1.20 -// +build go1.20 package utils diff --git a/utils/convert_b2s_old.go b/utils/convert_b2s_old.go index e00be0ee89..36cbe30967 100644 --- a/utils/convert_b2s_old.go +++ b/utils/convert_b2s_old.go @@ -1,5 +1,4 @@ //go:build !go1.20 -// +build !go1.20 package utils diff --git a/utils/convert_s2b_new.go b/utils/convert_s2b_new.go index abe9a8e82a..5da5c81a61 100644 --- a/utils/convert_s2b_new.go +++ b/utils/convert_s2b_new.go @@ -1,5 +1,4 @@ //go:build go1.20 -// +build go1.20 package utils diff --git a/utils/convert_s2b_old.go b/utils/convert_s2b_old.go index e817dc3bee..c9435bd484 100644 --- a/utils/convert_s2b_old.go +++ b/utils/convert_s2b_old.go @@ -1,5 +1,4 @@ //go:build !go1.20 -// +build !go1.20 package utils From ab4e73160777e133d4307c6804011fc3ce9b4b12 Mon Sep 17 00:00:00 2001 From: Tiago Peczenyj Date: Thu, 5 Oct 2023 13:14:30 +0200 Subject: [PATCH 55/84] Run gofumpt and goimports (#2662) * run goimports -w -local github.com/gofiber/fiber . * run gofumpt -w -extra . --- internal/go-ole/com.go | 8 +-- internal/go-ole/com_func.go | 8 +-- internal/go-ole/connect.go | 4 +- internal/go-ole/guid.go | 10 ++-- internal/go-ole/idispatch_windows.go | 2 +- internal/go-ole/oleutil/connection.go | 2 +- internal/go-ole/safearray_func.go | 2 +- internal/go-ole/safearray_windows.go | 6 +-- internal/go-ole/utility.go | 2 +- internal/gopsutil/common/binary.go | 6 ++- internal/gopsutil/common/common.go | 3 +- internal/gopsutil/common/common_linux.go | 4 +- internal/gopsutil/common/common_windows.go | 5 +- internal/gopsutil/common/sleep.go | 2 +- internal/gopsutil/cpu/cpu.go | 6 ++- internal/gopsutil/cpu/cpu_darwin_cgo.go | 1 - internal/gopsutil/cpu/cpu_dragonfly.go | 21 ++++---- internal/gopsutil/cpu/cpu_freebsd.go | 23 ++++---- internal/gopsutil/cpu/cpu_linux.go | 4 +- internal/gopsutil/cpu/cpu_openbsd.go | 5 +- internal/gopsutil/cpu/cpu_solaris.go | 2 +- internal/gopsutil/cpu/cpu_windows.go | 3 +- internal/gopsutil/load/load.go | 3 +- internal/gopsutil/load/load_bsd.go | 3 +- internal/gopsutil/load/load_darwin.go | 3 +- internal/gopsutil/mem/mem_linux.go | 7 ++- internal/gopsutil/mem/mem_openbsd.go | 3 +- internal/gopsutil/mem/mem_windows.go | 3 +- internal/gopsutil/net/net.go | 3 +- internal/gopsutil/net/net_aix.go | 9 +--- internal/gopsutil/net/net_linux.go | 8 +-- internal/gopsutil/net/net_openbsd.go | 8 +-- internal/gopsutil/net/net_unix.go | 3 +- internal/gopsutil/net/net_windows.go | 22 +++++--- internal/gopsutil/process/process.go | 4 +- internal/gopsutil/process/process_darwin.go | 33 +++++++++--- .../gopsutil/process/process_darwin_cgo.go | 1 + internal/gopsutil/process/process_fallback.go | 39 +++++++++++++- internal/gopsutil/process/process_freebsd.go | 30 +++++++++-- internal/gopsutil/process/process_linux.go | 12 ++--- internal/gopsutil/process/process_openbsd.go | 39 ++++++++++---- internal/gopsutil/process/process_posix.go | 5 +- internal/gopsutil/process/process_windows.go | 53 +++++++++++------- .../gopsutil/process/process_windows_386.go | 20 +++---- .../gopsutil/process/process_windows_amd64.go | 6 +-- internal/gopsutil/process/types_darwin.go | 8 +-- internal/memory/memory_test.go | 3 +- internal/storage/memory/memory_test.go | 8 +-- internal/wmi/swbemservices.go | 54 +++++++++---------- internal/wmi/wmi.go | 2 +- listen.go | 3 +- middleware/adaptor/adaptor.go | 5 +- middleware/adaptor/adaptor_test.go | 3 +- path.go | 3 +- prefork.go | 3 +- 55 files changed, 333 insertions(+), 205 deletions(-) diff --git a/internal/go-ole/com.go b/internal/go-ole/com.go index 34ba4ae6c4..afc58cfa09 100644 --- a/internal/go-ole/com.go +++ b/internal/go-ole/com.go @@ -177,7 +177,7 @@ func StringFromIID(iid *GUID) (str string, err error) { } // CreateInstance of single uninitialized object with GUID. -func CreateInstance(clsid *GUID, iid *GUID) (unk *IUnknown, err error) { +func CreateInstance(clsid, iid *GUID) (unk *IUnknown, err error) { if iid == nil { iid = IID_IUnknown } @@ -194,7 +194,7 @@ func CreateInstance(clsid *GUID, iid *GUID) (unk *IUnknown, err error) { } // GetActiveObject retrieves pointer to active object. -func GetActiveObject(clsid *GUID, iid *GUID) (unk *IUnknown, err error) { +func GetActiveObject(clsid, iid *GUID) (unk *IUnknown, err error) { if iid == nil { iid = IID_IUnknown } @@ -316,7 +316,7 @@ func CreateDispTypeInfo(idata *INTERFACEDATA) (pptinfo *IUnknown, err error) { } // copyMemory moves location of a block of memory. -func copyMemory(dest unsafe.Pointer, src unsafe.Pointer, length uint32) { +func copyMemory(dest, src unsafe.Pointer, length uint32) { procCopyMemory.Call(uintptr(dest), uintptr(src), uintptr(length)) } @@ -330,7 +330,7 @@ func GetUserDefaultLCID() (lcid uint32) { // GetMessage in message queue from runtime. // // This function appears to block. PeekMessage does not block. -func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (ret int32, err error) { +func GetMessage(msg *Msg, hwnd, MsgFilterMin, MsgFilterMax uint32) (ret int32, err error) { r0, _, err := procGetMessageW.Call(uintptr(unsafe.Pointer(msg)), uintptr(hwnd), uintptr(MsgFilterMin), uintptr(MsgFilterMax)) ret = int32(r0) return diff --git a/internal/go-ole/com_func.go b/internal/go-ole/com_func.go index d6518bd49f..cc5f7b8802 100644 --- a/internal/go-ole/com_func.go +++ b/internal/go-ole/com_func.go @@ -92,12 +92,12 @@ func StringFromIID(iid *GUID) (string, error) { } // CreateInstance of single uninitialized object with GUID. -func CreateInstance(clsid *GUID, iid *GUID) (*IUnknown, error) { +func CreateInstance(clsid, iid *GUID) (*IUnknown, error) { return nil, NewError(E_NOTIMPL) } // GetActiveObject retrieves pointer to active object. -func GetActiveObject(clsid *GUID, iid *GUID) (*IUnknown, error) { +func GetActiveObject(clsid, iid *GUID) (*IUnknown, error) { return nil, NewError(E_NOTIMPL) } @@ -150,7 +150,7 @@ func CreateDispTypeInfo(idata *INTERFACEDATA) (*IUnknown, error) { } // copyMemory moves location of a block of memory. -func copyMemory(dest unsafe.Pointer, src unsafe.Pointer, length uint32) {} +func copyMemory(dest, src unsafe.Pointer, length uint32) {} // GetUserDefaultLCID retrieves current user default locale. func GetUserDefaultLCID() uint32 { @@ -160,7 +160,7 @@ func GetUserDefaultLCID() uint32 { // GetMessage in message queue from runtime. // // This function appears to block. PeekMessage does not block. -func GetMessage(msg *Msg, hwnd uint32, MsgFilterMin uint32, MsgFilterMax uint32) (int32, error) { +func GetMessage(msg *Msg, hwnd, MsgFilterMin, MsgFilterMax uint32) (int32, error) { return int32(0), NewError(E_NOTIMPL) } diff --git a/internal/go-ole/connect.go b/internal/go-ole/connect.go index b910f0e329..bca3a656b0 100644 --- a/internal/go-ole/connect.go +++ b/internal/go-ole/connect.go @@ -44,8 +44,8 @@ func (c *Connection) Release() { // Load COM object from list of programIDs or strings. func (c *Connection) Load(names ...string) (errors []error) { - var tempErrors = make([]error, len(names)) - var numErrors = 0 + tempErrors := make([]error, len(names)) + numErrors := 0 for _, name := range names { err := c.Create(name) if err != nil { diff --git a/internal/go-ole/guid.go b/internal/go-ole/guid.go index 27f9557b3a..a3921cb2d5 100644 --- a/internal/go-ole/guid.go +++ b/internal/go-ole/guid.go @@ -89,8 +89,10 @@ var ( CLSID_COMTestScalarClass = NewGUID("{865B85C5-0334-4AC6-9EF6-AACEC8FC5E86}") ) -const hextable = "0123456789ABCDEF" -const emptyGUID = "{00000000-0000-0000-0000-000000000000}" +const ( + hextable = "0123456789ABCDEF" + emptyGUID = "{00000000-0000-0000-0000-000000000000}" +) // GUID is Windows API specific GUID type. // @@ -177,7 +179,7 @@ func decodeHexUint16(src []byte) (value uint16, ok bool) { return } -func decodeHexByte64(s1 []byte, s2 []byte) (value [8]byte, ok bool) { +func decodeHexByte64(s1, s2 []byte) (value [8]byte, ok bool) { var ok1, ok2, ok3, ok4, ok5, ok6, ok7, ok8 bool value[0], ok1 = decodeHexByte(s1[0], s1[1]) value[1], ok2 = decodeHexByte(s1[2], s1[3]) @@ -269,7 +271,7 @@ func putByteHex(dst, src []byte) { // IsEqualGUID compares two GUID. // // Not constant time comparison. -func IsEqualGUID(guid1 *GUID, guid2 *GUID) bool { +func IsEqualGUID(guid1, guid2 *GUID) bool { return guid1.Data1 == guid2.Data1 && guid1.Data2 == guid2.Data2 && guid1.Data3 == guid2.Data3 && diff --git a/internal/go-ole/idispatch_windows.go b/internal/go-ole/idispatch_windows.go index d4f5058bd0..98a555ba2f 100644 --- a/internal/go-ole/idispatch_windows.go +++ b/internal/go-ole/idispatch_windows.go @@ -73,7 +73,7 @@ func invoke(disp *IDispatch, dispid int32, dispatch int16, params ...interface{} if len(params) > 0 { vargs = make([]VARIANT, len(params)) for i, v := range params { - //n := len(params)-i-1 + // n := len(params)-i-1 n := len(params) - i - 1 VariantInit(&vargs[n]) switch vv := v.(type) { diff --git a/internal/go-ole/oleutil/connection.go b/internal/go-ole/oleutil/connection.go index ef2f42aa0f..c3e7d48aae 100644 --- a/internal/go-ole/oleutil/connection.go +++ b/internal/go-ole/oleutil/connection.go @@ -56,7 +56,7 @@ func dispRelease(this *ole.IUnknown) int32 { return pthis.ref } -func dispGetIDsOfNames(this *ole.IUnknown, iid *ole.GUID, wnames []*uint16, namelen int, lcid int, pdisp []int32) uintptr { +func dispGetIDsOfNames(this *ole.IUnknown, iid *ole.GUID, wnames []*uint16, namelen, lcid int, pdisp []int32) uintptr { pthis := (*stdDispatch)(unsafe.Pointer(this)) names := make([]string, len(wnames)) for i := 0; i < len(names); i++ { diff --git a/internal/go-ole/safearray_func.go b/internal/go-ole/safearray_func.go index 1bbe4ab80a..c5bd36388e 100644 --- a/internal/go-ole/safearray_func.go +++ b/internal/go-ole/safearray_func.go @@ -51,7 +51,7 @@ func safeArrayCopy(original *SafeArray) (*SafeArray, error) { // safeArrayCopyData duplicates SafeArray into another SafeArray object. // // AKA: SafeArrayCopyData in Windows API. -func safeArrayCopyData(original *SafeArray, duplicate *SafeArray) error { +func safeArrayCopyData(original, duplicate *SafeArray) error { return NewError(E_NOTIMPL) } diff --git a/internal/go-ole/safearray_windows.go b/internal/go-ole/safearray_windows.go index f3292d7bd4..67f98e5fcf 100644 --- a/internal/go-ole/safearray_windows.go +++ b/internal/go-ole/safearray_windows.go @@ -32,8 +32,8 @@ var ( procSafeArrayUnaccessData = modoleaut32.NewProc("SafeArrayUnaccessData") procSafeArrayUnlock = modoleaut32.NewProc("SafeArrayUnlock") procSafeArrayPutElement = modoleaut32.NewProc("SafeArrayPutElement") - //procSafeArrayRedim = modoleaut32.NewProc("SafeArrayRedim") // TODO - //procSafeArraySetIID = modoleaut32.NewProc("SafeArraySetIID") // TODO + // procSafeArrayRedim = modoleaut32.NewProc("SafeArrayRedim") // TODO + // procSafeArraySetIID = modoleaut32.NewProc("SafeArraySetIID") // TODO procSafeArrayGetRecordInfo = modoleaut32.NewProc("SafeArrayGetRecordInfo") procSafeArraySetRecordInfo = modoleaut32.NewProc("SafeArraySetRecordInfo") ) @@ -101,7 +101,7 @@ func safeArrayCopy(original *SafeArray) (safearray *SafeArray, err error) { // safeArrayCopyData duplicates SafeArray into another SafeArray object. // // AKA: SafeArrayCopyData in Windows API. -func safeArrayCopyData(original *SafeArray, duplicate *SafeArray) (err error) { +func safeArrayCopyData(original, duplicate *SafeArray) (err error) { err = convertHresultToError( procSafeArrayCopyData.Call( uintptr(unsafe.Pointer(original)), diff --git a/internal/go-ole/utility.go b/internal/go-ole/utility.go index 99ee82dc34..1ba6628ec7 100644 --- a/internal/go-ole/utility.go +++ b/internal/go-ole/utility.go @@ -93,7 +93,7 @@ func lpOleStrLen(p *uint16) (length int64) { } // convertHresultToError converts syscall to error, if call is unsuccessful. -func convertHresultToError(hr uintptr, r2 uintptr, ignore error) (err error) { +func convertHresultToError(hr, r2 uintptr, ignore error) (err error) { if hr != 0 { err = NewError(hr) } diff --git a/internal/gopsutil/common/binary.go b/internal/gopsutil/common/binary.go index 9b5dc55b49..446c3597fd 100644 --- a/internal/gopsutil/common/binary.go +++ b/internal/gopsutil/common/binary.go @@ -388,8 +388,10 @@ type coder struct { buf []byte } -type decoder coder -type encoder coder +type ( + decoder coder + encoder coder +) func (d *decoder) uint8() uint8 { x := d.buf[0] diff --git a/internal/gopsutil/common/common.go b/internal/gopsutil/common/common.go index a02fce4b1a..7181ad0b06 100644 --- a/internal/gopsutil/common/common.go +++ b/internal/gopsutil/common/common.go @@ -97,7 +97,6 @@ var ErrNotImplementedError = errors.New("not implemented yet") // ReadFile reads contents from a file func ReadFile(filename string) (string, error) { content, err := os.ReadFile(filename) - if err != nil { return "", err } @@ -320,7 +319,7 @@ func PathExists(filename string) bool { } // GetEnv retrieves the environment variable key. If it does not exist it returns the default. -func GetEnv(key string, dfault string, combineWith ...string) string { +func GetEnv(key, dfault string, combineWith ...string) string { value := os.Getenv(key) if value == "" { value = dfault diff --git a/internal/gopsutil/common/common_linux.go b/internal/gopsutil/common/common_linux.go index 6c0bb2bdaf..ae0f495924 100644 --- a/internal/gopsutil/common/common_linux.go +++ b/internal/gopsutil/common/common_linux.go @@ -60,7 +60,6 @@ func NumProcs() (uint64, error) { } func BootTimeWithContext(ctx context.Context) (uint64, error) { - system, role, err := Virtualization() if err != nil { return 0, err @@ -191,7 +190,6 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { if PathExists(filepath.Join(filename, "self", "status")) { contents, err := ReadLines(filepath.Join(filename, "self", "status")) if err == nil { - if StringsContains(contents, "s_context:") || StringsContains(contents, "VxID:") { system = "linux-vserver" @@ -240,7 +238,7 @@ func VirtualizationWithContext(ctx context.Context) (string, string, error) { return system, role, nil } -func GetOSRelease() (platform string, version string, err error) { +func GetOSRelease() (platform, version string, err error) { contents, err := ReadLines(HostEtc("os-release")) if err != nil { return "", "", nil // return empty diff --git a/internal/gopsutil/common/common_windows.go b/internal/gopsutil/common/common_windows.go index 00db4c3d20..ebd71705b0 100644 --- a/internal/gopsutil/common/common_windows.go +++ b/internal/gopsutil/common/common_windows.go @@ -10,8 +10,9 @@ import ( "syscall" "unsafe" - "github.com/gofiber/fiber/v2/internal/wmi" "golang.org/x/sys/windows" + + "github.com/gofiber/fiber/v2/internal/wmi" ) // for double values @@ -155,7 +156,7 @@ func NewWin32PerformanceCounter(postName, counterName string) (*Win32Performance if err != nil { return nil, err } - var counter = Win32PerformanceCounter{ + counter := Win32PerformanceCounter{ Query: query, PostName: postName, CounterName: counterName, diff --git a/internal/gopsutil/common/sleep.go b/internal/gopsutil/common/sleep.go index 57f5a35fc4..9bed2419ed 100644 --- a/internal/gopsutil/common/sleep.go +++ b/internal/gopsutil/common/sleep.go @@ -8,7 +8,7 @@ import ( // Sleep awaits for provided interval. // Can be interrupted by context cancelation. func Sleep(ctx context.Context, interval time.Duration) error { - var timer = time.NewTimer(interval) + timer := time.NewTimer(interval) select { case <-ctx.Done(): if !timer.Stop() { diff --git a/internal/gopsutil/cpu/cpu.go b/internal/gopsutil/cpu/cpu.go index 5e77be20d7..5814d78597 100644 --- a/internal/gopsutil/cpu/cpu.go +++ b/internal/gopsutil/cpu/cpu.go @@ -51,8 +51,10 @@ type lastPercent struct { lastPerCPUTimes []TimesStat } -var lastCPUPercent lastPercent -var invoke common.Invoker = common.Invoke{} +var ( + lastCPUPercent lastPercent + invoke common.Invoker = common.Invoke{} +) func init() { lastCPUPercent.Lock() diff --git a/internal/gopsutil/cpu/cpu_darwin_cgo.go b/internal/gopsutil/cpu/cpu_darwin_cgo.go index 43c61c5417..0ac88040ef 100644 --- a/internal/gopsutil/cpu/cpu_darwin_cgo.go +++ b/internal/gopsutil/cpu/cpu_darwin_cgo.go @@ -107,5 +107,4 @@ func allCPUTimes() ([]TimesStat, error) { } return []TimesStat{c}, nil - } diff --git a/internal/gopsutil/cpu/cpu_dragonfly.go b/internal/gopsutil/cpu/cpu_dragonfly.go index f7f76e138a..8c5158098e 100644 --- a/internal/gopsutil/cpu/cpu_dragonfly.go +++ b/internal/gopsutil/cpu/cpu_dragonfly.go @@ -11,18 +11,21 @@ import ( "strings" "unsafe" - "github.com/gofiber/fiber/v2/internal/gopsutil/common" "golang.org/x/sys/unix" + + "github.com/gofiber/fiber/v2/internal/gopsutil/common" ) -var ClocksPerSec = float64(128) -var cpuMatch = regexp.MustCompile(`^CPU:`) -var originMatch = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`) -var featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`) -var featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`) -var cpuEnd = regexp.MustCompile(`^Trying to mount root`) -var cpuTimesSize int -var emptyTimes cpuTimes +var ( + ClocksPerSec = float64(128) + cpuMatch = regexp.MustCompile(`^CPU:`) + originMatch = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`) + featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`) + featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`) + cpuEnd = regexp.MustCompile(`^Trying to mount root`) + cpuTimesSize int + emptyTimes cpuTimes +) func init() { getconf, err := exec.LookPath("getconf") diff --git a/internal/gopsutil/cpu/cpu_freebsd.go b/internal/gopsutil/cpu/cpu_freebsd.go index 3effa5e69d..50e0240679 100644 --- a/internal/gopsutil/cpu/cpu_freebsd.go +++ b/internal/gopsutil/cpu/cpu_freebsd.go @@ -11,19 +11,22 @@ import ( "strings" "unsafe" - "github.com/gofiber/fiber/v2/internal/gopsutil/common" "golang.org/x/sys/unix" + + "github.com/gofiber/fiber/v2/internal/gopsutil/common" ) -var ClocksPerSec = float64(128) -var cpuMatch = regexp.MustCompile(`^CPU:`) -var originMatch = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Family\s*=\s*(.+)\s+Model\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`) -var featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`) -var featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`) -var cpuEnd = regexp.MustCompile(`^Trying to mount root`) -var cpuCores = regexp.MustCompile(`FreeBSD/SMP: (\d*) package\(s\) x (\d*) core\(s\)`) -var cpuTimesSize int -var emptyTimes cpuTimes +var ( + ClocksPerSec = float64(128) + cpuMatch = regexp.MustCompile(`^CPU:`) + originMatch = regexp.MustCompile(`Origin\s*=\s*"(.+)"\s+Id\s*=\s*(.+)\s+Family\s*=\s*(.+)\s+Model\s*=\s*(.+)\s+Stepping\s*=\s*(.+)`) + featuresMatch = regexp.MustCompile(`Features=.+<(.+)>`) + featuresMatch2 = regexp.MustCompile(`Features2=[a-f\dx]+<(.+)>`) + cpuEnd = regexp.MustCompile(`^Trying to mount root`) + cpuCores = regexp.MustCompile(`FreeBSD/SMP: (\d*) package\(s\) x (\d*) core\(s\)`) + cpuTimesSize int + emptyTimes cpuTimes +) func init() { getconf, err := exec.LookPath("getconf") diff --git a/internal/gopsutil/cpu/cpu_linux.go b/internal/gopsutil/cpu/cpu_linux.go index e3f45641a4..ddc65b999e 100644 --- a/internal/gopsutil/cpu/cpu_linux.go +++ b/internal/gopsutil/cpu/cpu_linux.go @@ -37,7 +37,7 @@ func Times(percpu bool) ([]TimesStat, error) { func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { filename := common.HostProc("stat") - var lines = []string{} + lines := []string{} if percpu { statlines, err := common.ReadLines(filename) if err != nil || len(statlines) < 2 { @@ -314,7 +314,7 @@ func CountsWithContext(ctx context.Context, logical bool) (int, error) { } // physical cores // https://github.com/giampaolo/psutil/blob/122174a10b75c9beebe15f6c07dcf3afbe3b120d/psutil/_pslinux.py#L621-L629 - var threadSiblingsLists = make(map[string]bool) + threadSiblingsLists := make(map[string]bool) if files, err := filepath.Glob(common.HostSys("devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list")); err == nil { for _, file := range files { lines, err := common.ReadLines(file) diff --git a/internal/gopsutil/cpu/cpu_openbsd.go b/internal/gopsutil/cpu/cpu_openbsd.go index b924fb392e..317f078e08 100644 --- a/internal/gopsutil/cpu/cpu_openbsd.go +++ b/internal/gopsutil/cpu/cpu_openbsd.go @@ -13,8 +13,9 @@ import ( "strings" "syscall" - "github.com/gofiber/fiber/v2/internal/gopsutil/common" "golang.org/x/sys/unix" + + "github.com/gofiber/fiber/v2/internal/gopsutil/common" ) // sys/sched.h @@ -116,7 +117,7 @@ func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { j *= 2 } - var cpuTimes = make([]int32, CPUStates) + cpuTimes := make([]int32, CPUStates) var mib []int32 if percpu { mib = []int32{CTLKern, KernCptime2, int32(j)} diff --git a/internal/gopsutil/cpu/cpu_solaris.go b/internal/gopsutil/cpu/cpu_solaris.go index b7942cc0d0..d5a14703cc 100644 --- a/internal/gopsutil/cpu/cpu_solaris.go +++ b/internal/gopsutil/cpu/cpu_solaris.go @@ -52,7 +52,7 @@ func TimesWithContext(ctx context.Context, percpu bool) ([]TimesStat, error) { user := make(map[float64]float64) kern := make(map[float64]float64) iowt := make(map[float64]float64) - //swap := make(map[float64]float64) + // swap := make(map[float64]float64) kstatSysOut, err := invoke.CommandWithContext(ctx, kstatSys, "-p", "cpu_stat:*:*:/^idle$|^user$|^kernel$|^iowait$|^swap$/") if err != nil { return nil, fmt.Errorf("cannot execute kstat: %s", err) diff --git a/internal/gopsutil/cpu/cpu_windows.go b/internal/gopsutil/cpu/cpu_windows.go index 3a22fe1c9b..bae5d09c12 100644 --- a/internal/gopsutil/cpu/cpu_windows.go +++ b/internal/gopsutil/cpu/cpu_windows.go @@ -7,9 +7,10 @@ import ( "fmt" "unsafe" + "golang.org/x/sys/windows" + "github.com/gofiber/fiber/v2/internal/gopsutil/common" "github.com/gofiber/fiber/v2/internal/wmi" - "golang.org/x/sys/windows" ) var ( diff --git a/internal/gopsutil/load/load.go b/internal/gopsutil/load/load.go index b2cc654de5..d5bd2c4536 100644 --- a/internal/gopsutil/load/load.go +++ b/internal/gopsutil/load/load.go @@ -4,8 +4,7 @@ import ( "encoding/json" ) -//var invoke common.Invoker = common.Invoke{} - +// var invoke common.Invoker = common.Invoke{} type AvgStat struct { Load1 float64 `json:"load1"` Load5 float64 `json:"load5"` diff --git a/internal/gopsutil/load/load_bsd.go b/internal/gopsutil/load/load_bsd.go index bdf979f6b3..0412ade49a 100644 --- a/internal/gopsutil/load/load_bsd.go +++ b/internal/gopsutil/load/load_bsd.go @@ -8,8 +8,9 @@ import ( "strings" "unsafe" - "github.com/gofiber/fiber/v2/internal/gopsutil/common" "golang.org/x/sys/unix" + + "github.com/gofiber/fiber/v2/internal/gopsutil/common" ) var invoke common.Invoker = common.Invoke{} diff --git a/internal/gopsutil/load/load_darwin.go b/internal/gopsutil/load/load_darwin.go index 959d861d53..37b7eac74c 100644 --- a/internal/gopsutil/load/load_darwin.go +++ b/internal/gopsutil/load/load_darwin.go @@ -8,8 +8,9 @@ import ( "strings" "unsafe" - "github.com/gofiber/fiber/v2/internal/gopsutil/common" "golang.org/x/sys/unix" + + "github.com/gofiber/fiber/v2/internal/gopsutil/common" ) var invoke common.Invoker = common.Invoke{} diff --git a/internal/gopsutil/mem/mem_linux.go b/internal/gopsutil/mem/mem_linux.go index fc994efb0f..d9e0321efd 100644 --- a/internal/gopsutil/mem/mem_linux.go +++ b/internal/gopsutil/mem/mem_linux.go @@ -10,8 +10,9 @@ import ( "strconv" "strings" - "github.com/gofiber/fiber/v2/internal/gopsutil/common" "golang.org/x/sys/unix" + + "github.com/gofiber/fiber/v2/internal/gopsutil/common" ) type VirtualMemoryExStat struct { @@ -188,7 +189,7 @@ func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { Free: uint64(sysinfo.Freeswap) * uint64(sysinfo.Unit), } ret.Used = ret.Total - ret.Free - //check Infinity + // check Infinity if ret.Total != 0 { ret.UsedPercent = float64(ret.Total-ret.Free) / float64(ret.Total) * 100.0 } else { @@ -251,7 +252,6 @@ func calcuateAvailVmem(ret *VirtualMemoryStat, retEx *VirtualMemoryExStat) uint6 fn := common.HostProc("zoneinfo") lines, err := common.ReadLines(fn) - if err != nil { return ret.Free + ret.Cached // fallback under kernel 2.6.13 } @@ -264,7 +264,6 @@ func calcuateAvailVmem(ret *VirtualMemoryStat, retEx *VirtualMemoryExStat) uint6 if strings.HasPrefix(fields[0], "low") { lowValue, err := strconv.ParseUint(fields[1], 10, 64) - if err != nil { lowValue = 0 } diff --git a/internal/gopsutil/mem/mem_openbsd.go b/internal/gopsutil/mem/mem_openbsd.go index 74414d81c0..cacbb13ab6 100644 --- a/internal/gopsutil/mem/mem_openbsd.go +++ b/internal/gopsutil/mem/mem_openbsd.go @@ -10,8 +10,9 @@ import ( "fmt" "os/exec" - "github.com/gofiber/fiber/v2/internal/gopsutil/common" "golang.org/x/sys/unix" + + "github.com/gofiber/fiber/v2/internal/gopsutil/common" ) func GetPageSize() (uint64, error) { diff --git a/internal/gopsutil/mem/mem_windows.go b/internal/gopsutil/mem/mem_windows.go index bd126d3643..dbec7328ad 100644 --- a/internal/gopsutil/mem/mem_windows.go +++ b/internal/gopsutil/mem/mem_windows.go @@ -6,8 +6,9 @@ import ( "context" "unsafe" - "github.com/gofiber/fiber/v2/internal/gopsutil/common" "golang.org/x/sys/windows" + + "github.com/gofiber/fiber/v2/internal/gopsutil/common" ) var ( diff --git a/internal/gopsutil/net/net.go b/internal/gopsutil/net/net.go index 53f2f7dd63..4c4e91f4cb 100644 --- a/internal/gopsutil/net/net.go +++ b/internal/gopsutil/net/net.go @@ -22,7 +22,6 @@ type IOCountersStat struct { Dropout uint64 `json:"dropout"` // total number of outgoing packets which were dropped (always 0 on OSX and BSD) Fifoin uint64 `json:"fifoin"` // total number of FIFO buffers errors while receiving Fifoout uint64 `json:"fifoout"` // total number of FIFO buffers errors while sending - } // Addr is implemented compatibility to psutil @@ -88,7 +87,7 @@ type ConntrackStat struct { SearchRestart uint32 `json:"search_restart"` // Conntrack table lookups restarted due to hashtable resizes } -func NewConntrackStat(e uint32, s uint32, f uint32, n uint32, inv uint32, ign uint32, del uint32, dlst uint32, ins uint32, insfail uint32, drop uint32, edrop uint32, ie uint32, en uint32, ec uint32, ed uint32, sr uint32) *ConntrackStat { +func NewConntrackStat(e, s, f, n, inv, ign, del, dlst, ins, insfail, drop, edrop, ie, en, ec, ed, sr uint32) *ConntrackStat { return &ConntrackStat{ Entries: e, Searched: s, diff --git a/internal/gopsutil/net/net_aix.go b/internal/gopsutil/net/net_aix.go index e7eabe716d..4b43de0e6a 100644 --- a/internal/gopsutil/net/net_aix.go +++ b/internal/gopsutil/net/net_aix.go @@ -102,7 +102,6 @@ func IOCountersWithContext(ctx context.Context, pernic bool) ([]IOCountersStat, return getIOCountersAll(iocounters) } return iocounters, nil - } // NetIOCountersByFile is an method which is added just a compatibility for linux. @@ -186,7 +185,7 @@ var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`) // This function only works for netstat returning addresses with a "." // before the port (0.0.0.0.22 instead of 0.0.0.0:22). -func parseNetstatAddr(local string, remote string, family uint32) (laddr Addr, raddr Addr, err error) { +func parseNetstatAddr(local, remote string, family uint32) (laddr, raddr Addr, err error) { parse := func(l string) (Addr, error) { matches := portMatch.FindStringSubmatch(l) if matches == nil { @@ -286,7 +285,7 @@ func hasCorrectInetProto(kind, proto string) bool { return false } -func parseNetstatA(output string, kind string) ([]ConnectionStat, error) { +func parseNetstatA(output, kind string) ([]ConnectionStat, error) { var ret []ConnectionStat lines := strings.Split(string(output), "\n") @@ -335,7 +334,6 @@ func parseNetstatA(output string, kind string) ([]ConnectionStat, error) { } return ret, nil - } func Connections(kind string) ([]ConnectionStat, error) { @@ -343,7 +341,6 @@ func Connections(kind string) ([]ConnectionStat, error) { } func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, error) { - args := []string{"-na"} switch strings.ToLower(kind) { default: @@ -367,7 +364,6 @@ func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, return nil, err } out, err := invoke.CommandWithContext(ctx, netstat, args...) - if err != nil { return nil, err } @@ -378,7 +374,6 @@ func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, } return ret, nil - } func ConnectionsMax(kind string, max int) ([]ConnectionStat, error) { diff --git a/internal/gopsutil/net/net_linux.go b/internal/gopsutil/net/net_linux.go index ebc0b53b17..7016de6598 100644 --- a/internal/gopsutil/net/net_linux.go +++ b/internal/gopsutil/net/net_linux.go @@ -234,7 +234,6 @@ func FilterCountersWithContext(ctx context.Context) ([]FilterStat, error) { maxfile := common.HostProc("sys/net/netfilter/nf_conntrack_max") count, err := common.ReadInts(countfile) - if err != nil { return nil, err } @@ -332,21 +331,25 @@ var kindTCP4 = netConnectionKindType{ sockType: syscall.SOCK_STREAM, filename: "tcp", } + var kindTCP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_STREAM, filename: "tcp6", } + var kindUDP4 = netConnectionKindType{ family: syscall.AF_INET, sockType: syscall.SOCK_DGRAM, filename: "udp", } + var kindUDP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_DGRAM, filename: "udp6", } + var kindUNIX = netConnectionKindType{ family: syscall.AF_UNIX, filename: "unix", @@ -748,7 +751,6 @@ func parseIPv6HexString(src []byte) (net.IP, error) { } func processInet(file string, kind netConnectionKindType, inodes map[string][]inodeMap, filterPid int32) ([]connTmp, error) { - if strings.HasSuffix(file, "6") && !common.PathExists(file) { // IPv6 not supported, return empty. return []connTmp{}, nil @@ -872,7 +874,7 @@ func processUnix(file string, kind netConnectionKindType, inodes map[string][]in return ret, nil } -func updateMap(src map[string][]inodeMap, add map[string][]inodeMap) map[string][]inodeMap { +func updateMap(src, add map[string][]inodeMap) map[string][]inodeMap { for key, value := range add { a, exists := src[key] if !exists { diff --git a/internal/gopsutil/net/net_openbsd.go b/internal/gopsutil/net/net_openbsd.go index 8a62a70b1d..2afd242f1b 100644 --- a/internal/gopsutil/net/net_openbsd.go +++ b/internal/gopsutil/net/net_openbsd.go @@ -17,8 +17,9 @@ import ( var portMatch = regexp.MustCompile(`(.*)\.(\d+)$`) -func ParseNetstat(output string, mode string, - iocs map[string]IOCountersStat) error { +func ParseNetstat(output, mode string, + iocs map[string]IOCountersStat, +) error { lines := strings.Split(output, "\n") exists := make([]string, 0, len(lines)-1) @@ -220,7 +221,7 @@ func parseNetstatLine(line string) (ConnectionStat, error) { return n, nil } -func parseNetstatAddr(local string, remote string, family uint32) (laddr Addr, raddr Addr, err error) { +func parseNetstatAddr(local, remote string, family uint32) (laddr, raddr Addr, err error) { parse := func(l string) (Addr, error) { matches := portMatch.FindStringSubmatch(l) if matches == nil { @@ -299,7 +300,6 @@ func ConnectionsWithContext(ctx context.Context, kind string) ([]ConnectionStat, return nil, err } out, err := invoke.CommandWithContext(ctx, netstat, args...) - if err != nil { return nil, err } diff --git a/internal/gopsutil/net/net_unix.go b/internal/gopsutil/net/net_unix.go index 16085966b8..67ef17fe46 100644 --- a/internal/gopsutil/net/net_unix.go +++ b/internal/gopsutil/net/net_unix.go @@ -80,7 +80,6 @@ func ConnectionsPidWithContext(ctx context.Context, kind string, pid int32) ([]C } n, err := parseNetLine(rr) if err != nil { - continue } @@ -151,7 +150,7 @@ func parseNetLine(line string) (ConnectionStat, error) { return n, nil } -func parseNetAddr(line string) (laddr Addr, raddr Addr, err error) { +func parseNetAddr(line string) (laddr, raddr Addr, err error) { parse := func(l string) (Addr, error) { host, port, err := net.SplitHostPort(l) if err != nil { diff --git a/internal/gopsutil/net/net_windows.go b/internal/gopsutil/net/net_windows.go index c3883f66e2..865f2aa5c1 100644 --- a/internal/gopsutil/net/net_windows.go +++ b/internal/gopsutil/net/net_windows.go @@ -10,8 +10,9 @@ import ( "syscall" "unsafe" - "github.com/gofiber/fiber/v2/internal/gopsutil/common" "golang.org/x/sys/windows" + + "github.com/gofiber/fiber/v2/internal/gopsutil/common" ) var ( @@ -44,16 +45,19 @@ var kindTCP4 = netConnectionKindType{ sockType: syscall.SOCK_STREAM, filename: "tcp", } + var kindTCP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_STREAM, filename: "tcp6", } + var kindUDP4 = netConnectionKindType{ family: syscall.AF_INET, sockType: syscall.SOCK_DGRAM, filename: "udp", } + var kindUDP6 = netConnectionKindType{ family: syscall.AF_INET6, sockType: syscall.SOCK_DGRAM, @@ -525,9 +529,7 @@ func getUDPConnections(family uint32) ([]ConnectionStat, error) { buf = make([]byte, size) } - var ( - index, step, length int - ) + var index, step, length int stats := make([]ConnectionStat, 0) switch family { @@ -694,8 +696,10 @@ type mibTCP6TableOwnerPid struct { Table [anySize]mibTCP6RowOwnerPid } -type pmibTCPTableOwnerPidAll *mibTCPTableOwnerPid -type pmibTCP6TableOwnerPidAll *mibTCP6TableOwnerPid +type ( + pmibTCPTableOwnerPidAll *mibTCPTableOwnerPid + pmibTCP6TableOwnerPidAll *mibTCP6TableOwnerPid +) // UDP @@ -750,8 +754,10 @@ type mibUDP6TableOwnerPid struct { Table [anySize]mibUDP6RowOwnerPid } -type pmibUDPTableOwnerPid *mibUDPTableOwnerPid -type pmibUDP6TableOwnerPid *mibUDP6TableOwnerPid +type ( + pmibUDPTableOwnerPid *mibUDPTableOwnerPid + pmibUDP6TableOwnerPid *mibUDP6TableOwnerPid +) func decodePort(port uint32) uint16 { return syscall.Ntohs(uint16(port)) diff --git a/internal/gopsutil/process/process.go b/internal/gopsutil/process/process.go index bbf0fdf148..80336d8eec 100644 --- a/internal/gopsutil/process/process.go +++ b/internal/gopsutil/process/process.go @@ -64,8 +64,8 @@ type SignalInfoStat struct { type RlimitStat struct { Resource int32 `json:"resource"` - Soft int32 `json:"soft"` //TODO too small. needs to be uint64 - Hard int32 `json:"hard"` //TODO too small. needs to be uint64 + Soft int32 `json:"soft"` // TODO too small. needs to be uint64 + Hard int32 `json:"hard"` // TODO too small. needs to be uint64 Used uint64 `json:"used"` } diff --git a/internal/gopsutil/process/process_darwin.go b/internal/gopsutil/process/process_darwin.go index fb795820e6..6a8deebed3 100644 --- a/internal/gopsutil/process/process_darwin.go +++ b/internal/gopsutil/process/process_darwin.go @@ -14,10 +14,11 @@ import ( "time" "unsafe" + "golang.org/x/sys/unix" + "github.com/gofiber/fiber/v2/internal/gopsutil/common" "github.com/gofiber/fiber/v2/internal/gopsutil/cpu" "github.com/gofiber/fiber/v2/internal/gopsutil/net" - "golang.org/x/sys/unix" ) // copied from sys/sysctl.h @@ -39,11 +40,9 @@ type _Ctype_struct___0 struct { } // MemoryInfoExStat is different between OSes -type MemoryInfoExStat struct { -} +type MemoryInfoExStat struct{} -type MemoryMapsStat struct { -} +type MemoryMapsStat struct{} func pidsWithContext(ctx context.Context) ([]int32, error) { var ret []int32 @@ -81,6 +80,7 @@ func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { return int32(v), err } + func (p *Process) Name() (string, error) { return p.NameWithContext(context.Background()) } @@ -109,9 +109,11 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) { return name, nil } + func (p *Process) Tgid() (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Exe() (string, error) { return p.ExeWithContext(context.Background()) } @@ -163,7 +165,7 @@ func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { elapsedDurations = append(elapsedDurations, time.Duration(p)) } - var elapsed = time.Duration(elapsedDurations[0]) * time.Second + elapsed := time.Duration(elapsedDurations[0]) * time.Second if len(elapsedDurations) > 1 { elapsed += time.Duration(elapsedDurations[1]) * time.Minute } @@ -177,6 +179,7 @@ func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { start := time.Now().Add(-elapsed) return start.Unix() * 1000, nil } + func (p *Process) Cwd() (string, error) { return p.CwdWithContext(context.Background()) } @@ -184,6 +187,7 @@ func (p *Process) Cwd() (string, error) { func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + func (p *Process) Parent() (*Process, error) { return p.ParentWithContext(context.Background()) } @@ -206,6 +210,7 @@ func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { } return nil, fmt.Errorf("could not find parent line") } + func (p *Process) Status() (string, error) { return p.StatusWithContext(context.Background()) } @@ -252,6 +257,7 @@ func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { return []int32{userEffectiveUID}, nil } + func (p *Process) Gids() ([]int32, error) { return p.GidsWithContext(context.Background()) } @@ -281,6 +287,7 @@ func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { return groups, nil } + func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) } @@ -302,6 +309,7 @@ func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { return termmap[ttyNr], nil */ } + func (p *Process) Nice() (int32, error) { return p.NiceWithContext(context.Background()) } @@ -313,6 +321,7 @@ func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { } return int32(k.Proc.P_nice), nil } + func (p *Process) IOnice() (int32, error) { return p.IOniceWithContext(context.Background()) } @@ -320,6 +329,7 @@ func (p *Process) IOnice() (int32, error) { func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Rlimit() ([]RlimitStat, error) { return p.RlimitWithContext(context.Background()) } @@ -328,6 +338,7 @@ func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { var rlimit []RlimitStat return rlimit, common.ErrNotImplementedError } + func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) { return p.RlimitUsageWithContext(context.Background(), gatherUsed) } @@ -336,6 +347,7 @@ func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ( var rlimit []RlimitStat return rlimit, common.ErrNotImplementedError } + func (p *Process) IOCounters() (*IOCountersStat, error) { return p.IOCountersWithContext(context.Background()) } @@ -343,6 +355,7 @@ func (p *Process) IOCounters() (*IOCountersStat, error) { func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { return p.NumCtxSwitchesWithContext(context.Background()) } @@ -350,6 +363,7 @@ func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) NumFDs() (int32, error) { return p.NumFDsWithContext(context.Background()) } @@ -357,6 +371,7 @@ func (p *Process) NumFDs() (int32, error) { func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) NumThreads() (int32, error) { return p.NumThreadsWithContext(context.Background()) } @@ -368,6 +383,7 @@ func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { } return int32(len(r)), nil } + func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) { return p.ThreadsWithContext(context.Background()) } @@ -422,13 +438,13 @@ func convertCPUTimes(s string) (ret float64, err error) { t += h return float64(t) / ClockTicks, nil } + func (p *Process) Times() (*cpu.TimesStat, error) { return p.TimesWithContext(context.Background()) } func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { r, err := callPsWithContext(ctx, "utime,stime", p.Pid, false) - if err != nil { return nil, err } @@ -449,6 +465,7 @@ func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) } return ret, nil } + func (p *Process) CPUAffinity() ([]int32, error) { return p.CPUAffinityWithContext(context.Background()) } @@ -456,6 +473,7 @@ func (p *Process) CPUAffinity() ([]int32, error) { func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } + func (p *Process) MemoryInfo() (*MemoryInfoStat, error) { return p.MemoryInfoWithContext(context.Background()) } @@ -486,6 +504,7 @@ func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, e return ret, nil } + func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) { return p.MemoryInfoExWithContext(context.Background()) } diff --git a/internal/gopsutil/process/process_darwin_cgo.go b/internal/gopsutil/process/process_darwin_cgo.go index 10a743608d..57714d9106 100644 --- a/internal/gopsutil/process/process_darwin_cgo.go +++ b/internal/gopsutil/process/process_darwin_cgo.go @@ -5,6 +5,7 @@ package process // #include // #include import "C" + import ( "context" "fmt" diff --git a/internal/gopsutil/process/process_fallback.go b/internal/gopsutil/process/process_fallback.go index 78455ca2b6..ab3ab447ff 100644 --- a/internal/gopsutil/process/process_fallback.go +++ b/internal/gopsutil/process/process_fallback.go @@ -25,8 +25,7 @@ type MemoryMapsStat struct { Swap uint64 `json:"swap"` } -type MemoryInfoExStat struct { -} +type MemoryInfoExStat struct{} func pidsWithContext(ctx context.Context) ([]int32, error) { return []int32{}, common.ErrNotImplementedError @@ -62,6 +61,7 @@ func (p *Process) Ppid() (int32, error) { func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Name() (string, error) { return p.NameWithContext(context.Background()) } @@ -69,9 +69,11 @@ func (p *Process) Name() (string, error) { func (p *Process) NameWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + func (p *Process) Tgid() (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Exe() (string, error) { return p.ExeWithContext(context.Background()) } @@ -79,6 +81,7 @@ func (p *Process) Exe() (string, error) { func (p *Process) ExeWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + func (p *Process) Cmdline() (string, error) { return p.CmdlineWithContext(context.Background()) } @@ -86,6 +89,7 @@ func (p *Process) Cmdline() (string, error) { func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + func (p *Process) CmdlineSlice() ([]string, error) { return p.CmdlineSliceWithContext(context.Background()) } @@ -97,6 +101,7 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Cwd() (string, error) { return p.CwdWithContext(context.Background()) } @@ -104,6 +109,7 @@ func (p *Process) Cwd() (string, error) { func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + func (p *Process) Parent() (*Process, error) { return p.ParentWithContext(context.Background()) } @@ -111,6 +117,7 @@ func (p *Process) Parent() (*Process, error) { func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { return nil, common.ErrNotImplementedError } + func (p *Process) Status() (string, error) { return p.StatusWithContext(context.Background()) } @@ -118,6 +125,7 @@ func (p *Process) Status() (string, error) { func (p *Process) StatusWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + func (p *Process) Foreground() (bool, error) { return p.ForegroundWithContext(context.Background()) } @@ -125,6 +133,7 @@ func (p *Process) Foreground() (bool, error) { func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { return false, common.ErrNotImplementedError } + func (p *Process) Uids() ([]int32, error) { return p.UidsWithContext(context.Background()) } @@ -132,6 +141,7 @@ func (p *Process) Uids() ([]int32, error) { func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { return []int32{}, common.ErrNotImplementedError } + func (p *Process) Gids() ([]int32, error) { return p.GidsWithContext(context.Background()) } @@ -143,6 +153,7 @@ func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { return []int32{}, common.ErrNotImplementedError } + func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) } @@ -150,6 +161,7 @@ func (p *Process) Terminal() (string, error) { func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + func (p *Process) Nice() (int32, error) { return p.NiceWithContext(context.Background()) } @@ -157,6 +169,7 @@ func (p *Process) Nice() (int32, error) { func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) IOnice() (int32, error) { return p.IOniceWithContext(context.Background()) } @@ -164,6 +177,7 @@ func (p *Process) IOnice() (int32, error) { func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Rlimit() ([]RlimitStat, error) { return p.RlimitWithContext(context.Background()) } @@ -171,6 +185,7 @@ func (p *Process) Rlimit() ([]RlimitStat, error) { func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) { return p.RlimitUsageWithContext(context.Background(), gatherUsed) } @@ -178,6 +193,7 @@ func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) { func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ([]RlimitStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) IOCounters() (*IOCountersStat, error) { return p.IOCountersWithContext(context.Background()) } @@ -185,6 +201,7 @@ func (p *Process) IOCounters() (*IOCountersStat, error) { func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { return p.NumCtxSwitchesWithContext(context.Background()) } @@ -192,6 +209,7 @@ func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) NumFDs() (int32, error) { return p.NumFDsWithContext(context.Background()) } @@ -199,6 +217,7 @@ func (p *Process) NumFDs() (int32, error) { func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) NumThreads() (int32, error) { return p.NumThreadsWithContext(context.Background()) } @@ -206,6 +225,7 @@ func (p *Process) NumThreads() (int32, error) { func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) { return p.ThreadsWithContext(context.Background()) } @@ -213,6 +233,7 @@ func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) { func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) Times() (*cpu.TimesStat, error) { return p.TimesWithContext(context.Background()) } @@ -220,6 +241,7 @@ func (p *Process) Times() (*cpu.TimesStat, error) { func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) CPUAffinity() ([]int32, error) { return p.CPUAffinityWithContext(context.Background()) } @@ -227,6 +249,7 @@ func (p *Process) CPUAffinity() ([]int32, error) { func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } + func (p *Process) MemoryInfo() (*MemoryInfoStat, error) { return p.MemoryInfoWithContext(context.Background()) } @@ -234,6 +257,7 @@ func (p *Process) MemoryInfo() (*MemoryInfoStat, error) { func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) { return p.MemoryInfoExWithContext(context.Background()) } @@ -241,12 +265,15 @@ func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) { func (p *Process) MemoryInfoExWithContext(ctx context.Context) (*MemoryInfoExStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) PageFaults() (*PageFaultsStat, error) { return p.PageFaultsWithContext(context.Background()) } + func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) Children() ([]*Process, error) { return p.ChildrenWithContext(context.Background()) } @@ -254,6 +281,7 @@ func (p *Process) Children() ([]*Process, error) { func (p *Process) ChildrenWithContext(ctx context.Context) ([]*Process, error) { return nil, common.ErrNotImplementedError } + func (p *Process) OpenFiles() ([]OpenFilesStat, error) { return p.OpenFilesWithContext(context.Background()) } @@ -261,6 +289,7 @@ func (p *Process) OpenFiles() ([]OpenFilesStat, error) { func (p *Process) OpenFilesWithContext(ctx context.Context) ([]OpenFilesStat, error) { return []OpenFilesStat{}, common.ErrNotImplementedError } + func (p *Process) Connections() ([]net.ConnectionStat, error) { return p.ConnectionsWithContext(context.Background()) } @@ -292,6 +321,7 @@ func (p *Process) MemoryMaps(grouped bool) (*[]MemoryMapsStat, error) { func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]MemoryMapsStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) SendSignal(sig syscall.Signal) error { return p.SendSignalWithContext(context.Background(), sig) } @@ -299,6 +329,7 @@ func (p *Process) SendSignal(sig syscall.Signal) error { func (p *Process) SendSignalWithContext(ctx context.Context, sig syscall.Signal) error { return common.ErrNotImplementedError } + func (p *Process) Suspend() error { return p.SuspendWithContext(context.Background()) } @@ -306,6 +337,7 @@ func (p *Process) Suspend() error { func (p *Process) SuspendWithContext(ctx context.Context) error { return common.ErrNotImplementedError } + func (p *Process) Resume() error { return p.ResumeWithContext(context.Background()) } @@ -313,6 +345,7 @@ func (p *Process) Resume() error { func (p *Process) ResumeWithContext(ctx context.Context) error { return common.ErrNotImplementedError } + func (p *Process) Terminate() error { return p.TerminateWithContext(context.Background()) } @@ -320,6 +353,7 @@ func (p *Process) Terminate() error { func (p *Process) TerminateWithContext(ctx context.Context) error { return common.ErrNotImplementedError } + func (p *Process) Kill() error { return p.KillWithContext(context.Background()) } @@ -327,6 +361,7 @@ func (p *Process) Kill() error { func (p *Process) KillWithContext(ctx context.Context) error { return common.ErrNotImplementedError } + func (p *Process) Username() (string, error) { return p.UsernameWithContext(context.Background()) } diff --git a/internal/gopsutil/process/process_freebsd.go b/internal/gopsutil/process/process_freebsd.go index 49690cdd72..e86c52e188 100644 --- a/internal/gopsutil/process/process_freebsd.go +++ b/internal/gopsutil/process/process_freebsd.go @@ -11,18 +11,17 @@ import ( "strconv" "strings" + "golang.org/x/sys/unix" + "github.com/gofiber/fiber/v2/internal/gopsutil/common" cpu "github.com/gofiber/fiber/v2/internal/gopsutil/cpu" net "github.com/gofiber/fiber/v2/internal/gopsutil/net" - "golang.org/x/sys/unix" ) // MemoryInfoExStat is different between OSes -type MemoryInfoExStat struct { -} +type MemoryInfoExStat struct{} -type MemoryMapsStat struct { -} +type MemoryMapsStat struct{} func pidsWithContext(ctx context.Context) ([]int32, error) { var ret []int32 @@ -50,6 +49,7 @@ func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { return k.Ppid, nil } + func (p *Process) Name() (string, error) { return p.NameWithContext(context.Background()) } @@ -78,9 +78,11 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) { return name, nil } + func (p *Process) Tgid() (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Exe() (string, error) { return p.ExeWithContext(context.Background()) } @@ -137,6 +139,7 @@ func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Cwd() (string, error) { return p.CwdWithContext(context.Background()) } @@ -144,6 +147,7 @@ func (p *Process) Cwd() (string, error) { func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + func (p *Process) Parent() (*Process, error) { return p.ParentWithContext(context.Background()) } @@ -151,6 +155,7 @@ func (p *Process) Parent() (*Process, error) { func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { return p, common.ErrNotImplementedError } + func (p *Process) Status() (string, error) { return p.StatusWithContext(context.Background()) } @@ -215,6 +220,7 @@ func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { return uids, nil } + func (p *Process) Gids() ([]int32, error) { return p.GidsWithContext(context.Background()) } @@ -244,6 +250,7 @@ func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { return groups, nil } + func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) } @@ -263,6 +270,7 @@ func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { return termmap[ttyNr], nil } + func (p *Process) Nice() (int32, error) { return p.NiceWithContext(context.Background()) } @@ -274,6 +282,7 @@ func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { } return int32(k.Nice), nil } + func (p *Process) IOnice() (int32, error) { return p.IOniceWithContext(context.Background()) } @@ -281,6 +290,7 @@ func (p *Process) IOnice() (int32, error) { func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Rlimit() ([]RlimitStat, error) { return p.RlimitWithContext(context.Background()) } @@ -289,6 +299,7 @@ func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { var rlimit []RlimitStat return rlimit, common.ErrNotImplementedError } + func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) { return p.RlimitUsageWithContext(context.Background(), gatherUsed) } @@ -297,6 +308,7 @@ func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ( var rlimit []RlimitStat return rlimit, common.ErrNotImplementedError } + func (p *Process) IOCounters() (*IOCountersStat, error) { return p.IOCountersWithContext(context.Background()) } @@ -311,6 +323,7 @@ func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, e WriteCount: uint64(k.Rusage.Oublock), }, nil } + func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { return p.NumCtxSwitchesWithContext(context.Background()) } @@ -318,6 +331,7 @@ func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) NumFDs() (int32, error) { return p.NumFDsWithContext(context.Background()) } @@ -325,6 +339,7 @@ func (p *Process) NumFDs() (int32, error) { func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) NumThreads() (int32, error) { return p.NumThreadsWithContext(context.Background()) } @@ -337,6 +352,7 @@ func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { return k.Numthreads, nil } + func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) { return p.ThreadsWithContext(context.Background()) } @@ -345,6 +361,7 @@ func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesS ret := make(map[int32]*cpu.TimesStat) return ret, common.ErrNotImplementedError } + func (p *Process) Times() (*cpu.TimesStat, error) { return p.TimesWithContext(context.Background()) } @@ -360,6 +377,7 @@ func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) System: float64(k.Rusage.Stime.Sec) + float64(k.Rusage.Stime.Usec)/1000000, }, nil } + func (p *Process) CPUAffinity() ([]int32, error) { return p.CPUAffinityWithContext(context.Background()) } @@ -367,6 +385,7 @@ func (p *Process) CPUAffinity() ([]int32, error) { func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } + func (p *Process) MemoryInfo() (*MemoryInfoStat, error) { return p.MemoryInfoWithContext(context.Background()) } @@ -387,6 +406,7 @@ func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, e VMS: uint64(k.Size), }, nil } + func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) { return p.MemoryInfoExWithContext(context.Background()) } diff --git a/internal/gopsutil/process/process_linux.go b/internal/gopsutil/process/process_linux.go index 67ca0f7b43..23007d507a 100644 --- a/internal/gopsutil/process/process_linux.go +++ b/internal/gopsutil/process/process_linux.go @@ -14,10 +14,11 @@ import ( "strconv" "strings" + "golang.org/x/sys/unix" + "github.com/gofiber/fiber/v2/internal/gopsutil/common" "github.com/gofiber/fiber/v2/internal/gopsutil/cpu" "github.com/gofiber/fiber/v2/internal/gopsutil/net" - "golang.org/x/sys/unix" ) var PageSize = uint64(os.Getpagesize()) @@ -332,7 +333,7 @@ func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ( case RLIMIT_AS: rs.Used = uint64(p.memInfo.VMS) case RLIMIT_LOCKS: - //TODO we can get the used value from /proc/$pid/locks. But linux doesn't enforce it, so not a high priority. + // TODO we can get the used value from /proc/$pid/locks. But linux doesn't enforce it, so not a high priority. case RLIMIT_SIGPENDING: rs.Used = p.sigInfo.PendingProcess case RLIMIT_NICE: @@ -477,7 +478,6 @@ func (p *Process) PageFaultsWithContext(ctx context.Context) (*PageFaultsStat, e return nil, err } return pageFaults, nil - } // Children returns a slice of Process of the process. @@ -571,7 +571,7 @@ func (p *Process) MemoryMapsWithContext(ctx context.Context, grouped bool) (*[]M lines := strings.Split(string(contents), "\n") // function of parsing a block - getBlock := func(first_line []string, block []string) (MemoryMapsStat, error) { + getBlock := func(first_line, block []string) (MemoryMapsStat, error) { m := MemoryMapsStat{} m.Path = first_line[len(first_line)-1] @@ -703,7 +703,7 @@ func (p *Process) fillFromLimitsWithContext(ctx context.Context) ([]RlimitStat, // Remove last item from string str = str[:len(str)-1] - //Now last item is a Soft limit + // Now last item is a Soft limit statItem.Soft, err = limitToInt(str[len(str)-1]) if err != nil { return nil, err @@ -711,7 +711,7 @@ func (p *Process) fillFromLimitsWithContext(ctx context.Context) ([]RlimitStat, // Remove last item from string str = str[:len(str)-1] - //The rest is a stats name + // The rest is a stats name resourceName := strings.Join(str, " ") switch resourceName { case "Max cpu time": diff --git a/internal/gopsutil/process/process_openbsd.go b/internal/gopsutil/process/process_openbsd.go index e65fea687c..08be6bddf0 100644 --- a/internal/gopsutil/process/process_openbsd.go +++ b/internal/gopsutil/process/process_openbsd.go @@ -13,19 +13,18 @@ import ( "strings" "unsafe" + "golang.org/x/sys/unix" + "github.com/gofiber/fiber/v2/internal/gopsutil/common" cpu "github.com/gofiber/fiber/v2/internal/gopsutil/cpu" mem "github.com/gofiber/fiber/v2/internal/gopsutil/mem" net "github.com/gofiber/fiber/v2/internal/gopsutil/net" - "golang.org/x/sys/unix" ) // MemoryInfoExStat is different between OSes -type MemoryInfoExStat struct { -} +type MemoryInfoExStat struct{} -type MemoryMapsStat struct { -} +type MemoryMapsStat struct{} func pidsWithContext(ctx context.Context) ([]int32, error) { var ret []int32 @@ -53,6 +52,7 @@ func (p *Process) PpidWithContext(ctx context.Context) (int32, error) { return k.Ppid, nil } + func (p *Process) Name() (string, error) { return p.NameWithContext(context.Background()) } @@ -81,9 +81,11 @@ func (p *Process) NameWithContext(ctx context.Context) (string, error) { return name, nil } + func (p *Process) Tgid() (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Exe() (string, error) { return p.ExeWithContext(context.Background()) } @@ -99,7 +101,6 @@ func (p *Process) CmdlineSlice() ([]string, error) { func (p *Process) CmdlineSliceWithContext(ctx context.Context) ([]string, error) { mib := []int32{CTLKern, KernProcArgs, p.Pid, KernProcArgv} buf, _, err := common.CallSyscall(mib) - if err != nil { return nil, err } @@ -134,6 +135,7 @@ func (p *Process) CmdlineWithContext(ctx context.Context) (string, error) { func (p *Process) createTimeWithContext(ctx context.Context) (int64, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Cwd() (string, error) { return p.CwdWithContext(context.Background()) } @@ -141,6 +143,7 @@ func (p *Process) Cwd() (string, error) { func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + func (p *Process) Parent() (*Process, error) { return p.ParentWithContext(context.Background()) } @@ -148,6 +151,7 @@ func (p *Process) Parent() (*Process, error) { func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { return p, common.ErrNotImplementedError } + func (p *Process) Status() (string, error) { return p.StatusWithContext(context.Background()) } @@ -173,6 +177,7 @@ func (p *Process) StatusWithContext(ctx context.Context) (string, error) { return s, nil } + func (p *Process) Foreground() (bool, error) { return p.ForegroundWithContext(context.Background()) } @@ -190,6 +195,7 @@ func (p *Process) ForegroundWithContext(ctx context.Context) (bool, error) { } return strings.IndexByte(string(out), '+') != -1, nil } + func (p *Process) Uids() ([]int32, error) { return p.UidsWithContext(context.Background()) } @@ -206,6 +212,7 @@ func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { return uids, nil } + func (p *Process) Gids() ([]int32, error) { return p.GidsWithContext(context.Background()) } @@ -221,6 +228,7 @@ func (p *Process) GidsWithContext(ctx context.Context) ([]int32, error) { return gids, nil } + func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { k, err := p.getKProc() if err != nil { @@ -229,6 +237,7 @@ func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { return k.Groups, nil } + func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) } @@ -248,6 +257,7 @@ func (p *Process) TerminalWithContext(ctx context.Context) (string, error) { return termmap[ttyNr], nil } + func (p *Process) Nice() (int32, error) { return p.NiceWithContext(context.Background()) } @@ -259,6 +269,7 @@ func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { } return int32(k.Nice), nil } + func (p *Process) IOnice() (int32, error) { return p.IOniceWithContext(context.Background()) } @@ -266,6 +277,7 @@ func (p *Process) IOnice() (int32, error) { func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Rlimit() ([]RlimitStat, error) { return p.RlimitWithContext(context.Background()) } @@ -274,6 +286,7 @@ func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { var rlimit []RlimitStat return rlimit, common.ErrNotImplementedError } + func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) { return p.RlimitUsageWithContext(context.Background(), gatherUsed) } @@ -282,6 +295,7 @@ func (p *Process) RlimitUsageWithContext(ctx context.Context, gatherUsed bool) ( var rlimit []RlimitStat return rlimit, common.ErrNotImplementedError } + func (p *Process) IOCounters() (*IOCountersStat, error) { return p.IOCountersWithContext(context.Background()) } @@ -296,6 +310,7 @@ func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, e WriteCount: uint64(k.Uru_oublock), }, nil } + func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { return p.NumCtxSwitchesWithContext(context.Background()) } @@ -303,6 +318,7 @@ func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) NumFDs() (int32, error) { return p.NumFDsWithContext(context.Background()) } @@ -310,6 +326,7 @@ func (p *Process) NumFDs() (int32, error) { func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) NumThreads() (int32, error) { return p.NumThreadsWithContext(context.Background()) } @@ -318,6 +335,7 @@ func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { /* not supported, just return 1 */ return 1, nil } + func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) { return p.ThreadsWithContext(context.Background()) } @@ -326,6 +344,7 @@ func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesS ret := make(map[int32]*cpu.TimesStat) return ret, common.ErrNotImplementedError } + func (p *Process) Times() (*cpu.TimesStat, error) { return p.TimesWithContext(context.Background()) } @@ -341,6 +360,7 @@ func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) System: float64(k.Ustime_sec) + float64(k.Ustime_usec)/1000000, }, nil } + func (p *Process) CPUAffinity() ([]int32, error) { return p.CPUAffinityWithContext(context.Background()) } @@ -348,6 +368,7 @@ func (p *Process) CPUAffinity() ([]int32, error) { func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } + func (p *Process) MemoryInfo() (*MemoryInfoStat, error) { return p.MemoryInfoWithContext(context.Background()) } @@ -368,6 +389,7 @@ func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, e uint64(k.Vm_ssize), }, nil } + func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) { return p.MemoryInfoExWithContext(context.Background()) } @@ -453,7 +475,6 @@ func ProcessesWithContext(ctx context.Context) ([]*Process, error) { results := []*Process{} buf, length, err := CallKernProcSyscall(KernProcAll, 0) - if err != nil { return results, err } @@ -506,11 +527,11 @@ func (p *Process) getKProcWithContext(ctx context.Context) (*KinfoProc, error) { return &k, nil } -func CallKernProcSyscall(op int32, arg int32) ([]byte, uint64, error) { +func CallKernProcSyscall(op, arg int32) ([]byte, uint64, error) { return CallKernProcSyscallWithContext(context.Background(), op, arg) } -func CallKernProcSyscallWithContext(ctx context.Context, op int32, arg int32) ([]byte, uint64, error) { +func CallKernProcSyscallWithContext(ctx context.Context, op, arg int32) ([]byte, uint64, error) { mib := []int32{CTLKern, KernProc, op, arg, sizeOfKinfoProc, 0} mibptr := unsafe.Pointer(&mib[0]) miblen := uint64(len(mib)) diff --git a/internal/gopsutil/process/process_posix.go b/internal/gopsutil/process/process_posix.go index c319649df0..6701fa83d9 100644 --- a/internal/gopsutil/process/process_posix.go +++ b/internal/gopsutil/process/process_posix.go @@ -14,8 +14,9 @@ import ( "strings" "syscall" - "github.com/gofiber/fiber/v2/internal/gopsutil/common" "golang.org/x/sys/unix" + + "github.com/gofiber/fiber/v2/internal/gopsutil/common" ) // POSIX @@ -82,7 +83,7 @@ func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { return false, err } - if _, err := os.Stat(common.HostProc()); err == nil { //Means that proc filesystem exist + if _, err := os.Stat(common.HostProc()); err == nil { // Means that proc filesystem exist // Checking PID existence based on existence of //proc/ folder // This covers the case when running inside container with a different process namespace (by default) diff --git a/internal/gopsutil/process/process_windows.go b/internal/gopsutil/process/process_windows.go index 591c598f0a..57f4cb6a84 100644 --- a/internal/gopsutil/process/process_windows.go +++ b/internal/gopsutil/process/process_windows.go @@ -11,10 +11,11 @@ import ( "syscall" "unsafe" + "golang.org/x/sys/windows" + "github.com/gofiber/fiber/v2/internal/gopsutil/common" cpu "github.com/gofiber/fiber/v2/internal/gopsutil/cpu" net "github.com/gofiber/fiber/v2/internal/gopsutil/net" - "golang.org/x/sys/windows" ) var ( @@ -76,11 +77,9 @@ type systemInfo struct { } // Memory_info_ex is different between OSes -type MemoryInfoExStat struct { -} +type MemoryInfoExStat struct{} -type MemoryMapsStat struct { -} +type MemoryMapsStat struct{} // ioCounters is an equivalent representation of IO_COUNTERS in the Windows API. // https://docs.microsoft.com/windows/win32/api/winnt/ns-winnt-io_counters @@ -128,8 +127,10 @@ type winTokenPriviledges struct { Privileges [1]winLUIDAndAttributes } -type winLong int32 -type winDWord uint32 +type ( + winLong int32 + winDWord uint32 +) func init() { var systemInfo systemInfo @@ -194,7 +195,6 @@ func pidsWithContext(ctx context.Context) ([]int32, error) { return ret, nil } - } func PidExistsWithContext(ctx context.Context, pid int32) (bool, error) { @@ -337,6 +337,7 @@ func (p *Process) Cwd() (string, error) { func (p *Process) CwdWithContext(ctx context.Context) (string, error) { return "", common.ErrNotImplementedError } + func (p *Process) Parent() (*Process, error) { return p.ParentWithContext(context.Background()) } @@ -349,6 +350,7 @@ func (p *Process) ParentWithContext(ctx context.Context) (*Process, error) { return NewProcess(ppid) } + func (p *Process) Status() (string, error) { return p.StatusWithContext(context.Background()) } @@ -401,6 +403,7 @@ func (p *Process) UidsWithContext(ctx context.Context) ([]int32, error) { return uids, common.ErrNotImplementedError } + func (p *Process) Gids() ([]int32, error) { return p.GidsWithContext(context.Background()) } @@ -414,6 +417,7 @@ func (p *Process) GroupsWithContext(ctx context.Context) ([]int32, error) { var groups []int32 return groups, common.ErrNotImplementedError } + func (p *Process) Terminal() (string, error) { return p.TerminalWithContext(context.Background()) } @@ -455,6 +459,7 @@ func (p *Process) NiceWithContext(ctx context.Context) (int32, error) { } return priority, nil } + func (p *Process) IOnice() (int32, error) { return p.IOniceWithContext(context.Background()) } @@ -462,6 +467,7 @@ func (p *Process) IOnice() (int32, error) { func (p *Process) IOniceWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) Rlimit() ([]RlimitStat, error) { return p.RlimitWithContext(context.Background()) } @@ -471,6 +477,7 @@ func (p *Process) RlimitWithContext(ctx context.Context) ([]RlimitStat, error) { return rlimit, common.ErrNotImplementedError } + func (p *Process) RlimitUsage(gatherUsed bool) ([]RlimitStat, error) { return p.RlimitUsageWithContext(context.Background(), gatherUsed) } @@ -505,6 +512,7 @@ func (p *Process) IOCountersWithContext(ctx context.Context) (*IOCountersStat, e return stats, nil } + func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { return p.NumCtxSwitchesWithContext(context.Background()) } @@ -512,6 +520,7 @@ func (p *Process) NumCtxSwitches() (*NumCtxSwitchesStat, error) { func (p *Process) NumCtxSwitchesWithContext(ctx context.Context) (*NumCtxSwitchesStat, error) { return nil, common.ErrNotImplementedError } + func (p *Process) NumFDs() (int32, error) { return p.NumFDsWithContext(context.Background()) } @@ -519,6 +528,7 @@ func (p *Process) NumFDs() (int32, error) { func (p *Process) NumFDsWithContext(ctx context.Context) (int32, error) { return 0, common.ErrNotImplementedError } + func (p *Process) NumThreads() (int32, error) { return p.NumThreadsWithContext(context.Background()) } @@ -530,6 +540,7 @@ func (p *Process) NumThreadsWithContext(ctx context.Context) (int32, error) { } return ret, nil } + func (p *Process) Threads() (map[int32]*cpu.TimesStat, error) { return p.ThreadsWithContext(context.Background()) } @@ -538,6 +549,7 @@ func (p *Process) ThreadsWithContext(ctx context.Context) (map[int32]*cpu.TimesS ret := make(map[int32]*cpu.TimesStat) return ret, common.ErrNotImplementedError } + func (p *Process) Times() (*cpu.TimesStat, error) { return p.TimesWithContext(context.Background()) } @@ -565,6 +577,7 @@ func (p *Process) TimesWithContext(ctx context.Context) (*cpu.TimesStat, error) System: kernel, }, nil } + func (p *Process) CPUAffinity() ([]int32, error) { return p.CPUAffinityWithContext(context.Background()) } @@ -572,6 +585,7 @@ func (p *Process) CPUAffinity() ([]int32, error) { func (p *Process) CPUAffinityWithContext(ctx context.Context) ([]int32, error) { return nil, common.ErrNotImplementedError } + func (p *Process) MemoryInfo() (*MemoryInfoStat, error) { return p.MemoryInfoWithContext(context.Background()) } @@ -589,6 +603,7 @@ func (p *Process) MemoryInfoWithContext(ctx context.Context) (*MemoryInfoStat, e return ret, nil } + func (p *Process) MemoryInfoEx() (*MemoryInfoExStat, error) { return p.MemoryInfoExWithContext(context.Background()) } @@ -878,7 +893,7 @@ func is32BitProcess(procHandle syscall.Handle) bool { return true } } else { - //if the OS does not support the call, we fallback into the bitness of the app + // if the OS does not support the call, we fallback into the bitness of the app if unsafe.Sizeof(wow64) == 4 { return true } @@ -919,7 +934,7 @@ func getProcessCommandLine(pid int32) (string, error) { procIs32Bits = is32BitProcess(syscall.Handle(h)) default: - //for other unknown platforms, we rely on process platform + // for other unknown platforms, we rely on process platform if unsafe.Sizeof(processorArchitecture) == 8 { procIs32Bits = false } @@ -937,17 +952,17 @@ func getProcessCommandLine(pid int32) (string, error) { } userProcParams := uint64(buf[0]) | (uint64(buf[1]) << 8) | (uint64(buf[2]) << 16) | (uint64(buf[3]) << 24) - //read CommandLine field from PRTL_USER_PROCESS_PARAMETERS + // read CommandLine field from PRTL_USER_PROCESS_PARAMETERS remoteCmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams+uint64(64), 8) if len(remoteCmdLine) != 8 { return "", errors.New("cannot read cmdline field") } - //remoteCmdLine is actually a UNICODE_STRING32 - //the first two bytes has the length + // remoteCmdLine is actually a UNICODE_STRING32 + // the first two bytes has the length cmdLineLength := uint(remoteCmdLine[0]) | (uint(remoteCmdLine[1]) << 8) if cmdLineLength > 0 { - //and, at offset 4, is the pointer to the buffer + // and, at offset 4, is the pointer to the buffer bufferAddress := uint32(remoteCmdLine[4]) | (uint32(remoteCmdLine[5]) << 8) | (uint32(remoteCmdLine[6]) << 16) | (uint32(remoteCmdLine[7]) << 24) @@ -966,17 +981,17 @@ func getProcessCommandLine(pid int32) (string, error) { userProcParams := uint64(buf[0]) | (uint64(buf[1]) << 8) | (uint64(buf[2]) << 16) | (uint64(buf[3]) << 24) | (uint64(buf[4]) << 32) | (uint64(buf[5]) << 40) | (uint64(buf[6]) << 48) | (uint64(buf[7]) << 56) - //read CommandLine field from PRTL_USER_PROCESS_PARAMETERS + // read CommandLine field from PRTL_USER_PROCESS_PARAMETERS remoteCmdLine := readProcessMemory(syscall.Handle(h), procIs32Bits, userProcParams+uint64(112), 16) if len(remoteCmdLine) != 16 { return "", errors.New("cannot read cmdline field") } - //remoteCmdLine is actually a UNICODE_STRING64 - //the first two bytes has the length + // remoteCmdLine is actually a UNICODE_STRING64 + // the first two bytes has the length cmdLineLength := uint(remoteCmdLine[0]) | (uint(remoteCmdLine[1]) << 8) if cmdLineLength > 0 { - //and, at offset 8, is the pointer to the buffer + // and, at offset 8, is the pointer to the buffer bufferAddress := uint64(remoteCmdLine[8]) | (uint64(remoteCmdLine[9]) << 8) | (uint64(remoteCmdLine[10]) << 16) | (uint64(remoteCmdLine[11]) << 24) | (uint64(remoteCmdLine[12]) << 32) | (uint64(remoteCmdLine[13]) << 40) | @@ -991,7 +1006,7 @@ func getProcessCommandLine(pid int32) (string, error) { } } - //if we reach here, we have no command line + // if we reach here, we have no command line return "", nil } diff --git a/internal/gopsutil/process/process_windows_386.go b/internal/gopsutil/process/process_windows_386.go index b9ef3c4b51..9f9f263117 100644 --- a/internal/gopsutil/process/process_windows_386.go +++ b/internal/gopsutil/process/process_windows_386.go @@ -24,7 +24,7 @@ type PROCESS_MEMORY_COUNTERS struct { func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) uint64 { if is32BitProcess { - //we are on a 32-bit process reading an external 32-bit process + // we are on a 32-bit process reading an external 32-bit process var info processBasicInformation32 ret, _, _ := common.ProcNtQueryInformationProcess.Call( @@ -38,8 +38,8 @@ func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) uint64 { return uint64(info.PebBaseAddress) } } else { - //we are on a 32-bit process reading an external 64-bit process - if common.ProcNtWow64QueryInformationProcess64.Find() == nil { //avoid panic + // we are on a 32-bit process reading an external 64-bit process + if common.ProcNtWow64QueryInformationProcess64.Find() == nil { // avoid panic var info processBasicInformation64 ret, _, _ := common.ProcNtWow64QueryInformationProcess64.Call( @@ -55,7 +55,7 @@ func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) uint64 { } } - //return 0 on error + // return 0 on error return 0 } @@ -76,19 +76,19 @@ func readProcessMemory(h syscall.Handle, is32BitProcess bool, address uint64, si return buffer[:read] } } else { - //reading a 64-bit process from a 32-bit one - if common.ProcNtWow64ReadVirtualMemory64.Find() == nil { //avoid panic + // reading a 64-bit process from a 32-bit one + if common.ProcNtWow64ReadVirtualMemory64.Find() == nil { // avoid panic var read uint64 buffer := make([]byte, size) ret, _, _ := common.ProcNtWow64ReadVirtualMemory64.Call( uintptr(h), - uintptr(address&0xFFFFFFFF), //the call expects a 64-bit value + uintptr(address&0xFFFFFFFF), // the call expects a 64-bit value uintptr(address>>32), uintptr(unsafe.Pointer(&buffer[0])), - uintptr(size), //the call expects a 64-bit value - uintptr(0), //but size is 32-bit so pass zero as the high dword + uintptr(size), // the call expects a 64-bit value + uintptr(0), // but size is 32-bit so pass zero as the high dword uintptr(unsafe.Pointer(&read)), ) if int(ret) >= 0 && read > 0 { @@ -97,6 +97,6 @@ func readProcessMemory(h syscall.Handle, is32BitProcess bool, address uint64, si } } - //if we reach here, an error happened + // if we reach here, an error happened return nil } diff --git a/internal/gopsutil/process/process_windows_amd64.go b/internal/gopsutil/process/process_windows_amd64.go index e7dd6c56e9..d9012a0099 100644 --- a/internal/gopsutil/process/process_windows_amd64.go +++ b/internal/gopsutil/process/process_windows_amd64.go @@ -24,7 +24,7 @@ type PROCESS_MEMORY_COUNTERS struct { func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) uint64 { if is32BitProcess { - //we are on a 64-bit process reading an external 32-bit process + // we are on a 64-bit process reading an external 32-bit process var wow64 uint ret, _, _ := common.ProcNtQueryInformationProcess.Call( @@ -38,7 +38,7 @@ func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) uint64 { return uint64(wow64) } } else { - //we are on a 64-bit process reading an external 64-bit process + // we are on a 64-bit process reading an external 64-bit process var info processBasicInformation64 ret, _, _ := common.ProcNtQueryInformationProcess.Call( @@ -53,7 +53,7 @@ func queryPebAddress(procHandle syscall.Handle, is32BitProcess bool) uint64 { } } - //return 0 on error + // return 0 on error return 0 } diff --git a/internal/gopsutil/process/types_darwin.go b/internal/gopsutil/process/types_darwin.go index 0782b476d4..7b8c7ac75c 100644 --- a/internal/gopsutil/process/types_darwin.go +++ b/internal/gopsutil/process/types_darwin.go @@ -153,9 +153,11 @@ type Posix_cred C.struct_posix_cred type Label C.struct_label -type AuditinfoAddr C.struct_auditinfo_addr -type AuMask C.struct_au_mask -type AuTidAddr C.struct_au_tid_addr +type ( + AuditinfoAddr C.struct_auditinfo_addr + AuMask C.struct_au_mask + AuTidAddr C.struct_au_tid_addr +) // TAILQ(ucred) type UcredQueue C.struct_ucred_queue diff --git a/internal/memory/memory_test.go b/internal/memory/memory_test.go index a28b9e63e2..a06048234c 100644 --- a/internal/memory/memory_test.go +++ b/internal/memory/memory_test.go @@ -11,7 +11,7 @@ import ( func Test_Memory(t *testing.T) { t.Parallel() - var store = New() + store := New() var ( key = "john" val interface{} = []byte("doe") @@ -75,7 +75,6 @@ func Benchmark_Memory(b *testing.B) { } for _, key := range keys { d.Delete(key) - } } }) diff --git a/internal/storage/memory/memory_test.go b/internal/storage/memory/memory_test.go index fb2b88a0e5..72692425cd 100644 --- a/internal/storage/memory/memory_test.go +++ b/internal/storage/memory/memory_test.go @@ -64,9 +64,7 @@ func Test_Storage_Memory_Set_Expiration(t *testing.T) { } func Test_Storage_Memory_Get_Expired(t *testing.T) { - var ( - key = "john" - ) + key := "john" result, err := testStore.Get(key) utils.AssertEqual(t, nil, err) @@ -101,9 +99,7 @@ func Test_Storage_Memory_Delete(t *testing.T) { func Test_Storage_Memory_Reset(t *testing.T) { t.Parallel() - var ( - val = []byte("doe") - ) + val := []byte("doe") err := testStore.Set("john1", val, 0) utils.AssertEqual(t, nil, err) diff --git a/internal/wmi/swbemservices.go b/internal/wmi/swbemservices.go index 925b5ac71d..fe812536f6 100644 --- a/internal/wmi/swbemservices.go +++ b/internal/wmi/swbemservices.go @@ -15,8 +15,8 @@ import ( // SWbemServices is used to access wmi. See https://msdn.microsoft.com/en-us/library/aa393719(v=vs.85).aspx type SWbemServices struct { - //TODO: track namespace. Not sure if we can re connect to a different namespace using the same instance - cWMIClient *Client //This could also be an embedded struct, but then we would need to branch on Client vs SWbemServices in the Query method + // TODO: track namespace. Not sure if we can re connect to a different namespace using the same instance + cWMIClient *Client // This could also be an embedded struct, but then we would need to branch on Client vs SWbemServices in the Query method sWbemLocatorIUnknown *ole.IUnknown sWbemLocatorIDispatch *ole.IDispatch queries chan *queryRequest @@ -33,8 +33,8 @@ type queryRequest struct { // InitializeSWbemServices will return a new SWbemServices object that can be used to query WMI func InitializeSWbemServices(c *Client, connectServerArgs ...interface{}) (*SWbemServices, error) { - //fmt.Println("InitializeSWbemServices: Starting") - //TODO: implement connectServerArgs as optional argument for init with connectServer call + // fmt.Println("InitializeSWbemServices: Starting") + // TODO: implement connectServerArgs as optional argument for init with connectServer call s := new(SWbemServices) s.cWMIClient = c s.queries = make(chan *queryRequest) @@ -43,9 +43,9 @@ func InitializeSWbemServices(c *Client, connectServerArgs ...interface{}) (*SWbe err, ok := <-initError if ok { - return nil, err //Send error to caller + return nil, err // Send error to caller } - //fmt.Println("InitializeSWbemServices: Finished") + // fmt.Println("InitializeSWbemServices: Finished") return s, nil } @@ -60,23 +60,23 @@ func (s *SWbemServices) Close() error { s.lQueryorClose.Unlock() return fmt.Errorf("SWbemServices has been closed") } - //fmt.Println("Close: sending close request") + // fmt.Println("Close: sending close request") var result error ce := make(chan error) - s.closeError = ce //Race condition if multiple callers to close. May need to lock here - close(s.queries) //Tell background to shut things down + s.closeError = ce // Race condition if multiple callers to close. May need to lock here + close(s.queries) // Tell background to shut things down s.lQueryorClose.Unlock() err, ok := <-ce if ok { result = err } - //fmt.Println("Close: finished") + // fmt.Println("Close: finished") return result } func (s *SWbemServices) process(initError chan error) { - //fmt.Println("process: starting background thread initialization") - //All OLE/WMI calls must happen on the same initialized thead, so lock this goroutine + // fmt.Println("process: starting background thread initialization") + // All OLE/WMI calls must happen on the same initialized thead, so lock this goroutine runtime.LockOSThread() defer runtime.UnlockOSThread() @@ -110,22 +110,22 @@ func (s *SWbemServices) process(initError chan error) { s.sWbemLocatorIDispatch = dispatch // we can't do the ConnectServer call outside the loop unless we find a way to track and re-init the connectServerArgs - //fmt.Println("process: initialized. closing initError") + // fmt.Println("process: initialized. closing initError") close(initError) - //fmt.Println("process: waiting for queries") + // fmt.Println("process: waiting for queries") for q := range s.queries { - //fmt.Printf("process: new query: len(query)=%d\n", len(q.query)) + // fmt.Printf("process: new query: len(query)=%d\n", len(q.query)) errQuery := s.queryBackground(q) - //fmt.Println("process: s.queryBackground finished") + // fmt.Println("process: s.queryBackground finished") if errQuery != nil { q.finished <- errQuery } close(q.finished) } - //fmt.Println("process: queries channel closed") - s.queries = nil //set channel to nil so we know it is closed - //TODO: I think the Release/Clear calls can panic if things are in a bad state. - //TODO: May need to recover from panics and send error to method caller instead. + // fmt.Println("process: queries channel closed") + s.queries = nil // set channel to nil so we know it is closed + // TODO: I think the Release/Clear calls can panic if things are in a bad state. + // TODO: May need to recover from panics and send error to method caller instead. close(s.closeError) } @@ -150,7 +150,7 @@ func (s *SWbemServices) Query(query string, dst interface{}, connectServerArgs . return fmt.Errorf("SWbemServices has been closed") } - //fmt.Println("Query: Sending query request") + // fmt.Println("Query: Sending query request") qr := queryRequest{ query: query, dst: dst, @@ -161,10 +161,10 @@ func (s *SWbemServices) Query(query string, dst interface{}, connectServerArgs . s.lQueryorClose.Unlock() err, ok := <-qr.finished if ok { - //fmt.Println("Query: Finished with error") - return err //Send error to caller + // fmt.Println("Query: Finished with error") + return err // Send error to caller } - //fmt.Println("Query: Finished") + // fmt.Println("Query: Finished") return nil } @@ -172,8 +172,8 @@ func (s *SWbemServices) queryBackground(q *queryRequest) error { if s == nil || s.sWbemLocatorIDispatch == nil { return fmt.Errorf("SWbemServices is not Initialized") } - wmi := s.sWbemLocatorIDispatch //Should just rename in the code, but this will help as we break things apart - //fmt.Println("queryBackground: Starting") + wmi := s.sWbemLocatorIDispatch // Should just rename in the code, but this will help as we break things apart + // fmt.Println("queryBackground: Starting") dv := reflect.ValueOf(q.dst) if dv.Kind() != reflect.Ptr || dv.IsNil() { @@ -256,6 +256,6 @@ func (s *SWbemServices) queryBackground(q *queryRequest) error { return err } } - //fmt.Println("queryBackground: Finished") + // fmt.Println("queryBackground: Finished") return errFieldMismatch } diff --git a/internal/wmi/wmi.go b/internal/wmi/wmi.go index a324b989ad..5992c6c279 100644 --- a/internal/wmi/wmi.go +++ b/internal/wmi/wmi.go @@ -285,7 +285,7 @@ func (c *Client) loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismat } defer prop.Clear() - if prop.VT == 0x1 { //VT_NULL + if prop.VT == 0x1 { // VT_NULL continue } diff --git a/listen.go b/listen.go index de4a86006e..342b05f802 100644 --- a/listen.go +++ b/listen.go @@ -19,10 +19,11 @@ import ( "strings" "text/tabwriter" - "github.com/gofiber/fiber/v2/log" "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "github.com/mattn/go-runewidth" + + "github.com/gofiber/fiber/v2/log" ) const ( diff --git a/middleware/adaptor/adaptor.go b/middleware/adaptor/adaptor.go index 84cc866aa8..db2149d921 100644 --- a/middleware/adaptor/adaptor.go +++ b/middleware/adaptor/adaptor.go @@ -7,10 +7,11 @@ import ( "reflect" "unsafe" - "github.com/gofiber/fiber/v2" - "github.com/gofiber/fiber/v2/utils" "github.com/valyala/fasthttp" "github.com/valyala/fasthttp/fasthttpadaptor" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/utils" ) // HTTPHandlerFunc wraps net/http handler func to fiber handler diff --git a/middleware/adaptor/adaptor_test.go b/middleware/adaptor/adaptor_test.go index 8187baefb9..340c05c04b 100644 --- a/middleware/adaptor/adaptor_test.go +++ b/middleware/adaptor/adaptor_test.go @@ -12,9 +12,10 @@ import ( "net/url" "testing" + "github.com/valyala/fasthttp" + "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/utils" - "github.com/valyala/fasthttp" ) func Test_HTTPHandler(t *testing.T) { diff --git a/path.go b/path.go index d0a3338abe..2cf88c7e5c 100644 --- a/path.go +++ b/path.go @@ -13,8 +13,9 @@ import ( "time" "unicode" - "github.com/gofiber/fiber/v2/utils" "github.com/google/uuid" + + "github.com/gofiber/fiber/v2/utils" ) // routeParser holds the path segments and param names diff --git a/prefork.go b/prefork.go index a26d931456..3f640121f7 100644 --- a/prefork.go +++ b/prefork.go @@ -12,8 +12,9 @@ import ( "sync/atomic" "time" - "github.com/gofiber/fiber/v2/log" "github.com/valyala/fasthttp/reuseport" + + "github.com/gofiber/fiber/v2/log" ) const ( From 0d3354675bbd9e47e5023a1b905d0c35315a8205 Mon Sep 17 00:00:00 2001 From: Tiago Peczenyj Date: Thu, 5 Oct 2023 13:49:57 +0200 Subject: [PATCH 56/84] Fix loop variable captured by func literal (#2660) * fix loop variable xxx captured by func literal * fix middleware/pprof tests --- middleware/compress/compress_test.go | 1 + middleware/filesystem/filesystem_test.go | 1 + middleware/pprof/pprof_test.go | 14 ++------------ 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/middleware/compress/compress_test.go b/middleware/compress/compress_test.go index 4baf19c73d..2c5c52d8a8 100644 --- a/middleware/compress/compress_test.go +++ b/middleware/compress/compress_test.go @@ -53,6 +53,7 @@ func Test_Compress_Different_Level(t *testing.T) { t.Parallel() levels := []Level{LevelBestSpeed, LevelBestCompression} for _, level := range levels { + level := level t.Run(fmt.Sprintf("level %d", level), func(t *testing.T) { t.Parallel() app := fiber.New() diff --git a/middleware/filesystem/filesystem_test.go b/middleware/filesystem/filesystem_test.go index d592046c45..4c646fdd90 100644 --- a/middleware/filesystem/filesystem_test.go +++ b/middleware/filesystem/filesystem_test.go @@ -119,6 +119,7 @@ func Test_FileSystem(t *testing.T) { } for _, tt := range tests { + tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, tt.url, nil)) diff --git a/middleware/pprof/pprof_test.go b/middleware/pprof/pprof_test.go index b76a6f1c65..c9c8e078a9 100644 --- a/middleware/pprof/pprof_test.go +++ b/middleware/pprof/pprof_test.go @@ -11,7 +11,6 @@ import ( ) func Test_Non_Pprof_Path(t *testing.T) { - t.Parallel() app := fiber.New(fiber.Config{DisableStartupMessage: true}) app.Use(New()) @@ -30,7 +29,6 @@ func Test_Non_Pprof_Path(t *testing.T) { } func Test_Non_Pprof_Path_WithPrefix(t *testing.T) { - t.Parallel() app := fiber.New(fiber.Config{DisableStartupMessage: true}) app.Use(New(Config{Prefix: "/federated-fiber"})) @@ -49,7 +47,6 @@ func Test_Non_Pprof_Path_WithPrefix(t *testing.T) { } func Test_Pprof_Index(t *testing.T) { - t.Parallel() app := fiber.New(fiber.Config{DisableStartupMessage: true}) app.Use(New()) @@ -69,7 +66,6 @@ func Test_Pprof_Index(t *testing.T) { } func Test_Pprof_Index_WithPrefix(t *testing.T) { - t.Parallel() app := fiber.New(fiber.Config{DisableStartupMessage: true}) app.Use(New(Config{Prefix: "/federated-fiber"})) @@ -89,7 +85,6 @@ func Test_Pprof_Index_WithPrefix(t *testing.T) { } func Test_Pprof_Subs(t *testing.T) { - t.Parallel() app := fiber.New(fiber.Config{DisableStartupMessage: true}) app.Use(New()) @@ -104,8 +99,8 @@ func Test_Pprof_Subs(t *testing.T) { } for _, sub := range subs { + sub := sub t.Run(sub, func(t *testing.T) { - t.Parallel() target := "/debug/pprof/" + sub if sub == "profile" { target += "?seconds=1" @@ -118,7 +113,6 @@ func Test_Pprof_Subs(t *testing.T) { } func Test_Pprof_Subs_WithPrefix(t *testing.T) { - t.Parallel() app := fiber.New(fiber.Config{DisableStartupMessage: true}) app.Use(New(Config{Prefix: "/federated-fiber"})) @@ -133,8 +127,8 @@ func Test_Pprof_Subs_WithPrefix(t *testing.T) { } for _, sub := range subs { + sub := sub t.Run(sub, func(t *testing.T) { - t.Parallel() target := "/federated-fiber/debug/pprof/" + sub if sub == "profile" { target += "?seconds=1" @@ -147,7 +141,6 @@ func Test_Pprof_Subs_WithPrefix(t *testing.T) { } func Test_Pprof_Other(t *testing.T) { - t.Parallel() app := fiber.New(fiber.Config{DisableStartupMessage: true}) app.Use(New()) @@ -162,7 +155,6 @@ func Test_Pprof_Other(t *testing.T) { } func Test_Pprof_Other_WithPrefix(t *testing.T) { - t.Parallel() app := fiber.New(fiber.Config{DisableStartupMessage: true}) app.Use(New(Config{Prefix: "/federated-fiber"})) @@ -178,7 +170,6 @@ func Test_Pprof_Other_WithPrefix(t *testing.T) { // go test -run Test_Pprof_Next func Test_Pprof_Next(t *testing.T) { - t.Parallel() app := fiber.New() app.Use(New(Config{ @@ -194,7 +185,6 @@ func Test_Pprof_Next(t *testing.T) { // go test -run Test_Pprof_Next_WithPrefix func Test_Pprof_Next_WithPrefix(t *testing.T) { - t.Parallel() app := fiber.New() app.Use(New(Config{ From 59409f38419dc2a7d73493782e0beb191fae892a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Fri, 6 Oct 2023 11:43:10 +0200 Subject: [PATCH 57/84] improve sendFile documentation --- docs/api/ctx.md | 4 +++ docs/api/middleware/filesystem.md | 45 +++++++++++++++++++++++++++++ middleware/filesystem/filesystem.go | 4 ++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/docs/api/ctx.md b/docs/api/ctx.md index fdd473aacc..b1e14f2d6d 100644 --- a/docs/api/ctx.md +++ b/docs/api/ctx.md @@ -1710,6 +1710,10 @@ app.Get("/file-with-url-chars", func(c *fiber.Ctx) error { }) ``` +:::info +For sending files from embedded file system [this functionality](./middleware/filesystem.md#sendfile) can be used +::: + ## SendStatus Sets the status code and the correct status message in the body, if the response body is **empty**. diff --git a/docs/api/middleware/filesystem.md b/docs/api/middleware/filesystem.md index 38e3622db7..bbeff14bf7 100644 --- a/docs/api/middleware/filesystem.md +++ b/docs/api/middleware/filesystem.md @@ -253,3 +253,48 @@ var ConfigDefault = Config{ ContentTypeCharset: "", } ``` + +## Utils + +### SendFile + +Serves a file from an [HTTP file system](https://pkg.go.dev/net/http#FileSystem) at the specified path. + +```go title="Signature" title="Signature" +func SendFile(c *fiber.Ctx, filesystem http.FileSystem, path string) error +``` +Import the middleware package that is part of the Fiber web framework + +```go +import ( + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/filesystem" +) +``` + +```go title="Example" +// Define a route to serve a specific file +app.Get("/download", func(c *fiber.Ctx) error { + // Serve the file using SendFile function + err := filesystem.SendFile(c, http.Dir("your/filesystem/root"), "path/to/your/file.txt") + if err != nil { + // Handle the error, e.g., return a 404 Not Found response + return c.Status(fiber.StatusNotFound).SendString("File not found") + } + + return nil +}) +``` + +```go title="Example" +// Serve static files from the "build" directory using Fiber's built-in middleware. +app.Use("/", filesystem.New(filesystem.Config{ + Root: http.FS(f), // Specify the root directory for static files. + PathPrefix: "build", // Define the path prefix where static files are served. +})) + +// For all other routes (wildcard "*"), serve the "index.html" file from the "build" directory. +app.Use("*", func(ctx *fiber.Ctx) error { + return filesystem.SendFile(ctx, http.FS(f), "build/index.html") +}) +``` diff --git a/middleware/filesystem/filesystem.go b/middleware/filesystem/filesystem.go index ea23ab05cf..1a6d2b2a79 100644 --- a/middleware/filesystem/filesystem.go +++ b/middleware/filesystem/filesystem.go @@ -219,7 +219,9 @@ func New(config ...Config) fiber.Handler { } } -// SendFile ... +// SendFile serves a file from an HTTP file system at the specified path. +// It handles content serving, sets appropriate headers, and returns errors when needed. +// Usage: err := SendFile(ctx, fs, "/path/to/file.txt") func SendFile(c *fiber.Ctx, filesystem http.FileSystem, path string) error { file, err := filesystem.Open(path) if err != nil { From 8228da91fc00adb2a7b11680ea715e67147113e4 Mon Sep 17 00:00:00 2001 From: Michael Bell Date: Fri, 6 Oct 2023 12:10:20 +0100 Subject: [PATCH 58/84] [filesystem middleware] improve status for SendFile (#2664) SendFile response code for success --- middleware/filesystem/filesystem.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/middleware/filesystem/filesystem.go b/middleware/filesystem/filesystem.go index 1a6d2b2a79..547dc34804 100644 --- a/middleware/filesystem/filesystem.go +++ b/middleware/filesystem/filesystem.go @@ -254,6 +254,8 @@ func SendFile(c *fiber.Ctx, filesystem http.FileSystem, path string) error { return fiber.ErrForbidden } + c.Status(fiber.StatusOK) + modTime := stat.ModTime() contentLength := int(stat.Size()) From 6ecd607d9717b3312e3bd0c2da5194bdba78ff00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Oct 2023 20:08:01 +0300 Subject: [PATCH 59/84] build(deps): bump golang.org/x/sys from 0.12.0 to 0.13.0 (#2665) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.12.0 to 0.13.0. - [Commits](https://github.com/golang/sys/compare/v0.12.0...v0.13.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 235d44af0e..d3bed281c4 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.50.0 - golang.org/x/sys v0.12.0 + golang.org/x/sys v0.13.0 ) require ( diff --git a/go.sum b/go.sum index c26d486a85..720bb1459f 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.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= -golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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= From fc2ab3387ade433b1f17bb3459eeb2a89483073f Mon Sep 17 00:00:00 2001 From: Jiun Lee Date: Sun, 8 Oct 2023 19:45:11 +0800 Subject: [PATCH 60/84] =?UTF-8?q?=F0=9F=A9=B9Fix=20incorrect=20log=20depth?= =?UTF-8?q?=20when=20use=20log.WithContext=20(#2666)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix withContext caller --- log/default.go | 6 +++++- log/default_test.go | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/log/default.go b/log/default.go index e78f1e3daf..c898cd6c83 100644 --- a/log/default.go +++ b/log/default.go @@ -188,7 +188,11 @@ func (l *defaultLogger) Panicw(msg string, keysAndValues ...interface{}) { } func (l *defaultLogger) WithContext(_ context.Context) CommonLogger { - return l + return &defaultLogger{ + stdlog: l.stdlog, + level: l.level, + depth: l.depth - 1, + } } func (l *defaultLogger) SetLevel(level Level) { diff --git a/log/default_test.go b/log/default_test.go index 7562b0a169..9dd5fd7c51 100644 --- a/log/default_test.go +++ b/log/default_test.go @@ -156,6 +156,22 @@ func Test_LogfKeyAndValues(t *testing.T) { } } +func Test_WithContextCaller(t *testing.T) { + logger = &defaultLogger{ + stdlog: log.New(os.Stderr, "", log.Lshortfile), + depth: 4, + } + + var w byteSliceWriter + SetOutput(&w) + ctx := context.TODO() + + WithContext(ctx).Info("") + Info("") + + utils.AssertEqual(t, "default_test.go:169: [Info] \ndefault_test.go:170: [Info] \n", string(w.b)) +} + func Test_SetLevel(t *testing.T) { setLogger := &defaultLogger{ stdlog: log.New(os.Stderr, "", log.LstdFlags|log.Lshortfile|log.Lmicroseconds), From ada2d4affdde6f3a998cc53e92a0c262dff07708 Mon Sep 17 00:00:00 2001 From: RW Date: Mon, 9 Oct 2023 08:58:49 +0200 Subject: [PATCH 61/84] Update hooks.md --- docs/guide/hooks.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/hooks.md b/docs/guide/hooks.md index 0b7db96b33..b001786535 100644 --- a/docs/guide/hooks.md +++ b/docs/guide/hooks.md @@ -1,6 +1,6 @@ --- id: hooks -title: 🪝 Hooks +title: 🎣 Hooks sidebar_position: 6 --- From 8c69065e83031e14be0a8c4102f73b77fe8c5e62 Mon Sep 17 00:00:00 2001 From: Josh Larsen <2565382+joshlarsen@users.noreply.github.com> Date: Tue, 10 Oct 2023 02:11:18 -0400 Subject: [PATCH 62/84] =?UTF-8?q?=F0=9F=93=9A=20[Doc]=20fix=20incorrect=20?= =?UTF-8?q?status=20code=20source=20(#2667)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix incorrect status code source * fix typo --- helpers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helpers.go b/helpers.go index cc36f13e10..0041458994 100644 --- a/helpers.go +++ b/helpers.go @@ -625,7 +625,7 @@ const ( MIMEApplicationJavaScriptCharsetUTF8 = "application/javascript; charset=utf-8" ) -// HTTP status codes were copied from https://github.com/nginx/nginx/blob/67d2a9541826ecd5db97d604f23460210fd3e517/conf/mime.types with the following updates: +// HTTP status codes were copied from net/http with the following updates: // - Rename StatusNonAuthoritativeInfo to StatusNonAuthoritativeInformation // - Add StatusSwitchProxy (306) // NOTE: Keep this list in sync with statusMessage From 9292a36e28c05e5b91ccdbcd7707a576594712ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Tue, 10 Oct 2023 09:23:23 +0300 Subject: [PATCH 63/84] :bug: bug: fix nil pointer dereference issue on idempotency middleware (#2668) --- middleware/idempotency/config.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/middleware/idempotency/config.go b/middleware/idempotency/config.go index f6dd8b4917..fee775938d 100644 --- a/middleware/idempotency/config.go +++ b/middleware/idempotency/config.go @@ -77,7 +77,14 @@ var ConfigDefault = Config{ func configDefault(config ...Config) Config { // Return default config if nothing provided if len(config) < 1 { - return ConfigDefault + cfg := ConfigDefault + + cfg.Lock = NewMemoryLock() + cfg.Storage = memory.New(memory.Config{ + GCInterval: cfg.Lifetime / 2, // Half the lifetime interval + }) + + return cfg } // Override default config From b50d91d58ecdff2a330bf07950244b6c4caf65b1 Mon Sep 17 00:00:00 2001 From: Jason McNeil Date: Wed, 11 Oct 2023 09:41:42 -0300 Subject: [PATCH 64/84] Merge pull request from GHSA-94w9-97p3-p368 * feat: improved csrf with session support * fix: double submit cookie * feat: add warning cookie extractor without session * feat: add warning CsrfFromCookie SameSite * fix: use byes.Equal instead * fix: Overriden CookieName KeyLookup cookie: * feat: Create helpers.go * feat: use compareTokens (constant time compare) * feat: validate cookie to prevent token injection * refactor: clean up csrf.go * docs: update comment about Double Submit Cookie * docs: update docs for CSRF changes * feat: add DeleteToken * refactor: no else * test: add more tests * refactor: re-order tests * docs: update safe methods RCF add note * test: add CSRF_Cookie_Injection_Exploit * feat: add SingleUseToken config * test: check for new token * docs: use warning * fix: always register type Token * feat: use UUIDv4 * test: swap in UUIDv4 here too --- docs/api/middleware/csrf.md | 117 +++++- middleware/csrf/config.go | 54 ++- middleware/csrf/csrf.go | 214 ++++++++-- middleware/csrf/csrf_test.go | 371 +++++++++++++++++- middleware/csrf/helpers.go | 7 + middleware/csrf/session_manager.go | 68 ++++ .../csrf/{manager.go => storage_manager.go} | 27 +- ...anager_msgp.go => storage_manager_msgp.go} | 0 middleware/csrf/token.go | 9 + 9 files changed, 793 insertions(+), 74 deletions(-) create mode 100644 middleware/csrf/helpers.go create mode 100644 middleware/csrf/session_manager.go rename middleware/csrf/{manager.go => storage_manager.go} (63%) rename middleware/csrf/{manager_msgp.go => storage_manager_msgp.go} (100%) create mode 100644 middleware/csrf/token.go diff --git a/docs/api/middleware/csrf.md b/docs/api/middleware/csrf.md index dbbf6007d9..66a3a6e62b 100644 --- a/docs/api/middleware/csrf.md +++ b/docs/api/middleware/csrf.md @@ -4,7 +4,7 @@ id: csrf # CSRF -CSRF middleware for [Fiber](https://github.com/gofiber/fiber) that provides [Cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery) protection by passing a csrf token via cookies. This cookie value will be used to compare against the client csrf token on requests, other than those defined as "safe" by RFC7231 \(GET, HEAD, OPTIONS, or TRACE\). When the csrf token is invalid, this middleware will return the `fiber.ErrForbidden` error. +CSRF middleware for [Fiber](https://github.com/gofiber/fiber) that provides [Cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery) protection by passing a csrf token via cookies. This cookie value will be used to compare against the client csrf token on requests, 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, or TRACE\). When the csrf token is invalid, this middleware will return the `fiber.ErrForbidden` error. CSRF Tokens are generated on GET requests. You can retrieve the CSRF token with `c.Locals(contextKey)`, where `contextKey` is the string you set in the config (see Custom Config below). @@ -14,6 +14,70 @@ When no `csrf_` cookie is set, or the token has expired, a new token will be gen This middleware uses our [Storage](https://github.com/gofiber/storage) package to support various databases through a single interface. The default configuration for this middleware saves data to memory, see the examples below for other databases. ::: +## Security Considerations + +This middleware is designed to protect against CSRF attacks. It does not protect against other attack vectors, such as XSS, and should be used in combination with other security measures. + +:::warning +Never use 'safe' methods to mutate data. For example, never use a GET request to delete a resource. This middleware will not protect against CSRF attacks on 'safe' methods. +::: + +### The Double Submit Cookie Pattern (Default) + +In the default configuration, the middleware will generate and store tokens using the `fiber.Storage` interface. These tokens are not associated with a user session, and, therefore, a Double Submit Cookie pattern is used to validate the token. This means that the token is stored in a cookie and also sent as a header on requests. The middleware will compare the cookie value with the header value to validate the token. This is a secure method of validating the token, as cookies are not accessible to JavaScript and, therefore, cannot be read by an attacker. + +:::warning +When using this method, it is important that you set the `CookieSameSite` option to `Lax` or `Strict` and that the Extractor is not `CsrfFromCookie`, and KeyLookup is not `cookie:`. +::: + +### The Synchronizer Token Pattern (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. + +:::warning +When using this method, pre-sessions are required and will be created if a session is not already present. This means that the middleware will create a session for every safe request, even if the request does not require a session. Therefore it is required that the existence of a session is not used to indicate that a user is logged in or authenticated, and that a session value is used to indicate this instead. +::: + +### Defense In Depth + +When using this middleware, it is recommended that you serve your pages over HTTPS, that the `CookieSecure` option is set to `true`, and that the `CookieSameSite` option is set to `Lax` or `Strict`. This will ensure that the cookie is only sent over HTTPS and that it is not sent on requests from external sites. + +### Referer Checking + +For HTTPS requests, this middleware performs strict referer checking. This means that 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. + +### Token Lifecycle + +Tokens are valid until they expire, or until they are deleted. By default, tokens are valid for 1 hour and each subsequent request will extend the expiration by 1 hour. This means that if a user makes a request every hour, the token will never expire. If a user makes a request after the token has expired, then a new token will be generated and the `csrf_` cookie will be set again. This means that the token will only expire if the user does not make a request for the duration of the expiration time. + +#### Token Reuse + +By default tokens may be used multiple times. This means that the token will not be deleted after it has been used. If you would like to delete the token after it has been used, then 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. + +:::note +Using `SingleUseToken` comes with usability tradeoffs, and therefore is not enabled by default. It can interfere with the user experience if the user has multiple tabs open, or if the user uses the back button. +::: + +#### Deleting Tokens + +When the authorization status changes, the CSRF token should be deleted and a new one generated. This can be done by calling `handler.DeleteToken(c)`. This will remove the token found in the request context from the storage and set the `csrf_` cookie to an empty value. The next 'safe' request will generate a new token and set the cookie again. + +```go +if handler, ok := app.AcquireCtx(ctx).Locals(ConfigDefault.HandlerContextKey).(*CSRFHandler); ok { + if err := handler.DeleteToken(app.AcquireCtx(ctx)); err != nil { + // handle error + } +} +``` + +:::note +If you are using this middleware with the fiber session middleware, then you can simply call `session.Destroy()`, `session.Regenerate()`, or `session.Reset()` to delete session and the token stored therein. +::: + +### BREACH + +It is important to note that the token is sent as a header on every request, and if you include the token in a page that is vulnerable to [BREACH](https://en.wikipedia.org/wiki/BREACH), then an attacker may be able to extract the token. To mitigate this, you should take steps such as ensuring that your pages are served over HTTPS, that HTTP compression is disabled, and rate limiting requests. + ## Signatures ```go @@ -43,7 +107,7 @@ app.Use(csrf.New(csrf.Config{ CookieName: "csrf_", CookieSameSite: "Lax", Expiration: 1 * time.Hour, - KeyGenerator: utils.UUID, + KeyGenerator: utils.UUIDv4, Extractor: func(c *fiber.Ctx) (string, error) { ... }, })) ``` @@ -52,6 +116,10 @@ app.Use(csrf.New(csrf.Config{ KeyLookup will be ignored if Extractor is explicitly set. ::: +### Use with fiber/middleware/session (recommended) + +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. + ## Config ### Config @@ -60,7 +128,7 @@ KeyLookup will be ignored if Extractor is explicitly set. |:------------------|:-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------| | 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" | -| CookieName | `string` | Name of the session cookie. This cookie will store the session key. | "csrf_" | +| 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. | "" | | CookieSecure | `bool` | Indicates if the CSRF cookie is secure. | false | @@ -68,26 +136,51 @@ KeyLookup will be ignored if Extractor is explicitly set. | CookieSameSite | `string` | Value of SameSite cookie. | "Lax" | | CookieSessionOnly | `bool` | Decides whether the cookie should last for only the browser session. Ignores Expiration if set to true. | false | | Expiration | `time.Duration` | Expiration is the duration before the CSRF token will expire. | 1 * time.Hour | -| Storage | `fiber.Storage` | Store is used to store the state of the middleware. | memory.New() | +| 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. | "" | | 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 | +| Cookie | `*fiber.Cookie` (Deprecated) | Deprecated: Please use Cookie* related fields. | `nil` | | TokenLookup | `string` (Deprecated) | Deprecated: Please use KeyLookup. | "" | | ErrorHandler | `fiber.ErrorHandler` | ErrorHandler is executed when an error is returned from fiber.Handler. | DefaultErrorHandler | | Extractor | `func(*fiber.Ctx) (string, error)` | Extractor returns the CSRF token. If set, this will be used in place of an Extractor based on KeyLookup. | Extractor based on KeyLookup | +| HandlerContextKey | `string` | HandlerContextKey is used to store the CSRF Handler into context. | "fiber.csrf.handler" | ## Default Config ```go var ConfigDefault = Config{ - KeyLookup: "header:" + HeaderName, - CookieName: "csrf_", - CookieSameSite: "Lax", - Expiration: 1 * time.Hour, - KeyGenerator: utils.UUID, - ErrorHandler: defaultErrorHandler, - Extractor: CsrfFromHeader(HeaderName), + KeyLookup: "header:" + HeaderName, + CookieName: "csrf_", + CookieSameSite: "Lax", + Expiration: 1 * time.Hour, + KeyGenerator: utils.UUIDv4, + ErrorHandler: defaultErrorHandler, + Extractor: CsrfFromHeader(HeaderName), + SessionKey: "fiber.csrf.token", + HandlerContextKey: "fiber.csrf.handler", +} +``` + +## Recommended Config (with session) + +```go +var ConfigDefault = Config{ + KeyLookup: "header:" + HeaderName, + CookieName: "csrf_", + CookieSameSite: "Lax", + CookieSessionOnly: true, + CookieHTTPOnly: true, + Expiration: 1 * time.Hour, + KeyGenerator: utils.UUIDv4, + ErrorHandler: defaultErrorHandler, + Extractor: CsrfFromHeader(HeaderName), + Session: session.Store, + SessionKey: "fiber.csrf.token", + HandlerContextKey: "fiber.csrf.handler", } ``` diff --git a/middleware/csrf/config.go b/middleware/csrf/config.go index f17f79a836..432378bfba 100644 --- a/middleware/csrf/config.go +++ b/middleware/csrf/config.go @@ -7,6 +7,7 @@ import ( "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/log" + "github.com/gofiber/fiber/v2/middleware/session" "github.com/gofiber/fiber/v2/utils" ) @@ -33,6 +34,7 @@ type Config struct { // Name of the session cookie. This cookie will store session key. // Optional. Default value "csrf_". + // Overriden if KeyLookup == "cookie:" CookieName string // Domain of the CSRF cookie. @@ -64,11 +66,29 @@ type Config struct { // Optional. Default: 1 * time.Hour Expiration time.Duration + // SingleUseToken indicates if the CSRF token be destroyed + // and a new one generated on each use. + // + // Optional. Default: false + SingleUseToken bool + // Store is used to store the state of the middleware // // Optional. Default: memory.New() + // Ignored if Session is set. Storage fiber.Storage + // Session is used to store the state of the middleware + // + // Optional. Default: nil + // If set, the middleware will use the session store instead of the storage + Session *session.Store + + // SessionKey is the key used to store the token in the session + // + // Default: "fiber.csrf.token" + SessionKey string + // Context key to store generated CSRF token into context. // If left empty, token will not be stored in context. // @@ -100,19 +120,26 @@ type Config struct { // // Optional. Default will create an Extractor based on KeyLookup. Extractor func(c *fiber.Ctx) (string, error) + + // HandlerContextKey is used to store the CSRF Handler into context + // + // Default: "fiber.csrf.handler" + HandlerContextKey string } const HeaderName = "X-Csrf-Token" // ConfigDefault is the default config var ConfigDefault = Config{ - KeyLookup: "header:" + HeaderName, - CookieName: "csrf_", - CookieSameSite: "Lax", - Expiration: 1 * time.Hour, - KeyGenerator: utils.UUID, - ErrorHandler: defaultErrorHandler, - Extractor: CsrfFromHeader(HeaderName), + KeyLookup: "header:" + HeaderName, + CookieName: "csrf_", + CookieSameSite: "Lax", + Expiration: 1 * time.Hour, + KeyGenerator: utils.UUIDv4, + ErrorHandler: defaultErrorHandler, + Extractor: CsrfFromHeader(HeaderName), + SessionKey: "fiber.csrf.token", + HandlerContextKey: "fiber.csrf.handler", } // default ErrorHandler that process return error from fiber.Handler @@ -174,6 +201,12 @@ func configDefault(config ...Config) Config { if cfg.ErrorHandler == nil { cfg.ErrorHandler = ConfigDefault.ErrorHandler } + if cfg.SessionKey == "" { + cfg.SessionKey = ConfigDefault.SessionKey + } + if cfg.HandlerContextKey == "" { + cfg.HandlerContextKey = ConfigDefault.HandlerContextKey + } // Generate the correct extractor to get the token from the correct location selectors := strings.Split(cfg.KeyLookup, ":") @@ -195,7 +228,14 @@ func configDefault(config ...Config) Config { case "param": cfg.Extractor = CsrfFromParam(selectors[1]) case "cookie": + if cfg.Session == nil { + log.Warn("[CSRF] Cookie extractor is not recommended without a session store") + } + if cfg.CookieSameSite == "None" || cfg.CookieSameSite != "Lax" && cfg.CookieSameSite != "Strict" { + log.Warn("[CSRF] Cookie extractor is only recommended for use with SameSite=Lax or SameSite=Strict") + } cfg.Extractor = CsrfFromCookie(selectors[1]) + cfg.CookieName = selectors[1] // Cookie name is the same as the key } } diff --git a/middleware/csrf/csrf.go b/middleware/csrf/csrf.go index 22123441d1..b7b0127469 100644 --- a/middleware/csrf/csrf.go +++ b/middleware/csrf/csrf.go @@ -2,22 +2,42 @@ package csrf import ( "errors" + "reflect" "time" "github.com/gofiber/fiber/v2" ) -var errTokenNotFound = errors.New("csrf token not found") +var ( + ErrTokenNotFound = errors.New("csrf token not found") + ErrTokenInvalid = errors.New("csrf token invalid") + ErrNoReferer = errors.New("referer not supplied") + ErrBadReferer = errors.New("referer invalid") + dummyValue = []byte{'+'} +) + +type CSRFHandler struct { + config *Config + sessionManager *sessionManager + storageManager *storageManager +} // New creates a new middleware handler func New(config ...Config) fiber.Handler { // Set default config cfg := configDefault(config...) - // Create manager to simplify storage operations ( see manager.go ) - manager := newManager(cfg.Storage) + // Create manager to simplify storage operations ( see *_manager.go ) + var sessionManager *sessionManager + var storageManager *storageManager + if cfg.Session != nil { + // Register the Token struct in the session store + cfg.Session.RegisterType(Token{}) - dummyValue := []byte{'+'} + sessionManager = newSessionManager(cfg.Session, cfg.SessionKey) + } else { + storageManager = newStorageManager(cfg.Storage) + } // Return new handler return func(c *fiber.Ctx) error { @@ -26,36 +46,69 @@ func New(config ...Config) fiber.Handler { return c.Next() } + // Store the CSRF handler in the context if a context key is specified + if cfg.HandlerContextKey != "" { + c.Locals(cfg.HandlerContextKey, &CSRFHandler{ + config: &cfg, + sessionManager: sessionManager, + storageManager: storageManager, + }) + } + var token string // Action depends on the HTTP method switch c.Method() { case fiber.MethodGet, fiber.MethodHead, fiber.MethodOptions, fiber.MethodTrace: - // Declare empty token and try to get existing CSRF from cookie - token = c.Cookies(cfg.CookieName) + cookieToken := c.Cookies(cfg.CookieName) + + if cookieToken != "" { + rawToken := getTokenFromStorage(c, cookieToken, cfg, sessionManager, storageManager) + + if rawToken != nil { + token = string(rawToken) + } + } default: // Assume that anything not defined as 'safe' by RFC7231 needs protection + // Enforce an origin check for HTTPS connections. + if c.Protocol() == "https" { + if err := refererMatchesHost(c); err != nil { + return cfg.ErrorHandler(c, err) + } + } + // Extract token from client request i.e. header, query, param, form or cookie - token, err := cfg.Extractor(c) + extractedToken, err := cfg.Extractor(c) if err != nil { return cfg.ErrorHandler(c, err) } - // if token does not exist in Storage - if manager.getRaw(token) == nil { - // Expire cookie - c.Cookie(&fiber.Cookie{ - Name: cfg.CookieName, - Domain: cfg.CookieDomain, - Path: cfg.CookiePath, - Expires: time.Now().Add(-1 * time.Minute), - Secure: cfg.CookieSecure, - HTTPOnly: cfg.CookieHTTPOnly, - SameSite: cfg.CookieSameSite, - SessionOnly: cfg.CookieSessionOnly, - }) - return cfg.ErrorHandler(c, errTokenNotFound) + if extractedToken == "" { + return cfg.ErrorHandler(c, ErrTokenNotFound) + } + + // If not using CsrfFromCookie extractor, check that the token matches the cookie + // This is to prevent CSRF attacks by using a Double Submit Cookie method + // Useful when we do not have access to the users Session + if !isCsrfFromCookie(cfg.Extractor) && extractedToken != c.Cookies(cfg.CookieName) { + return cfg.ErrorHandler(c, ErrTokenInvalid) + } + + rawToken := getTokenFromStorage(c, extractedToken, cfg, sessionManager, storageManager) + + if rawToken == nil { + // If token is not in storage, expire the cookie + expireCSRFCookie(c, cfg) + // and return an error + return cfg.ErrorHandler(c, ErrTokenNotFound) + } + if cfg.SingleUseToken { + // If token is single use, delete it from storage + deleteTokenFromStorage(c, extractedToken, cfg, sessionManager, storageManager) + } else { + token = string(rawToken) } } @@ -65,29 +118,16 @@ func New(config ...Config) fiber.Handler { token = cfg.KeyGenerator() } - // Add/update token to Storage - manager.setRaw(token, dummyValue, cfg.Expiration) - - // Create cookie to pass token to client - cookie := &fiber.Cookie{ - Name: cfg.CookieName, - Value: token, - Domain: cfg.CookieDomain, - Path: cfg.CookiePath, - Expires: time.Now().Add(cfg.Expiration), - Secure: cfg.CookieSecure, - HTTPOnly: cfg.CookieHTTPOnly, - SameSite: cfg.CookieSameSite, - SessionOnly: cfg.CookieSessionOnly, - } - // Set cookie to response - c.Cookie(cookie) + // Create or extend the token in the storage + createOrExtendTokenInStorage(c, token, cfg, sessionManager, storageManager) - // Protect clients from caching the response by telling the browser - // a new header value is generated + // Update the CSRF cookie + updateCSRFCookie(c, cfg, token) + + // Tell the browser that a new header value is generated c.Vary(fiber.HeaderCookie) - // Store token in context if set + // Store the token in the context if a context key is specified if cfg.ContextKey != "" { c.Locals(cfg.ContextKey, token) } @@ -96,3 +136,95 @@ func New(config ...Config) fiber.Handler { return c.Next() } } + +// getTokenFromStorage returns the raw token from the storage +// returns nil if the token does not exist, is expired or is invalid +func getTokenFromStorage(c *fiber.Ctx, token string, cfg Config, sessionManager *sessionManager, storageManager *storageManager) []byte { + if cfg.Session != nil { + return sessionManager.getRaw(c, token, dummyValue) + } + return storageManager.getRaw(token) +} + +// createOrExtendTokenInStorage creates or extends the token in the storage +func createOrExtendTokenInStorage(c *fiber.Ctx, token string, cfg Config, sessionManager *sessionManager, storageManager *storageManager) { + if cfg.Session != nil { + sessionManager.setRaw(c, token, dummyValue, cfg.Expiration) + } else { + storageManager.setRaw(token, dummyValue, cfg.Expiration) + } +} + +func deleteTokenFromStorage(c *fiber.Ctx, token string, cfg Config, sessionManager *sessionManager, storageManager *storageManager) { + if cfg.Session != nil { + sessionManager.delRaw(c) + } else { + storageManager.delRaw(token) + } +} + +// Update CSRF cookie +// if expireCookie is true, the cookie will expire immediately +func updateCSRFCookie(c *fiber.Ctx, cfg Config, token string) { + setCSRFCookie(c, cfg, token, cfg.Expiration) +} + +func expireCSRFCookie(c *fiber.Ctx, cfg Config) { + setCSRFCookie(c, cfg, "", -time.Hour) +} + +func setCSRFCookie(c *fiber.Ctx, cfg Config, token string, expiry time.Duration) { + cookie := &fiber.Cookie{ + Name: cfg.CookieName, + Value: token, + Domain: cfg.CookieDomain, + Path: cfg.CookiePath, + Secure: cfg.CookieSecure, + HTTPOnly: cfg.CookieHTTPOnly, + SameSite: cfg.CookieSameSite, + SessionOnly: cfg.CookieSessionOnly, + Expires: time.Now().Add(expiry), + } + + // Set the CSRF cookie to the response + c.Cookie(cookie) +} + +// DeleteToken removes the token found in the context from the storage +// and expires the CSRF cookie +func (handler *CSRFHandler) DeleteToken(c *fiber.Ctx) error { + // Get the config from the context + config := handler.config + if config == nil { + panic("CSRFHandler config not found in context") + } + // Extract token from the client request cookie + cookieToken := c.Cookies(config.CookieName) + if cookieToken == "" { + return config.ErrorHandler(c, ErrTokenNotFound) + } + // Remove the token from storage + deleteTokenFromStorage(c, cookieToken, *config, handler.sessionManager, handler.storageManager) + // Expire the cookie + expireCSRFCookie(c, *config) + return nil +} + +// isCsrfFromCookie checks if the extractor is set to ExtractFromCookie +func isCsrfFromCookie(extractor interface{}) bool { + return reflect.ValueOf(extractor).Pointer() == reflect.ValueOf(CsrfFromCookie).Pointer() +} + +// refererMatchesHost checks that the referer header matches the host header +// returns an error if the referer header is not present or is invalid +// returns nil if the referer header is valid +func refererMatchesHost(c *fiber.Ctx) error { + referer := c.Get(fiber.HeaderReferer) + if referer == "" { + return ErrNoReferer + } + if referer != c.Protocol()+"://"+c.Hostname() { + return ErrBadReferer + } + return nil +} diff --git a/middleware/csrf/csrf_test.go b/middleware/csrf/csrf_test.go index 446ae2f72d..c83061e610 100644 --- a/middleware/csrf/csrf_test.go +++ b/middleware/csrf/csrf_test.go @@ -6,6 +6,7 @@ import ( "testing" "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/middleware/session" "github.com/gofiber/fiber/v2/utils" "github.com/valyala/fasthttp" @@ -58,11 +59,146 @@ func Test_CSRF(t *testing.T) { ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodPost) ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) h(ctx) utils.AssertEqual(t, 200, ctx.Response.StatusCode()) } } +func Test_CSRF_WithSession(t *testing.T) { + t.Parallel() + + // session store + store := session.New(session.Config{ + KeyLookup: "cookie:_session", + }) + + // fiber instance + app := fiber.New() + + // fiber context + ctx := &fasthttp.RequestCtx{} + defer app.ReleaseCtx(app.AcquireCtx(ctx)) + + // get session + sess, err := store.Get(app.AcquireCtx(ctx)) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, true, sess.Fresh()) + + // the session string is no longer be 123 + newSessionIDString := sess.ID() + app.AcquireCtx(ctx).Request().Header.SetCookie("_session", newSessionIDString) + + // middleware config + config := Config{ + Session: store, + } + + // middleware + app.Use(New(config)) + + app.Post("/", func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) + + h := app.Handler() + + methods := [4]string{fiber.MethodGet, fiber.MethodHead, fiber.MethodOptions, fiber.MethodTrace} + + for _, method := range methods { + // Generate CSRF token + ctx.Request.Header.SetMethod(fiber.MethodGet) + ctx.Request.Header.SetCookie("_session", newSessionIDString) + h(ctx) + + // Without CSRF cookie + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.SetCookie("_session", newSessionIDString) + h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode()) + + // Empty/invalid CSRF token + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, "johndoe") + ctx.Request.Header.SetCookie("_session", newSessionIDString) + h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode()) + + // Valid CSRF token + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(method) + ctx.Request.Header.SetCookie("_session", newSessionIDString) + h(ctx) + token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + for _, header := range strings.Split(token, ";") { + if strings.Split(strings.TrimSpace(header), "=")[0] == ConfigDefault.CookieName { + token = strings.Split(header, "=")[1] + break + } + } + + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie("_session", newSessionIDString) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 200, ctx.Response.StatusCode()) + } +} + +// go test -run Test_CSRF_SingleUseToken +func Test_CSRF_SingleUseToken(t *testing.T) { + t.Parallel() + app := fiber.New() + + app.Use(New(Config{ + SingleUseToken: true, + })) + + app.Post("/", func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) + + h := app.Handler() + ctx := &fasthttp.RequestCtx{} + + // Generate CSRF token + ctx.Request.Header.SetMethod(fiber.MethodGet) + h(ctx) + token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + token = strings.Split(strings.Split(token, ";")[0], "=")[1] + + // Use the CSRF token + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 200, ctx.Response.StatusCode()) + newToken := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + newToken = strings.Split(strings.Split(newToken, ";")[0], "=")[1] + if token == newToken { + t.Error("new token should not be the same as the old token") + } + + // Use the CSRF token again + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode()) +} + // go test -run Test_CSRF_Next func Test_CSRF_Next(t *testing.T) { t.Parallel() @@ -127,6 +263,7 @@ func Test_CSRF_From_Form(t *testing.T) { ctx.Request.Header.SetMethod(fiber.MethodPost) ctx.Request.Header.Set(fiber.HeaderContentType, fiber.MIMEApplicationForm) ctx.Request.SetBodyString("_csrf=" + token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) h(ctx) utils.AssertEqual(t, 200, ctx.Response.StatusCode()) } @@ -146,7 +283,7 @@ func Test_CSRF_From_Query(t *testing.T) { // Invalid CSRF token ctx.Request.Header.SetMethod(fiber.MethodPost) - ctx.Request.SetRequestURI("/?_csrf=" + utils.UUID()) + ctx.Request.SetRequestURI("/?_csrf=" + utils.UUIDv4()) h(ctx) utils.AssertEqual(t, 403, ctx.Response.StatusCode()) @@ -163,6 +300,7 @@ func Test_CSRF_From_Query(t *testing.T) { ctx.Response.Reset() ctx.Request.SetRequestURI("/?_csrf=" + token) ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) h(ctx) utils.AssertEqual(t, 200, ctx.Response.StatusCode()) utils.AssertEqual(t, "OK", string(ctx.Response.Body())) @@ -183,7 +321,7 @@ func Test_CSRF_From_Param(t *testing.T) { // Invalid CSRF token ctx.Request.Header.SetMethod(fiber.MethodPost) - ctx.Request.SetRequestURI("/" + utils.UUID()) + ctx.Request.SetRequestURI("/" + utils.UUIDv4()) h(ctx) utils.AssertEqual(t, 403, ctx.Response.StatusCode()) @@ -191,7 +329,7 @@ func Test_CSRF_From_Param(t *testing.T) { ctx.Request.Reset() ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodGet) - ctx.Request.SetRequestURI("/" + utils.UUID()) + ctx.Request.SetRequestURI("/" + utils.UUIDv4()) h(ctx) token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) token = strings.Split(strings.Split(token, ";")[0], "=")[1] @@ -200,6 +338,7 @@ func Test_CSRF_From_Param(t *testing.T) { ctx.Response.Reset() ctx.Request.SetRequestURI("/" + token) ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) h(ctx) utils.AssertEqual(t, 200, ctx.Response.StatusCode()) utils.AssertEqual(t, "OK", string(ctx.Response.Body())) @@ -221,7 +360,7 @@ func Test_CSRF_From_Cookie(t *testing.T) { // Invalid CSRF token ctx.Request.Header.SetMethod(fiber.MethodPost) ctx.Request.SetRequestURI("/") - ctx.Request.Header.Set(fiber.HeaderCookie, "csrf="+utils.UUID()+";") + ctx.Request.Header.Set(fiber.HeaderCookie, "csrf="+utils.UUIDv4()+";") h(ctx) utils.AssertEqual(t, 403, ctx.Response.StatusCode()) @@ -285,16 +424,170 @@ func Test_CSRF_From_Custom(t *testing.T) { ctx.Request.Header.SetMethod(fiber.MethodPost) ctx.Request.Header.Set(fiber.HeaderContentType, fiber.MIMETextPlain) ctx.Request.SetBodyString("_csrf=" + token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) h(ctx) utils.AssertEqual(t, 200, ctx.Response.StatusCode()) } +func Test_CSRF_Referer(t *testing.T) { + t.Parallel() + app := fiber.New() + + app.Use(New(Config{CookieSecure: true})) + + app.Post("/", func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) + + h := app.Handler() + ctx := &fasthttp.RequestCtx{} + ctx.Request.Header.SetMethod(fiber.MethodGet) + ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https") + h(ctx) + token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + token = strings.Split(strings.Split(token, ";")[0], "=")[1] + + // Test Correct Referer + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https") + ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com") + ctx.Request.Header.Set(fiber.HeaderReferer, "https://example.com") + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 200, ctx.Response.StatusCode()) + + // Test Wrong Referer + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https") + ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com") + ctx.Request.Header.Set(fiber.HeaderReferer, "https://csrf.example.com") + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode()) +} + +func Test_CSRF_DeleteToken(t *testing.T) { + t.Parallel() + app := fiber.New() + + config := ConfigDefault + + app.Use(New(config)) + + app.Post("/", func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) + + h := app.Handler() + ctx := &fasthttp.RequestCtx{} + + // Generate CSRF token + ctx.Request.Header.SetMethod(fiber.MethodGet) + h(ctx) + token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + token = strings.Split(strings.Split(token, ";")[0], "=")[1] + + // Delete the CSRF token + ctx.Request.Header.SetMethod(fiber.MethodGet) + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + if handler, ok := app.AcquireCtx(ctx).Locals(ConfigDefault.HandlerContextKey).(*CSRFHandler); ok { + if err := handler.DeleteToken(app.AcquireCtx(ctx)); err != nil { + t.Fatal(err) + } + } + h(ctx) + + ctx.Request.Header.SetMethod(fiber.MethodGet) + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode()) +} + +func Test_CSRF_DeleteToken_WithSession(t *testing.T) { + t.Parallel() + + // session store + store := session.New(session.Config{ + KeyLookup: "cookie:_session", + }) + + // fiber instance + app := fiber.New() + + // fiber context + ctx := &fasthttp.RequestCtx{} + defer app.ReleaseCtx(app.AcquireCtx(ctx)) + + // get session + sess, err := store.Get(app.AcquireCtx(ctx)) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, true, sess.Fresh()) + + // the session string is no longer be 123 + newSessionIDString := sess.ID() + app.AcquireCtx(ctx).Request().Header.SetCookie("_session", newSessionIDString) + + // middleware config + config := Config{ + Session: store, + } + + // middleware + app.Use(New(config)) + + app.Post("/", func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) + + h := app.Handler() + + // Generate CSRF token + ctx.Request.Header.SetMethod(fiber.MethodGet) + ctx.Request.Header.SetCookie("_session", newSessionIDString) + h(ctx) + token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + token = strings.Split(strings.Split(token, ";")[0], "=")[1] + + // Delete the CSRF token + ctx.Request.Header.SetMethod(fiber.MethodGet) + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + if handler, ok := app.AcquireCtx(ctx).Locals(ConfigDefault.HandlerContextKey).(*CSRFHandler); ok { + if err := handler.DeleteToken(app.AcquireCtx(ctx)); err != nil { + t.Fatal(err) + } + } + h(ctx) + + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + ctx.Request.Header.SetCookie("_session", newSessionIDString) + h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode()) +} + func Test_CSRF_ErrorHandler_InvalidToken(t *testing.T) { t.Parallel() app := fiber.New() errHandler := func(ctx *fiber.Ctx, err error) error { - utils.AssertEqual(t, errTokenNotFound, err) + utils.AssertEqual(t, ErrTokenInvalid, err) return ctx.Status(419).Send([]byte("invalid CSRF token")) } @@ -352,6 +645,74 @@ func Test_CSRF_ErrorHandler_EmptyToken(t *testing.T) { utils.AssertEqual(t, "empty CSRF token", string(ctx.Response.Body())) } +func Test_CSRF_ErrorHandler_MissingReferer(t *testing.T) { + t.Parallel() + app := fiber.New() + + errHandler := func(ctx *fiber.Ctx, err error) error { + utils.AssertEqual(t, ErrNoReferer, err) + return ctx.Status(419).Send([]byte("empty CSRF token")) + } + + app.Use(New(Config{ + CookieSecure: true, + ErrorHandler: errHandler, + })) + + app.Post("/", func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) + + h := app.Handler() + ctx := &fasthttp.RequestCtx{} + ctx.Request.Header.SetMethod(fiber.MethodGet) + ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https") + h(ctx) + token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + token = strings.Split(strings.Split(token, ";")[0], "=")[1] + + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https") + ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com") + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 419, ctx.Response.StatusCode()) +} + +func Test_CSRF_Cookie_Injection_Exploit(t *testing.T) { + t.Parallel() + app := fiber.New() + + app.Use(New()) + + app.Post("/", func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) + + h := app.Handler() + ctx := &fasthttp.RequestCtx{} + + // Inject CSRF token + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodGet) + ctx.Request.Header.Set(fiber.HeaderCookie, "csrf_=pwned;") + ctx.Request.SetRequestURI("/") + h(ctx) + token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + token = strings.Split(strings.Split(token, ";")[0], "=")[1] + + // Exploit CSRF token we just injected + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.Set(fiber.HeaderCookie, "csrf_=pwned;") + h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode(), "CSRF exploit successful") +} + // TODO: use this test case and make the unsafe header value bug from https://github.com/gofiber/fiber/issues/2045 reproducible and permanently fixed/tested by this testcase // func Test_CSRF_UnsafeHeaderValue(t *testing.T) { // t.Parallel() diff --git a/middleware/csrf/helpers.go b/middleware/csrf/helpers.go new file mode 100644 index 0000000000..d4349608d5 --- /dev/null +++ b/middleware/csrf/helpers.go @@ -0,0 +1,7 @@ +package csrf + +import "crypto/subtle" + +func compareTokens(a, b []byte) bool { + return subtle.ConstantTimeCompare(a, b) == 1 +} diff --git a/middleware/csrf/session_manager.go b/middleware/csrf/session_manager.go new file mode 100644 index 0000000000..5497f8ef79 --- /dev/null +++ b/middleware/csrf/session_manager.go @@ -0,0 +1,68 @@ +package csrf + +import ( + "time" + + "github.com/gofiber/fiber/v2" + "github.com/gofiber/fiber/v2/log" + "github.com/gofiber/fiber/v2/middleware/session" +) + +type sessionManager struct { + key string + session *session.Store +} + +func newSessionManager(s *session.Store, k string) *sessionManager { + // Create new storage handler + sessionManager := &sessionManager{ + key: k, + } + if s != nil { + // Use provided storage if provided + sessionManager.session = s + } + return sessionManager +} + +// get token from session +func (m *sessionManager) getRaw(c *fiber.Ctx, key string, raw []byte) []byte { + sess, err := m.session.Get(c) + if err != nil { + return nil + } + token, ok := sess.Get(m.key).(Token) + if ok { + if token.Expiration.Before(time.Now()) || key != token.Key || !compareTokens(raw, token.Raw) { + return nil + } + return token.Raw + } + + return nil +} + +// set token in session +func (m *sessionManager) setRaw(c *fiber.Ctx, key string, raw []byte, exp time.Duration) { + sess, err := m.session.Get(c) + if err != nil { + return + } + // the key is crucial in crsf and sometimes a reference to another value which can be reused later(pool/unsafe values concept), so a copy is made here + sess.Set(m.key, &Token{key, raw, time.Now().Add(exp)}) + if err := sess.Save(); err != nil { + log.Warn("csrf: failed to save session: ", err) + } +} + +// delete token from session +func (m *sessionManager) delRaw(c *fiber.Ctx) { + sess, err := m.session.Get(c) + if err != nil { + return + } + sess.Delete(m.key) + if err := sess.Save(); err != nil { + log.Warn("csrf: failed to save session: ", err) + } +} diff --git a/middleware/csrf/manager.go b/middleware/csrf/storage_manager.go similarity index 63% rename from middleware/csrf/manager.go rename to middleware/csrf/storage_manager.go index 20d3d93e1a..49b3186f94 100644 --- a/middleware/csrf/manager.go +++ b/middleware/csrf/storage_manager.go @@ -10,19 +10,19 @@ import ( ) // go:generate msgp -// msgp -file="manager.go" -o="manager_msgp.go" -tests=false -unexported +// msgp -file="storage_manager.go" -o="storage_manager_msgp.go" -tests=false -unexported type item struct{} //msgp:ignore manager -type manager struct { +type storageManager struct { pool sync.Pool memory *memory.Storage storage fiber.Storage } -func newManager(storage fiber.Storage) *manager { +func newStorageManager(storage fiber.Storage) *storageManager { // Create new storage handler - manager := &manager{ + storageManager := &storageManager{ pool: sync.Pool{ New: func() interface{} { return new(item) @@ -31,16 +31,16 @@ func newManager(storage fiber.Storage) *manager { } if storage != nil { // Use provided storage if provided - manager.storage = storage + storageManager.storage = storage } else { // Fallback too memory storage - manager.memory = memory.New() + storageManager.memory = memory.New() } - return manager + return storageManager } // get raw data from storage or memory -func (m *manager) getRaw(key string) []byte { +func (m *storageManager) getRaw(key string) []byte { var raw []byte if m.storage != nil { raw, _ = m.storage.Get(key) //nolint:errcheck // TODO: Do not ignore error @@ -51,7 +51,7 @@ func (m *manager) getRaw(key string) []byte { } // set data to storage or memory -func (m *manager) setRaw(key string, raw []byte, exp time.Duration) { +func (m *storageManager) setRaw(key string, raw []byte, exp time.Duration) { if m.storage != nil { _ = m.storage.Set(key, raw, exp) //nolint:errcheck // TODO: Do not ignore error } else { @@ -59,3 +59,12 @@ func (m *manager) setRaw(key string, raw []byte, exp time.Duration) { m.memory.Set(utils.CopyString(key), raw, exp) } } + +// delete data from storage or memory +func (m *storageManager) delRaw(key string) { + if m.storage != nil { + _ = m.storage.Delete(key) //nolint:errcheck // TODO: Do not ignore error + } else { + m.memory.Delete(key) + } +} diff --git a/middleware/csrf/manager_msgp.go b/middleware/csrf/storage_manager_msgp.go similarity index 100% rename from middleware/csrf/manager_msgp.go rename to middleware/csrf/storage_manager_msgp.go diff --git a/middleware/csrf/token.go b/middleware/csrf/token.go new file mode 100644 index 0000000000..e9e1cecb7c --- /dev/null +++ b/middleware/csrf/token.go @@ -0,0 +1,9 @@ +package csrf + +import "time" + +type Token struct { + Key string `json:"key"` + Raw []byte `json:"raw"` + Expiration time.Time `json:"expiration"` +} From bb90fc11875666048182e81511c827316f4a54ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Wed, 11 Oct 2023 15:16:35 +0200 Subject: [PATCH 65/84] fix lint errors --- middleware/csrf/config.go | 2 +- middleware/csrf/helpers.go | 6 ++++-- middleware/csrf/token.go | 4 +++- utils/assertions.go | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/middleware/csrf/config.go b/middleware/csrf/config.go index 432378bfba..baab88e946 100644 --- a/middleware/csrf/config.go +++ b/middleware/csrf/config.go @@ -34,7 +34,7 @@ type Config struct { // Name of the session cookie. This cookie will store session key. // Optional. Default value "csrf_". - // Overriden if KeyLookup == "cookie:" + // Overridden if KeyLookup == "cookie:" CookieName string // Domain of the CSRF cookie. diff --git a/middleware/csrf/helpers.go b/middleware/csrf/helpers.go index d4349608d5..7604b97595 100644 --- a/middleware/csrf/helpers.go +++ b/middleware/csrf/helpers.go @@ -1,7 +1,9 @@ package csrf -import "crypto/subtle" +import ( + "crypto/subtle" +) func compareTokens(a, b []byte) bool { - return subtle.ConstantTimeCompare(a, b) == 1 + return subtle.ConstantTimeCompare(a, b) == 1 } diff --git a/middleware/csrf/token.go b/middleware/csrf/token.go index e9e1cecb7c..ee88b9aee0 100644 --- a/middleware/csrf/token.go +++ b/middleware/csrf/token.go @@ -1,6 +1,8 @@ package csrf -import "time" +import ( + "time" +) type Token struct { Key string `json:"key"` diff --git a/utils/assertions.go b/utils/assertions.go index 2cc4cac21a..3682d56542 100644 --- a/utils/assertions.go +++ b/utils/assertions.go @@ -53,7 +53,7 @@ func AssertEqual(tb testing.TB, expected, actual interface{}, description ...str _, _ = fmt.Fprintf(w, "\nExpect:\t%v\t(%s)", expected, aType) _, _ = fmt.Fprintf(w, "\nResult:\t%v\t(%s)", actual, bType) - result := "" + var result string if err := w.Flush(); err != nil { result = err.Error() } else { From e70b2e28d66473ab6ad0d69f788dd2a6009c247e Mon Sep 17 00:00:00 2001 From: joey1123455 <112909075+joey1123455@users.noreply.github.com> Date: Thu, 12 Oct 2023 09:44:15 +0100 Subject: [PATCH 66/84] Cookie parser (#2656) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * prep for branching * feature: added a cookie parser and tests appropriate tests * :sparkles: feature: added a cookie parser and appropriate tests * made correction to docs * linted using gofumpt * ctx_test linted, cookieParser schema added * fix lint errors (Cookie parser #2656) * removed extra lines, tested return values --------- Co-authored-by: René Werner --- ctx.go | 41 +++++++++++++- ctx_test.go | 146 ++++++++++++++++++++++++++++++++++++++++++++++++ docs/api/ctx.md | 32 +++++++++++ 3 files changed, 216 insertions(+), 3 deletions(-) diff --git a/ctx.go b/ctx.go index 3d19a45fbf..a5ba85f947 100644 --- a/ctx.go +++ b/ctx.go @@ -38,22 +38,23 @@ const ( // maxParams defines the maximum number of parameters per route. const maxParams = 30 -// Some constants for BodyParser, QueryParser and ReqHeaderParser. +// Some constants for BodyParser, QueryParser, CookieParser and ReqHeaderParser. const ( queryTag = "query" reqHeaderTag = "reqHeader" bodyTag = "form" paramsTag = "params" + cookieTag = "cookie" ) // userContextKey define the key name for storing context.Context in *fasthttp.RequestCtx const userContextKey = "__local_user_context__" var ( - // decoderPoolMap helps to improve BodyParser's, QueryParser's and ReqHeaderParser's performance + // decoderPoolMap helps to improve BodyParser's, QueryParser's, CookieParser's and ReqHeaderParser's performance decoderPoolMap = map[string]*sync.Pool{} // tags is used to classify parser's pool - tags = []string{queryTag, bodyTag, reqHeaderTag, paramsTag} + tags = []string{queryTag, bodyTag, reqHeaderTag, paramsTag, cookieTag} ) func init() { @@ -502,6 +503,40 @@ func (c *Ctx) Cookies(key string, defaultValue ...string) string { return defaultString(c.app.getString(c.fasthttp.Request.Header.Cookie(key)), defaultValue) } +// CookieParser is used to bind cookies to a struct +func (c *Ctx) CookieParser(out interface{}) error { + data := make(map[string][]string) + var err error + + // loop through all cookies + c.fasthttp.Request.Header.VisitAllCookie(func(key, val []byte) { + if err != nil { + return + } + + k := c.app.getString(key) + v := c.app.getString(val) + + if strings.Contains(k, "[") { + k, err = parseParamSquareBrackets(k) + } + + if c.app.config.EnableSplittingOnParsers && strings.Contains(v, ",") && equalFieldType(out, reflect.Slice, k, cookieTag) { + values := strings.Split(v, ",") + for i := 0; i < len(values); i++ { + data[k] = append(data[k], values[i]) + } + } else { + data[k] = append(data[k], v) + } + }) + if err != nil { + return err + } + + return c.parseToStruct(cookieTag, out, data) +} + // Download transfers the file from path as an attachment. // Typically, browsers will prompt the user for download. // By default, the Content-Disposition header filename= parameter is the filepath (this typically appears in the browser dialog). diff --git a/ctx_test.go b/ctx_test.go index d8edea0e9e..ef9007293f 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -928,6 +928,152 @@ func Benchmark_Ctx_Cookie(b *testing.B) { utils.AssertEqual(b, "John=Doe; path=/; SameSite=Lax", app.getString(c.Response().Header.Peek("Set-Cookie"))) } +// go test -run Test_Ctx_CookieParser -v +func Test_Ctx_CookieParser(t *testing.T) { + t.Parallel() + app := New(Config{EnableSplittingOnParsers: true}) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + type Cookie struct { + Name string + Class int + Courses []string + } + c.Request().Header.Set("Cookie", "name=doe") + c.Request().Header.Set("Cookie", "class=100") + c.Request().Header.Set("Cookie", "courses=maths,english") + cookie := new(Cookie) + + // correct test cases + utils.AssertEqual(t, nil, c.CookieParser(cookie)) + utils.AssertEqual(t, "doe", cookie.Name) + utils.AssertEqual(t, 100, cookie.Class) + utils.AssertEqual(t, 2, len(cookie.Courses)) + + // wrong test cases + empty := new(Cookie) + c.Request().Header.Set("Cookie", "name") + c.Request().Header.Set("Cookie", "class") + c.Request().Header.Set("Cookie", "courses") + utils.AssertEqual(t, nil, c.CookieParser(cookie)) + utils.AssertEqual(t, "", empty.Name) + utils.AssertEqual(t, 0, empty.Class) + utils.AssertEqual(t, 0, len(empty.Courses)) +} + +// go test -run Test_Ctx_CookieParserUsingTag -v +func Test_Ctx_CookieParserUsingTag(t *testing.T) { + t.Parallel() + app := New(Config{EnableSplittingOnParsers: true}) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + type Cook struct { + ID int `cookie:"id"` + Name string `cookie:"name"` + Courses []string `cookie:"courses"` + Enrolled bool `cookie:"student"` + Fees float32 `cookie:"fee"` + Grades []uint8 `cookie:"score"` + } + cookie1 := new(Cook) + cookie1.Name = "Joseph" + utils.AssertEqual(t, "Joseph", cookie1.Name) + + c.Request().Header.Set("Cookie", "id=1") + c.Request().Header.Set("Cookie", "name=Joey") + c.Request().Header.Set("Cookie", "courses=maths,english, chemistry, physics") + c.Request().Header.Set("Cookie", "student=true") + c.Request().Header.Set("Cookie", "fee=45.78") + c.Request().Header.Set("Cookie", "score=7,6,10") + utils.AssertEqual(t, nil, c.CookieParser(cookie1)) + utils.AssertEqual(t, "Joey", cookie1.Name) + utils.AssertEqual(t, true, cookie1.Enrolled) + utils.AssertEqual(t, float32(45.78), cookie1.Fees) + utils.AssertEqual(t, []uint8{7, 6, 10}, cookie1.Grades) + + type RequiredCookie struct { + House string `cookie:"house,required"` + } + rc := new(RequiredCookie) + utils.AssertEqual(t, "failed to decode: house is empty", c.CookieParser(rc).Error()) + + type ArrayCookie struct { + Dates []int + } + + ac := new(ArrayCookie) + c.Request().Header.Set("Cookie", "dates[]=7,6,10") + utils.AssertEqual(t, nil, c.CookieParser(ac)) + utils.AssertEqual(t, 3, len(ac.Dates)) +} + +// go test -run Test_Ctx_CookieParserSchema -v +func Test_Ctx_CookieParser_Schema(t *testing.T) { + t.Parallel() + app := New() + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + type result struct { + Maths int `cookie:"maths"` + English int `cookie:"english"` + } + type resStruct struct { + Name string `cookie:"name"` + Age int `cookie:"age"` + Result result `cookie:"result"` + } + res := &resStruct{ + Name: "Joseph", + Age: 10, + Result: result{ + Maths: 10, + English: 10, + }, + } + + // set cookie + c.Request().Header.Set("Cookie", "name=Joseph") + c.Request().Header.Set("Cookie", "age=10") + c.Request().Header.Set("Cookie", "result.maths=10") + c.Request().Header.Set("Cookie", "result.english=10") + hR := new(resStruct) + r := c.CookieParser(hR) + + utils.AssertEqual(t, nil, r) + utils.AssertEqual(t, *res, *hR) +} + +// go test -run Benchmark_Ctx_CookieParser -v +func Benchmark_Ctx_CookieParser(b *testing.B) { + app := New(Config{EnableSplittingOnParsers: true}) + c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) + type Cook struct { + ID int `cookie:"id"` + Name string `cookie:"name"` + Courses []string `cookie:"courses"` + Enrolled bool `cookie:"student"` + Fees float32 `cookie:"fee"` + Grades []uint8 `cookie:"score"` + } + cookie1 := new(Cook) + cookie1.Name = "Joseph" + + c.Request().Header.Set("Cookie", "id=1") + c.Request().Header.Set("Cookie", "name=Joey") + c.Request().Header.Set("Cookie", "courses=maths,english, chemistry, physics") + c.Request().Header.Set("Cookie", "student=true") + c.Request().Header.Set("Cookie", "fee=45.78") + c.Request().Header.Set("Cookie", "score=7,6,10") + + var err error + // Run the function b.N times + for i := 0; i < b.N; i++ { + err = c.CookieParser(cookie1) + } + utils.AssertEqual(b, nil, err) +} + // go test -run Test_Ctx_Cookies func Test_Ctx_Cookies(t *testing.T) { t.Parallel() diff --git a/docs/api/ctx.md b/docs/api/ctx.md index b1e14f2d6d..1729438d7f 100644 --- a/docs/api/ctx.md +++ b/docs/api/ctx.md @@ -403,6 +403,38 @@ app.Get("/", func(c *fiber.Ctx) error { }) ``` +## CookieParser + +This method is similar to [BodyParser](ctx.md#bodyparser), but for cookie parameters. +It is important to use the struct tag "cookie". For example, if you want to parse a cookie with a field called Age, you would use a struct field of `cookie:"age"`. + +```go title="Signature" +func (c *Ctx) CookieParser(out interface{}) error +``` + +```go title="Example" +// Field names should start with an uppercase letter +type Person struct { + Name string `cookie:"name"` + Age int `cookie:"age"` + Job bool `cookie:"job"` +} + +app.Get("/", func(c *fiber.Ctx) error { + p := new(Person) + + if err := c.CookieParser(p); err != nil { + return err + } + + log.Println(p.Name) // Joseph + log.Println(p.Age) // 23 + log.Println(p.Job) // true +}) +// Run tests with the following curl command +// curl.exe --cookie "name=Joseph; age=23; job=true" http://localhost:8000/ +``` + ## Cookies Get cookie value by key, you could pass an optional default value that will be returned if the cookie key does not exist. From d974cf3c990060245447c69e4b7c265240663fbd Mon Sep 17 00:00:00 2001 From: Javier Scappini Date: Fri, 13 Oct 2023 11:37:06 +0000 Subject: [PATCH 67/84] Fix typo in requestid.md Minor typo fix in requestid.md. --- docs/api/middleware/requestid.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/middleware/requestid.md b/docs/api/middleware/requestid.md index 200ebf4bdd..c8ca8d599e 100644 --- a/docs/api/middleware/requestid.md +++ b/docs/api/middleware/requestid.md @@ -4,7 +4,7 @@ id: requestid # RequestID -RequestID middleware for [Fiber](https://github.com/gofiber/fiber) that adds an indentifier to the response. +RequestID middleware for [Fiber](https://github.com/gofiber/fiber) that adds an identifier to the response. ## Signatures From d736d3a64433385b0fc0189e16a36a2f4facb67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Mon, 16 Oct 2023 10:02:53 +0300 Subject: [PATCH 68/84] :bug: bug: fix path checking on route naming (#2676) * :bug: bug: fix path checking on route naming * fix several tests * fix several tests --- app.go | 2 +- app_test.go | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- listen_test.go | 2 -- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/app.go b/app.go index 5ec5d0dbc7..c298a0ec2c 100644 --- a/app.go +++ b/app.go @@ -620,7 +620,7 @@ func (app *App) Name(name string) Router { for _, routes := range app.stack { for _, route := range routes { - if route.Path == app.latestRoute.path { + if route.Path == app.latestRoute.Path { route.Name = name if route.group != nil { diff --git a/app_test.go b/app_test.go index 9e0e617049..d0acc68c6c 100644 --- a/app_test.go +++ b/app_test.go @@ -1458,7 +1458,6 @@ func (invalidView) Render(io.Writer, string, interface{}, ...string) error { pan // go test -run Test_App_Init_Error_View func Test_App_Init_Error_View(t *testing.T) { - t.Parallel() app := New(Config{Views: invalidView{}}) defer func() { @@ -1618,7 +1617,6 @@ func Test_App_Server(t *testing.T) { } func Test_App_Error_In_Fasthttp_Server(t *testing.T) { - t.Parallel() app := New() app.config.ErrorHandler = func(ctx *Ctx, err error) error { return errors.New("fake error") @@ -1860,3 +1858,50 @@ func Test_Middleware_Route_Naming_With_Use(t *testing.T) { } } } + +func Test_Route_Naming_Issue_2671(t *testing.T) { + app := New() + + app.Get("/", emptyHandler).Name("index") + utils.AssertEqual(t, "/", app.GetRoute("index").Path) + + app.Get("/a/:a_id", emptyHandler).Name("a") + utils.AssertEqual(t, "/a/:a_id", app.GetRoute("a").Path) + + app.Post("/b/:bId", emptyHandler).Name("b") + utils.AssertEqual(t, "/b/:bId", app.GetRoute("b").Path) + + c := app.Group("/c") + c.Get("", emptyHandler).Name("c.get") + utils.AssertEqual(t, "/c", app.GetRoute("c.get").Path) + + c.Post("", emptyHandler).Name("c.post") + utils.AssertEqual(t, "/c", app.GetRoute("c.post").Path) + + c.Get("/d", emptyHandler).Name("c.get.d") + utils.AssertEqual(t, "/c/d", app.GetRoute("c.get.d").Path) + + d := app.Group("/d/:d_id") + d.Get("", emptyHandler).Name("d.get") + utils.AssertEqual(t, "/d/:d_id", app.GetRoute("d.get").Path) + + d.Post("", emptyHandler).Name("d.post") + utils.AssertEqual(t, "/d/:d_id", app.GetRoute("d.post").Path) + + e := app.Group("/e/:eId") + e.Get("", emptyHandler).Name("e.get") + utils.AssertEqual(t, "/e/:eId", app.GetRoute("e.get").Path) + + e.Post("", emptyHandler).Name("e.post") + utils.AssertEqual(t, "/e/:eId", app.GetRoute("e.post").Path) + + e.Get("f", emptyHandler).Name("e.get.f") + utils.AssertEqual(t, "/e/:eId/f", app.GetRoute("e.get.f").Path) + + postGroup := app.Group("/post/:postId") + postGroup.Get("", emptyHandler).Name("post.get") + utils.AssertEqual(t, "/post/:postId", app.GetRoute("post.get").Path) + + postGroup.Post("", emptyHandler).Name("post.update") + utils.AssertEqual(t, "/post/:postId", app.GetRoute("post.update").Path) +} diff --git a/listen_test.go b/listen_test.go index 80f6441301..6a44bf4412 100644 --- a/listen_test.go +++ b/listen_test.go @@ -303,7 +303,6 @@ func Test_App_Master_Process_Show_Startup_MessageWithAppNameNonAscii(t *testing. } func Test_App_print_Route(t *testing.T) { - t.Parallel() app := New(Config{EnablePrintRoutes: true}) app.Get("/", emptyHandler).Name("routeName") printRoutesMessage := captureOutput(func() { @@ -316,7 +315,6 @@ func Test_App_print_Route(t *testing.T) { } func Test_App_print_Route_with_group(t *testing.T) { - t.Parallel() app := New(Config{EnablePrintRoutes: true}) app.Get("/", emptyHandler) From 8c3916dbf4ad2ed427d02c6eb63ae8b2fa8f019a Mon Sep 17 00:00:00 2001 From: Jason McNeil Date: Mon, 16 Oct 2023 04:06:30 -0300 Subject: [PATCH 69/84] Merge pull request from GHSA-94w9-97p3-p368 * feat: improved csrf with session support * fix: double submit cookie * feat: add warning cookie extractor without session * feat: add warning CsrfFromCookie SameSite * fix: use byes.Equal instead * fix: Overriden CookieName KeyLookup cookie: * feat: Create helpers.go * feat: use compareTokens (constant time compare) * feat: validate cookie to prevent token injection * refactor: clean up csrf.go * docs: update comment about Double Submit Cookie * docs: update docs for CSRF changes * feat: add DeleteToken * refactor: no else * test: add more tests * refactor: re-order tests * docs: update safe methods RCF add note * test: add CSRF_Cookie_Injection_Exploit * feat: add SingleUseToken config * test: check for new token * docs: use warning * fix: always register type Token * feat: use UUIDv4 * test: swap in UUIDv4 here too * fix: raw token injection * fix: merege error * feat: Sentinel errors * chore: rename test * fix: url parse * test: add path to referer * test: add expiration tests * docs: add cookie prefix note * docs: fix typo * docs: add warning for refer checks * test: add referer edge cases And call ctx.Request.Reset() and ctx.Response.Reset() before re-using ctx. --- docs/api/middleware/csrf.md | 10 ++ middleware/csrf/csrf.go | 28 +++-- middleware/csrf/csrf_test.go | 230 +++++++++++++++++++++++++++++++++- middleware/csrf/extractors.go | 20 +-- middleware/csrf/helpers.go | 4 + 5 files changed, 266 insertions(+), 26 deletions(-) diff --git a/docs/api/middleware/csrf.md b/docs/api/middleware/csrf.md index 66a3a6e62b..3430e0098f 100644 --- a/docs/api/middleware/csrf.md +++ b/docs/api/middleware/csrf.md @@ -42,10 +42,20 @@ When using this method, pre-sessions are required and will be created if a sessi When using this middleware, it is recommended that you serve your pages over HTTPS, that the `CookieSecure` option is set to `true`, and that the `CookieSameSite` option is set to `Lax` or `Strict`. This will ensure that the cookie is only sent over HTTPS and that it is not sent 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. + +To use these prefixes, set the `CookieName` option to `__Host-csrf_` or `__Secure-csrf_`. +::: + ### Referer Checking For HTTPS requests, this middleware performs strict referer checking. This means that 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. +:::warning +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. +::: + ### Token Lifecycle Tokens are valid until they expire, or until they are deleted. By default, tokens are valid for 1 hour and each subsequent request will extend the expiration by 1 hour. This means that if a user makes a request every hour, the token will never expire. If a user makes a request after the token has expired, then a new token will be generated and the `csrf_` cookie will be set again. This means that the token will only expire if the user does not make a request for the duration of the expiration time. diff --git a/middleware/csrf/csrf.go b/middleware/csrf/csrf.go index b7b0127469..f4dee74c8e 100644 --- a/middleware/csrf/csrf.go +++ b/middleware/csrf/csrf.go @@ -2,6 +2,7 @@ package csrf import ( "errors" + "net/url" "reflect" "time" @@ -63,10 +64,10 @@ func New(config ...Config) fiber.Handler { cookieToken := c.Cookies(cfg.CookieName) if cookieToken != "" { - rawToken := getTokenFromStorage(c, cookieToken, cfg, sessionManager, storageManager) + raw := getRawFromStorage(c, cookieToken, cfg, sessionManager, storageManager) - if rawToken != nil { - token = string(rawToken) + if raw != nil { + token = cookieToken // Token is valid, safe to set it } } default: @@ -92,13 +93,13 @@ func New(config ...Config) fiber.Handler { // If not using CsrfFromCookie extractor, check that the token matches the cookie // This is to prevent CSRF attacks by using a Double Submit Cookie method // Useful when we do not have access to the users Session - if !isCsrfFromCookie(cfg.Extractor) && extractedToken != c.Cookies(cfg.CookieName) { + if !isCsrfFromCookie(cfg.Extractor) && !compareStrings(extractedToken, c.Cookies(cfg.CookieName)) { return cfg.ErrorHandler(c, ErrTokenInvalid) } - rawToken := getTokenFromStorage(c, extractedToken, cfg, sessionManager, storageManager) + raw := getRawFromStorage(c, extractedToken, cfg, sessionManager, storageManager) - if rawToken == nil { + if raw == nil { // If token is not in storage, expire the cookie expireCSRFCookie(c, cfg) // and return an error @@ -108,7 +109,7 @@ func New(config ...Config) fiber.Handler { // If token is single use, delete it from storage deleteTokenFromStorage(c, extractedToken, cfg, sessionManager, storageManager) } else { - token = string(rawToken) + token = extractedToken // Token is valid, safe to set it } } @@ -137,9 +138,9 @@ func New(config ...Config) fiber.Handler { } } -// getTokenFromStorage returns the raw token from the storage +// getRawFromStorage returns the raw value from the storage for the given token // returns nil if the token does not exist, is expired or is invalid -func getTokenFromStorage(c *fiber.Ctx, token string, cfg Config, sessionManager *sessionManager, storageManager *storageManager) []byte { +func getRawFromStorage(c *fiber.Ctx, token string, cfg Config, sessionManager *sessionManager, storageManager *storageManager) []byte { if cfg.Session != nil { return sessionManager.getRaw(c, token, dummyValue) } @@ -223,8 +224,15 @@ func refererMatchesHost(c *fiber.Ctx) error { if referer == "" { return ErrNoReferer } - if referer != c.Protocol()+"://"+c.Hostname() { + + refererURL, err := url.Parse(referer) + if err != nil { return ErrBadReferer } + + if refererURL.Scheme+"://"+refererURL.Host != c.Protocol()+"://"+c.Hostname() { + return ErrBadReferer + } + return nil } diff --git a/middleware/csrf/csrf_test.go b/middleware/csrf/csrf_test.go index c83061e610..562bfaf67b 100644 --- a/middleware/csrf/csrf_test.go +++ b/middleware/csrf/csrf_test.go @@ -4,6 +4,7 @@ import ( "net/http/httptest" "strings" "testing" + "time" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/session" @@ -153,6 +154,170 @@ func Test_CSRF_WithSession(t *testing.T) { } } +// go test -run Test_CSRF_ExpiredToken +func Test_CSRF_ExpiredToken(t *testing.T) { + t.Parallel() + app := fiber.New() + + app.Use(New(Config{ + Expiration: 1 * time.Second, + })) + + app.Post("/", func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) + + h := app.Handler() + ctx := &fasthttp.RequestCtx{} + + // Generate CSRF token + ctx.Request.Header.SetMethod(fiber.MethodGet) + h(ctx) + token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + token = strings.Split(strings.Split(token, ";")[0], "=")[1] + + // Use the CSRF token + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 200, ctx.Response.StatusCode()) + + // Wait for the token to expire + time.Sleep(1 * time.Second) + + // Expired CSRF token + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode()) +} + +// go test -run Test_CSRF_ExpiredToken_WithSession +func Test_CSRF_ExpiredToken_WithSession(t *testing.T) { + t.Parallel() + + // session store + store := session.New(session.Config{ + KeyLookup: "cookie:_session", + }) + + // fiber instance + app := fiber.New() + + // fiber context + ctx := &fasthttp.RequestCtx{} + defer app.ReleaseCtx(app.AcquireCtx(ctx)) + + // get session + sess, err := store.Get(app.AcquireCtx(ctx)) + utils.AssertEqual(t, nil, err) + utils.AssertEqual(t, true, sess.Fresh()) + + // get session id + newSessionIDString := sess.ID() + app.AcquireCtx(ctx).Request().Header.SetCookie("_session", newSessionIDString) + + // middleware config + config := Config{ + Session: store, + Expiration: 1 * time.Second, + } + + // middleware + app.Use(New(config)) + + app.Post("/", func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) + + h := app.Handler() + + // Generate CSRF token + ctx.Request.Header.SetMethod(fiber.MethodGet) + ctx.Request.Header.SetCookie("_session", newSessionIDString) + h(ctx) + token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + for _, header := range strings.Split(token, ";") { + if strings.Split(strings.TrimSpace(header), "=")[0] == ConfigDefault.CookieName { + token = strings.Split(header, "=")[1] + break + } + } + + // Use the CSRF token + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie("_session", newSessionIDString) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 200, ctx.Response.StatusCode()) + + // Wait for the token to expire + time.Sleep(1 * time.Second) + + // Expired CSRF token + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie("_session", newSessionIDString) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode()) +} + +// go test -run Test_CSRF_MultiUseToken +func Test_CSRF_MultiUseToken(t *testing.T) { + t.Parallel() + app := fiber.New() + + app.Use(New(Config{ + KeyLookup: "header:X-CSRF-Token", + })) + + app.Post("/", func(c *fiber.Ctx) error { + return c.SendStatus(fiber.StatusOK) + }) + + h := app.Handler() + ctx := &fasthttp.RequestCtx{} + + // Invalid CSRF token + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set("X-CSRF-Token", "johndoe") + h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode()) + + // Generate CSRF token + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodGet) + h(ctx) + token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) + token = strings.Split(strings.Split(token, ";")[0], "=")[1] + + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + 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)) + newToken = strings.Split(strings.Split(newToken, ";")[0], "=")[1] + utils.AssertEqual(t, 200, ctx.Response.StatusCode()) + + // Check if the token is not a dummy value + utils.AssertEqual(t, token, newToken) +} + // go test -run Test_CSRF_SingleUseToken func Test_CSRF_SingleUseToken(t *testing.T) { t.Parallel() @@ -260,6 +425,8 @@ func Test_CSRF_From_Form(t *testing.T) { token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) token = strings.Split(strings.Split(token, ";")[0], "=")[1] + ctx.Request.Reset() + ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodPost) ctx.Request.Header.Set(fiber.HeaderContentType, fiber.MIMEApplicationForm) ctx.Request.SetBodyString("_csrf=" + token) @@ -393,7 +560,7 @@ func Test_CSRF_From_Custom(t *testing.T) { selectors := strings.Split(body, "=") if len(selectors) != 2 || selectors[1] == "" { - return "", errMissingParam + return "", ErrMissingParam } return selectors[1], nil } @@ -421,6 +588,8 @@ func Test_CSRF_From_Custom(t *testing.T) { token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) token = strings.Split(strings.Split(token, ";")[0], "=")[1] + ctx.Request.Reset() + ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodPost) ctx.Request.Header.Set(fiber.HeaderContentType, fiber.MIMETextPlain) ctx.Request.SetBodyString("_csrf=" + token) @@ -447,17 +616,67 @@ func Test_CSRF_Referer(t *testing.T) { token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) token = strings.Split(strings.Split(token, ";")[0], "=")[1] - // Test Correct Referer + // Test Correct Referer with port + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.URI().SetScheme("https") + ctx.Request.URI().SetHost("example.com:8443") + ctx.Request.Header.SetProtocol("https") + ctx.Request.Header.SetHost("example.com:8443") + ctx.Request.Header.Set(fiber.HeaderReferer, ctx.Request.URI().String()) + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 200, ctx.Response.StatusCode()) + + // Test Correct Referer with ReverseProxy + ctx.Request.Reset() + ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.URI().SetScheme("https") + ctx.Request.URI().SetHost("10.0.1.42.com:8443") + ctx.Request.Header.SetProtocol("https") + ctx.Request.Header.SetHost("10.0.1.42:8443") ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https") ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com") + ctx.Request.Header.Set(fiber.HeaderXForwardedFor, `192.0.2.43, "[2001:db8:cafe::17]"`) + ctx.Request.Header.Set(fiber.HeaderReferer, "https://example.com") + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) + utils.AssertEqual(t, 200, ctx.Response.StatusCode()) + + // Test Correct Referer with ReverseProxy Missing X-Forwarded-* Headers + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.URI().SetScheme("https") + ctx.Request.URI().SetHost("10.0.1.42:8443") + ctx.Request.Header.SetProtocol("https") + ctx.Request.Header.SetHost("10.0.1.42:8443") + ctx.Request.Header.Set(fiber.HeaderXUrlScheme, "https") // We need to set this header to make sure c.Protocol() returns https ctx.Request.Header.Set(fiber.HeaderReferer, "https://example.com") ctx.Request.Header.Set(HeaderName, token) ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) h(ctx) + utils.AssertEqual(t, 403, ctx.Response.StatusCode()) + + // Test Correct Referer with path + ctx.Request.Reset() + ctx.Response.Reset() + ctx.Request.Header.SetMethod(fiber.MethodPost) + ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https") + ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com") + ctx.Request.Header.Set(fiber.HeaderReferer, "https://example.com/action/items?gogogo=true") + ctx.Request.Header.Set(HeaderName, token) + ctx.Request.Header.SetCookie(ConfigDefault.CookieName, token) + h(ctx) utils.AssertEqual(t, 200, ctx.Response.StatusCode()) // Test Wrong Referer + ctx.Request.Reset() + ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodPost) ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https") ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com") @@ -490,7 +709,6 @@ func Test_CSRF_DeleteToken(t *testing.T) { token = strings.Split(strings.Split(token, ";")[0], "=")[1] // Delete the CSRF token - ctx.Request.Header.SetMethod(fiber.MethodGet) ctx.Request.Reset() ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodPost) @@ -503,7 +721,6 @@ func Test_CSRF_DeleteToken(t *testing.T) { } h(ctx) - ctx.Request.Header.SetMethod(fiber.MethodGet) ctx.Request.Reset() ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodPost) @@ -559,7 +776,6 @@ func Test_CSRF_DeleteToken_WithSession(t *testing.T) { token = strings.Split(strings.Split(token, ";")[0], "=")[1] // Delete the CSRF token - ctx.Request.Header.SetMethod(fiber.MethodGet) ctx.Request.Reset() ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodPost) @@ -619,7 +835,7 @@ func Test_CSRF_ErrorHandler_EmptyToken(t *testing.T) { app := fiber.New() errHandler := func(ctx *fiber.Ctx, err error) error { - utils.AssertEqual(t, errMissingHeader, err) + utils.AssertEqual(t, ErrMissingHeader, err) return ctx.Status(419).Send([]byte("empty CSRF token")) } @@ -671,6 +887,8 @@ func Test_CSRF_ErrorHandler_MissingReferer(t *testing.T) { token := string(ctx.Response.Header.Peek(fiber.HeaderSetCookie)) token = strings.Split(strings.Split(token, ";")[0], "=")[1] + ctx.Request.Reset() + ctx.Response.Reset() ctx.Request.Header.SetMethod(fiber.MethodPost) ctx.Request.Header.Set(fiber.HeaderXForwardedProto, "https") ctx.Request.Header.Set(fiber.HeaderXForwardedHost, "example.com") diff --git a/middleware/csrf/extractors.go b/middleware/csrf/extractors.go index ab669bb47a..a9260e89f3 100644 --- a/middleware/csrf/extractors.go +++ b/middleware/csrf/extractors.go @@ -7,11 +7,11 @@ import ( ) var ( - errMissingHeader = errors.New("missing csrf token in header") - errMissingQuery = errors.New("missing csrf token in query") - errMissingParam = errors.New("missing csrf token in param") - errMissingForm = errors.New("missing csrf token in form") - errMissingCookie = errors.New("missing csrf token in cookie") + ErrMissingHeader = errors.New("missing csrf token in header") + ErrMissingQuery = errors.New("missing csrf token in query") + ErrMissingParam = errors.New("missing csrf token in param") + ErrMissingForm = errors.New("missing csrf token in form") + ErrMissingCookie = errors.New("missing csrf token in cookie") ) // csrfFromParam returns a function that extracts token from the url param string. @@ -19,7 +19,7 @@ func CsrfFromParam(param string) func(c *fiber.Ctx) (string, error) { return func(c *fiber.Ctx) (string, error) { token := c.Params(param) if token == "" { - return "", errMissingParam + return "", ErrMissingParam } return token, nil } @@ -30,7 +30,7 @@ func CsrfFromForm(param string) func(c *fiber.Ctx) (string, error) { return func(c *fiber.Ctx) (string, error) { token := c.FormValue(param) if token == "" { - return "", errMissingForm + return "", ErrMissingForm } return token, nil } @@ -41,7 +41,7 @@ func CsrfFromCookie(param string) func(c *fiber.Ctx) (string, error) { return func(c *fiber.Ctx) (string, error) { token := c.Cookies(param) if token == "" { - return "", errMissingCookie + return "", ErrMissingCookie } return token, nil } @@ -52,7 +52,7 @@ func CsrfFromHeader(param string) func(c *fiber.Ctx) (string, error) { return func(c *fiber.Ctx) (string, error) { token := c.Get(param) if token == "" { - return "", errMissingHeader + return "", ErrMissingHeader } return token, nil } @@ -63,7 +63,7 @@ func CsrfFromQuery(param string) func(c *fiber.Ctx) (string, error) { return func(c *fiber.Ctx) (string, error) { token := c.Query(param) if token == "" { - return "", errMissingQuery + return "", ErrMissingQuery } return token, nil } diff --git a/middleware/csrf/helpers.go b/middleware/csrf/helpers.go index 7604b97595..708762c7e3 100644 --- a/middleware/csrf/helpers.go +++ b/middleware/csrf/helpers.go @@ -7,3 +7,7 @@ import ( func compareTokens(a, b []byte) bool { return subtle.ConstantTimeCompare(a, b) == 1 } + +func compareStrings(a, b string) bool { + return subtle.ConstantTimeCompare([]byte(a), []byte(b)) == 1 +} From c864da091dc188d8463d24d1d755d20897cd2d7b Mon Sep 17 00:00:00 2001 From: RW Date: Mon, 16 Oct 2023 09:59:55 +0200 Subject: [PATCH 70/84] prepare release v2.50.0 prepare release v2.50.0 --- app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.go b/app.go index c298a0ec2c..cc43e95a77 100644 --- a/app.go +++ b/app.go @@ -30,7 +30,7 @@ import ( ) // Version of current fiber package -const Version = "2.49.2" +const Version = "2.50.0" // Handler defines a function to serve HTTP requests. type Handler = func(*Ctx) error From af3999835f33943c7d63aa1cfc70e64e94319eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Mon, 16 Oct 2023 10:35:42 +0200 Subject: [PATCH 71/84] Add more description to GetClientInfo --- ctx.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ctx.go b/ctx.go index a5ba85f947..34d49a9b11 100644 --- a/ctx.go +++ b/ctx.go @@ -104,8 +104,9 @@ type TLSHandler struct { clientHelloInfo *tls.ClientHelloInfo } -// GetClientInfo Callback function to set CHI -// TODO: Why is this a getter which sets stuff? +// GetClientInfo Callback function to set ClientHelloInfo +// Must comply with the method structure of https://cs.opensource.google/go/go/+/refs/tags/go1.20:src/crypto/tls/common.go;l=554-563 +// Since we overlay the method of the tls config in the listener method func (t *TLSHandler) GetClientInfo(info *tls.ClientHelloInfo) (*tls.Certificate, error) { t.clientHelloInfo = info return nil, nil //nolint:nilnil // Not returning anything useful here is probably fine From 6f0d34d39e2fce09f66ba15922736c898b67f4d9 Mon Sep 17 00:00:00 2001 From: RW Date: Mon, 16 Oct 2023 14:31:28 +0200 Subject: [PATCH 72/84] Update csrf.md --- docs/api/middleware/csrf.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/api/middleware/csrf.md b/docs/api/middleware/csrf.md index 3430e0098f..33e1adaa10 100644 --- a/docs/api/middleware/csrf.md +++ b/docs/api/middleware/csrf.md @@ -132,8 +132,6 @@ It's recommended to use this middleware with [fiber/middleware/session](https:// ## Config -### Config - | Property | Type | Description | Default | |:------------------|:-----------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------| | Next | `func(*fiber.Ctx) bool` | Next defines a function to skip this middleware when returned true. | `nil` | From 37ad7c799091b5c85c5c37d9ab0b28e220ae8bcd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:53:32 +0200 Subject: [PATCH 73/84] build(deps): bump github.com/mattn/go-isatty from 0.0.19 to 0.0.20 (#2679) Bumps [github.com/mattn/go-isatty](https://github.com/mattn/go-isatty) from 0.0.19 to 0.0.20. - [Commits](https://github.com/mattn/go-isatty/compare/v0.0.19...v0.0.20) --- updated-dependencies: - dependency-name: github.com/mattn/go-isatty dependency-type: direct:production update-type: version-update:semver-patch ... 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 d3bed281c4..5f4cc162f3 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/google/uuid v1.3.1 github.com/mattn/go-colorable v0.1.13 - github.com/mattn/go-isatty v0.0.19 + github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-runewidth v0.0.15 github.com/tinylib/msgp v1.1.8 github.com/valyala/bytebufferpool v1.0.0 diff --git a/go.sum b/go.sum index 720bb1459f..13e17009b9 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,8 @@ github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQs 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= -github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= -github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw= From 94acde8fe5dd2b793ab07924cd9d0ee728eb753c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Efe=20=C3=87etin?= Date: Mon, 23 Oct 2023 10:12:52 +0300 Subject: [PATCH 74/84] :bug: bug: fix method validation on route naming (#2686) * :bug: bug: fix route naming issue when using same path for different methods * fix linter * add new testcase for HEAD route * add comments to tests * fix tests --- app.go | 6 ++++-- app_test.go | 31 ++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/app.go b/app.go index cc43e95a77..ebf1025167 100644 --- a/app.go +++ b/app.go @@ -620,9 +620,11 @@ func (app *App) Name(name string) Router { for _, routes := range app.stack { for _, route := range routes { - if route.Path == app.latestRoute.Path { - route.Name = name + isMethodValid := route.Method == app.latestRoute.Method || app.latestRoute.use || + (app.latestRoute.Method == MethodGet && route.Method == MethodHead) + if route.Path == app.latestRoute.Path && isMethodValid { + route.Name = name if route.group != nil { route.Name = route.group.name + route.Name } diff --git a/app_test.go b/app_test.go index d0acc68c6c..f650d52a97 100644 --- a/app_test.go +++ b/app_test.go @@ -1859,7 +1859,7 @@ func Test_Middleware_Route_Naming_With_Use(t *testing.T) { } } -func Test_Route_Naming_Issue_2671(t *testing.T) { +func Test_Route_Naming_Issue_2671_2685(t *testing.T) { app := New() app.Get("/", emptyHandler).Name("index") @@ -1904,4 +1904,33 @@ func Test_Route_Naming_Issue_2671(t *testing.T) { postGroup.Post("", emptyHandler).Name("post.update") utils.AssertEqual(t, "/post/:postId", app.GetRoute("post.update").Path) + + // Add testcase for routes use the same PATH on different methods + app.Get("/users", nil).Name("get-users") + app.Post("/users", nil).Name("add-user") + getUsers := app.GetRoute("get-users") + utils.AssertEqual(t, getUsers.Path, "/users") + + addUser := app.GetRoute("add-user") + utils.AssertEqual(t, addUser.Path, "/users") + + // Add testcase for routes use the same PATH on different methods (for groups) + newGrp := app.Group("/name-test") + newGrp.Get("/users", nil).Name("grp-get-users") + newGrp.Post("/users", nil).Name("grp-add-user") + getUsers = app.GetRoute("grp-get-users") + utils.AssertEqual(t, getUsers.Path, "/name-test/users") + + addUser = app.GetRoute("grp-add-user") + utils.AssertEqual(t, addUser.Path, "/name-test/users") + + // Add testcase for HEAD route naming + app.Get("/simple-route", emptyHandler).Name("simple-route") + app.Head("/simple-route", emptyHandler).Name("simple-route2") + + sRoute := app.GetRoute("simple-route") + utils.AssertEqual(t, sRoute.Path, "/simple-route") + + sRoute2 := app.GetRoute("simple-route2") + utils.AssertEqual(t, sRoute2.Path, "/simple-route") } From db62f9c21856f50d315d72c7adbc6f945c1cd772 Mon Sep 17 00:00:00 2001 From: RW Date: Mon, 23 Oct 2023 13:58:00 +0200 Subject: [PATCH 75/84] =?UTF-8?q?=F0=9F=90=9B=20[Bug]:=20Naming=20of=20rou?= =?UTF-8?q?tes=20works=20wrong=20after=20mount=20#2688=20(#2689)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mount_test.go | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ router.go | 5 ++-- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/mount_test.go b/mount_test.go index 2ae67fb142..c0ca6bf3c9 100644 --- a/mount_test.go +++ b/mount_test.go @@ -400,6 +400,79 @@ func Test_App_UseMountedErrorHandlerForBestPrefixMatch(t *testing.T) { utils.AssertEqual(t, "hi, i'm a custom sub sub fiber error", string(b), "Third fiber Response body") } +// go test -run Test_Mount_Route_Names +func Test_Mount_Route_Names(t *testing.T) { + // create sub-app with 2 handlers: + subApp1 := New() + subApp1.Get("/users", func(c *Ctx) error { + url, err := c.GetRouteURL("add-user", Map{}) + utils.AssertEqual(t, err, nil) + utils.AssertEqual(t, url, "/app1/users", "handler: app1.add-user") // the prefix is /app1 because of the mount + // if subApp1 is not mounted, expected url just /users + return nil + }).Name("get-users") + subApp1.Post("/users", func(c *Ctx) error { + route := c.App().GetRoute("get-users") + utils.AssertEqual(t, route.Method, MethodGet, "handler: app1.get-users method") + utils.AssertEqual(t, route.Path, "/app1/users", "handler: app1.get-users path") + return nil + }).Name("add-user") + + // create sub-app with 2 handlers inside a group: + subApp2 := New() + app2Grp := subApp2.Group("/users").Name("users.") + app2Grp.Get("", nil).Name("get") + app2Grp.Post("", nil).Name("add") + + // put both sub-apps into root app + rootApp := New() + _ = rootApp.Mount("/app1", subApp1) + _ = rootApp.Mount("/app2", subApp2) + + rootApp.startupProcess() + + // take route directly from sub-app + route := subApp1.GetRoute("get-users") + utils.AssertEqual(t, route.Method, MethodGet) + utils.AssertEqual(t, route.Path, "/users") + + route = subApp1.GetRoute("add-user") + utils.AssertEqual(t, route.Method, MethodPost) + utils.AssertEqual(t, route.Path, "/users") + + // take route directly from sub-app with group + route = subApp2.GetRoute("users.get") + utils.AssertEqual(t, route.Method, MethodGet) + utils.AssertEqual(t, route.Path, "/users") + + route = subApp2.GetRoute("users.add") + utils.AssertEqual(t, route.Method, MethodPost) + utils.AssertEqual(t, route.Path, "/users") + + // take route from root app (using names of sub-apps) + route = rootApp.GetRoute("add-user") + utils.AssertEqual(t, route.Method, MethodPost) + utils.AssertEqual(t, route.Path, "/app1/users") + + route = rootApp.GetRoute("users.add") + utils.AssertEqual(t, route.Method, MethodPost) + utils.AssertEqual(t, route.Path, "/app2/users") + + // GetRouteURL inside handler + req := httptest.NewRequest(MethodGet, "/app1/users", nil) + resp, err := rootApp.Test(req) + + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code") + + // ctx.App().GetRoute() inside handler + req = httptest.NewRequest(MethodPost, "/app1/users", nil) + resp, err = rootApp.Test(req) + + utils.AssertEqual(t, nil, err, "app.Test(req)") + utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code") +} + // go test -run Test_Ctx_Render_Mount func Test_Ctx_Render_Mount(t *testing.T) { t.Parallel() diff --git a/router.go b/router.go index e80bc57d1e..4afa741537 100644 --- a/router.go +++ b/router.go @@ -47,7 +47,7 @@ type Router interface { // Route is a struct that holds all metadata for each registered handler. type Route struct { - // always keep in sync with the copy method "app.copyRoute" + // ### important: always keep in sync with the copy method "app.copyRoute" ### // Data for routing pos uint32 // Position in stack -> important for the sort of the matched routes use bool // USE matches path prefixes @@ -214,13 +214,14 @@ func (*App) copyRoute(route *Route) *Route { // Path data path: route.path, routeParser: route.routeParser, - Params: route.Params, // misc pos: route.pos, // Public data Path: route.Path, + Params: route.Params, + Name: route.Name, Method: route.Method, Handlers: route.Handlers, } From 9347a86cdba6b8e8582016fa95a881daebee4ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Werner?= Date: Tue, 24 Oct 2023 08:35:50 +0200 Subject: [PATCH 76/84] =?UTF-8?q?=F0=9F=93=97=20Add=20example=20for=20resp?= =?UTF-8?q?onse=20handling=20with=20fiber=20client?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/api/client.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/docs/api/client.md b/docs/api/client.md index c3ed4b11a6..7ec9f3b033 100644 --- a/docs/api/client.md +++ b/docs/api/client.md @@ -537,6 +537,61 @@ agent.SetResponse(resp) ReleaseResponse(resp) ``` +
Example handling for response values + +```go title="Example handling response" +// Create a Fiber HTTP client agent +agent := fiber.Get("https://httpbin.org/get") + +// Acquire a response object to store the result +resp := fiber.AcquireResponse() +agent.SetResponse(resp) + +// Perform the HTTP GET request +code, body, errs := agent.String() +if errs != nil { + // Handle any errors that occur during the request + panic(errs) +} + +// Print the HTTP response code and body +fmt.Println("Response Code:", code) +fmt.Println("Response Body:", body) + +// Visit and print all the headers in the response +resp.Header.VisitAll(func(key, value []byte) { + fmt.Println("Header", string(key), "value", string(value)) +}) + +// Release the response to free up resources +fiber.ReleaseResponse(resp) +``` + +Output: +```txt title="Output" +Response Code: 200 +Response Body: { + "args": {}, + "headers": { + "Host": "httpbin.org", + "User-Agent": "fiber", + "X-Amzn-Trace-Id": "Root=1-653763d0-2555d5ba3838f1e9092f9f72" + }, + "origin": "83.137.191.1", + "url": "https://httpbin.org/get" +} + +Header Content-Length value 226 +Header Content-Type value application/json +Header Server value gunicorn/19.9.0 +Header Date value Tue, 24 Oct 2023 06:27:28 GMT +Header Connection value keep-alive +Header Access-Control-Allow-Origin value * +Header Access-Control-Allow-Credentials value true +``` + +
+ ### Dest Dest sets custom dest. The contents of dest will be replaced by the response body, if the dest is too small a new slice will be allocated. From 7eadeb8ed3a2e10f7848ffde7f93c58bdc959a11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Oct 2023 23:10:00 +0200 Subject: [PATCH 77/84] build(deps): bump actions/setup-node from 3 to 4 (#2690) Bumps [actions/setup-node](https://github.com/actions/setup-node) from 3 to 4. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-node dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/sync-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-docs.yml b/.github/workflows/sync-docs.yml index a92449e35c..eb35d75bd2 100644 --- a/.github/workflows/sync-docs.yml +++ b/.github/workflows/sync-docs.yml @@ -21,7 +21,7 @@ jobs: fetch-depth: 2 - name: Setup Node.js environment - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: "18" From 4bf36951255a4a0dab6702f9c1de434cb1276d7b Mon Sep 17 00:00:00 2001 From: Jason McNeil Date: Fri, 27 Oct 2023 08:45:30 -0300 Subject: [PATCH 78/84] =?UTF-8?q?=F0=9F=93=84=20docs:=20enhance=20csrf.md?= =?UTF-8?q?=20(#2692)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: enhance csrf.md * docs: simplify language * docs: update csrf.md * docs: delete token/session reminders * docs: and ! or --- docs/api/middleware/csrf.md | 124 ++++++++++++++++++++++++------------ 1 file changed, 84 insertions(+), 40 deletions(-) diff --git a/docs/api/middleware/csrf.md b/docs/api/middleware/csrf.md index 33e1adaa10..58cd4f13d0 100644 --- a/docs/api/middleware/csrf.md +++ b/docs/api/middleware/csrf.md @@ -4,43 +4,51 @@ id: csrf # CSRF -CSRF middleware for [Fiber](https://github.com/gofiber/fiber) that provides [Cross-site request forgery](https://en.wikipedia.org/wiki/Cross-site_request_forgery) protection by passing a csrf token via cookies. This cookie value will be used to compare against the client csrf token on requests, 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, or TRACE\). When the csrf token is invalid, this middleware will return the `fiber.ErrForbidden` 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 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. -CSRF Tokens are generated on GET requests. You can retrieve the CSRF token with `c.Locals(contextKey)`, where `contextKey` is the string you set in the config (see Custom Config below). +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. -When no `csrf_` cookie is set, or the token has expired, a new token will be generated and `csrf_` cookie set. +## Token Generation -:::note -This middleware uses our [Storage](https://github.com/gofiber/storage) package to support various databases through a single interface. The default configuration for this middleware saves data to memory, see the examples below for other databases. -::: +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. ## Security Considerations -This middleware is designed to protect against CSRF attacks. It does not protect against other attack vectors, such as XSS, and should be used in combination with other security measures. +This middleware is designed to protect against CSRF attacks but does not protect against other attack vectors, such as XSS. It should be used in combination with other security measures. -:::warning -Never use 'safe' methods to mutate data. For example, never use a GET request to delete a resource. This middleware will not protect against CSRF attacks on 'safe' methods. +:::danger +Never use 'safe' methods to mutate data, for example, never use a GET request to modify a resource. This middleware will not protect against CSRF attacks on 'safe' methods. ::: -### The Double Submit Cookie Pattern (Default) +### Token Validation Patterns + +#### 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. -In the default configuration, the middleware will generate and store tokens using the `fiber.Storage` interface. These tokens are not associated with a user session, and, therefore, a Double Submit Cookie pattern is used to validate the token. This means that the token is stored in a cookie and also sent as a header on requests. The middleware will compare the cookie value with the header value to validate the token. This is a secure method of validating the token, as cookies are not accessible to JavaScript and, therefore, cannot be read by an attacker. +When using this pattern, it's important to delete the token when the authorization status changes, see: [Token Lifecycle](#token-lifecycle) for more information. -:::warning -When using this method, it is important that you set the `CookieSameSite` option to `Lax` or `Strict` and that the Extractor is not `CsrfFromCookie`, and KeyLookup is not `cookie:`. +:::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:`. ::: -### The Synchronizer Token Pattern (Session) +:::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) + +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 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 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. -:::warning -When using this method, pre-sessions are required and will be created if a session is not already present. This means that the middleware will create a session for every safe request, even if the request does not require a session. Therefore it is required that the existence of a session is not used to indicate that a user is logged in or authenticated, and that a session value is used to indicate this instead. +:::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. ::: ### Defense In Depth -When using this middleware, it is recommended that you serve your pages over HTTPS, that the `CookieSecure` option is set to `true`, and that the `CookieSameSite` option is set to `Lax` or `Strict`. This will ensure that the cookie is only sent over HTTPS and that it is not sent on requests from external sites. +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. @@ -50,43 +58,44 @@ To use these prefixes, set the `CookieName` option to `__Host-csrf_` or `__Secur ### Referer Checking -For HTTPS requests, this middleware performs strict referer checking. This means that 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. +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. -:::warning +:::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. ::: + ### Token Lifecycle -Tokens are valid until they expire, or until they are deleted. By default, tokens are valid for 1 hour and each subsequent request will extend the expiration by 1 hour. This means that if a user makes a request every hour, the token will never expire. If a user makes a request after the token has expired, then a new token will be generated and the `csrf_` cookie will be set again. This means that the token will only expire if the user does not make a request for the duration of the expiration time. +Tokens are valid until they expire or until they are deleted. By default, tokens are valid for 1 hour, and each subsequent request extends the expiration by 1 hour. The token only expires if the user doesn't make a request for the duration of the expiration time. #### Token Reuse -By default tokens may be used multiple times. This means that the token will not be deleted after it has been used. If you would like to delete the token after it has been used, then 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. +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. -:::note -Using `SingleUseToken` comes with usability tradeoffs, and therefore is not enabled by default. It can interfere with the user experience if the user has multiple tabs open, or if the user uses the back button. +:::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. ::: #### Deleting Tokens -When the authorization status changes, the CSRF token should be deleted and a new one generated. This can be done by calling `handler.DeleteToken(c)`. This will remove the token found in the request context from the storage and set the `csrf_` cookie to an empty value. The next 'safe' request will generate a new token and set the cookie again. +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 err := handler.DeleteToken(app.AcquireCtx(ctx)); err != nil { - // handle error - } + if err := handler.DeleteToken(app.AcquireCtx(ctx)); err != nil { + // handle error + } } ``` -:::note +:::tip If you are using this middleware with the fiber session middleware, then you can simply call `session.Destroy()`, `session.Regenerate()`, or `session.Reset()` to delete session and the token stored therein. ::: ### BREACH -It is important to note that the token is sent as a header on every request, and if you include the token in a page that is vulnerable to [BREACH](https://en.wikipedia.org/wiki/BREACH), then an attacker may be able to extract the token. To mitigate this, you should take steps such as ensuring that your pages are served over HTTPS, that HTTP compression is disabled, and rate limiting requests. +It's important to note that the token is sent as a header on every request. If you include the token in a page that is vulnerable to [BREACH](https://en.wikipedia.org/wiki/BREACH), an attacker may be able to extract the token. To mitigate this, ensure your pages are served over HTTPS, disable HTTP compression, and implement rate limiting for requests. ## Signatures @@ -96,7 +105,7 @@ func New(config ...Config) fiber.Handler ## Examples -Import the middleware package that is part of the Fiber web framework +Import the middleware package that is part of the Fiber web framework: ```go import ( @@ -105,7 +114,7 @@ import ( ) ``` -After you initiate your Fiber app, you can use the following possibilities: +After initializing your Fiber app, you can use the following code to initialize the middleware: ```go // Initialize default config @@ -122,14 +131,10 @@ app.Use(csrf.New(csrf.Config{ })) ``` -:::note +:::info KeyLookup will be ignored if Extractor is explicitly set. ::: -### Use with fiber/middleware/session (recommended) - -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. - ## Config | Property | Type | Description | Default | @@ -157,7 +162,7 @@ It's recommended to use this middleware with [fiber/middleware/session](https:// | Extractor | `func(*fiber.Ctx) (string, error)` | Extractor returns the CSRF token. If set, this will be used in place of an Extractor based on KeyLookup. | Extractor based on KeyLookup | | HandlerContextKey | `string` | HandlerContextKey is used to store the CSRF Handler into context. | "fiber.csrf.handler" | -## Default Config +### Default Config ```go var ConfigDefault = Config{ @@ -173,7 +178,9 @@ var ConfigDefault = Config{ } ``` -## Recommended Config (with session) +### 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. ```go var ConfigDefault = Config{ @@ -200,7 +207,44 @@ const ( ) ``` -### Custom Storage/Database +## Sentinel Errors + +The CSRF middleware utilizes a set of sentinel errors to handle various scenarios and communicate errors effectively. These can be used within a [custom error handler](#custom-error-handler) to handle errors returned by the middleware. + +### Errors Returned to Error Handler + +- `ErrTokenNotFound`: Indicates that the CSRF token was not found. +- `ErrTokenInvalid`: Indicates that the CSRF token is invalid. +- `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. + +## Custom Error Handler + +You can use a custom error handler to handle errors returned by the CSRF middleware. The error handler is executed when an error is returned from the middleware. The error handler is passed the error returned from the middleware and the fiber.Ctx. + +Example, returning a JSON response for API requests and rendering an error page for other requests: + +```go +app.Use(csrf.New(csrf.Config{ + ErrorHandler: func(c *fiber.Ctx, err error) error { + accepts := c.Accepts("html", "json") + path := c.Path() + if accepts == "json" || strings.HasPrefix(path, "/api/") { + return c.Status(fiber.StatusForbidden).JSON(fiber.Map{ + "error": "Forbidden", + }) + } + return c.Status(fiber.StatusForbidden).Render("error", fiber.Map{ + "Title": "Forbidden", + "Status": fiber.StatusForbidden, + }, "layouts/main") + }, +})) +``` + +## Custom Storage/Database You can use any storage from our [storage](https://github.com/gofiber/storage/) package. From 7bbffab19f1a6377f199d764e3b68f31237deed2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 29 Oct 2023 20:36:01 +0300 Subject: [PATCH 79/84] build(deps): bump github.com/google/uuid from 1.3.1 to 1.4.0 (#2693) Bumps [github.com/google/uuid](https://github.com/google/uuid) from 1.3.1 to 1.4.0. - [Release notes](https://github.com/google/uuid/releases) - [Changelog](https://github.com/google/uuid/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/uuid/compare/v1.3.1...v1.4.0) --- updated-dependencies: - dependency-name: github.com/google/uuid 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 5f4cc162f3..cd49d43234 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/gofiber/fiber/v2 go 1.20 require ( - github.com/google/uuid v1.3.1 + github.com/google/uuid v1.4.0 github.com/mattn/go-colorable v0.1.13 github.com/mattn/go-isatty v0.0.20 github.com/mattn/go-runewidth v0.0.15 diff --git a/go.sum b/go.sum index 13e17009b9..01b9e73023 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +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/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= From 4099ef87bb35db39c160c17b9b6ded34e71d007d Mon Sep 17 00:00:00 2001 From: RW Date: Wed, 1 Nov 2023 08:22:10 +0100 Subject: [PATCH 80/84] Update routing.md fix invalid regex constraint --- docs/guide/routing.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide/routing.md b/docs/guide/routing.md index 7b092461ce..b6534532b0 100644 --- a/docs/guide/routing.md +++ b/docs/guide/routing.md @@ -162,7 +162,7 @@ Constraints aren't validation for parameters. If constraint aren't valid for par | range(min,max) | :age | 91 (Integer value must be at least 18 but no more than 120) | | alpha | :name | Rick (String must consist of one or more alphabetical characters, a-z and case-insensitive) | | datetime | :dob | 2005-11-01 | -| regex(expression) | :date | 2022-08-27 (Must match regular expression) | +| regex(expression) | :date | 2022-08-27 (Must match regular expression) | **Examples** @@ -203,7 +203,7 @@ app.Get("/:test", func(c *fiber.Ctx) error { Fiber precompiles regex query when to register routes. So there're no performance overhead for regex constraint. ```go -app.Get(`/:date`, func(c *fiber.Ctx) error { +app.Get(`/:date`, func(c *fiber.Ctx) error { return c.SendString(c.Params("date")) }) From 0104e59e9fe5a42539356f52d61d63025838569d Mon Sep 17 00:00:00 2001 From: HardikBandhiya Date: Wed, 1 Nov 2023 13:54:14 +0530 Subject: [PATCH 81/84] fix: changed "Twitter" to "X (Twitter)" in README.md Contribute Section (#2696) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update README.md in README.md contribute section the name of twitter was old i changed it to 𝕏 * Update README.md updated domain as per suggested * Update CONTRIBUTING.md * Update README_az.md * Update README_ckb.md in this i changed domain only. * Update README_de.md * Update README_eg.md in this i changed domain * Update README_es.md * Update README_fa.md * Update README_fr.md * Update README_he.md * Update README_id.md * Update README_it.md * Update README_ja.md * Update README_ko.md * Update README_nl.md * Update README_pl.md * Update README_pt.md * Update README_ru.md * Update README_sa.md * Update README_tr.md * Update README_uk.md * Update README_zh-CN.md * Update README_zh-TW.md --- .github/CONTRIBUTING.md | 2 +- .github/README.md | 2 +- .github/README_az.md | 2 +- .github/README_ckb.md | 2 +- .github/README_de.md | 2 +- .github/README_eg.md | 2 +- .github/README_es.md | 2 +- .github/README_fa.md | 2 +- .github/README_fr.md | 2 +- .github/README_he.md | 2 +- .github/README_id.md | 2 +- .github/README_it.md | 2 +- .github/README_ja.md | 2 +- .github/README_ko.md | 2 +- .github/README_nl.md | 2 +- .github/README_pl.md | 2 +- .github/README_pt.md | 2 +- .github/README_ru.md | 2 +- .github/README_sa.md | 2 +- .github/README_tr.md | 2 +- .github/README_uk.md | 2 +- .github/README_zh-CN.md | 2 +- .github/README_zh-TW.md | 2 +- 23 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ae1a1a6057..d23c99af24 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -22,6 +22,6 @@ All pull request that contains a feature or fix is mandatory to have unit tests. If you want to say **thank you** and/or support the active development of `Fiber`: 1. Add a [GitHub Star](https://github.com/gofiber/fiber/stargazers) to the project. -2. Tweet about the project [on your Twitter](https://twitter.com/intent/tweet?text=%F0%9F%9A%80%20Fiber%20%E2%80%94%20is%20an%20Express.js%20inspired%20web%20framework%20build%20on%20Fasthttp%20for%20%23Go%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Tweet about the project [on your 𝕏 (Twitter)](https://x.com/intent/tweet?text=%F0%9F%9A%80%20Fiber%20%E2%80%94%20is%20an%20Express.js%20inspired%20web%20framework%20build%20on%20Fasthttp%20for%20%23Go%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Write a review or tutorial on [Medium](https://medium.com/), [Dev.to](https://dev.to/) or personal blog. 4. Support the project by donating a [cup of coffee](https://buymeacoff.ee/fenny). diff --git a/.github/README.md b/.github/README.md index bf397b96a3..172ecc599f 100644 --- a/.github/README.md +++ b/.github/README.md @@ -659,7 +659,7 @@ For more articles, middlewares, examples or tools check our [awesome list](https If you want to say **thank you** and/or support the active development of `Fiber`: 1. Add a [GitHub Star](https://github.com/gofiber/fiber/stargazers) to the project. -2. Tweet about the project [on your Twitter](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Tweet about the project [on your 𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Write a review or tutorial on [Medium](https://medium.com/), [Dev.to](https://dev.to/) or personal blog. 4. Support the project by donating a [cup of coffee](https://buymeacoff.ee/fenny). diff --git a/.github/README_az.md b/.github/README_az.md index ade4fa8857..f1b6174e98 100644 --- a/.github/README_az.md +++ b/.github/README_az.md @@ -659,7 +659,7 @@ Aşağıda Fiber-in daxilində olan middleware-lər siyahı şəklində göstər Əgər `Fiber`-ə dəstək olmaq və ya **təşəkkür etmək** istəyirsinizsə: 1. Layihəni [GitHub Ulduzu](https://github.com/gofiber/fiber/stargazers) ilə işarələyin. -2. Layihə haqqında [şəxsi twitter hesabınızda](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber) paylaşın. +2. Layihə haqqında [şəxsi 𝕏 (Twitter) hesabınızda](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber) paylaşın. 3. [Medium](https://medium.com/), [Dev.to](https://dev.to/) və ya şəxsi bloqunuz üzərindən bir incələmə və ya tədris yönümlü bir yazı dərc edin. 4. Bizim üçün, sadəcə bir [fincan kofe alın](https://buymeacoff.ee/fenny). diff --git a/.github/README_ckb.md b/.github/README_ckb.md index 9c1704a7af..5f52bf8aea 100644 --- a/.github/README_ckb.md +++ b/.github/README_ckb.md @@ -657,7 +657,7 @@ For more articles, middlewares, examples or tools check our [awesome list](https ئەگەر دەتەوێت دەستخۆشی لە فایبەر بکەیت: 1. [ئەستێرەیەک](https://github.com/gofiber/fiber/stargazers)ـی بۆ دا بنێ. -2. لە تویتەر [تویتی لەسەر بکە](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. لە تویتەر [تویتی لەسەر بکە](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. بە وێبڵۆگێک باسی بکە. 4. [پشتگیری بکە](https://buymeacoff.ee/fenny). diff --git a/.github/README_de.md b/.github/README_de.md index 72b4d02f0a..8fd8935263 100644 --- a/.github/README_de.md +++ b/.github/README_de.md @@ -630,7 +630,7 @@ Weitere Artikel, Middlewares, Beispiele oder Tools finden Sie in unserer [awesom Falls du **danke** sagen möchtest und/oder aktiv die Entwicklung von `fiber` fördern möchtest: 1. Füge dem Projekt einen [GitHub Stern](https://github.com/gofiber/fiber/stargazers) hinzu. -2. Twittere über das Projekt [auf deinem Twitter](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Twittere über das Projekt [auf deinem 𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Schreibe eine Rezension auf [Medium](https://medium.com/), [Dev.to](https://dev.to/) oder einem persönlichem Blog. 4. Unterstütze das Projekt, indem du ☕ [uns einen Kaffee kaufst](https://buymeacoff.ee/fenny). diff --git a/.github/README_eg.md b/.github/README_eg.md index 7b337b567a..3eea1171ac 100644 --- a/.github/README_eg.md +++ b/.github/README_eg.md @@ -660,7 +660,7 @@ Here is a list of middleware that are included within the Fiber framework. لو عاوز تقول **شكرا** او تدعمنا في تطوير `فايبر`: 1. اعمل [GitHub Star](https://github.com/gofiber/fiber/stargazers) للبروجكت. -2. تويت عن البروجكت [على تويتر](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. تويت عن البروجكت [على تويتر](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. اكتب ريفيو او توتوريال على [Medium](https://medium.com/), [Dev.to](https://dev.to/) او البلوج بتاعتك. 4. او ادعم المشروع [بكوباية شاي](https://buymeacoff.ee/fenny). diff --git a/.github/README_es.md b/.github/README_es.md index 73af515002..b3e5b9f7bf 100644 --- a/.github/README_es.md +++ b/.github/README_es.md @@ -630,7 +630,7 @@ For more articles, middlewares, examples or tools check our [awesome list](https Si quiere **agradecer** y/o apoyar el desarrollo activo de `Fiber`: 1. Agrega una [estrella de GitHub](https://github.com/gofiber/fiber/stargazers) al proyecto. -2. Tuitea sobre el proyecto [en tu Twitter](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Tuitea sobre el proyecto [en tu 𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Escribe una reseña o tutorial en [Medium](https://medium.com/) , [Dev.to](https://dev.to/) o blog personal. 4. Apoya el proyecto donando una [tasa de café](https://buymeacoff.ee/fenny). diff --git a/.github/README_fa.md b/.github/README_fa.md index cafbf5e526..390922d68b 100644 --- a/.github/README_fa.md +++ b/.github/README_fa.md @@ -780,7 +780,7 @@ func main() { اگر شما میخواهید **تشکر** کنید و یا از توسعه فعال Fiber حمایت کنید : 1. یک [GitHub Star](https://github.com/gofiber/fiber/stargazers) به پروژه اضافه کنید. -2. ارسال توییت درباره Fiber برروی [صفحه توییتر شما](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. ارسال توییت درباره Fiber برروی [صفحه توییتر شما](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. یک آموزش یا نظر برروی [Medium](https://medium.com/), [Dev.to](https://dev.to/) یا وبلاگ شخصیتان. 4. پشتیبانی پروژه با حمایت مالی از طریق [یک فنجان قهوه](https://buymeacoff.ee/fenny). diff --git a/.github/README_fr.md b/.github/README_fr.md index 8691e59d5f..2f93e567de 100644 --- a/.github/README_fr.md +++ b/.github/README_fr.md @@ -632,7 +632,7 @@ For more articles, middlewares, examples or tools check our [awesome list](https Si vous voulez nous remercier et/ou soutenir le développement actif de `Fiber`: 1. Ajoutez une [GitHub Star](https://github.com/gofiber/fiber/stargazers) à ce projet. -2. Twittez à propos de ce projet [sur votre Twitter](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Twittez à propos de ce projet [sur votre 𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Ecrivez un article (review, tutorial) sur [Medium](https://medium.com/), [Dev.to](https://dev.to/), ou encore un blog personnel. 4. Support the project by donating a [cup of coffee](https://buymeacoff.ee/fenny). diff --git a/.github/README_he.md b/.github/README_he.md index 44ed8c4627..0ddda261df 100644 --- a/.github/README_he.md +++ b/.github/README_he.md @@ -780,7 +780,7 @@ For more articles, middlewares, examples or tools check our [awesome list](https
1. תוסיפו [GitHub Star](https://github.com/gofiber/fiber/stargazers) לפרויקט. -2. צייצו לגבי הפרויקט [בטוויטר שלכם](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. צייצו לגבי הפרויקט [בטוויטר שלכם](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. כתבו ביקורת או מדריך ב-[Medium](https://medium.com/), [Dev.to](https://dev.to/) או בבלוג האישי שלכם. 4. תמכו בפרויקט על ידי תרומת [כוס קפה](https://buymeacoff.ee/fenny).
diff --git a/.github/README_id.md b/.github/README_id.md index 69ada3f3e5..47da87b419 100644 --- a/.github/README_id.md +++ b/.github/README_id.md @@ -632,7 +632,7 @@ Untuk artikel lainnya, middlewares, contoh atau tools check kami [awesome list]( Apabila anda ingin mengucapkan **terima kasih** dan/atau mendukung pengembangan `Fiber`: 1. Berikan bintang atau [GitHub Star](https://github.com/gofiber/fiber/stargazers) ke proyek ini. -2. Bagikan [di Twitter anda](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Bagikan [di 𝕏 (Twitter) anda](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Buat ulasan atau tutorial di [Medium](https://medium.com/), [Dev.to](https://dev.to/) atau blog pribadi anda. 4. Dukung proyek ini dengan membelikan [secangkir kopi](https://buymeacoff.ee/fenny). diff --git a/.github/README_it.md b/.github/README_it.md index 56e9c5b411..159bcff9a1 100644 --- a/.github/README_it.md +++ b/.github/README_it.md @@ -655,7 +655,7 @@ Per piu articoli, middlewares, esempi o attrezzi puoi usare la [awesome list](ht Se vuoi dirci **grazie** e/o supportare lo sviluppo di `Fiber`: 1. Aggiungi una [stella GitHub](https://github.com/gofiber/fiber/stargazers) al progetto. -2. Twitta del progetto [su Twitter](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Twitta del progetto [su 𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Scrivi una recensione o un tutorial su [Medium](https://medium.com/), [Dev.to](https://dev.to/) o sul tuo blog personale. 4. Supporta il progetto donando una [tazza di caffè](https://buymeacoff.ee/fenny). diff --git a/.github/README_ja.md b/.github/README_ja.md index 08a794d9de..23dfb60999 100644 --- a/.github/README_ja.md +++ b/.github/README_ja.md @@ -634,7 +634,7 @@ func main() { `Fiber`に開発支援してくださるなら: 1. [GitHub Star](https://github.com/gofiber/fiber/stargazers)をつけてください 。 -2. [あなたの Twitter で](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber)プロジェクトについてツイートしてください。 +2. [あなたの 𝕏 (Twitter) で](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber)プロジェクトについてツイートしてください。 3. [Medium](https://medium.com/) 、 [Dev.to](https://dev.to/)、または個人のブログでレビューやチュートリアルを書いてください。 4. [cup of coffee](https://buymeacoff.ee/fenny)の寄付でプロジェクトを支援しましょう。 diff --git a/.github/README_ko.md b/.github/README_ko.md index 50f1afd943..c2ed6afb9b 100644 --- a/.github/README_ko.md +++ b/.github/README_ko.md @@ -636,7 +636,7 @@ For more articles, middlewares, examples or tools check our [awesome list](https `Fiber`의 활발한 개발을 지원하고 감사 인사를 하고 싶다면: 1. 프로젝트에 [GitHub Star](https://github.com/gofiber/fiber/stargazers)를 추가하세요. -2. [트위터에서](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber) 프로젝트에 대해 트윗하세요. +2. [트위터에서](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber) 프로젝트에 대해 트윗하세요. 3. [Medium](https://medium.com/), [Dev.to](https://dev.to/) 또는 개인 블로그에 리뷰 또는 튜토리얼을 작성하세요. 4. Support the project by donating a [cup of coffee](https://buymeacoff.ee/fenny). diff --git a/.github/README_nl.md b/.github/README_nl.md index 33528c6185..e31040a06d 100644 --- a/.github/README_nl.md +++ b/.github/README_nl.md @@ -636,7 +636,7 @@ For more articles, middlewares, examples or tools check our [awesome list](https Om de actieve ontwikkelingen van `Fiber` te ondersteunen of om een **bedankje** te geven: 1. Voeg een [GitHub Star](https://github.com/gofiber/fiber/stargazers) toe aan het project. -2. Tweet over het project [op je Twitter account](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Tweet over het project [op je 𝕏 (Twitter) account](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Schrijf een recensie of tutorial op [Medium](https://medium.com/), [Dev.to](https://dev.to/) of een persoonlijke blog. 4. Support the project by donating a [cup of coffee](https://buymeacoff.ee/fenny). diff --git a/.github/README_pl.md b/.github/README_pl.md index 3bb94e8c8b..5cff10c87e 100644 --- a/.github/README_pl.md +++ b/.github/README_pl.md @@ -658,7 +658,7 @@ Po więcej artykułów, middleware, przykładów lub narzędzi sprawdź naszą [ Jeżeli chcesz podziękować i/lub wesprzeć aktywny rozwój `Fiber'a`: 1. Dodaj [Gwiazdkę GitHub](https://github.com/gofiber/fiber/stargazers) dla tego projektu. -2. Zatweetuj o tym projekcie [na twoim Twitterze](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Zatweetuj o tym projekcie [na twoim 𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Napisz recenzję lub tutorial na [Medium](https://medium.com/), [Dev.to](https://dev.to/) lub personalnym blogu. 4. Wesprzyj projekt, przekazując darowiznę w postaci [filiżanki kawy](https://buymeacoff.ee/fenny). diff --git a/.github/README_pt.md b/.github/README_pt.md index 3f18533b2e..e55f4f58b7 100644 --- a/.github/README_pt.md +++ b/.github/README_pt.md @@ -630,7 +630,7 @@ Para mais artigos, middlewares, exemplos ou ferramentas, confira nossa [lista in Se você quer **agradecer** e/ou apoiar o desenvolvimento ativo do `Fiber`: 1. Deixe uma [estrela no GitHub](https://github.com/gofiber/fiber/stargazers) do projeto. -2. Tweet sobre o projeto [no seu Twitter](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Tweet sobre o projeto [no seu 𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Escreva um review ou tutorial no [Medium](https://medium.com/), [Dev.to](https://dev.to/) ou blog pessoal. 4. Apoie o projeto pagando uma [xícara de café](https://buymeacoff.ee/fenny). diff --git a/.github/README_ru.md b/.github/README_ru.md index 534f6c6734..bfb41661d8 100644 --- a/.github/README_ru.md +++ b/.github/README_ru.md @@ -637,7 +637,7 @@ func main() { Если вы хотите сказать **спасибо** и/или поддержать активное развитие `Fiber`: 1. Добавьте [GitHub Star](https://github.com/gofiber/fiber/stargazers) в проект. -2. Напишите о проекте [в вашем Twitter](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Напишите о проекте [в вашем 𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Сделайте обзор фреймворка на [Medium](https://medium.com/), [Dev.to](https://dev.to/) или в личном блоге. 4. Поддержите проект, купив [чашку кофе](https://buymeacoff.ee/fenny). diff --git a/.github/README_sa.md b/.github/README_sa.md index c36b4ba495..a5a54e9e47 100644 --- a/.github/README_sa.md +++ b/.github/README_sa.md @@ -701,7 +701,7 @@ For more articles, middlewares, examples or tools check our [awesome list](https إذا كنت تريد أن تقول **شكرا جزيل** و/او دعم التنمية النشطة للـ `Fiber`: 1. اضف [GitHub نجمة](https://github.com/gofiber/fiber/stargazers) للمشروع. -2. غرد عن المشروع [في تويتر ](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. غرد عن المشروع [في تويتر ](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. اكتب مراجعة أو برنامج تعليمي عن [Medium](https://medium.com/), [Dev.to](https://dev.to/) او في موقعك الشخصي. 4. دعم المشروع بالتبرع بـ [كوب من القهوة](https://buymeacoff.ee/fenny). diff --git a/.github/README_tr.md b/.github/README_tr.md index 8053f4e846..3ab0f15a6d 100644 --- a/.github/README_tr.md +++ b/.github/README_tr.md @@ -629,7 +629,7 @@ Daha fazla yazı, middleware, örnek veya araç için [awesome list](https://git Eğer **teşekkür etmek** veya `Fiber`'ın aktif geliştirilmesini desteklemek istiyorsanız: 1. Projeye [yıldız](https://github.com/gofiber/fiber/stargazers) verebilirsiniz. -2. [Twitter hesabınızdan](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber) proje hakkında tweet atabilirsiniz. +2. [𝕏 (Twitter) hesabınızdan](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber) proje hakkında tweet atabilirsiniz. 3. [Medium](https://medium.com/), [Dev.to](https://dev.to/) veya kişisel blogunuz üzerinden bir inceleme veya eğitici yazı yazabilirsiniz. 4. Projeye [bir fincan kahve](https://buymeacoff.ee/fenny) bağışlayarak destek olabilirsiniz. diff --git a/.github/README_uk.md b/.github/README_uk.md index d87c23c210..ef9f36536b 100644 --- a/.github/README_uk.md +++ b/.github/README_uk.md @@ -664,7 +664,7 @@ func main() { Якщо ви хочете сказати **дякую** та/або підтримати активний розвиток `Fiber`: 1. Додайте [зірку GitHub](https://github.com/gofiber/fiber/stargazers) до проекту. -2. Напишіть про проект [у своєму Twitter](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). +2. Напишіть про проект [у своєму 𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber). 3. Напишіть огляд або підручник на [Medium](https://medium.com/), [Dev.to](https://dev.to/) або особистому блогу. 4. Підтримайте проект, пожертвувавши [чашку кави](https://buymeacoff.ee/fenny). diff --git a/.github/README_zh-CN.md b/.github/README_zh-CN.md index ee9d098476..4314e0580f 100644 --- a/.github/README_zh-CN.md +++ b/.github/README_zh-CN.md @@ -637,7 +637,7 @@ For more articles, middlewares, examples or tools check our [awesome list](https 如果想**感谢**我们或支持 `Fiber` 的积极发展: 1. 为 [`Fiber`](https://github.com/gofiber/fiber/stargazers) 点个 ⭐ 星星。 -2. 在 [Twitter](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber) 上发布有关项目的[推文](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber)。 +2. 在 [𝕏 (Twitter)](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber) 上发布有关项目的[推文](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber)。 3. 在 [Medium](https://medium.com/),[Dev.to](https://dev.to/) 或个人博客上写评论或教程。 4. 通过捐赠[一杯咖啡](https://buymeacoff.ee/fenny)来支持本项目。 diff --git a/.github/README_zh-TW.md b/.github/README_zh-TW.md index 1b2bc055fc..7bf431a99f 100644 --- a/.github/README_zh-TW.md +++ b/.github/README_zh-TW.md @@ -668,7 +668,7 @@ func main() { 如果您想和我們 **道謝**,或者是支持 `Fiber` 繼續積極開發下去(也可以兩個都做): 1. 送給專案一顆 [GitHub 星星](https://github.com/gofiber/fiber/stargazers)。 -2. [在您的 Twitter 上](https://twitter.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber)發出關於本專案的推文。 +2. [在您的 𝕏 (Twitter) 上](https://x.com/intent/tweet?text=Fiber%20is%20an%20Express%20inspired%20%23web%20%23framework%20built%20on%20top%20of%20Fasthttp%2C%20the%20fastest%20HTTP%20engine%20for%20%23Go.%20Designed%20to%20ease%20things%20up%20for%20%23fast%20development%20with%20zero%20memory%20allocation%20and%20%23performance%20in%20mind%20%F0%9F%9A%80%20https%3A%2F%2Fgithub.com%2Fgofiber%2Ffiber)發出關於本專案的推文。 3. 在 [Medium](https://medium.com/)、[Dev.to](https://dev.to/) 或者是個人部落格上寫下評論或教學。 4. 捐專案 [一杯咖啡的費用](https://buymeacoff.ee/fenny) 以示支持。 From fe395b98502417514025ef7e1908ffe29aff3a5a Mon Sep 17 00:00:00 2001 From: Moritz Date: Wed, 1 Nov 2023 21:42:57 +0100 Subject: [PATCH 82/84] =?UTF-8?q?=F0=9F=93=9A=20Doc:=20Add=20additional=20?= =?UTF-8?q?information=20as=20to=20why=20GetReqHeaders=20returns=20a=20map?= =?UTF-8?q?=20where=20the=20values=20are=20slices=20of=20strings=20=20(#26?= =?UTF-8?q?98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update ctx.md Added additional information to why GetReqHeaders returns a map where the values are slices of strings (instead of a single string as one might expect) * Update ctx.md added the same explanation to GetRespHeaders too --- docs/api/ctx.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/ctx.md b/docs/api/ctx.md index 1729438d7f..2d77090a43 100644 --- a/docs/api/ctx.md +++ b/docs/api/ctx.md @@ -583,7 +583,7 @@ app.Get("/", func(c *fiber.Ctx) error { ## GetReqHeaders -Returns the HTTP request headers. +Returns the HTTP request headers as a map. Since a header can be set multiple times in a single request, the values of the map are slices of strings containing all the different values of the header. ```go title="Signature" func (c *Ctx) GetReqHeaders() map[string][]string @@ -618,7 +618,7 @@ app.Get("/", func(c *fiber.Ctx) error { ## GetRespHeaders -Returns the HTTP response headers. +Returns the HTTP response headers as a map. Since a header can be set multiple times in a single request, the values of the map are slices of strings containing all the different values of the header. ```go title="Signature" func (c *Ctx) GetRespHeaders() map[string][]string From 426dd3aff9c224060989772a323fae0ab045b641 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 16:27:04 +0300 Subject: [PATCH 83/84] build(deps): bump golang.org/x/sys from 0.13.0 to 0.14.0 (#2707) Bumps [golang.org/x/sys](https://github.com/golang/sys) from 0.13.0 to 0.14.0. - [Commits](https://github.com/golang/sys/compare/v0.13.0...v0.14.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 cd49d43234..aa0abbe4f2 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.50.0 - golang.org/x/sys v0.13.0 + golang.org/x/sys v0.14.0 ) require ( diff --git a/go.sum b/go.sum index 01b9e73023..5b72a92d54 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.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.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/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= From cbcb1aec0a1b6cdc265cf3e9bb57c14728e1688a Mon Sep 17 00:00:00 2001 From: nickajacks1 <128185314+nickajacks1@users.noreply.github.com> Date: Mon, 6 Nov 2023 23:25:23 -0800 Subject: [PATCH 84/84] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20support=20for?= =?UTF-8?q?=20parameters=20in=20content=20negotiation=20(#2678)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ feat: add support for parameters in content negotiation Attempts to approach the level of support offered by express, but behavior may differ in unusual corner cases. Some key behaviors from Express that are implemented: - If an offer does not have every parameter listed in the given Accept, it is rejected. - Parameters do not affect specificity. - In a given specificity, more parameters gives greater precedence - Parameters are unordered - Matching is case-insensitive - Surrounding quotes for parameter values are stripped - If an Accept type specifies a parameter more than once, the last value provided is taken. - Parameters after q are not processed. https://www.rfc-editor.org/rfc/rfc9110#name-parameters * doc: properly attribute reader.go for validHeaderFieldByte * fix: remove underscores from fuzz test name * test(forEachParameter): improve coverage * doc: add comment clarifying RFC 9110 non-compliance for corner case --- docs/api/ctx.md | 31 ++++ helpers.go | 352 +++++++++++++++++++++++++++++++++++-------- helpers_fuzz_test.go | 23 +++ helpers_test.go | 283 +++++++++++++++++++++++++++++++++- 4 files changed, 625 insertions(+), 64 deletions(-) create mode 100644 helpers_fuzz_test.go diff --git a/docs/api/ctx.md b/docs/api/ctx.md index 2d77090a43..860799f451 100644 --- a/docs/api/ctx.md +++ b/docs/api/ctx.md @@ -49,6 +49,37 @@ app.Get("/", func(c *fiber.Ctx) error { }) ``` +Media-Type parameters are supported. + +```go title="Example 3" +// Accept: text/plain, application/json; version=1; foo=bar + +app.Get("/", func(c *fiber.Ctx) error { + // Extra parameters in the accept are ignored + c.Accepts("text/plain;format=flowed") // "text/plain;format=flowed" + + // An offer must contain all parameters present in the Accept type + c.Accepts("application/json") // "" + + // Parameter order and capitalization does not matter. Quotes on values are stripped. + c.Accepts(`application/json;foo="bar";VERSION=1`) // "application/json;foo="bar";VERSION=1" +}) +``` + +```go title="Example 4" +// Accept: text/plain;format=flowed;q=0.9, text/plain +// i.e., "I prefer text/plain;format=flowed less than other forms of text/plain" +app.Get("/", func(c *fiber.Ctx) error { + // Beware: the order in which offers are listed matters. + // Although the client specified they prefer not to receive format=flowed, + // the text/plain Accept matches with "text/plain;format=flowed" first, so it is returned. + c.Accepts("text/plain;format=flowed", "text/plain") // "text/plain;format=flowed" + + // Here, things behave as expected: + c.Accepts("text/plain", "text/plain;format=flowed") // "text/plain" +}) +``` + Fiber provides similar functions for the other accept headers. ```go diff --git a/helpers.go b/helpers.go index 0041458994..dd8de15f91 100644 --- a/helpers.go +++ b/helpers.go @@ -26,13 +26,14 @@ import ( ) // acceptType is a struct that holds the parsed value of an Accept header -// along with quality, specificity, and order. -// used for sorting accept headers. +// along with quality, specificity, parameters, and order. +// Used for sorting accept headers. type acceptedType struct { spec string quality float64 specificity int order int + params string } // getTLSConfig returns a net listener's tls config @@ -228,7 +229,7 @@ func getGroupPath(prefix, path string) string { // acceptsOffer This function determines if an offer matches a given specification. // It checks if the specification ends with a '*' or if the offer has the prefix of the specification. // Returns true if the offer matches the specification, false otherwise. -func acceptsOffer(spec, offer string) bool { +func acceptsOffer(spec, offer, _ string) bool { if len(spec) >= 1 && spec[len(spec)-1] == '*' { return true } else if strings.HasPrefix(spec, offer) { @@ -241,34 +242,94 @@ func acceptsOffer(spec, offer string) bool { // It checks if the specification is equal to */* (i.e., all types are accepted). // It gets the MIME type of the offer (either from the offer itself or by its file extension). // It checks if the offer MIME type matches the specification MIME type or if the specification is of the form /* and the offer MIME type has the same MIME type. +// It checks if the offer contains every parameter present in the specification. // Returns true if the offer type matches the specification, false otherwise. -func acceptsOfferType(spec, offerType string) bool { +func acceptsOfferType(spec, offerType, specParams string) bool { + var offerMime, offerParams string + + if i := strings.IndexByte(offerType, ';'); i == -1 { + offerMime = offerType + } else { + offerMime = offerType[:i] + offerParams = offerType[i:] + } + // Accept: */* if spec == "*/*" { - return true + return paramsMatch(specParams, offerParams) } var mimetype string - if strings.IndexByte(offerType, '/') != -1 { - mimetype = offerType // MIME type + if strings.IndexByte(offerMime, '/') != -1 { + mimetype = offerMime // MIME type } else { - mimetype = utils.GetMIME(offerType) // extension + mimetype = utils.GetMIME(offerMime) // extension } if spec == mimetype { // Accept: / - return true + return paramsMatch(specParams, offerParams) } s := strings.IndexByte(mimetype, '/') // Accept: /* if strings.HasPrefix(spec, mimetype[:s]) && (spec[s:] == "/*" || mimetype[s:] == "/*") { - return true + return paramsMatch(specParams, offerParams) } return false } +// paramsMatch returns whether offerParams contains all parameters present in specParams. +// Matching is case insensitive, and surrounding quotes are stripped. +// To align with the behavior of res.format from Express, the order of parameters is +// ignored, and if a parameter is specified twice in the incoming Accept, the last +// provided value is given precedence. +// In the case of quoted values, RFC 9110 says that we must treat any character escaped +// by a backslash as equivalent to the character itself (e.g., "a\aa" is equivalent to "aaa"). +// For the sake of simplicity, we forgo this and compare the value as-is. Besides, it would +// be highly unusual for a client to escape something other than a double quote or backslash. +// See https://www.rfc-editor.org/rfc/rfc9110#name-parameters +func paramsMatch(specParamStr, offerParams string) bool { + if specParamStr == "" { + return true + } + + // Preprocess the spec params to more easily test + // for out-of-order parameters + specParams := make([][2]string, 0, 2) + forEachParameter(specParamStr, func(s1, s2 string) bool { + if s1 == "q" || s1 == "Q" { + return false + } + for i := range specParams { + if utils.EqualFold(s1, specParams[i][0]) { + specParams[i][1] = s2 + return false + } + } + specParams = append(specParams, [2]string{s1, s2}) + return true + }) + + allSpecParamsMatch := true + for i := range specParams { + foundParam := false + forEachParameter(offerParams, func(offerParam, offerVal string) bool { + if utils.EqualFold(specParams[i][0], offerParam) { + foundParam = true + allSpecParamsMatch = utils.EqualFold(specParams[i][1], offerVal) + return false + } + return true + }) + if !foundParam || !allSpecParamsMatch { + return false + } + } + return allSpecParamsMatch +} + // getSplicedStrList function takes a string and a string slice as an argument, divides the string into different // elements divided by ',' and stores these elements in the string slice. // It returns the populated string slice as an output. @@ -304,8 +365,177 @@ func getSplicedStrList(headerValue string, dst []string) []string { return dst } +// forEachMediaRange parses an Accept or Content-Type header, calling functor +// on each media range. +// See: https://www.rfc-editor.org/rfc/rfc9110#name-content-negotiation-fields +func forEachMediaRange(header string, functor func(string)) { + hasDQuote := strings.IndexByte(header, '"') != -1 + + for len(header) > 0 { + n := 0 + header = utils.TrimLeft(header, ' ') + quotes := 0 + escaping := false + + if hasDQuote { + // Complex case. We need to keep track of quotes and quoted-pairs (i.e., characters escaped with \ ) + loop: + for n < len(header) { + switch header[n] { + case ',': + if quotes%2 == 0 { + break loop + } + case '"': + if !escaping { + quotes++ + } + case '\\': + if quotes%2 == 1 { + escaping = !escaping + } + } + n++ + } + } else { + // Simple case. Just look for the next comma. + if n = strings.IndexByte(header, ','); n == -1 { + n = len(header) + } + } + + functor(header[:n]) + + if n >= len(header) { + return + } + header = header[n+1:] + } +} + +// forEachParamter parses a given parameter list, calling functor +// on each valid parameter. If functor returns false, we stop processing. +// It expects a leading ';'. +// See: https://www.rfc-editor.org/rfc/rfc9110#section-5.6.6 +// According to RFC-9110 2.4, it is up to our discretion whether +// to attempt to recover from errors in HTTP semantics. Therefor, +// we take the simple approach and exit early when a semantic error +// is detected in the header. +// +// parameter = parameter-name "=" parameter-value +// parameter-name = token +// parameter-value = ( token / quoted-string ) +// parameters = *( OWS ";" OWS [ parameter ] ) +func forEachParameter(params string, functor func(string, string) bool) { + for len(params) > 0 { + // eat OWS ";" OWS + params = utils.TrimLeft(params, ' ') + if len(params) == 0 || params[0] != ';' { + return + } + params = utils.TrimLeft(params[1:], ' ') + + n := 0 + + // make sure the parameter is at least one character long + if len(params) == 0 || !validHeaderFieldByte(params[n]) { + return + } + n++ + for n < len(params) && validHeaderFieldByte(params[n]) { + n++ + } + + // We should hit a '=' (that has more characters after it) + // If not, the parameter is invalid. + // param=foo + // ~~~~~^ + if n >= len(params)-1 || params[n] != '=' { + return + } + param := params[:n] + n++ + + if params[n] == '"' { + // Handle quoted strings and quoted-pairs (i.e., characters escaped with \ ) + // See: https://www.rfc-editor.org/rfc/rfc9110#section-5.6.4 + foundEndQuote := false + escaping := false + n++ + m := n + for ; n < len(params); n++ { + if params[n] == '"' && !escaping { + foundEndQuote = true + break + } + // Recipients that process the value of a quoted-string MUST handle + // a quoted-pair as if it were replaced by the octet following the backslash + escaping = params[n] == '\\' && !escaping + } + if !foundEndQuote { + // Not a valid parameter + return + } + if !functor(param, params[m:n]) { + return + } + n++ + } else if validHeaderFieldByte(params[n]) { + // Parse a normal value, which should just be a token. + m := n + n++ + for n < len(params) && validHeaderFieldByte(params[n]) { + n++ + } + if !functor(param, params[m:n]) { + return + } + } else { + // Value was invalid + return + } + params = params[n:] + } +} + +// validHeaderFieldByte returns true if a valid tchar +// +// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / +// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +// +// See: https://www.rfc-editor.org/rfc/rfc9110#section-5.6.2 +// Function copied from net/textproto: +// https://github.com/golang/go/blob/master/src/net/textproto/reader.go#L663 +func validHeaderFieldByte(c byte) bool { + // mask is a 128-bit bitmap with 1s for allowed bytes, + // so that the byte c can be tested with a shift and an and. + // If c >= 128, then 1<>64)) != 0 +} + // getOffer return valid offer for header negotiation -func getOffer(header string, isAccepted func(spec, offer string) bool, offers ...string) string { +func getOffer(header string, isAccepted func(spec, offer, specParams string) bool, offers ...string) string { if len(offers) == 0 { return "" } @@ -313,49 +543,52 @@ func getOffer(header string, isAccepted func(spec, offer string) bool, offers .. return offers[0] } + acceptedTypes := make([]acceptedType, 0, 8) + order := 0 + // Parse header and get accepted types with their quality and specificity // See: https://www.rfc-editor.org/rfc/rfc9110#name-content-negotiation-fields - spec, commaPos, order := "", 0, 0 - acceptedTypes := make([]acceptedType, 0, 20) - for len(header) > 0 { + forEachMediaRange(header, func(accept string) { order++ + spec, quality, params := accept, 1.0, "" - // Skip spaces - header = utils.TrimLeft(header, ' ') - - // Get spec - commaPos = strings.IndexByte(header, ',') - if commaPos != -1 { - spec = utils.Trim(header[:commaPos], ' ') - } else { - spec = utils.TrimLeft(header, ' ') - } + if i := strings.IndexByte(accept, ';'); i != -1 { + spec = accept[:i] - // Get quality - quality := 1.0 - if factorSign := strings.IndexByte(spec, ';'); factorSign != -1 { - factor := utils.Trim(spec[factorSign+1:], ' ') - if strings.HasPrefix(factor, "q=") { - if q, err := fasthttp.ParseUfloat(utils.UnsafeBytes(factor[2:])); err == nil { + // The vast majority of requests will have only the q parameter with + // no whitespace. Check this first to see if we can skip + // the more involved parsing. + if strings.HasPrefix(accept[i:], ";q=") && strings.IndexByte(accept[i+3:], ';') == -1 { + if q, err := fasthttp.ParseUfloat([]byte(utils.TrimRight(accept[i+3:], ' '))); err == nil { quality = q } - } - spec = spec[:factorSign] - } - - // Skip if quality is 0.0 - // See: https://www.rfc-editor.org/rfc/rfc9110#quality.values - if quality == 0.0 { - if commaPos != -1 { - header = header[commaPos+1:] } else { - break + hasParams := false + forEachParameter(accept[i:], func(param, val string) bool { + if param == "q" || param == "Q" { + if q, err := fasthttp.ParseUfloat([]byte(val)); err == nil { + quality = q + } + return false + } + hasParams = true + return true + }) + if hasParams { + params = accept[i:] + } + } + // Skip this accept type if quality is 0.0 + // See: https://www.rfc-editor.org/rfc/rfc9110#quality.values + if quality == 0.0 { + return } - continue } + spec = utils.TrimRight(spec, ' ') + // Get specificity - specificity := 0 + var specificity int // check for wildcard this could be a mime */* or a wildcard character * if spec == "*/*" || spec == "*" { specificity = 1 @@ -368,15 +601,8 @@ func getOffer(header string, isAccepted func(spec, offer string) bool, offers .. } // Add to accepted types - acceptedTypes = append(acceptedTypes, acceptedType{spec, quality, specificity, order}) - - // Next - if commaPos != -1 { - header = header[commaPos+1:] - } else { - break - } - } + acceptedTypes = append(acceptedTypes, acceptedType{spec, quality, specificity, order, params}) + }) if len(acceptedTypes) > 1 { // Sort accepted types by quality and specificity, preserving order of equal elements @@ -389,7 +615,7 @@ func getOffer(header string, isAccepted func(spec, offer string) bool, offers .. if len(offer) == 0 { continue } - if isAccepted(acceptedType.spec, offer) { + if isAccepted(acceptedType.spec, offer, acceptedType.params) { return offer } } @@ -399,30 +625,30 @@ func getOffer(header string, isAccepted func(spec, offer string) bool, offers .. } // sortAcceptedTypes sorts accepted types by quality and specificity, preserving order of equal elements -// -// Parameters are not supported, they are ignored when sorting by specificity. -// +// A type with parameters has higher priority than an equivalent one without parameters. +// e.g., text/html;a=1;b=2 comes before text/html;a=1 // See: https://www.rfc-editor.org/rfc/rfc9110#name-content-negotiation-fields -func sortAcceptedTypes(at *[]acceptedType) { - if at == nil || len(*at) < 2 { +func sortAcceptedTypes(acceptedTypes *[]acceptedType) { + if acceptedTypes == nil || len(*acceptedTypes) < 2 { return } - acceptedTypes := *at + at := *acceptedTypes - for i := 1; i < len(acceptedTypes); i++ { + for i := 1; i < len(at); i++ { lo, hi := 0, i-1 for lo <= hi { mid := (lo + hi) / 2 - if acceptedTypes[i].quality < acceptedTypes[mid].quality || - (acceptedTypes[i].quality == acceptedTypes[mid].quality && acceptedTypes[i].specificity < acceptedTypes[mid].specificity) || - (acceptedTypes[i].quality == acceptedTypes[mid].quality && acceptedTypes[i].specificity == acceptedTypes[mid].specificity && acceptedTypes[i].order > acceptedTypes[mid].order) { + if at[i].quality < at[mid].quality || + (at[i].quality == at[mid].quality && at[i].specificity < at[mid].specificity) || + (at[i].quality == at[mid].quality && at[i].specificity < at[mid].specificity && len(at[i].params) < len(at[mid].params)) || + (at[i].quality == at[mid].quality && at[i].specificity == at[mid].specificity && len(at[i].params) == len(at[mid].params) && at[i].order > at[mid].order) { lo = mid + 1 } else { hi = mid - 1 } } for j := i; j > lo; j-- { - acceptedTypes[j-1], acceptedTypes[j] = acceptedTypes[j], acceptedTypes[j-1] + at[j-1], at[j] = at[j], at[j-1] } } } diff --git a/helpers_fuzz_test.go b/helpers_fuzz_test.go new file mode 100644 index 0000000000..2fce6475dd --- /dev/null +++ b/helpers_fuzz_test.go @@ -0,0 +1,23 @@ +//go:build go1.18 + +package fiber + +import ( + "testing" +) + +// go test -v -run=^$ -fuzz=FuzzUtilsGetOffer +func FuzzUtilsGetOffer(f *testing.F) { + inputs := []string{ + `application/json; v=1; foo=bar; q=0.938; extra=param, text/plain;param="big fox"; q=0.43`, + `text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8`, + `*/*`, + `text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c`, + } + for _, input := range inputs { + f.Add(input) + } + f.Fuzz(func(_ *testing.T, spec string) { + getOffer(spec, acceptsOfferType, `application/json;version=1;v=1;foo=bar`, `text/plain;param="big fox"`) + }) +} diff --git a/helpers_test.go b/helpers_test.go index 788b7a9a47..39292d77cd 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -77,6 +77,28 @@ func Test_Utils_GetOffer(t *testing.T) { utils.AssertEqual(t, "text/html", getOffer("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", acceptsOfferType, "text/html")) utils.AssertEqual(t, "application/pdf", getOffer("text/plain;q=0,application/pdf;q=0.9,*/*;q=0.000", acceptsOfferType, "application/pdf", "application/json")) utils.AssertEqual(t, "application/pdf", getOffer("text/plain;q=0,application/pdf;q=0.9,*/*;q=0.000", acceptsOfferType, "application/pdf", "application/json")) + utils.AssertEqual(t, "text/plain;a=1", getOffer("text/plain;a=1", acceptsOfferType, "text/plain;a=1")) + utils.AssertEqual(t, "", getOffer("text/plain;a=1;b=2", acceptsOfferType, "text/plain;b=2")) + + // Spaces, quotes, out of order params, and case insensitivity + utils.AssertEqual(t, "text/plain", getOffer("text/plain ", acceptsOfferType, "text/plain")) + utils.AssertEqual(t, "text/plain", getOffer("text/plain;q=0.4 ", acceptsOfferType, "text/plain")) + utils.AssertEqual(t, "text/plain", getOffer("text/plain;q=0.4 ;", acceptsOfferType, "text/plain")) + utils.AssertEqual(t, "text/plain", getOffer("text/plain;q=0.4 ; p=foo", acceptsOfferType, "text/plain")) + utils.AssertEqual(t, "text/plain;b=2;a=1", getOffer("text/plain ;a=1;b=2", acceptsOfferType, "text/plain;b=2;a=1")) + utils.AssertEqual(t, "text/plain;a=1", getOffer("text/plain; a=1 ", acceptsOfferType, "text/plain;a=1")) + utils.AssertEqual(t, `text/plain;a="1;b=2\",text/plain"`, getOffer(`text/plain;a="1;b=2\",text/plain";q=0.9`, acceptsOfferType, `text/plain;a=1;b=2`, `text/plain;a="1;b=2\",text/plain"`)) + utils.AssertEqual(t, "text/plain;A=CAPS", getOffer(`text/plain;a="caPs"`, acceptsOfferType, "text/plain;A=CAPS")) + + // Priority + utils.AssertEqual(t, "text/plain", getOffer("text/plain", acceptsOfferType, "text/plain", "text/plain;a=1")) + utils.AssertEqual(t, "text/plain;a=1", getOffer("text/plain", acceptsOfferType, "text/plain;a=1", "text/plain")) + utils.AssertEqual(t, "text/plain;a=1", getOffer("text/plain,text/plain;a=1", acceptsOfferType, "text/plain", "text/plain;a=1")) + utils.AssertEqual(t, "text/plain", getOffer("text/plain;q=0.899,text/plain;a=1;q=0.898", acceptsOfferType, "text/plain", "text/plain;a=1")) + utils.AssertEqual(t, "text/plain;a=1;b=2", getOffer("text/plain,text/plain;a=1,text/plain;a=1;b=2", acceptsOfferType, "text/plain", "text/plain;a=1", "text/plain;a=1;b=2")) + + // Takes the last value specified + utils.AssertEqual(t, "text/plain;a=1;b=2", getOffer("text/plain;a=1;b=1;B=2", acceptsOfferType, "text/plain;a=1;b=1", "text/plain;a=1;b=2")) utils.AssertEqual(t, "", getOffer("utf-8, iso-8859-1;q=0.5", acceptsOffer)) utils.AssertEqual(t, "", getOffer("utf-8, iso-8859-1;q=0.5", acceptsOffer, "ascii")) @@ -87,6 +109,7 @@ func Test_Utils_GetOffer(t *testing.T) { utils.AssertEqual(t, "", getOffer("gzip, deflate;q=0", acceptsOffer, "deflate")) } +// 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", @@ -107,6 +130,262 @@ func Benchmark_Utils_GetOffer(b *testing.B) { } } +// 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]...) + } + } +} + +func Test_Utils_ForEachParameter(t *testing.T) { + testCases := []struct { + description string + paramStr string + expectedParams [][]string + }{ + { + description: "empty input", + paramStr: ``, + }, + { + description: "no parameters", + paramStr: `; `, + }, + { + description: "naked equals", + paramStr: `; = `, + }, + { + description: "no value", + paramStr: `;s=`, + }, + { + description: "no name", + paramStr: `;=bar`, + }, + { + description: "illegal characters in name", + paramStr: `; foo@bar=baz`, + }, + { + description: "value starts with illegal characters", + paramStr: `; foo=@baz; param=val`, + }, + { + description: "unterminated quoted value", + paramStr: `; foo="bar`, + }, + { + description: "illegal character after value terminates parsing", + paramStr: `; foo=bar@baz; param=val`, + expectedParams: [][]string{ + {"foo", "bar"}, + }, + }, + { + description: "parses parameters", + paramStr: `; foo=bar; PARAM=BAZ`, + expectedParams: [][]string{ + {"foo", "bar"}, + {"PARAM", "BAZ"}, + }, + }, + { + description: "stops parsing when functor returns false", + paramStr: `; foo=bar; end=baz; extra=unparsed`, + expectedParams: [][]string{ + {"foo", "bar"}, + {"end", "baz"}, + }, + }, + { + description: "stops parsing when encountering a non-parameter string", + paramStr: `; foo=bar; gzip; param=baz`, + expectedParams: [][]string{ + {"foo", "bar"}, + }, + }, + { + description: "quoted string with escapes and special characters", + // Note: the sequence \\\" is effectively an escaped backslash \\ and + // an escaped double quote \" + paramStr: `;foo="20t\w,b\\\"b;s=k o"`, + expectedParams: [][]string{ + {"foo", `20t\w,b\\\"b;s=k o`}, + }, + }, + { + description: "complex", + paramStr: ` ; foo=1 ; bar="\"value\""; end="20tw,b\\\"b;s=k o" ; action=skip `, + expectedParams: [][]string{ + {"foo", "1"}, + {"bar", `\"value\"`}, + {"end", `20tw,b\\\"b;s=k o`}, + }, + }, + } + for _, tc := range testCases { + n := 0 + forEachParameter(tc.paramStr, func(p, v string) bool { + utils.AssertEqual(t, true, n < len(tc.expectedParams), "Received more parameters than expected: "+p+"="+v) + utils.AssertEqual(t, tc.expectedParams[n][0], p, tc.description) + utils.AssertEqual(t, tc.expectedParams[n][1], v, tc.description) + n++ + + // Stop parsing at the first parameter called "end" + return p != "end" + }) + utils.AssertEqual(t, len(tc.expectedParams), n, tc.description+": number of parameters differs") + } + // Check that we exited on the second parameter (bar) +} + +// go test -v -run=^$ -bench=Benchmark_Utils_ForEachParameter -benchmem -count=4 +func Benchmark_Utils_ForEachParameter(b *testing.B) { + for n := 0; n < b.N; n++ { + forEachParameter(` ; josua=1 ; vermant="20tw\",bob;sack o" ; version=1; foo=bar; `, func(s1, s2 string) bool { + return true + }) + } +} + +func Test_Utils_ParamsMatch(t *testing.T) { + testCases := []struct { + description string + accept string + offer string + match bool + }{ + { + description: "empty accept and offer", + accept: "", + offer: "", + match: true, + }, + { + description: "accept is empty, offer has params", + accept: "", + offer: ";foo=bar", + match: true, + }, + { + description: "offer is empty, accept has params", + accept: ";foo=bar", + offer: "", + match: false, + }, + { + description: "accept has extra parameters", + accept: ";foo=bar;a=1", + offer: ";foo=bar", + match: false, + }, + { + description: "matches regardless of order", + accept: "; a=1; b=2", + offer: ";b=2;a=1", + match: true, + }, + { + description: "case insensitive", + accept: ";ParaM=FoO", + offer: ";pAram=foO", + match: true, + }, + { + description: "ignores q", + accept: ";q=0.42", + offer: "", + match: true, + }, + } + + for _, tc := range testCases { + utils.AssertEqual(t, tc.match, paramsMatch(tc.accept, tc.offer), tc.description) + } +} + +func Benchmark_Utils_ParamsMatch(b *testing.B) { + var match bool + for n := 0; n < b.N; n++ { + match = paramsMatch(`; appLe=orange; param="foo"`, `;param=foo; apple=orange`) + } + utils.AssertEqual(b, true, match) +} + +func Test_Utils_AcceptsOfferType(t *testing.T) { + testCases := []struct { + description string + spec string + specParams string + offerType string + accepts bool + }{ + { + description: "no params, matching", + spec: "application/json", + offerType: "application/json", + accepts: true, + }, + { + description: "no params, mismatch", + spec: "application/json", + offerType: "application/xml", + accepts: false, + }, + { + description: "params match", + spec: "application/json", + specParams: `; format=foo; version=1`, + offerType: "application/json;version=1;format=foo;q=0.1", + accepts: true, + }, + { + description: "spec has extra params", + spec: "text/html", + specParams: "; charset=utf-8", + offerType: "text/html", + accepts: false, + }, + { + description: "offer has extra params", + spec: "text/html", + offerType: "text/html;charset=utf-8", + accepts: true, + }, + { + description: "ignores optional whitespace", + spec: "application/json", + specParams: `;format=foo; version=1`, + offerType: "application/json; version=1 ; format=foo ", + accepts: true, + }, + { + description: "ignores optional whitespace", + spec: "application/json", + specParams: `;format="foo bar"; version=1`, + offerType: `application/json;version="1";format="foo bar"`, + accepts: true, + }, + } + for _, tc := range testCases { + accepts := acceptsOfferType(tc.spec, tc.offerType, tc.specParams) + utils.AssertEqual(t, tc.accepts, accepts, tc.description) + } +} + func Test_Utils_GetSplicedStrList(t *testing.T) { testCases := []struct { description string @@ -147,7 +426,7 @@ func Test_Utils_GetSplicedStrList(t *testing.T) { func Benchmark_Utils_GetSplicedStrList(b *testing.B) { destination := make([]string, 5) result := destination - const input = "deflate, gzip,br,brotli" + const input = `deflate, gzip,br,brotli` for n := 0; n < b.N; n++ { result = getSplicedStrList(input, destination) } @@ -168,6 +447,7 @@ func Test_Utils_SortAcceptedTypes(t *testing.T) { {spec: "image/*", quality: 1, specificity: 2, order: 8}, {spec: "image/gif", quality: 1, specificity: 3, order: 9}, {spec: "text/plain", quality: 1, specificity: 3, order: 10}, + {spec: "application/json", quality: 0.999, specificity: 3, params: ";a=1", order: 11}, } sortAcceptedTypes(&acceptedTypes) utils.AssertEqual(t, acceptedTypes, []acceptedType{ @@ -179,6 +459,7 @@ func Test_Utils_SortAcceptedTypes(t *testing.T) { {spec: "image/gif", quality: 1, specificity: 3, order: 9}, {spec: "text/plain", quality: 1, specificity: 3, order: 10}, {spec: "image/*", quality: 1, specificity: 2, order: 8}, + {spec: "application/json", quality: 0.999, specificity: 3, params: ";a=1", order: 11}, {spec: "application/json", quality: 0.999, specificity: 3, order: 3}, {spec: "text/*", quality: 0.5, specificity: 2, order: 1}, {spec: "*/*", quality: 0.1, specificity: 1, order: 2},