mirror of
https://github.com/gofiber/fiber.git
synced 2025-02-06 11:02:01 +00:00
🔥 feat: Add support for CBOR encoding (#3173)
* feat(cbor): allow encoding response bodies in cbor * fix(tests::cbor): encode struct instead of a randomly ordered hashmap * docs(whats_new): add cbor in context section * feat(binder): introduce CBOR * feat(client): allow cbor in fiber client * chore(tests): add more test * chore(packages): go mod tidy * fix(binder): update CBOR name and test * improve test coverage * improve test coverage * update1 * add docs * doc fixes * update * Fix markdown lint * Add missing entry from binder README * add/refresh documentation --------- Co-authored-by: Juan Calderon-Perez <835733+gaby@users.noreply.github.com> Co-authored-by: M. Efe Çetin <efectn@protonmail.com> Co-authored-by: RW <rene@gofiber.io>
This commit is contained in:
parent
89452fea32
commit
26cc477500
22
app.go
22
app.go
@ -25,9 +25,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/gofiber/fiber/v3/log"
|
||||
"github.com/gofiber/utils/v2"
|
||||
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
@ -320,6 +320,20 @@ type Config struct { //nolint:govet // Aligning the struct fields is not necessa
|
||||
// Default: json.Unmarshal
|
||||
JSONDecoder utils.JSONUnmarshal `json:"-"`
|
||||
|
||||
// When set by an external client of Fiber it will use the provided implementation of a
|
||||
// CBORMarshal
|
||||
//
|
||||
// Allowing for flexibility in using another cbor library for encoding
|
||||
// Default: cbor.Marshal
|
||||
CBOREncoder utils.CBORMarshal `json:"-"`
|
||||
|
||||
// When set by an external client of Fiber it will use the provided implementation of a
|
||||
// CBORUnmarshal
|
||||
//
|
||||
// Allowing for flexibility in using another cbor library for decoding
|
||||
// Default: cbor.Unmarshal
|
||||
CBORDecoder utils.CBORUnmarshal `json:"-"`
|
||||
|
||||
// XMLEncoder set by an external client of Fiber it will use the provided implementation of a
|
||||
// XMLMarshal
|
||||
//
|
||||
@ -537,6 +551,12 @@ func New(config ...Config) *App {
|
||||
if app.config.JSONDecoder == nil {
|
||||
app.config.JSONDecoder = json.Unmarshal
|
||||
}
|
||||
if app.config.CBOREncoder == nil {
|
||||
app.config.CBOREncoder = cbor.Marshal
|
||||
}
|
||||
if app.config.CBORDecoder == nil {
|
||||
app.config.CBORDecoder = cbor.Unmarshal
|
||||
}
|
||||
if app.config.XMLEncoder == nil {
|
||||
app.config.XMLEncoder = xml.Marshal
|
||||
}
|
||||
|
14
bind.go
14
bind.go
@ -23,7 +23,7 @@ type Bind struct {
|
||||
dontHandleErrs bool
|
||||
}
|
||||
|
||||
// If you want to handle binder errors manually, you can use `WithoutAutoHandling`.
|
||||
// WithoutAutoHandling If you want to handle binder errors manually, you can use `WithoutAutoHandling`.
|
||||
// It's default behavior of binder.
|
||||
func (b *Bind) WithoutAutoHandling() *Bind {
|
||||
b.dontHandleErrs = true
|
||||
@ -31,7 +31,7 @@ func (b *Bind) WithoutAutoHandling() *Bind {
|
||||
return b
|
||||
}
|
||||
|
||||
// If you want to handle binder errors automatically, you can use `WithAutoHandling`.
|
||||
// WithAutoHandling If you want to handle binder errors automatically, you can use `WithAutoHandling`.
|
||||
// If there's an error, it will return the error and set HTTP status to `400 Bad Request`.
|
||||
// You must still return on error explicitly
|
||||
func (b *Bind) WithAutoHandling() *Bind {
|
||||
@ -121,6 +121,14 @@ func (b *Bind) JSON(out any) error {
|
||||
return b.validateStruct(out)
|
||||
}
|
||||
|
||||
// CBOR binds the body string into the struct.
|
||||
func (b *Bind) CBOR(out any) error {
|
||||
if err := b.returnErr(binder.CBORBinder.Bind(b.ctx.Body(), b.ctx.App().Config().CBORDecoder, out)); err != nil {
|
||||
return err
|
||||
}
|
||||
return b.validateStruct(out)
|
||||
}
|
||||
|
||||
// XML binds the body string into the struct.
|
||||
func (b *Bind) XML(out any) error {
|
||||
if err := b.returnErr(binder.XMLBinder.Bind(b.ctx.Body(), out)); err != nil {
|
||||
@ -183,6 +191,8 @@ func (b *Bind) Body(out any) error {
|
||||
return b.JSON(out)
|
||||
case MIMETextXML, MIMEApplicationXML:
|
||||
return b.XML(out)
|
||||
case MIMEApplicationCBOR:
|
||||
return b.CBOR(out)
|
||||
case MIMEApplicationForm:
|
||||
return b.Form(out)
|
||||
case MIMEMultipartForm:
|
||||
|
71
bind_test.go
71
bind_test.go
@ -12,6 +12,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/gofiber/fiber/v3/binder"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/valyala/fasthttp"
|
||||
@ -157,7 +158,7 @@ func Test_Bind_Query_WithSetParserDecoder(t *testing.T) {
|
||||
}
|
||||
|
||||
nonRFCTime := binder.ParserType{
|
||||
Customtype: NonRFCTime{},
|
||||
CustomType: NonRFCTime{},
|
||||
Converter: nonRFCConverter,
|
||||
}
|
||||
|
||||
@ -411,7 +412,7 @@ func Test_Bind_Header_WithSetParserDecoder(t *testing.T) {
|
||||
}
|
||||
|
||||
nonRFCTime := binder.ParserType{
|
||||
Customtype: NonRFCTime{},
|
||||
CustomType: NonRFCTime{},
|
||||
Converter: nonRFCConverter,
|
||||
}
|
||||
|
||||
@ -922,11 +923,11 @@ func Test_Bind_Body(t *testing.T) {
|
||||
testCompressedBody(t, compressedBody, "zstd")
|
||||
})
|
||||
|
||||
testDecodeParser := func(t *testing.T, contentType, body string) {
|
||||
testDecodeParser := func(t *testing.T, contentType string, body []byte) {
|
||||
t.Helper()
|
||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
c.Request().Header.SetContentType(contentType)
|
||||
c.Request().SetBody([]byte(body))
|
||||
c.Request().SetBody(body)
|
||||
c.Request().Header.SetContentLength(len(body))
|
||||
d := new(Demo)
|
||||
require.NoError(t, c.Bind().Body(d))
|
||||
@ -934,19 +935,36 @@ func Test_Bind_Body(t *testing.T) {
|
||||
}
|
||||
|
||||
t.Run("JSON", func(t *testing.T) {
|
||||
testDecodeParser(t, MIMEApplicationJSON, `{"name":"john"}`)
|
||||
testDecodeParser(t, MIMEApplicationJSON, []byte(`{"name":"john"}`))
|
||||
})
|
||||
t.Run("CBOR", func(t *testing.T) {
|
||||
enc, err := cbor.Marshal(&Demo{Name: "john"})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
testDecodeParser(t, MIMEApplicationCBOR, enc)
|
||||
|
||||
// Test invalid CBOR data
|
||||
t.Run("Invalid", func(t *testing.T) {
|
||||
invalidData := []byte{0xFF, 0xFF} // Invalid CBOR data
|
||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
c.Request().Header.SetContentType(MIMEApplicationCBOR)
|
||||
c.Request().SetBody(invalidData)
|
||||
d := new(Demo)
|
||||
require.Error(t, c.Bind().Body(d))
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("XML", func(t *testing.T) {
|
||||
testDecodeParser(t, MIMEApplicationXML, `<Demo><name>john</name></Demo>`)
|
||||
testDecodeParser(t, MIMEApplicationXML, []byte(`<Demo><name>john</name></Demo>`))
|
||||
})
|
||||
|
||||
t.Run("Form", func(t *testing.T) {
|
||||
testDecodeParser(t, MIMEApplicationForm, "name=john")
|
||||
testDecodeParser(t, MIMEApplicationForm, []byte("name=john"))
|
||||
})
|
||||
|
||||
t.Run("MultipartForm", func(t *testing.T) {
|
||||
testDecodeParser(t, MIMEMultipartForm+`;boundary="b"`, "--b\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\njohn\r\n--b--")
|
||||
testDecodeParser(t, MIMEMultipartForm+`;boundary="b"`, []byte("--b\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\njohn\r\n--b--"))
|
||||
})
|
||||
|
||||
testDecodeParserError := func(t *testing.T, contentType, body string) {
|
||||
@ -1009,7 +1027,7 @@ func Test_Bind_Body_WithSetParserDecoder(t *testing.T) {
|
||||
}
|
||||
|
||||
customTime := binder.ParserType{
|
||||
Customtype: CustomTime{},
|
||||
CustomType: CustomTime{},
|
||||
Converter: timeConverter,
|
||||
}
|
||||
|
||||
@ -1100,6 +1118,35 @@ func Benchmark_Bind_Body_XML(b *testing.B) {
|
||||
require.Equal(b, "john", d.Name)
|
||||
}
|
||||
|
||||
// go test -v -run=^$ -bench=Benchmark_Bind_Body_CBOR -benchmem -count=4
|
||||
func Benchmark_Bind_Body_CBOR(b *testing.B) {
|
||||
var err error
|
||||
|
||||
app := New()
|
||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
|
||||
type Demo struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
body, err := cbor.Marshal(&Demo{Name: "john"})
|
||||
if err != nil {
|
||||
b.Error(err)
|
||||
}
|
||||
c.Request().SetBody(body)
|
||||
c.Request().Header.SetContentType(MIMEApplicationCBOR)
|
||||
c.Request().Header.SetContentLength(len(body))
|
||||
d := new(Demo)
|
||||
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
|
||||
for n := 0; n < b.N; n++ {
|
||||
err = c.Bind().Body(d)
|
||||
}
|
||||
require.NoError(b, err)
|
||||
require.Equal(b, "john", d.Name)
|
||||
}
|
||||
|
||||
// go test -v -run=^$ -bench=Benchmark_Bind_Body_Form -benchmem -count=4
|
||||
func Benchmark_Bind_Body_Form(b *testing.B) {
|
||||
var err error
|
||||
@ -1404,7 +1451,7 @@ func Test_Bind_Cookie_WithSetParserDecoder(t *testing.T) {
|
||||
}
|
||||
|
||||
nonRFCTime := binder.ParserType{
|
||||
Customtype: NonRFCTime{},
|
||||
CustomType: NonRFCTime{},
|
||||
Converter: nonRFCConverter,
|
||||
}
|
||||
|
||||
@ -1720,8 +1767,12 @@ func Test_Bind_RepeatParserWithSameStruct(t *testing.T) {
|
||||
require.Equal(t, "body_param", r.BodyParam)
|
||||
}
|
||||
|
||||
cb, err := cbor.Marshal(&Request{BodyParam: "body_param"})
|
||||
require.NoError(t, err, "Failed to marshal CBOR data")
|
||||
|
||||
testDecodeParser(MIMEApplicationJSON, `{"body_param":"body_param"}`)
|
||||
testDecodeParser(MIMEApplicationXML, `<Demo><body_param>body_param</body_param></Demo>`)
|
||||
testDecodeParser(MIMEApplicationCBOR, string(cb))
|
||||
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--")
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ Fiber provides several default binders out of the box:
|
||||
- [Cookie](cookie.go)
|
||||
- [JSON](json.go)
|
||||
- [XML](xml.go)
|
||||
- [CBOR](cbor.go)
|
||||
|
||||
## Guides
|
||||
|
||||
|
@ -20,4 +20,5 @@ var (
|
||||
URIBinder = &uriBinding{}
|
||||
XMLBinder = &xmlBinding{}
|
||||
JSONBinder = &jsonBinding{}
|
||||
CBORBinder = &cborBinding{}
|
||||
)
|
||||
|
18
binder/cbor.go
Normal file
18
binder/cbor.go
Normal file
@ -0,0 +1,18 @@
|
||||
package binder
|
||||
|
||||
import (
|
||||
"github.com/gofiber/utils/v2"
|
||||
)
|
||||
|
||||
// cborBinding is the CBOR binder for CBOR request body.
|
||||
type cborBinding struct{}
|
||||
|
||||
// Name returns the binding name.
|
||||
func (*cborBinding) Name() string {
|
||||
return "cbor"
|
||||
}
|
||||
|
||||
// Bind parses the request body as CBOR and returns the result.
|
||||
func (*cborBinding) Bind(body []byte, cborDecoder utils.CBORUnmarshal, out any) error {
|
||||
return cborDecoder(body, out)
|
||||
}
|
@ -8,12 +8,15 @@ import (
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// cookieBinding is the cookie binder for cookie request body.
|
||||
type cookieBinding struct{}
|
||||
|
||||
// Name returns the binding name.
|
||||
func (*cookieBinding) Name() string {
|
||||
return "cookie"
|
||||
}
|
||||
|
||||
// Bind parses the request cookie and returns the result.
|
||||
func (b *cookieBinding) Bind(reqCtx *fasthttp.RequestCtx, out any) error {
|
||||
data := make(map[string][]string)
|
||||
var err error
|
||||
|
@ -8,12 +8,15 @@ import (
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// formBinding is the form binder for form request body.
|
||||
type formBinding struct{}
|
||||
|
||||
// Name returns the binding name.
|
||||
func (*formBinding) Name() string {
|
||||
return "form"
|
||||
}
|
||||
|
||||
// Bind parses the request body and returns the result.
|
||||
func (b *formBinding) Bind(reqCtx *fasthttp.RequestCtx, out any) error {
|
||||
data := make(map[string][]string)
|
||||
var err error
|
||||
@ -47,6 +50,7 @@ func (b *formBinding) Bind(reqCtx *fasthttp.RequestCtx, out any) error {
|
||||
return parse(b.Name(), out, data)
|
||||
}
|
||||
|
||||
// BindMultipart parses the request body and returns the result.
|
||||
func (b *formBinding) BindMultipart(reqCtx *fasthttp.RequestCtx, out any) error {
|
||||
data, err := reqCtx.MultipartForm()
|
||||
if err != nil {
|
||||
|
@ -8,12 +8,15 @@ import (
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// headerBinding is the header binder for header request body.
|
||||
type headerBinding struct{}
|
||||
|
||||
// Name returns the binding name.
|
||||
func (*headerBinding) Name() string {
|
||||
return "header"
|
||||
}
|
||||
|
||||
// Bind parses the request header and returns the result.
|
||||
func (b *headerBinding) Bind(req *fasthttp.Request, out any) error {
|
||||
data := make(map[string][]string)
|
||||
req.Header.VisitAll(func(key, val []byte) {
|
||||
|
@ -4,12 +4,15 @@ import (
|
||||
"github.com/gofiber/utils/v2"
|
||||
)
|
||||
|
||||
// jsonBinding is the JSON binder for JSON request body.
|
||||
type jsonBinding struct{}
|
||||
|
||||
// Name returns the binding name.
|
||||
func (*jsonBinding) Name() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
// Bind parses the request body as JSON and returns the result.
|
||||
func (*jsonBinding) Bind(body []byte, jsonDecoder utils.JSONUnmarshal, out any) error {
|
||||
return jsonDecoder(body, out)
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ type ParserConfig struct {
|
||||
// ParserType require two element, type and converter for register.
|
||||
// Use ParserType with BodyParser for parsing custom type in form data.
|
||||
type ParserType struct {
|
||||
Customtype any
|
||||
CustomType any
|
||||
Converter func(string) reflect.Value
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ func decoderBuilder(parserConfig ParserConfig) any {
|
||||
decoder.SetAliasTag(parserConfig.SetAliasTag)
|
||||
}
|
||||
for _, v := range parserConfig.ParserType {
|
||||
decoder.RegisterConverter(reflect.ValueOf(v.Customtype).Interface(), v.Converter)
|
||||
decoder.RegisterConverter(reflect.ValueOf(v.CustomType).Interface(), v.Converter)
|
||||
}
|
||||
decoder.ZeroEmpty(parserConfig.ZeroEmpty)
|
||||
return decoder
|
||||
|
@ -8,12 +8,15 @@ import (
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// queryBinding is the query binder for query request body.
|
||||
type queryBinding struct{}
|
||||
|
||||
// Name returns the binding name.
|
||||
func (*queryBinding) Name() string {
|
||||
return "query"
|
||||
}
|
||||
|
||||
// Bind parses the request query and returns the result.
|
||||
func (b *queryBinding) Bind(reqCtx *fasthttp.RequestCtx, out any) error {
|
||||
data := make(map[string][]string)
|
||||
var err error
|
||||
|
@ -8,12 +8,15 @@ import (
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// respHeaderBinding is the respHeader binder for response header.
|
||||
type respHeaderBinding struct{}
|
||||
|
||||
// Name returns the binding name.
|
||||
func (*respHeaderBinding) Name() string {
|
||||
return "respHeader"
|
||||
}
|
||||
|
||||
// Bind parses the response header and returns the result.
|
||||
func (b *respHeaderBinding) Bind(resp *fasthttp.Response, out any) error {
|
||||
data := make(map[string][]string)
|
||||
resp.Header.VisitAll(func(key, val []byte) {
|
||||
|
@ -1,11 +1,14 @@
|
||||
package binder
|
||||
|
||||
// uriBinding is the URI binder for URI parameters.
|
||||
type uriBinding struct{}
|
||||
|
||||
// Name returns the binding name.
|
||||
func (*uriBinding) Name() string {
|
||||
return "uri"
|
||||
}
|
||||
|
||||
// Bind parses the URI parameters and returns the result.
|
||||
func (b *uriBinding) Bind(params []string, paramsFunc func(key string, defaultValue ...string) string, out any) error {
|
||||
data := make(map[string][]string, len(params))
|
||||
for _, param := range params {
|
||||
|
@ -5,12 +5,15 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// xmlBinding is the XML binder for XML request body.
|
||||
type xmlBinding struct{}
|
||||
|
||||
// Name returns the binding name.
|
||||
func (*xmlBinding) Name() string {
|
||||
return "xml"
|
||||
}
|
||||
|
||||
// Bind parses the request body as XML and returns the result.
|
||||
func (*xmlBinding) Bind(body []byte, out any) error {
|
||||
if err := xml.Unmarshal(body, out); err != nil {
|
||||
return fmt.Errorf("failed to unmarshal xml: %w", err)
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/gofiber/fiber/v3/log"
|
||||
|
||||
"github.com/gofiber/utils/v2"
|
||||
@ -44,6 +45,8 @@ type Client struct {
|
||||
jsonUnmarshal utils.JSONUnmarshal
|
||||
xmlMarshal utils.XMLMarshal
|
||||
xmlUnmarshal utils.XMLUnmarshal
|
||||
cborMarshal utils.CBORMarshal
|
||||
cborUnmarshal utils.CBORUnmarshal
|
||||
|
||||
cookieJar *CookieJar
|
||||
|
||||
@ -150,6 +153,28 @@ func (c *Client) SetXMLUnmarshal(f utils.XMLUnmarshal) *Client {
|
||||
return c
|
||||
}
|
||||
|
||||
// CBORMarshal returns CBOR marshal function in Core.
|
||||
func (c *Client) CBORMarshal() utils.CBORMarshal {
|
||||
return c.cborMarshal
|
||||
}
|
||||
|
||||
// SetCBORMarshal sets CBOR encoder.
|
||||
func (c *Client) SetCBORMarshal(f utils.CBORMarshal) *Client {
|
||||
c.cborMarshal = f
|
||||
return c
|
||||
}
|
||||
|
||||
// CBORUnmarshal returns CBOR unmarshal function in Core.
|
||||
func (c *Client) CBORUnmarshal() utils.CBORUnmarshal {
|
||||
return c.cborUnmarshal
|
||||
}
|
||||
|
||||
// SetCBORUnmarshal sets CBOR decoder.
|
||||
func (c *Client) SetCBORUnmarshal(f utils.CBORUnmarshal) *Client {
|
||||
c.cborUnmarshal = f
|
||||
return c
|
||||
}
|
||||
|
||||
// TLSConfig returns tlsConfig in client.
|
||||
// If client don't have tlsConfig, this function will init it.
|
||||
func (c *Client) TLSConfig() *tls.Config {
|
||||
@ -706,6 +731,8 @@ func NewWithClient(c *fasthttp.Client) *Client {
|
||||
jsonMarshal: json.Marshal,
|
||||
jsonUnmarshal: json.Unmarshal,
|
||||
xmlMarshal: xml.Marshal,
|
||||
cborMarshal: cbor.Marshal,
|
||||
cborUnmarshal: cbor.Unmarshal,
|
||||
xmlUnmarshal: xml.Unmarshal,
|
||||
logger: log.DefaultLogger(),
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package client
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
"net"
|
||||
@ -225,6 +226,33 @@ func Test_Client_Marshal(t *testing.T) {
|
||||
require.Equal(t, errors.New("empty xml"), err)
|
||||
})
|
||||
|
||||
t.Run("set cbor marshal", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
bs, err := hex.DecodeString("f6")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
client := New().
|
||||
SetCBORMarshal(func(_ any) ([]byte, error) {
|
||||
return bs, nil
|
||||
})
|
||||
val, err := client.CBORMarshal()(nil)
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, bs, val)
|
||||
})
|
||||
|
||||
t.Run("set cbor marshal error", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := New().SetCBORMarshal(func(_ any) ([]byte, error) {
|
||||
return nil, errors.New("invalid struct")
|
||||
})
|
||||
|
||||
val, err := client.CBORMarshal()(nil)
|
||||
require.Nil(t, val)
|
||||
require.Equal(t, errors.New("invalid struct"), err)
|
||||
})
|
||||
|
||||
t.Run("set xml unmarshal", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := New().
|
||||
@ -1443,11 +1471,12 @@ func Test_Set_Config_To_Request(t *testing.T) {
|
||||
|
||||
t.Run("set ctx", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
key := struct{}{}
|
||||
|
||||
type ctxKey struct{}
|
||||
var key ctxKey = struct{}{}
|
||||
|
||||
ctx := context.Background()
|
||||
ctx = context.WithValue(ctx, key, "v1") //nolint: staticcheck // not needed for tests
|
||||
|
||||
ctx = context.WithValue(ctx, key, "v1")
|
||||
req := AcquireRequest()
|
||||
|
||||
setConfigToRequest(req, Config{Ctx: ctx})
|
||||
|
@ -23,6 +23,7 @@ var (
|
||||
headerAccept = "Accept"
|
||||
|
||||
applicationJSON = "application/json"
|
||||
applicationCBOR = "application/cbor"
|
||||
applicationXML = "application/xml"
|
||||
applicationForm = "application/x-www-form-urlencoded"
|
||||
multipartFormData = "multipart/form-data"
|
||||
@ -129,6 +130,8 @@ func parserRequestHeader(c *Client, req *Request) error {
|
||||
req.RawRequest.Header.Set(headerAccept, applicationJSON)
|
||||
case xmlBody:
|
||||
req.RawRequest.Header.SetContentType(applicationXML)
|
||||
case cborBody:
|
||||
req.RawRequest.Header.SetContentType(applicationCBOR)
|
||||
case formBody:
|
||||
req.RawRequest.Header.SetContentType(applicationForm)
|
||||
case filesBody:
|
||||
@ -189,6 +192,12 @@ func parserRequestBody(c *Client, req *Request) error {
|
||||
return err
|
||||
}
|
||||
req.RawRequest.SetBody(body)
|
||||
case cborBody:
|
||||
body, err := c.cborMarshal(req.body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.RawRequest.SetBody(body)
|
||||
case formBody:
|
||||
req.RawRequest.SetBody(req.formData.QueryString())
|
||||
case filesBody:
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/gofiber/fiber/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@ -456,6 +457,30 @@ func Test_Parser_Request_Body(t *testing.T) {
|
||||
require.Equal(t, []byte("<body><name>foo</name></body>"), req.RawRequest.Body())
|
||||
})
|
||||
|
||||
t.Run("CBOR body", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
type cborData struct {
|
||||
Name string `cbor:"name"`
|
||||
Age int `cbor:"age"`
|
||||
}
|
||||
|
||||
data := cborData{
|
||||
Name: "foo",
|
||||
Age: 12,
|
||||
}
|
||||
|
||||
client := New()
|
||||
req := AcquireRequest().
|
||||
SetCBOR(data)
|
||||
|
||||
err := parserRequestBody(client, req)
|
||||
require.NoError(t, err)
|
||||
|
||||
encoded, err := cbor.Marshal(data)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, encoded, req.RawRequest.Body())
|
||||
})
|
||||
|
||||
t.Run("form data body", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
client := New()
|
||||
|
@ -34,6 +34,7 @@ const (
|
||||
formBody
|
||||
filesBody
|
||||
rawBody
|
||||
cborBody
|
||||
)
|
||||
|
||||
var ErrClientNil = errors.New("client can not be nil")
|
||||
@ -337,6 +338,13 @@ func (r *Request) SetXML(v any) *Request {
|
||||
return r
|
||||
}
|
||||
|
||||
// SetCBOR method sets CBOR body in request.
|
||||
func (r *Request) SetCBOR(v any) *Request {
|
||||
r.body = v
|
||||
r.bodyType = cborBody
|
||||
return r
|
||||
}
|
||||
|
||||
// SetRawBody method sets body with raw data in request.
|
||||
func (r *Request) SetRawBody(v []byte) *Request {
|
||||
r.body = v
|
||||
|
@ -80,11 +80,12 @@ func Test_Request_Context(t *testing.T) {
|
||||
|
||||
req := AcquireRequest()
|
||||
ctx := req.Context()
|
||||
key := struct{}{}
|
||||
type ctxKey struct{}
|
||||
var key ctxKey = struct{}{}
|
||||
|
||||
require.Nil(t, ctx.Value(key))
|
||||
|
||||
ctx = context.WithValue(ctx, key, "string") //nolint: staticcheck // not needed for tests
|
||||
ctx = context.WithValue(ctx, key, "string")
|
||||
req.SetContext(ctx)
|
||||
ctx = req.Context()
|
||||
|
||||
@ -1006,6 +1007,25 @@ func Test_Request_Body_With_Server(t *testing.T) {
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("cbor body", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
testRequest(t,
|
||||
func(c fiber.Ctx) error {
|
||||
require.Equal(t, "application/cbor", string(c.Request().Header.ContentType()))
|
||||
return c.SendString(string(c.Request().Body()))
|
||||
},
|
||||
func(agent *Request) {
|
||||
type args struct {
|
||||
Content string `cbor:"content"`
|
||||
}
|
||||
agent.SetCBOR(args{
|
||||
Content: "hello",
|
||||
})
|
||||
},
|
||||
"\xa1gcontentehello",
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("formdata", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
testRequest(t,
|
||||
|
@ -75,6 +75,11 @@ func (r *Response) JSON(v any) error {
|
||||
return r.client.jsonUnmarshal(r.Body(), v)
|
||||
}
|
||||
|
||||
// CBOR method will unmarshal body to CBOR.
|
||||
func (r *Response) CBOR(v any) error {
|
||||
return r.client.cborUnmarshal(r.Body(), v)
|
||||
}
|
||||
|
||||
// XML method will unmarshal body to xml.
|
||||
func (r *Response) XML(v any) error {
|
||||
return r.client.xmlUnmarshal(r.Body(), v)
|
||||
|
@ -240,6 +240,18 @@ func Test_Response_Body(t *testing.T) {
|
||||
app.Get("/xml", func(c fiber.Ctx) error {
|
||||
return c.SendString("<status><name>success</name></status>")
|
||||
})
|
||||
|
||||
app.Get("/cbor", func(c fiber.Ctx) error {
|
||||
type cborData struct {
|
||||
Name string `cbor:"name"`
|
||||
Age int `cbor:"age"`
|
||||
}
|
||||
|
||||
return c.CBOR(cborData{
|
||||
Name: "foo",
|
||||
Age: 12,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return server
|
||||
@ -327,6 +339,36 @@ func Test_Response_Body(t *testing.T) {
|
||||
require.Equal(t, "success", tmp.Status)
|
||||
resp.Close()
|
||||
})
|
||||
|
||||
t.Run("cbor body", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
type cborData struct {
|
||||
Name string `cbor:"name"`
|
||||
Age int `cbor:"age"`
|
||||
}
|
||||
|
||||
data := cborData{
|
||||
Name: "foo",
|
||||
Age: 12,
|
||||
}
|
||||
|
||||
server := setupApp()
|
||||
defer server.stop()
|
||||
|
||||
client := New().SetDial(server.dial())
|
||||
|
||||
resp, err := AcquireRequest().
|
||||
SetClient(client).
|
||||
Get("http://example.com/cbor")
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
tmp := &cborData{}
|
||||
err = resp.CBOR(tmp)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, data, *tmp)
|
||||
resp.Close()
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Response_Save(t *testing.T) {
|
||||
|
@ -23,6 +23,7 @@ const (
|
||||
MIMETextCSS = "text/css"
|
||||
MIMEApplicationXML = "application/xml"
|
||||
MIMEApplicationJSON = "application/json"
|
||||
MIMEApplicationCBOR = "application/cbor"
|
||||
// Deprecated: use MIMETextJavaScript instead
|
||||
MIMEApplicationJavaScript = "application/javascript"
|
||||
MIMEApplicationForm = "application/x-www-form-urlencoded"
|
||||
|
18
ctx.go
18
ctx.go
@ -884,6 +884,24 @@ func (c *DefaultCtx) JSON(data any, ctype ...string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// CBOR converts any interface or string to CBOR encoded bytes.
|
||||
// If the ctype parameter is given, this method will set the
|
||||
// Content-Type header equal to ctype. If ctype is not given,
|
||||
// The Content-Type header will be set to application/cbor.
|
||||
func (c *DefaultCtx) CBOR(data any, ctype ...string) error {
|
||||
raw, err := c.app.config.CBOREncoder(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.fasthttp.Response.SetBodyRaw(raw)
|
||||
if len(ctype) > 0 {
|
||||
c.fasthttp.Response.Header.SetContentType(ctype[0])
|
||||
} else {
|
||||
c.fasthttp.Response.Header.SetContentType(MIMEApplicationCBOR)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// JSONP sends a JSON response with JSONP support.
|
||||
// This method is identical to JSON, except that it opts-in to JSONP callback support.
|
||||
// By default, the callback name is simply callback.
|
||||
|
@ -164,6 +164,11 @@ type Ctx interface {
|
||||
// Content-Type header equal to ctype. If ctype is not given,
|
||||
// The Content-Type header will be set to application/json.
|
||||
JSON(data any, ctype ...string) error
|
||||
// CBOR converts any interface or string to CBOR encoded bytes.
|
||||
// If the ctype parameter is given, this method will set the
|
||||
// Content-Type header equal to ctype. If ctype is not given,
|
||||
// The Content-Type header will be set to application/cbor.
|
||||
CBOR(data any, ctype ...string) error
|
||||
// JSONP sends a JSON response with JSONP support.
|
||||
// This method is identical to JSON, except that it opts-in to JSONP callback support.
|
||||
// By default, the callback name is simply callback.
|
||||
|
93
ctx_test.go
93
ctx_test.go
@ -12,6 +12,7 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"embed"
|
||||
"encoding/hex"
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -3618,6 +3619,98 @@ func Benchmark_Ctx_JSON(b *testing.B) {
|
||||
require.JSONEq(b, `{"Name":"Grame","Age":20}`, string(c.Response().Body()))
|
||||
}
|
||||
|
||||
// go test -run Test_Ctx_CBOR
|
||||
func Test_Ctx_CBOR(t *testing.T) {
|
||||
t.Parallel()
|
||||
app := New()
|
||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
|
||||
require.Error(t, c.CBOR(complex(1, 1)))
|
||||
|
||||
type dummyStruct struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
// Test without ctype
|
||||
err := c.CBOR(dummyStruct{ // map has no order
|
||||
Name: "Grame",
|
||||
Age: 20,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, `a2644e616d65654772616d656341676514`, hex.EncodeToString(c.Response().Body()))
|
||||
require.Equal(t, "application/cbor", string(c.Response().Header.Peek("content-type")))
|
||||
|
||||
// Test with ctype
|
||||
err = c.CBOR(dummyStruct{ // map has no order
|
||||
Name: "Grame",
|
||||
Age: 20,
|
||||
}, "application/problem+cbor")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, `a2644e616d65654772616d656341676514`, hex.EncodeToString(c.Response().Body()))
|
||||
require.Equal(t, "application/problem+cbor", string(c.Response().Header.Peek("content-type")))
|
||||
|
||||
testEmpty := func(v any, r string) {
|
||||
err := c.CBOR(v)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, r, hex.EncodeToString(c.Response().Body()))
|
||||
}
|
||||
|
||||
testEmpty(nil, "f6")
|
||||
testEmpty("", `60`)
|
||||
testEmpty(0, "00")
|
||||
testEmpty([]int{}, "80")
|
||||
|
||||
// Test invalid types
|
||||
err = c.CBOR(make(chan int))
|
||||
require.Error(t, err)
|
||||
|
||||
err = c.CBOR(func() {})
|
||||
require.Error(t, err)
|
||||
|
||||
t.Run("custom cbor encoder", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
app := New(Config{
|
||||
CBOREncoder: func(_ any) ([]byte, error) {
|
||||
return []byte(hex.EncodeToString([]byte("random"))), nil
|
||||
},
|
||||
})
|
||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
|
||||
err := c.CBOR(Map{ // map has no order
|
||||
"Name": "Grame",
|
||||
"Age": 20,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, `72616e646f6d`, string(c.Response().Body()))
|
||||
require.Equal(t, "application/cbor", string(c.Response().Header.Peek("content-type")))
|
||||
})
|
||||
}
|
||||
|
||||
// go test -run=^$ -bench=Benchmark_Ctx_CBOR -benchmem -count=4
|
||||
func Benchmark_Ctx_CBOR(b *testing.B) {
|
||||
app := New()
|
||||
c := app.AcquireCtx(&fasthttp.RequestCtx{})
|
||||
|
||||
type SomeStruct struct {
|
||||
Name string
|
||||
Age uint8
|
||||
}
|
||||
data := SomeStruct{
|
||||
Name: "Grame",
|
||||
Age: 20,
|
||||
}
|
||||
var err error
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for n := 0; n < b.N; n++ {
|
||||
err = c.CBOR(data)
|
||||
}
|
||||
require.NoError(b, err)
|
||||
require.Equal(b, `a2644e616d65654772616d656341676514`, hex.EncodeToString(c.Response().Body()))
|
||||
}
|
||||
|
||||
// go test -run=^$ -bench=Benchmark_Ctx_JSON_Ctype -benchmem -count=4
|
||||
func Benchmark_Ctx_JSON_Ctype(b *testing.B) {
|
||||
app := New()
|
||||
|
@ -20,6 +20,7 @@ Make copies or use the [**`Immutable`**](./ctx.md) setting instead. [Read more..
|
||||
- [JSON](#json)
|
||||
- [MultipartForm](#multipartform)
|
||||
- [XML](#xml)
|
||||
- [CBOR](#cbor)
|
||||
- [Cookie](#cookie)
|
||||
- [Header](#header)
|
||||
- [Query](#query)
|
||||
@ -226,6 +227,43 @@ Run tests with the following `curl` command:
|
||||
curl -X POST -H "Content-Type: application/xml" --data "<login><name>john</name><pass>doe</pass></login>" localhost:3000
|
||||
```
|
||||
|
||||
### CBOR
|
||||
|
||||
Binds the request CBOR 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 CBOR body with a field called `Pass`, you would use a struct field with `cbor:"pass"`.
|
||||
|
||||
```go title="Signature"
|
||||
func (b *Bind) CBOR(out any) error
|
||||
```
|
||||
|
||||
```go title="Example"
|
||||
// Field names should start with an uppercase letter
|
||||
type Person struct {
|
||||
Name string `cbor:"name"`
|
||||
Pass string `cbor:"pass"`
|
||||
}
|
||||
|
||||
app.Post("/", func(c fiber.Ctx) error {
|
||||
p := new(Person)
|
||||
|
||||
if err := c.Bind().CBOR(p); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Println(p.Name) // john
|
||||
log.Println(p.Pass) // doe
|
||||
|
||||
// ...
|
||||
})
|
||||
```
|
||||
|
||||
Run tests with the following `curl` command:
|
||||
|
||||
```bash
|
||||
curl -X POST -H "Content-Type: application/cbor" --data "\xa2dnamedjohndpasscdoe" localhost:3000
|
||||
```
|
||||
|
||||
### Cookie
|
||||
|
||||
This method is similar to [Body Binding](#body), but for cookie parameters.
|
||||
|
@ -26,25 +26,26 @@ const (
|
||||
|
||||
```go
|
||||
const (
|
||||
MIMETextXML = "text/xml"
|
||||
MIMETextHTML = "text/html"
|
||||
MIMETextPlain = "text/plain"
|
||||
MIMETextJavaScript = "text/javascript"
|
||||
MIMETextCSS = "text/css"
|
||||
MIMEApplicationXML = "application/xml"
|
||||
MIMEApplicationJSON = "application/json"
|
||||
MIMEApplicationJavaScript = "application/javascript"
|
||||
MIMEApplicationForm = "application/x-www-form-urlencoded"
|
||||
MIMEOctetStream = "application/octet-stream"
|
||||
MIMEMultipartForm = "multipart/form-data"
|
||||
MIMETextXML = "text/xml"
|
||||
MIMETextHTML = "text/html"
|
||||
MIMETextPlain = "text/plain"
|
||||
MIMETextJavaScript = "text/javascript"
|
||||
MIMETextCSS = "text/css"
|
||||
MIMEApplicationXML = "application/xml"
|
||||
MIMEApplicationJSON = "application/json"
|
||||
MIMEApplicationCBOR = "application/cbor"
|
||||
MIMEApplicationJavaScript = "application/javascript"
|
||||
MIMEApplicationForm = "application/x-www-form-urlencoded"
|
||||
MIMEOctetStream = "application/octet-stream"
|
||||
MIMEMultipartForm = "multipart/form-data"
|
||||
|
||||
MIMETextXMLCharsetUTF8 = "text/xml; charset=utf-8"
|
||||
MIMETextHTMLCharsetUTF8 = "text/html; charset=utf-8"
|
||||
MIMETextPlainCharsetUTF8 = "text/plain; charset=utf-8"
|
||||
MIMETextJavaScriptCharsetUTF8 = "text/javascript; charset=utf-8"
|
||||
MIMETextCSSCharsetUTF8 = "text/css; charset=utf-8"
|
||||
MIMEApplicationXMLCharsetUTF8 = "application/xml; charset=utf-8"
|
||||
MIMEApplicationJSONCharsetUTF8 = "application/json; charset=utf-8"
|
||||
MIMETextXMLCharsetUTF8 = "text/xml; charset=utf-8"
|
||||
MIMETextHTMLCharsetUTF8 = "text/html; charset=utf-8"
|
||||
MIMETextPlainCharsetUTF8 = "text/plain; charset=utf-8"
|
||||
MIMETextJavaScriptCharsetUTF8 = "text/javascript; charset=utf-8"
|
||||
MIMETextCSSCharsetUTF8 = "text/css; charset=utf-8"
|
||||
MIMEApplicationXMLCharsetUTF8 = "application/xml; charset=utf-8"
|
||||
MIMEApplicationJSONCharsetUTF8 = "application/json; charset=utf-8"
|
||||
MIMEApplicationJavaScriptCharsetUTF8 = "application/javascript; charset=utf-8"
|
||||
)```
|
||||
|
||||
@ -72,6 +73,7 @@ const (
|
||||
StatusSeeOther = 303 // RFC 7231, 6.4.4
|
||||
StatusNotModified = 304 // RFC 7232, 4.1
|
||||
StatusUseProxy = 305 // RFC 7231, 6.4.5
|
||||
StatusSwitchProxy = 306 // RFC 9110, 15.4.7 (Unused)
|
||||
StatusTemporaryRedirect = 307 // RFC 7231, 6.4.7
|
||||
StatusPermanentRedirect = 308 // RFC 7538, 3
|
||||
StatusBadRequest = 400 // RFC 7231, 6.5.1
|
||||
@ -168,127 +170,129 @@ HTTP Headers were copied from net/http.
|
||||
|
||||
```go
|
||||
const (
|
||||
HeaderAuthorization = "Authorization"
|
||||
HeaderProxyAuthenticate = "Proxy-Authenticate"
|
||||
HeaderProxyAuthorization = "Proxy-Authorization"
|
||||
HeaderWWWAuthenticate = "WWW-Authenticate"
|
||||
HeaderAge = "Age"
|
||||
HeaderCacheControl = "Cache-Control"
|
||||
HeaderClearSiteData = "Clear-Site-Data"
|
||||
HeaderExpires = "Expires"
|
||||
HeaderPragma = "Pragma"
|
||||
HeaderWarning = "Warning"
|
||||
HeaderAcceptCH = "Accept-CH"
|
||||
HeaderAcceptCHLifetime = "Accept-CH-Lifetime"
|
||||
HeaderContentDPR = "Content-DPR"
|
||||
HeaderDPR = "DPR"
|
||||
HeaderEarlyData = "Early-Data"
|
||||
HeaderSaveData = "Save-Data"
|
||||
HeaderViewportWidth = "Viewport-Width"
|
||||
HeaderWidth = "Width"
|
||||
HeaderETag = "ETag"
|
||||
HeaderIfMatch = "If-Match"
|
||||
HeaderIfModifiedSince = "If-Modified-Since"
|
||||
HeaderIfNoneMatch = "If-None-Match"
|
||||
HeaderIfUnmodifiedSince = "If-Unmodified-Since"
|
||||
HeaderLastModified = "Last-Modified"
|
||||
HeaderVary = "Vary"
|
||||
HeaderConnection = "Connection"
|
||||
HeaderKeepAlive = "Keep-Alive"
|
||||
HeaderAccept = "Accept"
|
||||
HeaderAcceptCharset = "Accept-Charset"
|
||||
HeaderAcceptEncoding = "Accept-Encoding"
|
||||
HeaderAcceptLanguage = "Accept-Language"
|
||||
HeaderCookie = "Cookie"
|
||||
HeaderExpect = "Expect"
|
||||
HeaderMaxForwards = "Max-Forwards"
|
||||
HeaderSetCookie = "Set-Cookie"
|
||||
HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
|
||||
HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers"
|
||||
HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods"
|
||||
HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"
|
||||
HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers"
|
||||
HeaderAccessControlMaxAge = "Access-Control-Max-Age"
|
||||
HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
|
||||
HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
|
||||
HeaderOrigin = "Origin"
|
||||
HeaderTimingAllowOrigin = "Timing-Allow-Origin"
|
||||
HeaderXPermittedCrossDomainPolicies = "X-Permitted-Cross-Domain-Policies"
|
||||
HeaderDNT = "DNT"
|
||||
HeaderTk = "Tk"
|
||||
HeaderContentDisposition = "Content-Disposition"
|
||||
HeaderContentEncoding = "Content-Encoding"
|
||||
HeaderContentLanguage = "Content-Language"
|
||||
HeaderContentLength = "Content-Length"
|
||||
HeaderContentLocation = "Content-Location"
|
||||
HeaderContentType = "Content-Type"
|
||||
HeaderForwarded = "Forwarded"
|
||||
HeaderVia = "Via"
|
||||
HeaderXForwardedFor = "X-Forwarded-For"
|
||||
HeaderXForwardedHost = "X-Forwarded-Host"
|
||||
HeaderXForwardedProto = "X-Forwarded-Proto"
|
||||
HeaderXForwardedProtocol = "X-Forwarded-Protocol"
|
||||
HeaderXForwardedSsl = "X-Forwarded-Ssl"
|
||||
HeaderXUrlScheme = "X-Url-Scheme"
|
||||
HeaderLocation = "Location"
|
||||
HeaderFrom = "From"
|
||||
HeaderHost = "Host"
|
||||
HeaderReferer = "Referer"
|
||||
HeaderReferrerPolicy = "Referrer-Policy"
|
||||
HeaderUserAgent = "User-Agent"
|
||||
HeaderAllow = "Allow"
|
||||
HeaderServer = "Server"
|
||||
HeaderAcceptRanges = "Accept-Ranges"
|
||||
HeaderContentRange = "Content-Range"
|
||||
HeaderIfRange = "If-Range"
|
||||
HeaderRange = "Range"
|
||||
HeaderContentSecurityPolicy = "Content-Security-Policy"
|
||||
HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
|
||||
HeaderCrossOriginResourcePolicy = "Cross-Origin-Resource-Policy"
|
||||
HeaderExpectCT = "Expect-CT"
|
||||
HeaderFeaturePolicy = "Feature-Policy"
|
||||
HeaderPublicKeyPins = "Public-Key-Pins"
|
||||
HeaderPublicKeyPinsReportOnly = "Public-Key-Pins-Report-Only"
|
||||
HeaderStrictTransportSecurity = "Strict-Transport-Security"
|
||||
HeaderUpgradeInsecureRequests = "Upgrade-Insecure-Requests"
|
||||
HeaderXContentTypeOptions = "X-Content-Type-Options"
|
||||
HeaderXDownloadOptions = "X-Download-Options"
|
||||
HeaderXFrameOptions = "X-Frame-Options"
|
||||
HeaderXPoweredBy = "X-Powered-By"
|
||||
HeaderXXSSProtection = "X-XSS-Protection"
|
||||
HeaderLastEventID = "Last-Event-ID"
|
||||
HeaderNEL = "NEL"
|
||||
HeaderPingFrom = "Ping-From"
|
||||
HeaderPingTo = "Ping-To"
|
||||
HeaderReportTo = "Report-To"
|
||||
HeaderTE = "TE"
|
||||
HeaderTrailer = "Trailer"
|
||||
HeaderTransferEncoding = "Transfer-Encoding"
|
||||
HeaderSecWebSocketAccept = "Sec-WebSocket-Accept"
|
||||
HeaderSecWebSocketExtensions = "Sec-WebSocket-Extensions"
|
||||
HeaderSecWebSocketKey = "Sec-WebSocket-Key"
|
||||
HeaderSecWebSocketProtocol = "Sec-WebSocket-Protocol"
|
||||
HeaderSecWebSocketVersion = "Sec-WebSocket-Version"
|
||||
HeaderAcceptPatch = "Accept-Patch"
|
||||
HeaderAcceptPushPolicy = "Accept-Push-Policy"
|
||||
HeaderAcceptSignature = "Accept-Signature"
|
||||
HeaderAltSvc = "Alt-Svc"
|
||||
HeaderDate = "Date"
|
||||
HeaderIndex = "Index"
|
||||
HeaderLargeAllocation = "Large-Allocation"
|
||||
HeaderLink = "Link"
|
||||
HeaderPushPolicy = "Push-Policy"
|
||||
HeaderRetryAfter = "Retry-After"
|
||||
HeaderServerTiming = "Server-Timing"
|
||||
HeaderSignature = "Signature"
|
||||
HeaderSignedHeaders = "Signed-Headers"
|
||||
HeaderSourceMap = "SourceMap"
|
||||
HeaderUpgrade = "Upgrade"
|
||||
HeaderXDNSPrefetchControl = "X-DNS-Prefetch-Control"
|
||||
HeaderXPingback = "X-Pingback"
|
||||
HeaderXRequestID = "X-Request-ID"
|
||||
HeaderXRequestedWith = "X-Requested-With"
|
||||
HeaderXRobotsTag = "X-Robots-Tag"
|
||||
HeaderXUACompatible = "X-UA-Compatible"
|
||||
HeaderAuthorization = "Authorization"
|
||||
HeaderProxyAuthenticate = "Proxy-Authenticate"
|
||||
HeaderProxyAuthorization = "Proxy-Authorization"
|
||||
HeaderWWWAuthenticate = "WWW-Authenticate"
|
||||
HeaderAge = "Age"
|
||||
HeaderCacheControl = "Cache-Control"
|
||||
HeaderClearSiteData = "Clear-Site-Data"
|
||||
HeaderExpires = "Expires"
|
||||
HeaderPragma = "Pragma"
|
||||
HeaderWarning = "Warning"
|
||||
HeaderAcceptCH = "Accept-CH"
|
||||
HeaderAcceptCHLifetime = "Accept-CH-Lifetime"
|
||||
HeaderContentDPR = "Content-DPR"
|
||||
HeaderDPR = "DPR"
|
||||
HeaderEarlyData = "Early-Data"
|
||||
HeaderSaveData = "Save-Data"
|
||||
HeaderViewportWidth = "Viewport-Width"
|
||||
HeaderWidth = "Width"
|
||||
HeaderETag = "ETag"
|
||||
HeaderIfMatch = "If-Match"
|
||||
HeaderIfModifiedSince = "If-Modified-Since"
|
||||
HeaderIfNoneMatch = "If-None-Match"
|
||||
HeaderIfUnmodifiedSince = "If-Unmodified-Since"
|
||||
HeaderLastModified = "Last-Modified"
|
||||
HeaderVary = "Vary"
|
||||
HeaderConnection = "Connection"
|
||||
HeaderKeepAlive = "Keep-Alive"
|
||||
HeaderAccept = "Accept"
|
||||
HeaderAcceptCharset = "Accept-Charset"
|
||||
HeaderAcceptEncoding = "Accept-Encoding"
|
||||
HeaderAcceptLanguage = "Accept-Language"
|
||||
HeaderCookie = "Cookie"
|
||||
HeaderExpect = "Expect"
|
||||
HeaderMaxForwards = "Max-Forwards"
|
||||
HeaderSetCookie = "Set-Cookie"
|
||||
HeaderAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
|
||||
HeaderAccessControlAllowHeaders = "Access-Control-Allow-Headers"
|
||||
HeaderAccessControlAllowMethods = "Access-Control-Allow-Methods"
|
||||
HeaderAccessControlAllowOrigin = "Access-Control-Allow-Origin"
|
||||
HeaderAccessControlExposeHeaders = "Access-Control-Expose-Headers"
|
||||
HeaderAccessControlMaxAge = "Access-Control-Max-Age"
|
||||
HeaderAccessControlRequestHeaders = "Access-Control-Request-Headers"
|
||||
HeaderAccessControlRequestMethod = "Access-Control-Request-Method"
|
||||
HeaderOrigin = "Origin"
|
||||
HeaderTimingAllowOrigin = "Timing-Allow-Origin"
|
||||
HeaderXPermittedCrossDomainPolicies = "X-Permitted-Cross-Domain-Policies"
|
||||
HeaderDNT = "DNT"
|
||||
HeaderTk = "Tk"
|
||||
HeaderContentDisposition = "Content-Disposition"
|
||||
HeaderContentEncoding = "Content-Encoding"
|
||||
HeaderContentLanguage = "Content-Language"
|
||||
HeaderContentLength = "Content-Length"
|
||||
HeaderContentLocation = "Content-Location"
|
||||
HeaderContentType = "Content-Type"
|
||||
HeaderForwarded = "Forwarded"
|
||||
HeaderVia = "Via"
|
||||
HeaderXForwardedFor = "X-Forwarded-For"
|
||||
HeaderXForwardedHost = "X-Forwarded-Host"
|
||||
HeaderXForwardedProto = "X-Forwarded-Proto"
|
||||
HeaderXForwardedProtocol = "X-Forwarded-Protocol"
|
||||
HeaderXForwardedSsl = "X-Forwarded-Ssl"
|
||||
HeaderXUrlScheme = "X-Url-Scheme"
|
||||
HeaderLocation = "Location"
|
||||
HeaderFrom = "From"
|
||||
HeaderHost = "Host"
|
||||
HeaderReferer = "Referer"
|
||||
HeaderReferrerPolicy = "Referrer-Policy"
|
||||
HeaderUserAgent = "User-Agent"
|
||||
HeaderAllow = "Allow"
|
||||
HeaderServer = "Server"
|
||||
HeaderAcceptRanges = "Accept-Ranges"
|
||||
HeaderContentRange = "Content-Range"
|
||||
HeaderIfRange = "If-Range"
|
||||
HeaderRange = "Range"
|
||||
HeaderContentSecurityPolicy = "Content-Security-Policy"
|
||||
HeaderContentSecurityPolicyReportOnly = "Content-Security-Policy-Report-Only"
|
||||
HeaderCrossOriginResourcePolicy = "Cross-Origin-Resource-Policy"
|
||||
HeaderExpectCT = "Expect-CT"
|
||||
HeaderFeaturePolicy = "Feature-Policy"
|
||||
HeaderPublicKeyPins = "Public-Key-Pins"
|
||||
HeaderPublicKeyPinsReportOnly = "Public-Key-Pins-Report-Only"
|
||||
HeaderStrictTransportSecurity = "Strict-Transport-Security"
|
||||
HeaderUpgradeInsecureRequests = "Upgrade-Insecure-Requests"
|
||||
HeaderXContentTypeOptions = "X-Content-Type-Options"
|
||||
HeaderXDownloadOptions = "X-Download-Options"
|
||||
HeaderXFrameOptions = "X-Frame-Options"
|
||||
HeaderXPoweredBy = "X-Powered-By"
|
||||
HeaderXXSSProtection = "X-XSS-Protection"
|
||||
HeaderLastEventID = "Last-Event-ID"
|
||||
HeaderNEL = "NEL"
|
||||
HeaderPingFrom = "Ping-From"
|
||||
HeaderPingTo = "Ping-To"
|
||||
HeaderReportTo = "Report-To"
|
||||
HeaderTE = "TE"
|
||||
HeaderTrailer = "Trailer"
|
||||
HeaderTransferEncoding = "Transfer-Encoding"
|
||||
HeaderSecWebSocketAccept = "Sec-WebSocket-Accept"
|
||||
HeaderSecWebSocketExtensions = "Sec-WebSocket-Extensions"
|
||||
HeaderSecWebSocketKey = "Sec-WebSocket-Key"
|
||||
HeaderSecWebSocketProtocol = "Sec-WebSocket-Protocol"
|
||||
HeaderSecWebSocketVersion = "Sec-WebSocket-Version"
|
||||
HeaderAcceptPatch = "Accept-Patch"
|
||||
HeaderAcceptPushPolicy = "Accept-Push-Policy"
|
||||
HeaderAcceptSignature = "Accept-Signature"
|
||||
HeaderAltSvc = "Alt-Svc"
|
||||
HeaderDate = "Date"
|
||||
HeaderIndex = "Index"
|
||||
HeaderLargeAllocation = "Large-Allocation"
|
||||
HeaderLink = "Link"
|
||||
HeaderPushPolicy = "Push-Policy"
|
||||
HeaderRetryAfter = "Retry-After"
|
||||
HeaderServerTiming = "Server-Timing"
|
||||
HeaderSignature = "Signature"
|
||||
HeaderSignedHeaders = "Signed-Headers"
|
||||
HeaderSourceMap = "SourceMap"
|
||||
HeaderUpgrade = "Upgrade"
|
||||
HeaderXDNSPrefetchControl = "X-DNS-Prefetch-Control"
|
||||
HeaderXPingback = "X-Pingback"
|
||||
HeaderXRequestID = "X-Request-ID"
|
||||
HeaderXRequestedWith = "X-Requested-With"
|
||||
HeaderXRobotsTag = "X-Robots-Tag"
|
||||
HeaderXUACompatible = "X-UA-Compatible"
|
||||
HeaderAccessControlAllowPrivateNetwork = "Access-Control-Allow-Private-Network"
|
||||
HeaderAccessControlRequestPrivateNetwork = "Access-Control-Request-Private-Network"
|
||||
)
|
||||
```
|
||||
|
@ -924,6 +924,54 @@ app.Get("/", func(c fiber.Ctx) error {
|
||||
})
|
||||
```
|
||||
|
||||
## CBOR
|
||||
|
||||
CBOR converts any interface or string to CBOR encoded bytes.
|
||||
|
||||
:::info
|
||||
CBOR also sets the content header to the `ctype` parameter. If no `ctype` is passed in, the header is set to `application/cbor`.
|
||||
:::
|
||||
|
||||
```go title="Signature"
|
||||
func (c fiber.Ctx) CBOR(data any, ctype ...string) error
|
||||
```
|
||||
|
||||
```go title="Example"
|
||||
type SomeStruct struct {
|
||||
Name string `cbor:"name"`
|
||||
Age uint8 `cbor:"age"`
|
||||
}
|
||||
|
||||
app.Get("/cbor", func(c fiber.Ctx) error {
|
||||
// Create data struct:
|
||||
data := SomeStruct{
|
||||
Name: "Grame",
|
||||
Age: 20,
|
||||
}
|
||||
|
||||
return c.CBOR(data)
|
||||
// => Content-Type: application/cbor
|
||||
// => \xa2dnameeGramecage\x14
|
||||
|
||||
return c.CBOR(fiber.Map{
|
||||
"name": "Grame",
|
||||
"age": 20,
|
||||
})
|
||||
// => Content-Type: application/cbor
|
||||
// => \xa2dnameeGramecage\x14
|
||||
|
||||
return c.CBOR(fiber.Map{
|
||||
"type": "https://example.com/probs/out-of-credit",
|
||||
"title": "You do not have enough credit.",
|
||||
"status": 403,
|
||||
"detail": "Your current balance is 30, but that costs 50.",
|
||||
"instance": "/account/12345/msgs/abc",
|
||||
})
|
||||
// => Content-Type: application/cbor
|
||||
// => \xa5dtypex'https://example.com/probs/out-of-creditetitlex\x1eYou do not have enough credit.fstatus\x19\x01\x93fdetailx.Your current balance is 30, but that costs 50.hinstancew/account/12345/msgs/abc
|
||||
})
|
||||
```
|
||||
|
||||
## Links
|
||||
|
||||
Joins the links followed by the property to populate the response’s [Link](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link) HTTP header field.
|
||||
|
@ -42,45 +42,47 @@ app := fiber.New(fiber.Config{
|
||||
|
||||
#### Config fields
|
||||
|
||||
| Property | Type | Description | Default |
|
||||
|---------------------------------------------------------------------------------------|-------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
|
||||
| <Reference id="appname">AppName</Reference> | `string` | This allows to setup app name for the app | `""` |
|
||||
| <Reference id="bodylimit">BodyLimit</Reference> | `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` |
|
||||
| <Reference id="casesensitive">CaseSensitive</Reference> | `bool` | When enabled, `/Foo` and `/foo` are different routes. When disabled, `/Foo`and `/foo` are treated the same. | `false` |
|
||||
| <Reference id="colorscheme">ColorScheme</Reference> | [`Colors`](https://github.com/gofiber/fiber/blob/master/color.go) | You can define custom color scheme. They'll be used for startup message, route list and some middlewares. | [`DefaultColors`](https://github.com/gofiber/fiber/blob/master/color.go) |
|
||||
| <Reference id="compressedfilesuffixes">CompressedFileSuffixes</Reference> | `map[string]string` | Adds a suffix to the original file name and tries saving the resulting compressed file under the new file name. | `{"gzip": ".fiber.gz", "br": ".fiber.br", "zstd": ".fiber.zst"}` |
|
||||
| <Reference id="concurrency">Concurrency</Reference> | `int` | Maximum number of concurrent connections. | `256 * 1024` |
|
||||
| <Reference id="disabledefaultcontenttype">DisableDefaultContentType</Reference> | `bool` | When set to true, causes the default Content-Type header to be excluded from the Response. | `false` |
|
||||
| <Reference id="disabledefaultdate">DisableDefaultDate</Reference> | `bool` | When set to true causes the default date header to be excluded from the response. | `false` |
|
||||
| <Reference id="disableheadernormalizing">DisableHeaderNormalizing</Reference> | `bool` | By default all header names are normalized: conteNT-tYPE -> Content-Type | `false` |
|
||||
| <Reference id="disablekeepalive">DisableKeepalive</Reference> | `bool` | Disable keep-alive connections, the server will close incoming connections after sending the first response to the client | `false` |
|
||||
| <Reference id="disablepreparsemultipartform">DisablePreParseMultipartForm</Reference> | `bool` | Will not pre parse Multipart Form data if set to true. This option is useful for servers that desire to treat multipart form data as a binary blob, or choose when to parse the data. | `false` |
|
||||
| <Reference id="enableipvalidation">EnableIPValidation</Reference> | `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 separated string.<br /><br />**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` |
|
||||
| <Reference id="enablesplittingonparsers">EnableSplittingOnParsers</Reference> | `bool` | EnableSplittingOnParsers splits the query/body/header parameters by comma when it's true. <br /> <br /> 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` |
|
||||
| Property | Type | Description | Default |
|
||||
|---------------------------------------------------------------------------------------|-------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------|
|
||||
| <Reference id="appname">AppName</Reference> | `string` | This allows to setup app name for the app | `""` |
|
||||
| <Reference id="bodylimit">BodyLimit</Reference> | `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` |
|
||||
| <Reference id="casesensitive">CaseSensitive</Reference> | `bool` | When enabled, `/Foo` and `/foo` are different routes. When disabled, `/Foo`and `/foo` are treated the same. | `false` |
|
||||
| <Reference id="colorscheme">ColorScheme</Reference> | [`Colors`](https://github.com/gofiber/fiber/blob/master/color.go) | You can define custom color scheme. They'll be used for startup message, route list and some middlewares. | [`DefaultColors`](https://github.com/gofiber/fiber/blob/master/color.go) |
|
||||
| <Reference id="compressedfilesuffixes">CompressedFileSuffixes</Reference> | `map[string]string` | Adds a suffix to the original file name and tries saving the resulting compressed file under the new file name. | `{"gzip": ".fiber.gz", "br": ".fiber.br", "zstd": ".fiber.zst"}` |
|
||||
| <Reference id="concurrency">Concurrency</Reference> | `int` | Maximum number of concurrent connections. | `256 * 1024` |
|
||||
| <Reference id="disabledefaultcontenttype">DisableDefaultContentType</Reference> | `bool` | When set to true, causes the default Content-Type header to be excluded from the Response. | `false` |
|
||||
| <Reference id="disabledefaultdate">DisableDefaultDate</Reference> | `bool` | When set to true causes the default date header to be excluded from the response. | `false` |
|
||||
| <Reference id="disableheadernormalizing">DisableHeaderNormalizing</Reference> | `bool` | By default all header names are normalized: conteNT-tYPE -> Content-Type | `false` |
|
||||
| <Reference id="disablekeepalive">DisableKeepalive</Reference> | `bool` | Disable keep-alive connections, the server will close incoming connections after sending the first response to the client | `false` |
|
||||
| <Reference id="disablepreparsemultipartform">DisablePreParseMultipartForm</Reference> | `bool` | Will not pre parse Multipart Form data if set to true. This option is useful for servers that desire to treat multipart form data as a binary blob, or choose when to parse the data. | `false` |
|
||||
| <Reference id="enableipvalidation">EnableIPValidation</Reference> | `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 separated string.<br /><br />**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` |
|
||||
| <Reference id="enablesplittingonparsers">EnableSplittingOnParsers</Reference> | `bool` | EnableSplittingOnParsers splits the query/body/header parameters by comma when it's true. <br /> <br /> 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` |
|
||||
| <Reference id="trustproxy">TrustProxy</Reference> | `bool` | When set to true, fiber will check whether proxy is trusted, using TrustProxyConfig.Proxies list. <br /><br />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. <br /> If `TrustProxy` is true, and `RemoteIP` is in the list of `TrustProxyConfig.Proxies` `c.Protocol()`, `c.IP()`, and `c.Hostname()` will have the same behaviour when `TrustProxy` disabled, if `RemoteIP` isn't in the list, `c.Protocol()` will return https when a 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` |
|
||||
| <Reference id="errorhandler">ErrorHandler</Reference> | `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` |
|
||||
| <Reference id="getonly">GETOnly</Reference> | `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` |
|
||||
| <Reference id="idletimeout">IdleTimeout</Reference> | `time.Duration` | The maximum amount of time to wait for the next request when keep-alive is enabled. If IdleTimeout is zero, the value of ReadTimeout is used. | `nil` |
|
||||
| <Reference id="immutable">Immutable</Reference> | `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` |
|
||||
| <Reference id="jsondecoder">JSONDecoder</Reference> | `utils.JSONUnmarshal` | Allowing for flexibility in using another json library for decoding. | `json.Unmarshal` |
|
||||
| <Reference id="jsonencoder">JSONEncoder</Reference> | `utils.JSONMarshal` | Allowing for flexibility in using another json library for encoding. | `json.Marshal` |
|
||||
| <Reference id="passlocalstoviews">PassLocalsToViews</Reference> | `bool` | PassLocalsToViews Enables passing of the locals set on a fiber.Ctx to the template engine. See our **Template Middleware** for supported engines. | `false` |
|
||||
| <Reference id="proxyheader">ProxyHeader</Reference> | `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-\*_. | `""` |
|
||||
| <Reference id="readbuffersize">ReadBufferSize</Reference> | `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` |
|
||||
| <Reference id="readtimeout">ReadTimeout</Reference> | `time.Duration` | The amount of time allowed to read the full request, including the body. The default timeout is unlimited. | `nil` |
|
||||
| <Reference id="reducememoryusage">ReduceMemoryUsage</Reference> | `bool` | Aggressively reduces memory usage at the cost of higher CPU usage if set to true. | `false` |
|
||||
| <Reference id="requestmethods">RequestMethods</Reference> | `[]string` | RequestMethods provides customizability for HTTP methods. You can add/remove methods as you wish. | `DefaultMethods` |
|
||||
| <Reference id="serverheader">ServerHeader</Reference> | `string` | Enables the `Server` HTTP header with the given value. | `""` |
|
||||
| <Reference id="streamrequestbody">StreamRequestBody</Reference> | `bool` | StreamRequestBody enables request body streaming, and calls the handler sooner when given body is larger than the current limit. | `false` |
|
||||
| <Reference id="strictrouting">StrictRouting</Reference> | `bool` | When enabled, the router treats `/foo` and `/foo/` as different. Otherwise, the router treats `/foo` and `/foo/` as the same. | `false` |
|
||||
| <Reference id="structvalidator">StructValidator</Reference> | `StructValidator` | If you want to validate header/form/query... automatically when to bind, you can define struct validator. Fiber doesn't have default validator, so it'll skip validator step if you don't use any validator. | `nil` |
|
||||
| <Reference id="trustproxyconfig">TrustProxyConfig</Reference> | `TrustProxyConfig` | Configure trusted proxy IP's. Look at `TrustProxy` doc. <br /> <br /> `TrustProxyConfig.Proxies` can take IP or IP range addresses. | `nil` |
|
||||
| <Reference id="unescapepath">UnescapePath</Reference> | `bool` | Converts all encoded characters in the route back before setting the path for the context, so that the routing can also work with URL encoded special characters | `false` |
|
||||
| <Reference id="views">Views</Reference> | `Views` | Views is the interface that wraps the Render function. See our **Template Middleware** for supported engines. | `nil` |
|
||||
| <Reference id="viewslayout">ViewsLayout</Reference> | `string` | Views Layout is the global layout for all template render until override on Render function. See our **Template Middleware** for supported engines. | `""` |
|
||||
| <Reference id="writebuffersize">WriteBufferSize</Reference> | `int` | Per-connection buffer size for responses' writing. | `4096` |
|
||||
| <Reference id="writetimeout">WriteTimeout</Reference> | `time.Duration` | The maximum duration before timing out writes of the response. The default timeout is unlimited. | `nil` |
|
||||
| <Reference id="xmlencoder">XMLEncoder</Reference> | `utils.XMLMarshal` | Allowing for flexibility in using another XML library for encoding. | `xml.Marshal` |
|
||||
| <Reference id="errorhandler">ErrorHandler</Reference> | `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` |
|
||||
| <Reference id="getonly">GETOnly</Reference> | `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` |
|
||||
| <Reference id="idletimeout">IdleTimeout</Reference> | `time.Duration` | The maximum amount of time to wait for the next request when keep-alive is enabled. If IdleTimeout is zero, the value of ReadTimeout is used. | `nil` |
|
||||
| <Reference id="immutable">Immutable</Reference> | `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` |
|
||||
| <Reference id="jsonencoder">JSONEncoder</Reference> | `utils.JSONMarshal` | Allowing for flexibility in using another json library for encoding. | `json.Marshal` |
|
||||
| <Reference id="jsondecoder">JSONDecoder</Reference> | `utils.JSONUnmarshal` | Allowing for flexibility in using another json library for decoding. | `json.Unmarshal` |
|
||||
| <Reference id="cborencoder">CBOREncoder</Reference> | `utils.CBORMarshal` | Allowing for flexibility in using another cbor library for encoding. | `cbor.Marshal` |
|
||||
| <Reference id="cbordecoder">CBORDecoder</Reference> | `utils.CBORUnmarshal` | Allowing for flexibility in using another cbor library for decoding. | `cbor.Unmarshal` |
|
||||
| <Reference id="passlocalstoviews">PassLocalsToViews</Reference> | `bool` | PassLocalsToViews Enables passing of the locals set on a fiber.Ctx to the template engine. See our **Template Middleware** for supported engines. | `false` |
|
||||
| <Reference id="proxyheader">ProxyHeader</Reference> | `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-\*_. | `""` |
|
||||
| <Reference id="readbuffersize">ReadBufferSize</Reference> | `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` |
|
||||
| <Reference id="readtimeout">ReadTimeout</Reference> | `time.Duration` | The amount of time allowed to read the full request, including the body. The default timeout is unlimited. | `nil` |
|
||||
| <Reference id="reducememoryusage">ReduceMemoryUsage</Reference> | `bool` | Aggressively reduces memory usage at the cost of higher CPU usage if set to true. | `false` |
|
||||
| <Reference id="requestmethods">RequestMethods</Reference> | `[]string` | RequestMethods provides customizability for HTTP methods. You can add/remove methods as you wish. | `DefaultMethods` |
|
||||
| <Reference id="serverheader">ServerHeader</Reference> | `string` | Enables the `Server` HTTP header with the given value. | `""` |
|
||||
| <Reference id="streamrequestbody">StreamRequestBody</Reference> | `bool` | StreamRequestBody enables request body streaming, and calls the handler sooner when given body is larger than the current limit. | `false` |
|
||||
| <Reference id="strictrouting">StrictRouting</Reference> | `bool` | When enabled, the router treats `/foo` and `/foo/` as different. Otherwise, the router treats `/foo` and `/foo/` as the same. | `false` |
|
||||
| <Reference id="structvalidator">StructValidator</Reference> | `StructValidator` | If you want to validate header/form/query... automatically when to bind, you can define struct validator. Fiber doesn't have default validator, so it'll skip validator step if you don't use any validator. | `nil` |
|
||||
| <Reference id="trustproxyconfig">TrustProxyConfig</Reference> | `TrustProxyConfig` | Configure trusted proxy IP's. Look at `TrustProxy` doc. <br /> <br /> `TrustProxyConfig.Proxies` can take IP or IP range addresses. | `nil` |
|
||||
| <Reference id="unescapepath">UnescapePath</Reference> | `bool` | Converts all encoded characters in the route back before setting the path for the context, so that the routing can also work with URL encoded special characters | `false` |
|
||||
| <Reference id="views">Views</Reference> | `Views` | Views is the interface that wraps the Render function. See our **Template Middleware** for supported engines. | `nil` |
|
||||
| <Reference id="viewslayout">ViewsLayout</Reference> | `string` | Views Layout is the global layout for all template render until override on Render function. See our **Template Middleware** for supported engines. | `""` |
|
||||
| <Reference id="writebuffersize">WriteBufferSize</Reference> | `int` | Per-connection buffer size for responses' writing. | `4096` |
|
||||
| <Reference id="writetimeout">WriteTimeout</Reference> | `time.Duration` | The maximum duration before timing out writes of the response. The default timeout is unlimited. | `nil` |
|
||||
| <Reference id="xmlencoder">XMLEncoder</Reference> | `utils.XMLMarshal` | Allowing for flexibility in using another XML library for encoding. | `xml.Marshal` |
|
||||
|
||||
## Server listening
|
||||
|
||||
|
@ -657,6 +657,15 @@ SetXML method sets XML body in request.
|
||||
func (r *Request) SetXML(v any) *Request
|
||||
```
|
||||
|
||||
## SetCBOR
|
||||
|
||||
SetCBOR method sets the request body using [CBOR](https://cbor.io/) encoding format.
|
||||
It automatically sets the Content-Type header to `"application/cbor"`.
|
||||
|
||||
```go title="Signature"
|
||||
func (r *Request) SetCBOR(v any) *Request
|
||||
```
|
||||
|
||||
## SetRawBody
|
||||
|
||||
SetRawBody method sets body with raw data in request.
|
||||
|
@ -187,6 +187,14 @@ XML method will unmarshal body to xml.
|
||||
func (r *Response) XML(v any) error
|
||||
```
|
||||
|
||||
## CBOR
|
||||
|
||||
CBOR method will unmarshal body to CBOR.
|
||||
|
||||
```go title="Signature"
|
||||
func (r *Response) CBOR(v any) error
|
||||
```
|
||||
|
||||
## Save
|
||||
|
||||
Save method will save the body to a file or io.Writer.
|
||||
|
@ -81,6 +81,8 @@ type Client struct {
|
||||
jsonUnmarshal utils.JSONUnmarshal
|
||||
xmlMarshal utils.XMLMarshal
|
||||
xmlUnmarshal utils.XMLUnmarshal
|
||||
cborMarshal utils.CBORMarshal
|
||||
cborUnmarshal utils.CBORUnmarshal
|
||||
|
||||
cookieJar *CookieJar
|
||||
|
||||
@ -314,6 +316,40 @@ SetXMLUnmarshal sets the XML decoder.
|
||||
func (c *Client) SetXMLUnmarshal(f utils.XMLUnmarshal) *Client
|
||||
```
|
||||
|
||||
### CBOR
|
||||
|
||||
#### CBORMarshal
|
||||
|
||||
CBORMarshal returns CBOR marshal function in Core.
|
||||
|
||||
```go title="Signature"
|
||||
func (c *Client) CBORMarshal() utils.CBORMarshal
|
||||
```
|
||||
|
||||
#### CBORUnmarshal
|
||||
|
||||
CBORUnmarshal returns CBOR unmarshal function in Core.
|
||||
|
||||
```go title="Signature"
|
||||
func (c *Client) CBORUnmarshal() utils.CBORUnmarshal
|
||||
```
|
||||
|
||||
#### SetCBORMarshal
|
||||
|
||||
SetCBORMarshal sets CBOR encoder.
|
||||
|
||||
```go title="Signature"
|
||||
func (c *Client) SetCBORMarshal(f utils.CBORMarshal) *Client
|
||||
```
|
||||
|
||||
#### SetCBORUnmarshal
|
||||
|
||||
SetCBORUnmarshal sets CBOR decoder.
|
||||
|
||||
```go title="Signature"
|
||||
func (c *Client) SetCBORUnmarshal(f utils.CBORUnmarshal) *Client
|
||||
```
|
||||
|
||||
### TLS
|
||||
|
||||
#### TLSConfig
|
||||
|
@ -310,6 +310,7 @@ testConfig := fiber.TestConfig{
|
||||
- **SendString**: Similar to Express.js, sends a string as the response.
|
||||
- **String**: Similar to Express.js, converts a value to a string.
|
||||
- **ViewBind**: Binds data to a view, replacing the old `Bind` method.
|
||||
- **CBOR**: Introducing [CBOR](https://cbor.io/) binary encoding format for both request & response body. CBOR is a binary data serialization format which is both compact and efficient, making it ideal for use in web applications.
|
||||
|
||||
### Removed Methods
|
||||
|
||||
|
2
go.mod
2
go.mod
@ -17,10 +17,12 @@ require (
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.1.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // direct
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
golang.org/x/net v0.30.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/text v0.19.0 // indirect
|
||||
|
6
middleware/cache/manager_msgp.go
vendored
6
middleware/cache/manager_msgp.go
vendored
@ -52,6 +52,9 @@ func (z *item) DecodeMsg(dc *msgp.Reader) (err error) {
|
||||
err = msgp.WrapError(err, "headers", za0001)
|
||||
return
|
||||
}
|
||||
if za0002 == nil {
|
||||
za0002 = make([]byte, 0)
|
||||
}
|
||||
z.headers[za0001] = za0002
|
||||
}
|
||||
case "body":
|
||||
@ -267,6 +270,9 @@ func (z *item) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
err = msgp.WrapError(err, "headers", za0001)
|
||||
return
|
||||
}
|
||||
if za0002 == nil {
|
||||
za0002 = make([]byte, 0)
|
||||
}
|
||||
z.headers[za0001] = za0002
|
||||
}
|
||||
case "body":
|
||||
|
Loading…
x
Reference in New Issue
Block a user