diff --git a/app_test.go b/app_test.go index 39890ead488..13c04987420 100644 --- a/app_test.go +++ b/app_test.go @@ -1666,7 +1666,7 @@ func Test_App_ReadBodyStream(t *testing.T) { app := New(Config{StreamRequestBody: true}) app.Post("/", func(c Ctx) error { // Calling c.Body() automatically reads the entire stream. - return c.SendString(fmt.Sprintf("%v %s", c.Request().IsBodyStream(), c.Body())) + return c.SendString(fmt.Sprintf("%v %s", c.Context().Request.IsBodyStream(), c.Body())) }) testString := "this is a test" resp, err := app.Test(httptest.NewRequest(MethodPost, "/", bytes.NewBufferString(testString))) @@ -1683,7 +1683,7 @@ func Test_App_DisablePreParseMultipartForm(t *testing.T) { app := New(Config{DisablePreParseMultipartForm: true, StreamRequestBody: true}) app.Post("/", func(c Ctx) error { - req := c.Request() + req := &c.Context().Request mpf, err := req.MultipartForm() if err != nil { return err diff --git a/bind.go b/bind.go index 0c9a63c4a8f..4a03ef8b59b 100644 --- a/bind.go +++ b/bind.go @@ -77,7 +77,7 @@ func (b *Bind) Custom(name string, dest any) error { // Header binds the request header strings into the struct, map[string]string and map[string][]string. func (b *Bind) Header(out any) error { - if err := b.returnErr(binder.HeaderBinder.Bind(b.ctx.Request(), out)); err != nil { + if err := b.returnErr(binder.HeaderBinder.Bind(&b.ctx.Context().Request, out)); err != nil { return err } @@ -141,7 +141,7 @@ func (b *Bind) Form(out any) error { // URI binds the route parameters into the struct, map[string]string and map[string][]string. func (b *Bind) URI(out any) error { - if err := b.returnErr(binder.URIBinder.Bind(b.ctx.route.Params, b.ctx.Params, out)); err != nil { + if err := b.returnErr(binder.URIBinder.Bind(b.ctx.req.route.Params, b.ctx.Params, out)); err != nil { return err } diff --git a/bind_test.go b/bind_test.go index 0c5b848f024..476a25415d4 100644 --- a/bind_test.go +++ b/bind_test.go @@ -30,25 +30,25 @@ func Test_Bind_Query(t *testing.T) { Name string Hobby []string } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") - c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football") q := new(Query) require.NoError(t, c.Bind().Query(q)) require.Len(t, q.Hobby, 2) - c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=basketball,football") q = new(Query) require.NoError(t, c.Bind().Query(q)) require.Len(t, q.Hobby, 2) - c.Request().URI().SetQueryString("id=1&name=tom&hobby=scoccer&hobby=basketball,football") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=scoccer&hobby=basketball,football") q = new(Query) require.NoError(t, c.Bind().Query(q)) require.Len(t, q.Hobby, 3) empty := new(Query) - c.Request().URI().SetQueryString("") + c.Context().URI().SetQueryString("") require.NoError(t, c.Bind().Query(empty)) require.Empty(t, empty.Hobby) @@ -63,7 +63,7 @@ func Test_Bind_Query(t *testing.T) { No []int64 } - c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1") q2 := new(Query2) q2.Bool = true q2.Name = helloWorld @@ -81,14 +81,14 @@ func Test_Bind_Query(t *testing.T) { Name string `query:"name,required"` } rq := new(RequiredQuery) - c.Request().URI().SetQueryString("") + c.Context().URI().SetQueryString("") require.Equal(t, "name is empty", c.Bind().Query(rq).Error()) type ArrayQuery struct { Data []string } aq := new(ArrayQuery) - c.Request().URI().SetQueryString("data[]=john&data[]=doe") + c.Context().URI().SetQueryString("data[]=john&data[]=doe") require.NoError(t, c.Bind().Query(aq)) require.Len(t, aq.Data, 2) } @@ -100,35 +100,35 @@ func Test_Bind_Query_Map(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") - c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football") q := make(map[string][]string) require.NoError(t, c.Bind().Query(&q)) require.Len(t, q["hobby"], 2) - c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=basketball,football") q = make(map[string][]string) require.NoError(t, c.Bind().Query(&q)) require.Len(t, q["hobby"], 2) - c.Request().URI().SetQueryString("id=1&name=tom&hobby=scoccer&hobby=basketball,football") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=scoccer&hobby=basketball,football") q = make(map[string][]string) require.NoError(t, c.Bind().Query(&q)) require.Len(t, q["hobby"], 3) - c.Request().URI().SetQueryString("id=1&name=tom&hobby=scoccer") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=scoccer") qq := make(map[string]string) require.NoError(t, c.Bind().Query(&qq)) require.Equal(t, "1", qq["id"]) empty := make(map[string][]string) - c.Request().URI().SetQueryString("") + c.Context().URI().SetQueryString("") require.NoError(t, c.Bind().Query(&empty)) require.Empty(t, empty["hobby"]) em := make(map[string][]int) - c.Request().URI().SetQueryString("") + c.Context().URI().SetQueryString("") require.ErrorIs(t, c.Bind().Query(&em), binder.ErrMapNotConvertable) } @@ -164,18 +164,18 @@ func Test_Bind_Query_WithSetParserDecoder(t *testing.T) { Body string `query:"body"` } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") q := new(NonRFCTimeInput) - c.Request().URI().SetQueryString("date=2021-04-10&title=CustomDateTest&Body=October") + c.Context().URI().SetQueryString("date=2021-04-10&title=CustomDateTest&Body=October") require.NoError(t, c.Bind().Query(q)) require.Equal(t, "CustomDateTest", q.Title) date := fmt.Sprintf("%v", q.Date) require.Equal(t, "{0 63753609600 }", date) require.Equal(t, "October", q.Body) - c.Request().URI().SetQueryString("date=2021-04-10&title&Body=October") + c.Context().URI().SetQueryString("date=2021-04-10&title&Body=October") q = &NonRFCTimeInput{ Title: "Existing title", Body: "Existing Body", @@ -196,21 +196,21 @@ func Test_Bind_Query_Schema(t *testing.T) { Age int `query:"age"` } `query:"nested,required"` } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") - c.Request().URI().SetQueryString("name=tom&nested.age=10") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") + c.Context().URI().SetQueryString("name=tom&nested.age=10") q := new(Query1) require.NoError(t, c.Bind().Query(q)) - c.Request().URI().SetQueryString("namex=tom&nested.age=10") + c.Context().URI().SetQueryString("namex=tom&nested.age=10") q = new(Query1) require.Equal(t, "name is empty", c.Bind().Query(q).Error()) - c.Request().URI().SetQueryString("name=tom&nested.agex=10") + c.Context().URI().SetQueryString("name=tom&nested.agex=10") q = new(Query1) require.NoError(t, c.Bind().Query(q)) - c.Request().URI().SetQueryString("name=tom&test.age=10") + c.Context().URI().SetQueryString("name=tom&test.age=10") q = new(Query1) require.Equal(t, "nested is empty", c.Bind().Query(q).Error()) @@ -220,19 +220,19 @@ func Test_Bind_Query_Schema(t *testing.T) { Age int `query:"age,required"` } `query:"nested"` } - c.Request().URI().SetQueryString("name=tom&nested.age=10") + c.Context().URI().SetQueryString("name=tom&nested.age=10") q2 := new(Query2) require.NoError(t, c.Bind().Query(q2)) - c.Request().URI().SetQueryString("nested.age=10") + c.Context().URI().SetQueryString("nested.age=10") q2 = new(Query2) require.NoError(t, c.Bind().Query(q2)) - c.Request().URI().SetQueryString("nested.agex=10") + c.Context().URI().SetQueryString("nested.agex=10") q2 = new(Query2) require.Equal(t, "nested.age is empty", c.Bind().Query(q2).Error()) - c.Request().URI().SetQueryString("nested.agex=10") + c.Context().URI().SetQueryString("nested.agex=10") q2 = new(Query2) require.Equal(t, "nested.age is empty", c.Bind().Query(q2).Error()) @@ -240,17 +240,17 @@ func Test_Bind_Query_Schema(t *testing.T) { Value int `query:"val,required"` Next *Node `query:"next,required"` } - c.Request().URI().SetQueryString("val=1&next.val=3") + c.Context().URI().SetQueryString("val=1&next.val=3") n := new(Node) require.NoError(t, c.Bind().Query(n)) require.Equal(t, 1, n.Value) require.Equal(t, 3, n.Next.Value) - c.Request().URI().SetQueryString("next.val=2") + c.Context().URI().SetQueryString("next.val=2") n = new(Node) require.Equal(t, "val is empty", c.Bind().Query(n).Error()) - c.Request().URI().SetQueryString("val=3&next.value=2") + c.Context().URI().SetQueryString("val=3&next.value=2") n = new(Node) n.Next = new(Node) require.NoError(t, c.Bind().Query(n)) @@ -266,7 +266,7 @@ func Test_Bind_Query_Schema(t *testing.T) { Data []Person `query:"data"` } - c.Request().URI().SetQueryString("data[0][name]=john&data[0][age]=10&data[1][name]=doe&data[1][age]=12") + c.Context().URI().SetQueryString("data[0][name]=john&data[0][age]=10&data[1][name]=doe&data[1][age]=12") cq := new(CollectionQuery) require.NoError(t, c.Bind().Query(cq)) require.Len(t, cq.Data, 2) @@ -275,7 +275,7 @@ func Test_Bind_Query_Schema(t *testing.T) { require.Equal(t, "doe", cq.Data[1].Name) require.Equal(t, 12, cq.Data[1].Age) - c.Request().URI().SetQueryString("data.0.name=john&data.0.age=10&data.1.name=doe&data.1.age=12") + c.Context().URI().SetQueryString("data.0.name=john&data.0.age=10&data.1.name=doe&data.1.age=12") cq = new(CollectionQuery) require.NoError(t, c.Bind().Query(cq)) require.Len(t, cq.Data, 2) @@ -296,24 +296,24 @@ func Test_Bind_Header(t *testing.T) { Name string Hobby []string } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") - c.Request().Header.Add("id", "1") - c.Request().Header.Add("Name", "John Doe") - c.Request().Header.Add("Hobby", "golang,fiber") + c.Context().Request.Header.Add("id", "1") + c.Context().Request.Header.Add("Name", "John Doe") + c.Context().Request.Header.Add("Hobby", "golang,fiber") q := new(Header) require.NoError(t, c.Bind().Header(q)) require.Len(t, q.Hobby, 2) - c.Request().Header.Del("hobby") - c.Request().Header.Add("Hobby", "golang,fiber,go") + c.Context().Request.Header.Del("hobby") + c.Context().Request.Header.Add("Hobby", "golang,fiber,go") q = new(Header) require.NoError(t, c.Bind().Header(q)) require.Len(t, q.Hobby, 3) empty := new(Header) - c.Request().Header.Del("hobby") + c.Context().Request.Header.Del("hobby") require.NoError(t, c.Bind().Query(empty)) require.Empty(t, empty.Hobby) @@ -328,13 +328,13 @@ func Test_Bind_Header(t *testing.T) { No []int64 } - 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") + c.Context().Request.Header.Add("id", "2") + c.Context().Request.Header.Add("Name", "Jane Doe") + c.Context().Request.Header.Del("hobby") + c.Context().Request.Header.Add("Hobby", "go,fiber") + c.Context().Request.Header.Add("favouriteDrinks", "milo,coke,pepsi") + c.Context().Request.Header.Add("alloc", "") + c.Context().Request.Header.Add("no", "1") h2 := new(Header2) h2.Bool = true @@ -353,7 +353,7 @@ func Test_Bind_Header(t *testing.T) { Name string `header:"name,required"` } rh := new(RequiredHeader) - c.Request().Header.Del("name") + c.Context().Request.Header.Del("name") require.Equal(t, "name is empty", c.Bind().Header(rh).Error()) } @@ -364,24 +364,24 @@ func Test_Bind_Header_Map(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") - c.Request().Header.Add("id", "1") - c.Request().Header.Add("Name", "John Doe") - c.Request().Header.Add("Hobby", "golang,fiber") + c.Context().Request.Header.Add("id", "1") + c.Context().Request.Header.Add("Name", "John Doe") + c.Context().Request.Header.Add("Hobby", "golang,fiber") q := make(map[string][]string, 0) require.NoError(t, c.Bind().Header(&q)) require.Len(t, q["Hobby"], 2) - c.Request().Header.Del("hobby") - c.Request().Header.Add("Hobby", "golang,fiber,go") + c.Context().Request.Header.Del("hobby") + c.Context().Request.Header.Add("Hobby", "golang,fiber,go") q = make(map[string][]string, 0) require.NoError(t, c.Bind().Header(&q)) require.Len(t, q["Hobby"], 3) empty := make(map[string][]string, 0) - c.Request().Header.Del("hobby") + c.Context().Request.Header.Del("hobby") require.NoError(t, c.Bind().Query(&empty)) require.Empty(t, empty["Hobby"]) } @@ -418,13 +418,13 @@ func Test_Bind_Header_WithSetParserDecoder(t *testing.T) { Body string `req:"body"` } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") r := new(NonRFCTimeInput) - c.Request().Header.Add("Date", "2021-04-10") - c.Request().Header.Add("Title", "CustomDateTest") - c.Request().Header.Add("Body", "October") + c.Context().Request.Header.Add("Date", "2021-04-10") + c.Context().Request.Header.Add("Title", "CustomDateTest") + c.Context().Request.Header.Add("Body", "October") require.NoError(t, c.Bind().Header(r)) require.Equal(t, "CustomDateTest", r.Title) @@ -432,7 +432,7 @@ func Test_Bind_Header_WithSetParserDecoder(t *testing.T) { require.Equal(t, "{0 63753609600 }", date) require.Equal(t, "October", r.Body) - c.Request().Header.Add("Title", "") + c.Context().Request.Header.Add("Title", "") r = &NonRFCTimeInput{ Title: "Existing title", Body: "Existing Body", @@ -453,30 +453,30 @@ func Test_Bind_Header_Schema(t *testing.T) { Age int `header:"Age"` } `header:"Nested,required"` } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") - c.Request().Header.Add("Name", "tom") - c.Request().Header.Add("Nested.Age", "10") + c.Context().Request.Header.Add("Name", "tom") + c.Context().Request.Header.Add("Nested.Age", "10") q := new(Header1) require.NoError(t, c.Bind().Header(q)) - c.Request().Header.Del("Name") + c.Context().Request.Header.Del("Name") q = new(Header1) require.Equal(t, "Name is empty", c.Bind().Header(q).Error()) - c.Request().Header.Add("Name", "tom") - c.Request().Header.Del("Nested.Age") - c.Request().Header.Add("Nested.Agex", "10") + c.Context().Request.Header.Add("Name", "tom") + c.Context().Request.Header.Del("Nested.Age") + c.Context().Request.Header.Add("Nested.Agex", "10") q = new(Header1) require.NoError(t, c.Bind().Header(q)) - c.Request().Header.Del("Nested.Agex") + c.Context().Request.Header.Del("Nested.Agex") q = new(Header1) require.Equal(t, "Nested is empty", c.Bind().Header(q).Error()) - c.Request().Header.Del("Nested.Agex") - c.Request().Header.Del("Name") + c.Context().Request.Header.Del("Nested.Agex") + c.Context().Request.Header.Del("Name") type Header2 struct { Name string `header:"Name"` @@ -485,19 +485,19 @@ func Test_Bind_Header_Schema(t *testing.T) { } `header:"Nested"` } - c.Request().Header.Add("Name", "tom") - c.Request().Header.Add("Nested.Age", "10") + c.Context().Request.Header.Add("Name", "tom") + c.Context().Request.Header.Add("Nested.Age", "10") h2 := new(Header2) require.NoError(t, c.Bind().Header(h2)) - c.Request().Header.Del("Name") + c.Context().Request.Header.Del("Name") h2 = new(Header2) require.NoError(t, c.Bind().Header(h2)) - c.Request().Header.Del("Name") - c.Request().Header.Del("Nested.Age") - c.Request().Header.Add("Nested.Agex", "10") + c.Context().Request.Header.Del("Name") + c.Context().Request.Header.Del("Nested.Age") + c.Context().Request.Header.Add("Nested.Agex", "10") h2 = new(Header2) require.Equal(t, "Nested.age is empty", c.Bind().Header(h2).Error()) @@ -505,20 +505,20 @@ func Test_Bind_Header_Schema(t *testing.T) { Value int `header:"Val,required"` Next *Node `header:"Next,required"` } - c.Request().Header.Add("Val", "1") - c.Request().Header.Add("Next.Val", "3") + c.Context().Request.Header.Add("Val", "1") + c.Context().Request.Header.Add("Next.Val", "3") n := new(Node) require.NoError(t, c.Bind().Header(n)) require.Equal(t, 1, n.Value) require.Equal(t, 3, n.Next.Value) - c.Request().Header.Del("Val") + c.Context().Request.Header.Del("Val") n = new(Node) require.Equal(t, "Val is empty", c.Bind().Header(n).Error()) - c.Request().Header.Add("Val", "3") - c.Request().Header.Del("Next.Val") - c.Request().Header.Add("Next.Value", "2") + c.Context().Request.Header.Add("Val", "3") + c.Context().Request.Header.Del("Next.Val") + c.Context().Request.Header.Add("Next.Value", "2") n = new(Node) n.Next = new(Node) require.NoError(t, c.Bind().Header(n)) @@ -537,8 +537,8 @@ func Test_Bind_RespHeader(t *testing.T) { Name string Hobby []string } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") c.Response().Header.Add("id", "1") c.Response().Header.Add("Name", "John Doe") @@ -605,8 +605,8 @@ func Test_Bind_RespHeader_Map(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") c.Response().Header.Add("id", "1") c.Response().Header.Add("Name", "John Doe") @@ -639,9 +639,9 @@ func Benchmark_Bind_Query(b *testing.B) { Name string Hobby []string } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") - c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football") q := new(Query) b.ReportAllocs() b.ResetTimer() @@ -658,9 +658,9 @@ func Benchmark_Bind_Query_Map(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") - c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football") q := make(map[string][]string) b.ReportAllocs() b.ResetTimer() @@ -686,9 +686,9 @@ func Benchmark_Bind_Query_WithParseParam(b *testing.B) { Data []Person `query:"data"` } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") - c.Request().URI().SetQueryString("data[0][name]=john&data[0][age]=10") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") + c.Context().URI().SetQueryString("data[0][name]=john&data[0][age]=10") cq := new(CollectionQuery) b.ReportAllocs() @@ -712,9 +712,9 @@ func Benchmark_Bind_Query_Comma(b *testing.B) { Name string Hobby []string } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") - c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=basketball,football") q := new(Query) b.ReportAllocs() b.ResetTimer() @@ -736,12 +736,12 @@ func Benchmark_Bind_Header(b *testing.B) { Name string Hobby []string } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") - c.Request().Header.Add("id", "1") - c.Request().Header.Add("Name", "John Doe") - c.Request().Header.Add("Hobby", "golang,fiber") + c.Context().Request.Header.Add("id", "1") + c.Context().Request.Header.Add("Name", "John Doe") + c.Context().Request.Header.Add("Hobby", "golang,fiber") q := new(ReqHeader) b.ReportAllocs() @@ -758,12 +758,12 @@ func Benchmark_Bind_Header_Map(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") - c.Request().Header.Add("id", "1") - c.Request().Header.Add("Name", "John Doe") - c.Request().Header.Add("Hobby", "golang,fiber") + c.Context().Request.Header.Add("id", "1") + c.Context().Request.Header.Add("Name", "John Doe") + c.Context().Request.Header.Add("Hobby", "golang,fiber") q := make(map[string][]string) b.ReportAllocs() @@ -786,8 +786,8 @@ func Benchmark_Bind_RespHeader(b *testing.B) { Name string Hobby []string } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") c.Response().Header.Add("id", "1") c.Response().Header.Add("Name", "John Doe") @@ -808,8 +808,8 @@ func Benchmark_Bind_RespHeader_Map(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") c.Response().Header.Add("id", "1") c.Response().Header.Add("Name", "John Doe") @@ -842,20 +842,20 @@ func Test_Bind_Body(t *testing.T) { err = w.Close() require.NoError(t, err) - c.Request().Header.SetContentType(MIMEApplicationJSON) - c.Request().Header.Set(HeaderContentEncoding, "gzip") - c.Request().SetBody(gzipJSON.Bytes()) - c.Request().Header.SetContentLength(len(gzipJSON.Bytes())) + c.Context().Request.Header.SetContentType(MIMEApplicationJSON) + c.Context().Request.Header.SetContentEncoding("gzip") + c.Context().Request.SetBody(gzipJSON.Bytes()) + c.Context().Request.Header.SetContentLength(len(gzipJSON.Bytes())) d := new(Demo) require.NoError(t, c.Bind().Body(d)) require.Equal(t, "john", d.Name) - c.Request().Header.Del(HeaderContentEncoding) + c.Context().Request.Header.Del(HeaderContentEncoding) } testDecodeParser := func(contentType, body string) { - c.Request().Header.SetContentType(contentType) - c.Request().SetBody([]byte(body)) - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.Header.SetContentType(contentType) + c.Context().Request.SetBody([]byte(body)) + c.Context().Request.Header.SetContentLength(len(body)) d := new(Demo) require.NoError(t, c.Bind().Body(d)) require.Equal(t, "john", d.Name) @@ -867,9 +867,9 @@ func Test_Bind_Body(t *testing.T) { testDecodeParser(MIMEMultipartForm+`;boundary="b"`, "--b\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\njohn\r\n--b--") testDecodeParserError := func(contentType, body string) { - c.Request().Header.SetContentType(contentType) - c.Request().SetBody([]byte(body)) - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.Header.SetContentType(contentType) + c.Context().Request.SetBody([]byte(body)) + c.Context().Request.Header.SetContentLength(len(body)) require.Error(t, c.Bind().Body(nil)) } @@ -880,20 +880,20 @@ func Test_Bind_Body(t *testing.T) { Data []Demo `query:"data"` } - c.Request().Reset() - c.Request().Header.SetContentType(MIMEApplicationForm) - c.Request().SetBody([]byte("data[0][name]=john&data[1][name]=doe")) - c.Request().Header.SetContentLength(len(c.Body())) + c.Context().Request.Reset() + c.Context().Request.Header.SetContentType(MIMEApplicationForm) + c.Context().Request.SetBody([]byte("data[0][name]=john&data[1][name]=doe")) + c.Context().Request.Header.SetContentLength(len(c.Body())) cq := new(CollectionQuery) require.NoError(t, c.Bind().Body(cq)) require.Len(t, cq.Data, 2) require.Equal(t, "john", cq.Data[0].Name) require.Equal(t, "doe", cq.Data[1].Name) - c.Request().Reset() - c.Request().Header.SetContentType(MIMEApplicationForm) - c.Request().SetBody([]byte("data.0.name=john&data.1.name=doe")) - c.Request().Header.SetContentLength(len(c.Body())) + c.Context().Request.Reset() + c.Context().Request.Header.SetContentType(MIMEApplicationForm) + c.Context().Request.SetBody([]byte("data.0.name=john&data.1.name=doe")) + c.Context().Request.Header.SetContentLength(len(c.Body())) cq = new(CollectionQuery) require.NoError(t, c.Bind().Body(cq)) require.Len(t, cq.Data, 2) @@ -934,9 +934,9 @@ func Test_Bind_Body_WithSetParserDecoder(t *testing.T) { } testDecodeParser := func(contentType, body string) { - c.Request().Header.SetContentType(contentType) - c.Request().SetBody([]byte(body)) - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.Header.SetContentType(contentType) + c.Context().Request.SetBody([]byte(body)) + c.Context().Request.Header.SetContentLength(len(body)) d := Demo{ Title: "Existing title", Body: "Existing Body", @@ -963,9 +963,9 @@ func Benchmark_Bind_Body_JSON(b *testing.B) { Name string `json:"name"` } body := []byte(`{"name":"john"}`) - c.Request().SetBody(body) - c.Request().Header.SetContentType(MIMEApplicationJSON) - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.SetBody(body) + c.Context().Request.Header.SetContentType(MIMEApplicationJSON) + c.Context().Request.Header.SetContentLength(len(body)) d := new(Demo) b.ReportAllocs() @@ -989,9 +989,9 @@ func Benchmark_Bind_Body_XML(b *testing.B) { Name string `xml:"name"` } body := []byte("john") - c.Request().SetBody(body) - c.Request().Header.SetContentType(MIMEApplicationXML) - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.SetBody(body) + c.Context().Request.Header.SetContentType(MIMEApplicationXML) + c.Context().Request.Header.SetContentLength(len(body)) d := new(Demo) b.ReportAllocs() @@ -1015,9 +1015,9 @@ func Benchmark_Bind_Body_Form(b *testing.B) { Name string `form:"name"` } body := []byte("name=john") - c.Request().SetBody(body) - c.Request().Header.SetContentType(MIMEApplicationForm) - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.SetBody(body) + c.Context().Request.Header.SetContentType(MIMEApplicationForm) + c.Context().Request.Header.SetContentLength(len(body)) d := new(Demo) b.ReportAllocs() @@ -1042,9 +1042,9 @@ func Benchmark_Bind_Body_MultipartForm(b *testing.B) { } body := []byte("--b\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\njohn\r\n--b--") - c.Request().SetBody(body) - c.Request().Header.SetContentType(MIMEMultipartForm + `;boundary="b"`) - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.SetBody(body) + c.Context().Request.Header.SetContentType(MIMEMultipartForm + `;boundary="b"`) + c.Context().Request.Header.SetContentLength(len(body)) d := new(Demo) b.ReportAllocs() @@ -1065,9 +1065,9 @@ func Benchmark_Bind_Body_Form_Map(b *testing.B) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) body := []byte("name=john") - c.Request().SetBody(body) - c.Request().Header.SetContentType(MIMEApplicationForm) - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.SetBody(body) + c.Context().Request.Header.SetContentType(MIMEApplicationForm) + c.Context().Request.Header.SetContentLength(len(body)) d := make(map[string]string) b.ReportAllocs() @@ -1132,12 +1132,12 @@ func Benchmark_Bind_URI(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.route = &Route{ + c.req.route = &Route{ Params: []string{ "param1", "param2", "param3", "param4", }, } - c.values = [maxParams]string{ + c.req.values = [maxParams]string{ "john", "doe", "is", "awesome", } @@ -1169,12 +1169,12 @@ func Benchmark_Bind_URI_Map(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.route = &Route{ + c.req.route = &Route{ Params: []string{ "param1", "param2", "param3", "param4", }, } - c.values = [maxParams]string{ + c.req.values = [maxParams]string{ "john", "doe", "is", "awesome", } @@ -1206,24 +1206,24 @@ func Test_Bind_Cookie(t *testing.T) { Name string Hobby []string } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") - c.Request().Header.SetCookie("id", "1") - c.Request().Header.SetCookie("Name", "John Doe") - c.Request().Header.SetCookie("Hobby", "golang,fiber") + c.Context().Request.Header.SetCookie("id", "1") + c.Context().Request.Header.SetCookie("Name", "John Doe") + c.Context().Request.Header.SetCookie("Hobby", "golang,fiber") q := new(Cookie) require.NoError(t, c.Bind().Cookie(q)) require.Len(t, q.Hobby, 2) - c.Request().Header.DelCookie("hobby") - c.Request().Header.SetCookie("Hobby", "golang,fiber,go") + c.Context().Request.Header.DelCookie("hobby") + c.Context().Request.Header.SetCookie("Hobby", "golang,fiber,go") q = new(Cookie) require.NoError(t, c.Bind().Cookie(q)) require.Len(t, q.Hobby, 3) empty := new(Cookie) - c.Request().Header.DelCookie("hobby") + c.Context().Request.Header.DelCookie("hobby") require.NoError(t, c.Bind().Query(empty)) require.Empty(t, empty.Hobby) @@ -1238,13 +1238,13 @@ func Test_Bind_Cookie(t *testing.T) { No []int64 } - c.Request().Header.SetCookie("id", "2") - c.Request().Header.SetCookie("Name", "Jane Doe") - c.Request().Header.DelCookie("hobby") - c.Request().Header.SetCookie("Hobby", "go,fiber") - c.Request().Header.SetCookie("favouriteDrinks", "milo,coke,pepsi") - c.Request().Header.SetCookie("alloc", "") - c.Request().Header.SetCookie("no", "1") + c.Context().Request.Header.SetCookie("id", "2") + c.Context().Request.Header.SetCookie("Name", "Jane Doe") + c.Context().Request.Header.DelCookie("hobby") + c.Context().Request.Header.SetCookie("Hobby", "go,fiber") + c.Context().Request.Header.SetCookie("favouriteDrinks", "milo,coke,pepsi") + c.Context().Request.Header.SetCookie("alloc", "") + c.Context().Request.Header.SetCookie("no", "1") h2 := new(Cookie2) h2.Bool = true @@ -1263,7 +1263,7 @@ func Test_Bind_Cookie(t *testing.T) { Name string `cookie:"name,required"` } rh := new(RequiredCookie) - c.Request().Header.DelCookie("name") + c.Context().Request.Header.DelCookie("name") require.Equal(t, "name is empty", c.Bind().Cookie(rh).Error()) } @@ -1274,24 +1274,24 @@ func Test_Bind_Cookie_Map(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") - c.Request().Header.SetCookie("id", "1") - c.Request().Header.SetCookie("Name", "John Doe") - c.Request().Header.SetCookie("Hobby", "golang,fiber") + c.Context().Request.Header.SetCookie("id", "1") + c.Context().Request.Header.SetCookie("Name", "John Doe") + c.Context().Request.Header.SetCookie("Hobby", "golang,fiber") q := make(map[string][]string) require.NoError(t, c.Bind().Cookie(&q)) require.Len(t, q["Hobby"], 2) - c.Request().Header.DelCookie("hobby") - c.Request().Header.SetCookie("Hobby", "golang,fiber,go") + c.Context().Request.Header.DelCookie("hobby") + c.Context().Request.Header.SetCookie("Hobby", "golang,fiber,go") q = make(map[string][]string) require.NoError(t, c.Bind().Cookie(&q)) require.Len(t, q["Hobby"], 3) empty := make(map[string][]string) - c.Request().Header.DelCookie("hobby") + c.Context().Request.Header.DelCookie("hobby") require.NoError(t, c.Bind().Query(&empty)) require.Empty(t, empty["Hobby"]) } @@ -1328,13 +1328,13 @@ func Test_Bind_Cookie_WithSetParserDecoder(t *testing.T) { Body string `cerez:"body"` } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") r := new(NonRFCTimeInput) - c.Request().Header.SetCookie("Date", "2021-04-10") - c.Request().Header.SetCookie("Title", "CustomDateTest") - c.Request().Header.SetCookie("Body", "October") + c.Context().Request.Header.SetCookie("Date", "2021-04-10") + c.Context().Request.Header.SetCookie("Title", "CustomDateTest") + c.Context().Request.Header.SetCookie("Body", "October") require.NoError(t, c.Bind().Cookie(r)) require.Equal(t, "CustomDateTest", r.Title) @@ -1342,7 +1342,7 @@ func Test_Bind_Cookie_WithSetParserDecoder(t *testing.T) { require.Equal(t, "{0 63753609600 }", date) require.Equal(t, "October", r.Body) - c.Request().Header.SetCookie("Title", "") + c.Context().Request.Header.SetCookie("Title", "") r = &NonRFCTimeInput{ Title: "Existing title", Body: "Existing Body", @@ -1364,30 +1364,30 @@ func Test_Bind_Cookie_Schema(t *testing.T) { Age int `cookie:"Age"` } `cookie:"Nested,required"` } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") - c.Request().Header.SetCookie("Name", "tom") - c.Request().Header.SetCookie("Nested.Age", "10") + c.Context().Request.Header.SetCookie("Name", "tom") + c.Context().Request.Header.SetCookie("Nested.Age", "10") q := new(Cookie1) require.NoError(t, c.Bind().Cookie(q)) - c.Request().Header.DelCookie("Name") + c.Context().Request.Header.DelCookie("Name") q = new(Cookie1) require.Equal(t, "Name is empty", c.Bind().Cookie(q).Error()) - c.Request().Header.SetCookie("Name", "tom") - c.Request().Header.DelCookie("Nested.Age") - c.Request().Header.SetCookie("Nested.Agex", "10") + c.Context().Request.Header.SetCookie("Name", "tom") + c.Context().Request.Header.DelCookie("Nested.Age") + c.Context().Request.Header.SetCookie("Nested.Agex", "10") q = new(Cookie1) require.NoError(t, c.Bind().Cookie(q)) - c.Request().Header.DelCookie("Nested.Agex") + c.Context().Request.Header.DelCookie("Nested.Agex") q = new(Cookie1) require.Equal(t, "Nested is empty", c.Bind().Cookie(q).Error()) - c.Request().Header.DelCookie("Nested.Agex") - c.Request().Header.DelCookie("Name") + c.Context().Request.Header.DelCookie("Nested.Agex") + c.Context().Request.Header.DelCookie("Name") type Cookie2 struct { Name string `cookie:"Name"` @@ -1396,19 +1396,19 @@ func Test_Bind_Cookie_Schema(t *testing.T) { } `cookie:"Nested"` } - c.Request().Header.SetCookie("Name", "tom") - c.Request().Header.SetCookie("Nested.Age", "10") + c.Context().Request.Header.SetCookie("Name", "tom") + c.Context().Request.Header.SetCookie("Nested.Age", "10") h2 := new(Cookie2) require.NoError(t, c.Bind().Cookie(h2)) - c.Request().Header.DelCookie("Name") + c.Context().Request.Header.DelCookie("Name") h2 = new(Cookie2) require.NoError(t, c.Bind().Cookie(h2)) - c.Request().Header.DelCookie("Name") - c.Request().Header.DelCookie("Nested.Age") - c.Request().Header.SetCookie("Nested.Agex", "10") + c.Context().Request.Header.DelCookie("Name") + c.Context().Request.Header.DelCookie("Nested.Age") + c.Context().Request.Header.SetCookie("Nested.Agex", "10") h2 = new(Cookie2) require.Equal(t, "Nested.Age is empty", c.Bind().Cookie(h2).Error()) @@ -1416,20 +1416,20 @@ func Test_Bind_Cookie_Schema(t *testing.T) { Value int `cookie:"Val,required"` Next *Node `cookie:"Next,required"` } - c.Request().Header.SetCookie("Val", "1") - c.Request().Header.SetCookie("Next.Val", "3") + c.Context().Request.Header.SetCookie("Val", "1") + c.Context().Request.Header.SetCookie("Next.Val", "3") n := new(Node) require.NoError(t, c.Bind().Cookie(n)) require.Equal(t, 1, n.Value) require.Equal(t, 3, n.Next.Value) - c.Request().Header.DelCookie("Val") + c.Context().Request.Header.DelCookie("Val") n = new(Node) require.Equal(t, "Val is empty", c.Bind().Cookie(n).Error()) - c.Request().Header.SetCookie("Val", "3") - c.Request().Header.DelCookie("Next.Val") - c.Request().Header.SetCookie("Next.Value", "2") + c.Context().Request.Header.SetCookie("Val", "3") + c.Context().Request.Header.DelCookie("Next.Val") + c.Context().Request.Header.SetCookie("Next.Value", "2") n = new(Node) n.Next = new(Node) require.NoError(t, c.Bind().Cookie(n)) @@ -1449,12 +1449,12 @@ func Benchmark_Bind_Cookie(b *testing.B) { Name string Hobby []string } - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") - c.Request().Header.SetCookie("id", "1") - c.Request().Header.SetCookie("Name", "John Doe") - c.Request().Header.SetCookie("Hobby", "golang,fiber") + c.Context().Request.Header.SetCookie("id", "1") + c.Context().Request.Header.SetCookie("Name", "John Doe") + c.Context().Request.Header.SetCookie("Hobby", "golang,fiber") q := new(Cookie) b.ReportAllocs() @@ -1473,12 +1473,12 @@ func Benchmark_Bind_Cookie_Map(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") - c.Request().Header.SetCookie("id", "1") - c.Request().Header.SetCookie("Name", "John Doe") - c.Request().Header.SetCookie("Hobby", "golang,fiber") + c.Context().Request.Header.SetCookie("id", "1") + c.Context().Request.Header.SetCookie("Name", "John Doe") + c.Context().Request.Header.SetCookie("Hobby", "golang,fiber") q := make(map[string][]string) b.ReportAllocs() @@ -1518,9 +1518,9 @@ func Test_Bind_CustomBinder(t *testing.T) { Name string `json:"name"` } body := []byte(`{"name":"john"}`) - c.Request().SetBody(body) - c.Request().Header.SetContentType("test") - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.SetBody(body) + c.Context().Request.Header.SetContentType("test") + c.Context().Request.Header.SetContentLength(len(body)) d := new(Demo) require.NoError(t, c.Bind().Body(d)) @@ -1538,7 +1538,7 @@ func Test_Bind_Must(t *testing.T) { Name string `query:"name,required"` } rq := new(RequiredQuery) - c.Request().URI().SetQueryString("") + c.Context().URI().SetQueryString("") err := c.Bind().Must().Query(rq) require.Equal(t, StatusBadRequest, c.Response().StatusCode()) require.Equal(t, "Bad request: name is empty", err.Error()) @@ -1575,11 +1575,11 @@ func Test_Bind_StructValidator(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) rq := new(simpleQuery) - c.Request().URI().SetQueryString("name=efe") + c.Context().URI().SetQueryString("name=efe") require.Equal(t, "you should have entered right name", c.Bind().Query(rq).Error()) rq = new(simpleQuery) - c.Request().URI().SetQueryString("name=john") + c.Context().URI().SetQueryString("name=john") require.NoError(t, c.Bind().Query(rq)) } @@ -1598,11 +1598,11 @@ func Test_Bind_RepeatParserWithSameStruct(t *testing.T) { r := new(Request) - c.Request().URI().SetQueryString("query_param=query_param") + c.Context().URI().SetQueryString("query_param=query_param") require.NoError(t, c.Bind().Query(r)) require.Equal(t, "query_param", r.QueryParam) - c.Request().Header.Add("header_param", "header_param") + c.Context().Request.Header.Add("header_param", "header_param") require.NoError(t, c.Bind().Header(r)) require.Equal(t, "header_param", r.HeaderParam) @@ -1612,18 +1612,18 @@ func Test_Bind_RepeatParserWithSameStruct(t *testing.T) { require.NoError(t, err) err = w.Close() require.NoError(t, err) - c.Request().Header.SetContentType(MIMEApplicationJSON) - c.Request().Header.Set(HeaderContentEncoding, "gzip") - c.Request().SetBody(gzipJSON.Bytes()) - c.Request().Header.SetContentLength(len(gzipJSON.Bytes())) + c.Context().Request.Header.SetContentType(MIMEApplicationJSON) + c.Context().Request.Header.SetContentEncoding("gzip") + c.Context().Request.SetBody(gzipJSON.Bytes()) + c.Context().Request.Header.SetContentLength(len(gzipJSON.Bytes())) require.NoError(t, c.Bind().Body(r)) require.Equal(t, "body_param", r.BodyParam) - c.Request().Header.Del(HeaderContentEncoding) + c.Context().Request.Header.Del(HeaderContentEncoding) testDecodeParser := func(contentType, body string) { - c.Request().Header.SetContentType(contentType) - c.Request().SetBody([]byte(body)) - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.Header.SetContentType(contentType) + c.Context().Request.SetBody([]byte(body)) + c.Context().Request.Header.SetContentLength(len(body)) require.NoError(t, c.Bind().Body(r)) require.Equal(t, "body_param", r.BodyParam) } diff --git a/client/client_test.go b/client/client_test.go index 0f81dda9e03..923ecd3955c 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -656,7 +656,7 @@ func Test_Client_UserAgent(t *testing.T) { setupApp := func() (*fiber.App, string) { app, addr := startTestServerWithPort(t, func(app *fiber.App) { app.Get("/", func(c fiber.Ctx) error { - return c.Send(c.Request().Header.UserAgent()) + return c.SendString(c.Get(fiber.HeaderUserAgent)) }) }) @@ -778,7 +778,7 @@ func Test_Client_Header(t *testing.T) { func Test_Client_Header_With_Server(t *testing.T) { handler := func(c fiber.Ctx) error { - c.Request().Header.VisitAll(func(key, value []byte) { + c.Context().Request.Header.VisitAll(func(key, value []byte) { if k := string(key); k == "K1" || k == "K2" { _, _ = c.Write(key) //nolint:errcheck // It is fine to ignore the error here _, _ = c.Write(value) //nolint:errcheck // It is fine to ignore the error here @@ -1011,7 +1011,7 @@ func Test_Client_CookieJar_Response(t *testing.T) { func Test_Client_Referer(t *testing.T) { handler := func(c fiber.Ctx) error { - return c.Send(c.Request().Header.Referer()) + return c.SendString(c.Get(fiber.HeaderReferer)) } wrapAgent := func(c *Client) { @@ -1383,7 +1383,7 @@ func Test_Replace(t *testing.T) { app, dial, start := createHelperServer(t) app.Get("/", func(c fiber.Ctx) error { - return c.SendString(string(c.Request().Header.Peek("k1"))) + return c.SendString(c.Get("k1")) }) go start() diff --git a/client/request_test.go b/client/request_test.go index e5369fbbaf3..807d78118e9 100644 --- a/client/request_test.go +++ b/client/request_test.go @@ -856,7 +856,7 @@ func Test_Request_Patch(t *testing.T) { func Test_Request_Header_With_Server(t *testing.T) { t.Parallel() handler := func(c fiber.Ctx) error { - c.Request().Header.VisitAll(func(key, value []byte) { + c.Context().Request.Header.VisitAll(func(key, value []byte) { if k := string(key); k == "K1" || k == "K2" { _, err := c.Write(key) require.NoError(t, err) @@ -886,7 +886,7 @@ func Test_Request_UserAgent_With_Server(t *testing.T) { t.Parallel() handler := func(c fiber.Ctx) error { - return c.Send(c.Request().Header.UserAgent()) + return c.SendString(c.Get(fiber.HeaderUserAgent)) } t.Run("default", func(t *testing.T) { @@ -924,7 +924,7 @@ func Test_Request_Cookie_With_Server(t *testing.T) { func Test_Request_Referer_With_Server(t *testing.T) { t.Parallel() handler := func(c fiber.Ctx) error { - return c.Send(c.Request().Header.Referer()) + return c.SendString(c.Get(fiber.HeaderReferer)) } wrapAgent := func(req *Request) { @@ -937,7 +937,7 @@ func Test_Request_Referer_With_Server(t *testing.T) { func Test_Request_QueryString_With_Server(t *testing.T) { t.Parallel() handler := func(c fiber.Ctx) error { - return c.Send(c.Request().URI().QueryString()) + return c.Send(c.Context().URI().QueryString()) } wrapAgent := func(req *Request) { @@ -975,8 +975,8 @@ func Test_Request_Body_With_Server(t *testing.T) { t.Parallel() testRequest(t, func(c fiber.Ctx) error { - require.Equal(t, "application/json", string(c.Request().Header.ContentType())) - return c.SendString(string(c.Request().Body())) + require.Equal(t, "application/json", c.Get(fiber.HeaderContentType)) + return c.SendString(string(c.Req().BodyRaw())) }, func(agent *Request) { agent.SetJSON(map[string]string{ @@ -991,8 +991,8 @@ func Test_Request_Body_With_Server(t *testing.T) { t.Parallel() testRequest(t, func(c fiber.Ctx) error { - require.Equal(t, "application/xml", string(c.Request().Header.ContentType())) - return c.SendString(string(c.Request().Body())) + require.Equal(t, "application/xml", c.Get(fiber.HeaderContentType)) + return c.SendString(string(c.Req().BodyRaw())) }, func(agent *Request) { type args struct { @@ -1010,7 +1010,7 @@ func Test_Request_Body_With_Server(t *testing.T) { t.Parallel() testRequest(t, func(c fiber.Ctx) error { - require.Equal(t, fiber.MIMEApplicationForm, string(c.Request().Header.ContentType())) + require.Equal(t, fiber.MIMEApplicationForm, c.Get(fiber.HeaderContentType)) return c.Send([]byte("foo=" + c.FormValue("foo") + "&bar=" + c.FormValue("bar") + "&fiber=" + c.FormValue("fiber"))) }, func(agent *Request) { @@ -1034,7 +1034,7 @@ func Test_Request_Body_With_Server(t *testing.T) { require.NoError(t, err) require.Equal(t, "bar", mf.Value["foo"][0]) - return c.Send(c.Request().Body()) + return c.Send(c.Req().Body()) }) go start() @@ -1126,7 +1126,7 @@ func Test_Request_Body_With_Server(t *testing.T) { reg := regexp.MustCompile(`multipart/form-data; boundary=[\-\w]{35}`) require.True(t, reg.MatchString(c.Get(fiber.HeaderContentType))) - return c.Send(c.Request().Body()) + return c.Send(c.Req().BodyRaw()) }) go start() @@ -1151,7 +1151,7 @@ func Test_Request_Body_With_Server(t *testing.T) { t.Parallel() testRequest(t, func(c fiber.Ctx) error { - return c.SendString(string(c.Request().Body())) + return c.SendString(string(c.Req().BodyRaw())) }, func(agent *Request) { agent.SetRawBody([]byte("hello")) @@ -1237,7 +1237,7 @@ func Test_Request_MaxRedirects(t *testing.T) { app := fiber.New() app.Get("/", func(c fiber.Ctx) error { - if c.Request().URI().QueryArgs().Has("foo") { + if c.Context().URI().QueryArgs().Has("foo") { return c.Redirect().To("/foo") } return c.Redirect().To("/") diff --git a/ctx.go b/ctx.go index 4be0d4f49fc..149d087ce1f 100644 --- a/ctx.go +++ b/ctx.go @@ -5,7 +5,6 @@ package fiber import ( - "bytes" "context" "crypto/tls" "errors" @@ -13,7 +12,6 @@ import ( "io" "mime/multipart" "net" - "net/http" "path/filepath" "strconv" "strings" @@ -42,20 +40,11 @@ type contextKey int const userContextKey contextKey = 0 // __local_user_context__ type DefaultCtx struct { - app *App // Reference to *App - route *Route // Reference to *Route + app *App // Reference to *App + req Request // Reference to *Request + // res *Response // Reference to *Response indexRoute int // Index of the current route indexHandler int // Index of the current handler - method string // HTTP method - methodINT int // HTTP method INT equivalent - baseURI string // HTTP base uri - path string // HTTP path with the modifications by the configuration -> string copy from pathBuffer - pathBuffer []byte // HTTP path buffer - detectionPath string // Route detection path -> string copy from detectionPathBuffer - detectionPathBuffer []byte // HTTP detectionPath buffer - treePath string // Path for the search in the tree - pathOriginal string // Original HTTP path - values [maxParams]string // Route parameter values fasthttp *fasthttp.RequestCtx // Reference to *fasthttp.RequestCtx matched bool // Non use route matched viewBindMap sync.Map // Default view map to bind template engine @@ -115,24 +104,24 @@ type ResFmt struct { Handler func(Ctx) error } -// Accepts checks if the specified extensions or content types are acceptable. +// Accepts is an alias of [Request.Accepts] func (c *DefaultCtx) Accepts(offers ...string) string { - return getOffer(c.fasthttp.Request.Header.Peek(HeaderAccept), acceptsOfferType, offers...) + return c.req.Accepts(offers...) } -// AcceptsCharsets checks if the specified charset is acceptable. +// AcceptsCharsets is an alias of [Request.AcceptsCharsets] func (c *DefaultCtx) AcceptsCharsets(offers ...string) string { - return getOffer(c.fasthttp.Request.Header.Peek(HeaderAcceptCharset), acceptsOffer, offers...) + return c.req.AcceptsCharsets(offers...) } -// AcceptsEncodings checks if the specified encoding is acceptable. +// AcceptsEncodings is an alias of [Request.AcceptsEncodings] func (c *DefaultCtx) AcceptsEncodings(offers ...string) string { - return getOffer(c.fasthttp.Request.Header.Peek(HeaderAcceptEncoding), acceptsOffer, offers...) + return c.req.AcceptsEncodings(offers...) } -// AcceptsLanguages checks if the specified language is acceptable. +// AcceptsLanguages is an alias of [Request.AcceptsLanguages] func (c *DefaultCtx) AcceptsLanguages(offers ...string) string { - return getOffer(c.fasthttp.Request.Header.Peek(HeaderAcceptLanguage), acceptsOffer, offers...) + return c.req.AcceptsLanguages(offers...) } // App returns the *App reference to the instance of the Fiber application @@ -173,117 +162,19 @@ func (c *DefaultCtx) Attachment(filename ...string) { c.setCanonical(HeaderContentDisposition, "attachment") } -// BaseURL returns (protocol + host + base path). +// BaseURL is an alias of [Request.BaseURL]. func (c *DefaultCtx) BaseURL() string { - // TODO: Could be improved: 53.8 ns/op 32 B/op 1 allocs/op - // Should work like https://codeigniter.com/user_guide/helpers/url_helper.html - if c.baseURI != "" { - return c.baseURI - } - c.baseURI = c.Scheme() + "://" + c.Host() - return c.baseURI + return c.req.BaseURL() } -// 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. +// BodyRaw is an alias of [Request.BodyRaw]. func (c *DefaultCtx) BodyRaw() []byte { - if c.app.config.Immutable { - return utils.CopyBytes(c.fasthttp.Request.Body()) - } - return c.fasthttp.Request.Body() -} - -func (c *DefaultCtx) 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 + return c.req.BodyRaw() } -// 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. +// Body is an alias of [Request.Body]. func (c *DefaultCtx) 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 { - headerEncoding = c.app.getString(value) - } - }) - - // 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 { - if c.app.config.Immutable { - return utils.CopyBytes(c.fasthttp.Request.Body()) - } - 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()) - } - - if c.app.config.Immutable { - return utils.CopyBytes(body) - } - return body + return c.req.Body() } // ClearCookie expires a specific cookie by key on the client side. @@ -355,13 +246,9 @@ func (c *DefaultCtx) Cookie(cookie *Cookie) { fasthttp.ReleaseCookie(fcookie) } -// Cookies are used for getting a cookie value by key. -// Defaults to the empty string "" if the cookie doesn't exist. -// If a default value is given, it will return that value if the cookie doesn't exist. -// The returned value is only valid within the handler. Do not store any references. -// Make copies or use the Immutable setting to use the value outside the Handler. +// Cookies is an alias of [Request.Cookies] func (c *DefaultCtx) Cookies(key string, defaultValue ...string) string { - return defaultString(c.app.getString(c.fasthttp.Request.Header.Cookie(key)), defaultValue) + return c.req.Cookies(key, defaultValue...) } // Download transfers the file from path as an attachment. @@ -379,11 +266,11 @@ func (c *DefaultCtx) Download(file string, filename ...string) error { return c.SendFile(file) } -// Request return the *fasthttp.Request object +// Req return the *fasthttp.Req object // This allows you to use all fasthttp request methods -// https://godoc.org/github.com/valyala/fasthttp#Request -func (c *DefaultCtx) Request() *fasthttp.Request { - return &c.fasthttp.Request +// https://godoc.org/github.com/valyala/fasthttp#Req +func (c *DefaultCtx) Req() *Request { + return &c.req } // Response return the *fasthttp.Response object @@ -493,71 +380,21 @@ func (c *DefaultCtx) FormValue(key string, defaultValue ...string) string { return defaultString(c.app.getString(c.fasthttp.FormValue(key)), defaultValue) } -// Fresh returns true when the response is still β€œfresh” in the client's cache, -// otherwise false is returned to indicate that the client cache is now stale -// and the full response should be sent. -// When a client sends the Cache-Control: no-cache request header to indicate an end-to-end -// reload request, this module will return false to make handling these requests transparent. -// https://github.com/jshttp/fresh/blob/10e0471669dbbfbfd8de65bc6efac2ddd0bfa057/index.js#L33 +// Fresh is an alias of [Request.Fresh] func (c *DefaultCtx) Fresh() bool { - // fields - modifiedSince := c.Get(HeaderIfModifiedSince) - noneMatch := c.Get(HeaderIfNoneMatch) - - // unconditional request - if modifiedSince == "" && noneMatch == "" { - return false - } - - // Always return stale when Cache-Control: no-cache - // to support end-to-end reload requests - // https://tools.ietf.org/html/rfc2616#section-14.9.4 - cacheControl := c.Get(HeaderCacheControl) - if cacheControl != "" && isNoCache(cacheControl) { - return false - } - - // if-none-match - if noneMatch != "" && noneMatch != "*" { - etag := c.app.getString(c.fasthttp.Response.Header.Peek(HeaderETag)) - if etag == "" { - return false - } - if c.app.isEtagStale(etag, c.app.getBytes(noneMatch)) { - return false - } - - if modifiedSince != "" { - lastModified := c.app.getString(c.fasthttp.Response.Header.Peek(HeaderLastModified)) - if lastModified != "" { - lastModifiedTime, err := http.ParseTime(lastModified) - if err != nil { - return false - } - modifiedSinceTime, err := http.ParseTime(modifiedSince) - if err != nil { - return false - } - return lastModifiedTime.Before(modifiedSinceTime) - } - } - } - return true + return c.req.Fresh() } -// Get returns the HTTP request header specified by field. -// Field names are case-insensitive -// Returned value is only valid within the handler. Do not store any references. -// Make copies or use the Immutable setting instead. +// Get is an alias of [Request.Get]. func (c *DefaultCtx) Get(key string, defaultValue ...string) string { - return GetReqHeader(c, key, defaultValue...) + return c.req.Get(key, defaultValue...) } // GetReqHeader returns the HTTP request header specified by filed. // This function is generic and can handle differnet headers type values. func GetReqHeader[V GenericType](c Ctx, key string, defaultValue ...V) V { var v V - return genericParseType[V](c.App().getString(c.Request().Header.Peek(key)), v, defaultValue...) + return genericParseType[V](c.Req().Get(key), v, defaultValue...) } // GetRespHeader returns the HTTP response header specified by field. @@ -585,38 +422,21 @@ func (c *DefaultCtx) GetRespHeaders() map[string][]string { // Make copies or use the Immutable setting instead. func (c *DefaultCtx) GetReqHeaders() map[string][]string { headers := make(map[string][]string) - c.Request().Header.VisitAll(func(k, v []byte) { + c.fasthttp.Request.Header.VisitAll(func(k, v []byte) { key := c.app.getString(k) headers[key] = append(headers[key], c.app.getString(v)) }) return headers } -// Host contains the host derived from the X-Forwarded-Host or Host HTTP header. -// Returned value is only valid within the handler. Do not store any references. -// Make copies or use the Immutable setting instead. -// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. +// Host is an alias of [Request.Host]. func (c *DefaultCtx) Host() string { - if c.IsProxyTrusted() { - if host := c.Get(HeaderXForwardedHost); len(host) > 0 { - commaPos := strings.Index(host, ",") - if commaPos != -1 { - return host[:commaPos] - } - return host - } - } - return c.app.getString(c.fasthttp.Request.URI().Host()) + return c.req.Host() } -// Hostname contains the hostname derived from the X-Forwarded-Host or Host HTTP header using the c.Host() method. -// Returned value is only valid within the handler. Do not store any references. -// Make copies or use the Immutable setting instead. -// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. +// Hostname is an alias of [Request.Hostname]. func (c *DefaultCtx) Hostname() string { - addr, _ := parseAddr(c.Host()) - - return addr + return c.req.Hostname() } // Port returns the remote port of the request. @@ -628,148 +448,19 @@ func (c *DefaultCtx) Port() string { return strconv.Itoa(tcpaddr.Port) } -// IP returns the remote IP address of the request. -// If ProxyHeader and IP Validation is configured, it will parse that header and return the first valid IP address. -// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. +// IP is an alias of [Request.IP]. func (c *DefaultCtx) IP() string { - if c.IsProxyTrusted() && len(c.app.config.ProxyHeader) > 0 { - return c.extractIPFromHeader(c.app.config.ProxyHeader) - } - - return c.fasthttp.RemoteIP().String() -} - -// extractIPsFromHeader will return a slice of IPs it found given a header name in the order they appear. -// When IP validation is enabled, any invalid IPs will be omitted. -func (c *DefaultCtx) extractIPsFromHeader(header string) []string { - // TODO: Reuse the c.extractIPFromHeader func somehow in here - - headerValue := c.Get(header) - - // We can't know how many IPs we will return, but we will try to guess with this constant division. - // Counting ',' makes function slower for about 50ns in general case. - const maxEstimatedCount = 8 - estimatedCount := len(headerValue) / maxEstimatedCount - if estimatedCount > maxEstimatedCount { - estimatedCount = maxEstimatedCount // Avoid big allocation on big header - } - - ipsFound := make([]string, 0, estimatedCount) - - i := 0 - j := -1 - -iploop: - for { - var v4, v6 bool - - // Manually splitting string without allocating slice, working with parts directly - i, j = j+1, j+2 - - if j > len(headerValue) { - break - } - - for j < len(headerValue) && headerValue[j] != ',' { - if headerValue[j] == ':' { - v6 = true - } else if headerValue[j] == '.' { - v4 = true - } - j++ - } - - for i < j && (headerValue[i] == ' ' || headerValue[i] == ',') { - i++ - } - - s := strings.TrimRight(headerValue[i:j], " ") - - if c.app.config.EnableIPValidation { - // Skip validation if IP is clearly not IPv4/IPv6, otherwise validate without allocations - if (!v6 && !v4) || (v6 && !utils.IsIPv6(s)) || (v4 && !utils.IsIPv4(s)) { - continue iploop - } - } - - ipsFound = append(ipsFound, s) - } - - return ipsFound -} - -// extractIPFromHeader will attempt to pull the real client IP from the given header when IP validation is enabled. -// currently, it will return the first valid IP address in header. -// when IP validation is disabled, it will simply return the value of the header without any inspection. -// Implementation is almost the same as in extractIPsFromHeader, but without allocation of []string. -func (c *DefaultCtx) extractIPFromHeader(header string) string { - if c.app.config.EnableIPValidation { - headerValue := c.Get(header) - - i := 0 - j := -1 - - iploop: - for { - var v4, v6 bool - - // Manually splitting string without allocating slice, working with parts directly - i, j = j+1, j+2 - - if j > len(headerValue) { - break - } - - for j < len(headerValue) && headerValue[j] != ',' { - if headerValue[j] == ':' { - v6 = true - } else if headerValue[j] == '.' { - v4 = true - } - j++ - } - - for i < j && headerValue[i] == ' ' { - i++ - } - - s := strings.TrimRight(headerValue[i:j], " ") - - if c.app.config.EnableIPValidation { - if (!v6 && !v4) || (v6 && !utils.IsIPv6(s)) || (v4 && !utils.IsIPv4(s)) { - continue iploop - } - } - - return s - } - - return c.fasthttp.RemoteIP().String() - } - - // default behavior if IP validation is not enabled is just to return whatever value is - // in the proxy header. Even if it is empty or invalid - return c.Get(c.app.config.ProxyHeader) + return c.req.IP() } -// IPs returns a string slice of IP addresses specified in the X-Forwarded-For request header. -// When IP validation is enabled, only valid IPs are returned. +// IPs is an alias of [Request.IPs]. func (c *DefaultCtx) IPs() []string { - return c.extractIPsFromHeader(HeaderXForwardedFor) + return c.req.IPs() } -// Is returns the matching content type, -// if the incoming request's Content-Type HTTP header field matches the MIME type specified by the type parameter +// Is is an alias of [Request.Is]. func (c *DefaultCtx) Is(extension string) bool { - extensionHeader := utils.GetMIME(extension) - if extensionHeader == "" { - return false - } - - return strings.HasPrefix( - strings.TrimLeft(utils.UnsafeString(c.fasthttp.Request.Header.ContentType()), " "), - extensionHeader, - ) + return c.req.Is(extension) } // JSON converts any interface or string to JSON. @@ -879,25 +570,9 @@ func (c *DefaultCtx) Location(path string) { c.setCanonical(HeaderLocation, path) } -// 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. +// Method is an alias of [Request.Method] func (c *DefaultCtx) Method(override ...string) string { - 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 + return c.Req().Method(override...) } // MultipartForm parse form entries from binary. @@ -921,9 +596,9 @@ func (c *DefaultCtx) Next() error { c.indexHandler++ var err error // Did we execute all route handlers? - if c.indexHandler < len(c.route.Handlers) { + if c.indexHandler < len(c.req.route.Handlers) { // Continue route stack - err = c.route.Handlers[c.indexHandler](c) + err = c.req.route.Handlers[c.indexHandler](c) } else { // Continue handler stack if c.app.newCtxFunc != nil { @@ -949,35 +624,14 @@ func (c *DefaultCtx) RestartRouting() error { return err } -// OriginalURL contains the original request URL. -// Returned value is only valid within the handler. Do not store any references. -// Make copies or use the Immutable setting to use the value outside the Handler. +// OriginalURL is an alias of [Request.OriginalURL] func (c *DefaultCtx) OriginalURL() string { - return c.app.getString(c.fasthttp.Request.Header.RequestURI()) + return c.req.OriginalURL() } -// Params is used to get the route parameters. -// Defaults to empty string "" if the param doesn't exist. -// If a default value is given, it will return that value if the param doesn't exist. -// Returned value is only valid within the handler. Do not store any references. -// Make copies or use the Immutable setting to use the value outside the Handler. +// Params is an alias of [Request.Params]. func (c *DefaultCtx) Params(key string, defaultValue ...string) string { - if key == "*" || key == "+" { - key += "1" - } - for i := range c.route.Params { - if len(key) != len(c.route.Params[i]) { - continue - } - if c.route.Params[i] == key || (!c.app.config.CaseSensitive && utils.EqualFold(c.route.Params[i], key)) { - // in case values are not here - if len(c.values) <= i || len(c.values[i]) == 0 { - break - } - return c.values[i] - } - } - return defaultString("", defaultValue) + return c.req.Params(key, defaultValue...) } // Params is used to get the route parameters. @@ -998,94 +652,27 @@ func Params[V GenericType](c Ctx, key string, defaultValue ...V) V { return genericParseType(c.Params(key), v, defaultValue...) } -// Path returns the path part of the request URL. -// Optionally, you could override the path. +// Path is an alias of [Request.Path]. func (c *DefaultCtx) Path(override ...string) string { - if len(override) != 0 && c.path != override[0] { - // Set new path to context - c.pathOriginal = override[0] - - // Set new path to request context - c.fasthttp.Request.URI().SetPath(c.pathOriginal) - // Prettify path - c.configDependentPaths() - } - return c.path + return c.req.Path(override...) } -// Scheme contains the request protocol string: http or https for TLS requests. -// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. +// Scheme is an alias of [Request.Scheme]. func (c *DefaultCtx) Scheme() string { - if c.fasthttp.IsTLS() { - return schemeHTTPS - } - if !c.IsProxyTrusted() { - return schemeHTTP - } - - scheme := schemeHTTP - const lenXHeaderName = 12 - c.fasthttp.Request.Header.VisitAll(func(key, val []byte) { - if len(key) < lenXHeaderName { - return // Neither "X-Forwarded-" nor "X-Url-Scheme" - } - switch { - case bytes.HasPrefix(key, []byte("X-Forwarded-")): - if bytes.Equal(key, []byte(HeaderXForwardedProto)) || - bytes.Equal(key, []byte(HeaderXForwardedProtocol)) { - v := c.app.getString(val) - commaPos := strings.Index(v, ",") - if commaPos != -1 { - scheme = v[:commaPos] - } else { - scheme = v - } - } else if bytes.Equal(key, []byte(HeaderXForwardedSsl)) && bytes.Equal(val, []byte("on")) { - scheme = schemeHTTPS - } - - case bytes.Equal(key, []byte(HeaderXUrlScheme)): - scheme = c.app.getString(val) - } - }) - return scheme + return c.req.Scheme() } -// Protocol returns the HTTP protocol of request: HTTP/1.1 and HTTP/2. +// Protocol is an alias of [Request.Protocol]. func (c *DefaultCtx) Protocol() string { - return utils.UnsafeString(c.fasthttp.Request.Header.Protocol()) + return c.req.Protocol() } -// Query returns the query string parameter in the url. -// Defaults to empty string "" if the query doesn't exist. -// If a default value is given, it will return that value if the query doesn't exist. -// Returned value is only valid within the handler. Do not store any references. -// Make copies or use the Immutable setting to use the value outside the Handler. +// Query is an alias of [Request.Query]. func (c *DefaultCtx) Query(key string, defaultValue ...string) string { - return Query[string](c, key, defaultValue...) + return c.req.Query(key, defaultValue...) } -// Queries returns a map of query parameters and their values. -// -// GET /?name=alex&wanna_cake=2&id= -// Queries()["name"] == "alex" -// Queries()["wanna_cake"] == "2" -// Queries()["id"] == "" -// -// GET /?field1=value1&field1=value2&field2=value3 -// Queries()["field1"] == "value2" -// Queries()["field2"] == "value3" -// -// GET /?list_a=1&list_a=2&list_a=3&list_b[]=1&list_b[]=2&list_b[]=3&list_c=1,2,3 -// Queries()["list_a"] == "3" -// Queries()["list_b[]"] == "3" -// Queries()["list_c"] == "1,2,3" -// -// GET /api/search?filters.author.name=John&filters.category.name=Technology&filters[customer][name]=Alice&filters[status]=pending -// Queries()["filters.author.name"] == "John" -// Queries()["filters.category.name"] == "Technology" -// Queries()["filters[customer][name]"] == "Alice" -// Queries()["filters[status]"] == "pending" +// Queries is an alias of [Request.Queries]. func (c *DefaultCtx) Queries() map[string]string { m := make(map[string]string, c.Context().QueryArgs().Len()) c.Context().QueryArgs().VisitAll(func(key, value []byte) { @@ -1117,76 +704,12 @@ func (c *DefaultCtx) Queries() map[string]string { // unknown := Query[string](c, "unknown", "default") // Returns "default" since the query parameter "unknown" is not found func Query[V GenericType](c Ctx, key string, defaultValue ...V) V { var v V - q := c.App().getString(c.Context().QueryArgs().Peek(key)) - - return genericParseType[V](q, v, defaultValue...) + return genericParseType[V](c.Req().Query(key), v, defaultValue...) } -// Range returns a struct containing the type and a slice of ranges. +// Range is an alias of [Request.Range]. func (c *DefaultCtx) Range(size int) (Range, error) { - var ( - rangeData Range - ranges string - ) - rangeStr := c.Get(HeaderRange) - - i := strings.IndexByte(rangeStr, '=') - if i == -1 || strings.Contains(rangeStr[i+1:], "=") { - return rangeData, ErrRangeMalformed - } - rangeData.Type = rangeStr[:i] - ranges = rangeStr[i+1:] - - var ( - singleRange string - moreRanges = ranges - ) - for moreRanges != "" { - singleRange = moreRanges - if i := strings.IndexByte(moreRanges, ','); i >= 0 { - singleRange = moreRanges[:i] - moreRanges = moreRanges[i+1:] - } else { - moreRanges = "" - } - - var ( - startStr, endStr string - i int - ) - if i = strings.IndexByte(singleRange, '-'); i == -1 { - return rangeData, ErrRangeMalformed - } - startStr = singleRange[:i] - endStr = singleRange[i+1:] - - start, startErr := fasthttp.ParseUint(utils.UnsafeBytes(startStr)) - end, endErr := fasthttp.ParseUint(utils.UnsafeBytes(endStr)) - if startErr != nil { // -nnn - start = size - end - end = size - 1 - } else if endErr != nil { // nnn- - end = size - 1 - } - if end > size-1 { // limit last-byte-pos to current length - end = size - 1 - } - if start > end || start < 0 { - continue - } - rangeData.Ranges = append(rangeData.Ranges, struct { - Start int - End int - }{ - start, - end, - }) - } - if len(rangeData.Ranges) < 1 { - return rangeData, ErrRangeUnsatisfiable - } - - return rangeData, nil + return c.req.Range(size) } // Redirect returns the Redirect reference. @@ -1342,19 +865,9 @@ func (c *DefaultCtx) renderExtensions(bind any) { } } -// Route returns the matched Route struct. +// Route is an alias of [Request.Route]. func (c *DefaultCtx) Route() *Route { - if c.route == nil { - // Fallback for fasthttp error handler - return &Route{ - path: c.pathOriginal, - Path: c.pathOriginal, - Method: c.method, - Handlers: make([]Handler, 0), - Params: make([]string, 0), - } - } - return c.route + return c.req.Route() } // SaveFile saves any multipart file to disk. @@ -1427,7 +940,7 @@ func (c *DefaultCtx) SendFile(file string, compress ...bool) error { }) // Keep original path for mutable params - c.pathOriginal = utils.CopyString(c.pathOriginal) + c.req.pathOriginal = utils.CopyString(c.req.pathOriginal) // Disable compression if len(compress) == 0 || !compress[0] { // https://github.com/valyala/fasthttp/blob/7cc6f4c513f9e0d3686142e0a1a5aa2f76b3194a/fs.go#L55 @@ -1531,9 +1044,9 @@ func (c *DefaultCtx) Subdomains(offset ...int) []string { return subdomains } -// Stale is not implemented yet, pull requests are welcome! +// Stale is an alias of [Request.Stale]. func (c *DefaultCtx) Stale() bool { - return !c.Fresh() + return c.req.Stale() } // Status sets the HTTP status for the response. @@ -1622,38 +1135,6 @@ func (c *DefaultCtx) XHR() bool { return utils.EqualFold(c.app.getBytes(c.Get(HeaderXRequestedWith)), []byte("xmlhttprequest")) } -// configDependentPaths set paths for route recognition and prepared paths for the user, -// here the features for caseSensitive, decoded paths, strict paths are evaluated -func (c *DefaultCtx) configDependentPaths() { - c.pathBuffer = append(c.pathBuffer[0:0], c.pathOriginal...) - // If UnescapePath enabled, we decode the path and save it for the framework user - if c.app.config.UnescapePath { - c.pathBuffer = fasthttp.AppendUnquotedArg(c.pathBuffer[:0], c.pathBuffer) - } - c.path = c.app.getString(c.pathBuffer) - - // another path is specified which is for routing recognition only - // use the path that was changed by the previous configuration flags - c.detectionPathBuffer = append(c.detectionPathBuffer[0:0], c.pathBuffer...) - // If CaseSensitive is disabled, we lowercase the original path - if !c.app.config.CaseSensitive { - c.detectionPathBuffer = utils.ToLowerBytes(c.detectionPathBuffer) - } - // If StrictRouting is disabled, we strip all trailing slashes - if !c.app.config.StrictRouting && len(c.detectionPathBuffer) > 1 && c.detectionPathBuffer[len(c.detectionPathBuffer)-1] == '/' { - c.detectionPathBuffer = bytes.TrimRight(c.detectionPathBuffer, "/") - } - c.detectionPath = c.app.getString(c.detectionPathBuffer) - - // Define the path for dividing routes into areas for fast tree detection, so that fewer routes need to be traversed, - // since the first three characters area select a list of routes - c.treePath = c.treePath[0:0] - const maxDetectionPaths = 3 - if len(c.detectionPath) >= maxDetectionPaths { - c.treePath = c.detectionPath[:maxDetectionPaths] - } -} - // IsProxyTrusted checks trustworthiness of remote ip. // If EnableTrustedProxyCheck false, it returns true // IsProxyTrusted can check remote ip by proxy ranges and ip map. diff --git a/ctx_interface.go b/ctx_interface.go index bb8cdec2607..7a61e0b7600 100644 --- a/ctx_interface.go +++ b/ctx_interface.go @@ -79,10 +79,9 @@ type Ctx interface { // Override this default with the filename parameter. Download(file string, filename ...string) error - // Request return the *fasthttp.Request object - // This allows you to use all fasthttp request methods - // https://godoc.org/github.com/valyala/fasthttp#Request - Request() *fasthttp.Request + // Req returns the [Request] object for the current request context. + // To access the underlying fasthttp request object, use [Ctx.Context]. + Req() *Request // Response return the *fasthttp.Response object // This allows you to use all fasthttp response methods @@ -401,10 +400,15 @@ type CustomCtx interface { func NewDefaultCtx(app *App) *DefaultCtx { // return ctx - return &DefaultCtx{ + ctx := &DefaultCtx{ // Set app reference app: app, + req: Request{ + app: app, + }, } + ctx.req.ctx = ctx + return ctx } func (app *App) newCtx() Ctx { @@ -445,21 +449,22 @@ func (c *DefaultCtx) Reset(fctx *fasthttp.RequestCtx) { // Reset matched flag c.matched = false // Set paths - c.pathOriginal = c.app.getString(fctx.URI().PathOriginal()) - // Set method - c.method = c.app.getString(fctx.Request.Header.Method()) - c.methodINT = c.app.methodInt(c.method) + c.req.pathOriginal = c.app.getString(fctx.URI().PathOriginal()) // Attach *fasthttp.RequestCtx to ctx c.fasthttp = fctx + c.req.fasthttp = &fctx.Request + // Set method + c.req.method = c.app.getString(fctx.Request.Header.Method()) + c.req.methodINT = c.app.methodInt(c.req.method) // reset base uri - c.baseURI = "" + c.req.baseURI = "" // Prettify path - c.configDependentPaths() + c.req.configDependentPaths() } // Release is a method to reset context fields when to use ReleaseCtx() func (c *DefaultCtx) release() { - c.route = nil + c.req.route = nil c.fasthttp = nil c.bind = nil c.redirectionMessages = c.redirectionMessages[:0] @@ -472,7 +477,7 @@ func (c *DefaultCtx) release() { // Methods to use with next stack. func (c *DefaultCtx) getMethodINT() int { - return c.methodINT + return c.req.methodINT } func (c *DefaultCtx) getIndexRoute() int { @@ -480,19 +485,19 @@ func (c *DefaultCtx) getIndexRoute() int { } func (c *DefaultCtx) getTreePath() string { - return c.treePath + return c.req.treePath } func (c *DefaultCtx) getDetectionPath() string { - return c.detectionPath + return c.req.detectionPath } func (c *DefaultCtx) getPathOriginal() string { - return c.pathOriginal + return c.req.pathOriginal } func (c *DefaultCtx) getValues() *[maxParams]string { - return &c.values + return &c.req.values } func (c *DefaultCtx) getMatched() bool { @@ -512,5 +517,5 @@ func (c *DefaultCtx) setMatched(matched bool) { } func (c *DefaultCtx) setRoute(route *Route) { - c.route = route + c.req.route = route } diff --git a/ctx_test.go b/ctx_test.go index fdd21a1672c..b6f5f69906a 100644 --- a/ctx_test.go +++ b/ctx_test.go @@ -42,17 +42,17 @@ func Test_Ctx_Accepts(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderAccept, "text/html,application/xhtml+xml,application/xml;q=0.9") + c.Context().Request.Header.Set(HeaderAccept, "text/html,application/xhtml+xml,application/xml;q=0.9") require.Equal(t, "", c.Accepts("")) require.Equal(t, "", c.Accepts()) require.Equal(t, ".xml", c.Accepts(".xml")) require.Equal(t, "", c.Accepts(".john")) require.Equal(t, "application/xhtml+xml", c.Accepts("application/xml", "application/xml+rss", "application/yaml", "application/xhtml+xml"), "must use client-preferred mime type") - c.Request().Header.Set(HeaderAccept, "application/json, text/plain, */*;q=0") + c.Context().Request.Header.Set(HeaderAccept, "application/json, text/plain, */*;q=0") require.Equal(t, "", c.Accepts("html"), "must treat */*;q=0 as not acceptable") - c.Request().Header.Set(HeaderAccept, "text/*, application/json") + c.Context().Request.Header.Set(HeaderAccept, "text/*, application/json") require.Equal(t, "html", c.Accepts("html")) require.Equal(t, "text/html", c.Accepts("text/html")) require.Equal(t, "json", c.Accepts("json", "text")) @@ -60,10 +60,10 @@ func Test_Ctx_Accepts(t *testing.T) { require.Equal(t, "", c.Accepts("image/png")) require.Equal(t, "", c.Accepts("png")) - c.Request().Header.Set(HeaderAccept, "text/html, application/json") + c.Context().Request.Header.Set(HeaderAccept, "text/html, application/json") require.Equal(t, "text/*", c.Accepts("text/*")) - c.Request().Header.Set(HeaderAccept, "*/*") + c.Context().Request.Header.Set(HeaderAccept, "*/*") require.Equal(t, "html", c.Accepts("html")) } @@ -73,7 +73,7 @@ func Benchmark_Ctx_Accepts(b *testing.B) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) acceptHeader := "text/html,application/xhtml+xml,application/xml;q=0.9" - c.Request().Header.Set("Accept", acceptHeader) + c.Context().Request.Header.Set("Accept", acceptHeader) acceptValues := [][]string{ {".xml"}, {"json", "xml"}, @@ -140,11 +140,11 @@ func Test_Ctx_Accepts_Wildcard(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderAccept, "*/*;q=0.9") + c.Context().Request.Header.Set(HeaderAccept, "*/*;q=0.9") require.Equal(t, "html", c.Accepts("html")) require.Equal(t, "foo", c.Accepts("foo")) require.Equal(t, ".bar", c.Accepts(".bar")) - c.Request().Header.Set(HeaderAccept, "text/html,application/*;q=0.9") + c.Context().Request.Header.Set(HeaderAccept, "text/html,application/*;q=0.9") require.Equal(t, "xml", c.Accepts("xml")) } @@ -154,7 +154,7 @@ func Test_Ctx_AcceptsCharsets(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderAcceptCharset, "utf-8, iso-8859-1;q=0.5") + c.Context().Request.Header.Set(HeaderAcceptCharset, "utf-8, iso-8859-1;q=0.5") require.Equal(t, "utf-8", c.AcceptsCharsets("utf-8")) } @@ -163,7 +163,7 @@ func Benchmark_Ctx_AcceptsCharsets(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set("Accept-Charset", "utf-8, iso-8859-1;q=0.5") + c.Context().Request.Header.Set("Accept-Charset", "utf-8, iso-8859-1;q=0.5") var res string b.ReportAllocs() b.ResetTimer() @@ -179,7 +179,7 @@ func Test_Ctx_AcceptsEncodings(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderAcceptEncoding, "deflate, gzip;q=1.0, *;q=0.5") + c.Context().Request.Header.Set(HeaderAcceptEncoding, "deflate, gzip;q=1.0, *;q=0.5") require.Equal(t, "gzip", c.AcceptsEncodings("gzip")) require.Equal(t, "abc", c.AcceptsEncodings("abc")) } @@ -189,7 +189,7 @@ func Benchmark_Ctx_AcceptsEncodings(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set(HeaderAcceptEncoding, "deflate, gzip;q=1.0, *;q=0.5") + c.Context().Request.Header.Set(HeaderAcceptEncoding, "deflate, gzip;q=1.0, *;q=0.5") var res string b.ReportAllocs() b.ResetTimer() @@ -205,7 +205,7 @@ func Test_Ctx_AcceptsLanguages(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderAcceptLanguage, "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5") + c.Context().Request.Header.Set(HeaderAcceptLanguage, "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5") require.Equal(t, "fr", c.AcceptsLanguages("fr")) } @@ -214,7 +214,7 @@ func Benchmark_Ctx_AcceptsLanguages(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set(HeaderAcceptLanguage, "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5") + c.Context().Request.Header.Set(HeaderAcceptLanguage, "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5") var res string b.ReportAllocs() b.ResetTimer() @@ -323,7 +323,7 @@ func Test_Ctx_BaseURL(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") + c.Context().Request.SetRequestURI("http://google.com/test") require.Equal(t, "http://google.com", c.BaseURL()) // Check cache require.Equal(t, "http://google.com", c.BaseURL()) @@ -334,8 +334,8 @@ func Benchmark_Ctx_BaseURL(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().SetHost("google.com:1337") - c.Request().URI().SetPath("/haha/oke/lol") + c.Context().URI().SetHost("google.com:1337") + c.Context().URI().SetPath("/haha/oke/lol") var res string b.ReportAllocs() b.ResetTimer() @@ -351,7 +351,7 @@ func Test_Ctx_Body(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().SetBody([]byte("john=doe")) + c.Context().Request.SetBody([]byte("john=doe")) require.Equal(t, []byte("john=doe"), c.Body()) } @@ -362,7 +362,7 @@ func Benchmark_Ctx_Body(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().SetBody([]byte(input)) + c.Context().Request.SetBody([]byte(input)) b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { @@ -379,7 +379,7 @@ func Test_Ctx_Body_Immutable(t *testing.T) { app.config.Immutable = true c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().SetBody([]byte("john=doe")) + c.Context().Request.SetBody([]byte("john=doe")) require.Equal(t, []byte("john=doe"), c.Body()) } @@ -391,7 +391,7 @@ func Benchmark_Ctx_Body_Immutable(b *testing.B) { app.config.Immutable = true c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().SetBody([]byte(input)) + c.Context().Request.SetBody([]byte(input)) b.ReportAllocs() b.ResetTimer() @@ -443,7 +443,7 @@ func Test_Ctx_Body_With_Compression(t *testing.T) { t.Parallel() app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set("Content-Encoding", tCase.contentEncoding) + c.Context().Request.Header.Set("Content-Encoding", tCase.contentEncoding) if strings.Contains(tCase.contentEncoding, "gzip") { var b bytes.Buffer @@ -460,13 +460,13 @@ func Test_Ctx_Body_With_Compression(t *testing.T) { tCase.body = b.Bytes() } - c.Request().SetBody(tCase.body) + c.Context().Request.SetBody(tCase.body) body := c.Body() require.Equal(t, tCase.expectedBody, body) // Check if body raw is the same as previous before decompression require.Equal( - t, tCase.body, c.Request().Body(), + t, tCase.body, c.Req().BodyRaw(), "Body raw must be the same as set before", ) }) @@ -580,11 +580,11 @@ func Benchmark_Ctx_Body_With_Compression(b *testing.B) { const input = "john=doe" c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set("Content-Encoding", ct.contentEncoding) + c.Context().Request.Header.Set("Content-Encoding", ct.contentEncoding) compressedBody, err := ct.compressWriter([]byte(input)) require.NoError(b, err) - c.Request().SetBody(compressedBody) + c.Context().Request.SetBody(compressedBody) for i := 0; i < b.N; i++ { _ = c.Body() } @@ -636,7 +636,7 @@ func Test_Ctx_Body_With_Compression_Immutable(t *testing.T) { app := New() app.config.Immutable = true c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set("Content-Encoding", tCase.contentEncoding) + c.Context().Request.Header.Set("Content-Encoding", tCase.contentEncoding) if strings.Contains(tCase.contentEncoding, "gzip") { var b bytes.Buffer @@ -653,13 +653,13 @@ func Test_Ctx_Body_With_Compression_Immutable(t *testing.T) { tCase.body = b.Bytes() } - c.Request().SetBody(tCase.body) + c.Context().Request.SetBody(tCase.body) body := c.Body() require.Equal(t, tCase.expectedBody, body) // Check if body raw is the same as previous before decompression require.Equal( - t, tCase.body, c.Request().Body(), + t, tCase.body, c.Req().BodyRaw(), "Body raw must be the same as set before", ) }) @@ -774,11 +774,11 @@ func Benchmark_Ctx_Body_With_Compression_Immutable(b *testing.B) { const input = "john=doe" c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set("Content-Encoding", ct.contentEncoding) + c.Context().Request.Header.Set("Content-Encoding", ct.contentEncoding) compressedBody, err := ct.compressWriter([]byte(input)) require.NoError(b, err) - c.Request().SetBody(compressedBody) + c.Context().Request.SetBody(compressedBody) for i := 0; i < b.N; i++ { _ = c.Body() } @@ -943,7 +943,7 @@ func Test_Ctx_Cookies(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set("Cookie", "john=doe") + c.Context().Request.Header.Set("Cookie", "john=doe") require.Equal(t, "doe", c.Cookies("john")) require.Equal(t, "default", c.Cookies("unknown", "default")) } @@ -968,7 +968,7 @@ func Test_Ctx_Format(t *testing.T) { return fmts } - c.Request().Header.Set(HeaderAccept, `text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7`) + c.Context().Request.Header.Set(HeaderAccept, `text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7`) err := c.Format(formatHandlers("application/xhtml+xml", "application/xml", "foo/bar")...) require.Equal(t, "application/xhtml+xml", accepted) require.Equal(t, "application/xhtml+xml", c.GetRespHeader(HeaderContentType)) @@ -985,7 +985,7 @@ func Test_Ctx_Format(t *testing.T) { err = c.Format(ResFmt{"text/html", func(_ Ctx) error { return myError }}) require.ErrorIs(t, err, myError) - c.Request().Header.Set(HeaderAccept, "application/json") + c.Context().Request.Header.Set(HeaderAccept, "application/json") err = c.Format(ResFmt{"text/html", func(c Ctx) error { return c.SendStatus(StatusOK) }}) require.Equal(t, StatusNotAcceptable, c.Response().StatusCode()) require.NoError(t, err) @@ -1002,7 +1002,7 @@ func Test_Ctx_Format(t *testing.T) { func Benchmark_Ctx_Format(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderAccept, "application/json,text/plain; format=flowed; q=0.9") + c.Context().Request.Header.Set(HeaderAccept, "application/json,text/plain; format=flowed; q=0.9") fail := func(_ Ctx) error { require.FailNow(b, "Wrong type chosen") @@ -1038,7 +1038,7 @@ func Benchmark_Ctx_Format(b *testing.B) { require.NoError(b, err) }) - c.Request().Header.Set("Accept", "text/plain") + c.Context().Request.Header.Set("Accept", "text/plain") b.Run("text/plain", func(b *testing.B) { offers := []ResFmt{ {"application/xml", fail}, @@ -1050,7 +1050,7 @@ func Benchmark_Ctx_Format(b *testing.B) { require.NoError(b, err) }) - c.Request().Header.Set("Accept", "json") + c.Context().Request.Header.Set("Accept", "json") b.Run("json", func(b *testing.B) { offers := []ResFmt{ {"xml", fail}, @@ -1070,27 +1070,27 @@ func Test_Ctx_AutoFormat(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderAccept, MIMETextPlain) + c.Context().Request.Header.Set(HeaderAccept, MIMETextPlain) err := c.AutoFormat([]byte("Hello, World!")) require.NoError(t, err) require.Equal(t, "Hello, World!", string(c.Response().Body())) - c.Request().Header.Set(HeaderAccept, MIMETextHTML) + c.Context().Request.Header.Set(HeaderAccept, MIMETextHTML) err = c.AutoFormat("Hello, World!") require.NoError(t, err) require.Equal(t, "

Hello, World!

", string(c.Response().Body())) - c.Request().Header.Set(HeaderAccept, MIMEApplicationJSON) + c.Context().Request.Header.Set(HeaderAccept, MIMEApplicationJSON) err = c.AutoFormat("Hello, World!") require.NoError(t, err) require.Equal(t, `"Hello, World!"`, string(c.Response().Body())) - c.Request().Header.Set(HeaderAccept, MIMETextPlain) + c.Context().Request.Header.Set(HeaderAccept, MIMETextPlain) err = c.AutoFormat(complex(1, 1)) require.NoError(t, err) require.Equal(t, "(1+1i)", string(c.Response().Body())) - c.Request().Header.Set(HeaderAccept, MIMEApplicationXML) + c.Context().Request.Header.Set(HeaderAccept, MIMEApplicationXML) err = c.AutoFormat("Hello, World!") require.NoError(t, err) require.Equal(t, `Hello, World!`, string(c.Response().Body())) @@ -1098,13 +1098,13 @@ func Test_Ctx_AutoFormat(t *testing.T) { err = c.AutoFormat(complex(1, 1)) require.Error(t, err) - c.Request().Header.Set(HeaderAccept, MIMETextPlain) + c.Context().Request.Header.Set(HeaderAccept, MIMETextPlain) err = c.AutoFormat(Map{}) require.NoError(t, err) require.Equal(t, "map[]", string(c.Response().Body())) type broken string - c.Request().Header.Set(HeaderAccept, "broken/accept") + c.Context().Request.Header.Set(HeaderAccept, "broken/accept") require.NoError(t, err) err = c.AutoFormat(broken("Hello, World!")) require.NoError(t, err) @@ -1127,7 +1127,7 @@ func Test_Ctx_AutoFormat_Struct(t *testing.T) { Urgency: 3, } - c.Request().Header.Set(HeaderAccept, MIMEApplicationJSON) + c.Context().Request.Header.Set(HeaderAccept, MIMEApplicationJSON) err := c.AutoFormat(data) require.NoError(t, err) require.Equal(t, @@ -1135,7 +1135,7 @@ func Test_Ctx_AutoFormat_Struct(t *testing.T) { string(c.Response().Body()), ) - c.Request().Header.Set(HeaderAccept, MIMEApplicationXML) + c.Context().Request.Header.Set(HeaderAccept, MIMEApplicationXML) err = c.AutoFormat(data) require.NoError(t, err) require.Equal(t, @@ -1149,7 +1149,7 @@ func Benchmark_Ctx_AutoFormat(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set("Accept", "text/plain") + c.Context().Request.Header.Set("Accept", "text/plain") b.ReportAllocs() b.ResetTimer() @@ -1166,7 +1166,7 @@ func Benchmark_Ctx_AutoFormat_HTML(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set("Accept", "text/html") + c.Context().Request.Header.Set("Accept", "text/html") b.ReportAllocs() b.ResetTimer() @@ -1183,7 +1183,7 @@ func Benchmark_Ctx_AutoFormat_JSON(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set("Accept", "application/json") + c.Context().Request.Header.Set("Accept", "application/json") b.ReportAllocs() b.ResetTimer() @@ -1200,7 +1200,7 @@ func Benchmark_Ctx_AutoFormat_XML(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set("Accept", "application/xml") + c.Context().Request.Header.Set("Accept", "application/xml") b.ReportAllocs() b.ResetTimer() @@ -1285,12 +1285,12 @@ func Benchmark_Ctx_Fresh_StaleEtag(b *testing.B) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) for n := 0; n < b.N; n++ { - c.Request().Header.Set(HeaderIfNoneMatch, "a, b, c, d") - c.Request().Header.Set(HeaderCacheControl, "c") + c.Context().Request.Header.Set(HeaderIfNoneMatch, "a, b, c, d") + c.Context().Request.Header.Set(HeaderCacheControl, "c") c.Fresh() - c.Request().Header.Set(HeaderIfNoneMatch, "a, b, c, d") - c.Request().Header.Set(HeaderCacheControl, "e") + c.Context().Request.Header.Set(HeaderIfNoneMatch, "a, b, c, d") + c.Context().Request.Header.Set(HeaderCacheControl, "e") c.Fresh() } } @@ -1303,41 +1303,41 @@ func Test_Ctx_Fresh(t *testing.T) { require.False(t, c.Fresh()) - c.Request().Header.Set(HeaderIfNoneMatch, "*") - c.Request().Header.Set(HeaderCacheControl, "no-cache") + c.Context().Request.Header.Set(HeaderIfNoneMatch, "*") + c.Context().Request.Header.Set(HeaderCacheControl, "no-cache") require.False(t, c.Fresh()) - c.Request().Header.Set(HeaderIfNoneMatch, "*") - c.Request().Header.Set(HeaderCacheControl, ",no-cache,") + c.Context().Request.Header.Set(HeaderIfNoneMatch, "*") + c.Context().Request.Header.Set(HeaderCacheControl, ",no-cache,") require.False(t, c.Fresh()) - c.Request().Header.Set(HeaderIfNoneMatch, "*") - c.Request().Header.Set(HeaderCacheControl, "aa,no-cache,") + c.Context().Request.Header.Set(HeaderIfNoneMatch, "*") + c.Context().Request.Header.Set(HeaderCacheControl, "aa,no-cache,") require.False(t, c.Fresh()) - c.Request().Header.Set(HeaderIfNoneMatch, "*") - c.Request().Header.Set(HeaderCacheControl, ",no-cache,bb") + c.Context().Request.Header.Set(HeaderIfNoneMatch, "*") + c.Context().Request.Header.Set(HeaderCacheControl, ",no-cache,bb") require.False(t, c.Fresh()) - c.Request().Header.Set(HeaderIfNoneMatch, "675af34563dc-tr34") - c.Request().Header.Set(HeaderCacheControl, "public") + c.Context().Request.Header.Set(HeaderIfNoneMatch, "675af34563dc-tr34") + c.Context().Request.Header.Set(HeaderCacheControl, "public") require.False(t, c.Fresh()) - c.Request().Header.Set(HeaderIfNoneMatch, "a, b") + c.Context().Request.Header.Set(HeaderIfNoneMatch, "a, b") c.Response().Header.Set(HeaderETag, "c") require.False(t, c.Fresh()) c.Response().Header.Set(HeaderETag, "a") require.True(t, c.Fresh()) - c.Request().Header.Set(HeaderIfModifiedSince, "xxWed, 21 Oct 2015 07:28:00 GMT") + c.Context().Request.Header.Set(HeaderIfModifiedSince, "xxWed, 21 Oct 2015 07:28:00 GMT") c.Response().Header.Set(HeaderLastModified, "xxWed, 21 Oct 2015 07:28:00 GMT") require.False(t, c.Fresh()) c.Response().Header.Set(HeaderLastModified, "Wed, 21 Oct 2015 07:28:00 GMT") require.False(t, c.Fresh()) - c.Request().Header.Set(HeaderIfModifiedSince, "Wed, 21 Oct 2015 07:28:00 GMT") + c.Context().Request.Header.Set(HeaderIfModifiedSince, "Wed, 21 Oct 2015 07:28:00 GMT") require.False(t, c.Fresh()) } @@ -1346,8 +1346,8 @@ func Benchmark_Ctx_Fresh_WithNoCache(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderIfNoneMatch, "*") - c.Request().Header.Set(HeaderCacheControl, "no-cache") + c.Context().Request.Header.Set(HeaderIfNoneMatch, "*") + c.Context().Request.Header.Set(HeaderCacheControl, "no-cache") for n := 0; n < b.N; n++ { c.Fresh() } @@ -1389,24 +1389,24 @@ func Test_Ctx_Parsers(t *testing.T) { t.Run("BodyParser:xml", func(t *testing.T) { t.Parallel() withValues(t, func(c Ctx, testStruct *TestStruct) error { - c.Request().Header.SetContentType(MIMEApplicationXML) - c.Request().SetBody([]byte(`foo111bar222foobartest`)) + c.Context().Request.Header.SetContentType(MIMEApplicationXML) + c.Context().Request.SetBody([]byte(`foo111bar222foobartest`)) return c.Bind().Body(testStruct) }) }) t.Run("BodyParser:form", func(t *testing.T) { t.Parallel() withValues(t, func(c Ctx, testStruct *TestStruct) error { - c.Request().Header.SetContentType(MIMEApplicationForm) - c.Request().SetBody([]byte(`name=foo&class=111&name2=bar&class2=222&names=foo,bar,test`)) + c.Context().Request.Header.SetContentType(MIMEApplicationForm) + c.Context().Request.SetBody([]byte(`name=foo&class=111&name2=bar&class2=222&names=foo,bar,test`)) return c.Bind().Body(testStruct) }) }) t.Run("BodyParser:json", func(t *testing.T) { t.Parallel() withValues(t, func(c Ctx, testStruct *TestStruct) error { - c.Request().Header.SetContentType(MIMEApplicationJSON) - c.Request().SetBody([]byte(`{"name":"foo","class":111,"name2":"bar","class2":222,"names":["foo","bar","test"]}`)) + c.Context().Request.Header.SetContentType(MIMEApplicationJSON) + c.Context().Request.SetBody([]byte(`{"name":"foo","class":111,"name2":"bar","class2":222,"names":["foo","bar","test"]}`)) return c.Bind().Body(testStruct) }) }) @@ -1414,23 +1414,23 @@ func Test_Ctx_Parsers(t *testing.T) { t.Parallel() withValues(t, func(c Ctx, testStruct *TestStruct) error { body := []byte("--b\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\nfoo\r\n--b\r\nContent-Disposition: form-data; name=\"class\"\r\n\r\n111\r\n--b\r\nContent-Disposition: form-data; name=\"name2\"\r\n\r\nbar\r\n--b\r\nContent-Disposition: form-data; name=\"class2\"\r\n\r\n222\r\n--b\r\nContent-Disposition: form-data; name=\"names\"\r\n\r\nfoo\r\n--b\r\nContent-Disposition: form-data; name=\"names\"\r\n\r\nbar\r\n--b\r\nContent-Disposition: form-data; name=\"names\"\r\n\r\ntest\r\n--b--") - c.Request().SetBody(body) - c.Request().Header.SetContentType(MIMEMultipartForm + `;boundary="b"`) - c.Request().Header.SetContentLength(len(body)) + c.Context().Request.SetBody(body) + c.Context().Request.Header.SetContentType(MIMEMultipartForm + `;boundary="b"`) + c.Context().Request.Header.SetContentLength(len(body)) return c.Bind().Body(testStruct) }) }) t.Run("CookieParser", func(t *testing.T) { t.Parallel() withValues(t, func(c Ctx, testStruct *TestStruct) error { - c.Request().Header.Set("Cookie", "name=foo;name2=bar;class=111;class2=222;names=foo,bar,test") + c.Context().Request.Header.Set("Cookie", "name=foo;name2=bar;class=111;class2=222;names=foo,bar,test") return c.Bind().Cookie(testStruct) }) }) t.Run("QueryParser", func(t *testing.T) { t.Parallel() withValues(t, func(c Ctx, testStruct *TestStruct) error { - c.Request().URI().SetQueryString("name=foo&name2=bar&class=111&class2=222&names=foo,bar,test") + c.Context().URI().SetQueryString("name=foo&name2=bar&class=111&class2=222&names=foo,bar,test") return c.Bind().Query(testStruct) }) }) @@ -1439,7 +1439,7 @@ func Test_Ctx_Parsers(t *testing.T) { //nolint:gocritic // TODO: uncomment // t.Parallel() // withValues(t, func(c Ctx, testStruct *TestStruct) error { - // c.route = &Route{Params: []string{"name", "name2", "class", "class2"}} + // c.req.route = &Route{Params: []string{"name", "name2", "class", "class2"}} // c.values = [30]string{"foo", "bar", "111", "222"} // return c.ParamsParser(testStruct) // }) @@ -1447,11 +1447,11 @@ func Test_Ctx_Parsers(t *testing.T) { t.Run("ReqHeaderParser", func(t *testing.T) { t.Parallel() withValues(t, func(c Ctx, testStruct *TestStruct) error { - c.Request().Header.Add("name", "foo") - c.Request().Header.Add("name2", "bar") - c.Request().Header.Add("class", "111") - c.Request().Header.Add("class2", "222") - c.Request().Header.Add("names", "foo,bar,test") + c.Context().Request.Header.Add("name", "foo") + c.Context().Request.Header.Add("name2", "bar") + c.Context().Request.Header.Add("class", "111") + c.Context().Request.Header.Add("class2", "222") + c.Context().Request.Header.Add("names", "foo,bar,test") return c.Bind().Header(testStruct) }) }) @@ -1463,8 +1463,8 @@ func Test_Ctx_Get(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderAcceptCharset, "utf-8, iso-8859-1;q=0.5") - c.Request().Header.Set(HeaderReferer, "Monster") + c.Context().Request.Header.Set(HeaderAcceptCharset, "utf-8, iso-8859-1;q=0.5") + c.Context().Request.Header.Set(HeaderReferer, "Monster") require.Equal(t, "utf-8, iso-8859-1;q=0.5", c.Get(HeaderAcceptCharset)) require.Equal(t, "Monster", c.Get(HeaderReferer)) require.Equal(t, "default", c.Get("unknown", "default")) @@ -1476,8 +1476,8 @@ func Test_Ctx_GetReqHeader(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set("foo", "bar") - c.Request().Header.Set("id", "123") + c.Context().Request.Header.Set("foo", "bar") + c.Context().Request.Header.Set("id", "123") require.Equal(t, 123, GetReqHeader[int](c, "id")) require.Equal(t, "bar", GetReqHeader[string](c, "foo")) } @@ -1488,7 +1488,7 @@ func Test_Ctx_Host(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") + c.Context().Request.SetRequestURI("http://google.com/test") require.Equal(t, "google.com", c.Host()) } @@ -1499,8 +1499,8 @@ func Test_Ctx_Host_UntrustedProxy(t *testing.T) { { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") - c.Request().Header.Set(HeaderXForwardedHost, "google1.com") + c.Context().Request.SetRequestURI("http://google.com/test") + c.Context().Request.Header.Set(HeaderXForwardedHost, "google1.com") require.Equal(t, "google.com", c.Host()) app.ReleaseCtx(c) } @@ -1508,8 +1508,8 @@ func Test_Ctx_Host_UntrustedProxy(t *testing.T) { { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.8.0.0", "0.8.0.1"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") - c.Request().Header.Set(HeaderXForwardedHost, "google1.com") + c.Context().Request.SetRequestURI("http://google.com/test") + c.Context().Request.Header.Set(HeaderXForwardedHost, "google1.com") require.Equal(t, "google.com", c.Host()) app.ReleaseCtx(c) } @@ -1521,8 +1521,8 @@ func Test_Ctx_Host_TrustedProxy(t *testing.T) { { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0", "0.8.0.1"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") - c.Request().Header.Set(HeaderXForwardedHost, "google1.com") + c.Context().Request.SetRequestURI("http://google.com/test") + c.Context().Request.Header.Set(HeaderXForwardedHost, "google1.com") require.Equal(t, "google1.com", c.Host()) app.ReleaseCtx(c) } @@ -1534,8 +1534,8 @@ func Test_Ctx_Host_TrustedProxyRange(t *testing.T) { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0/30"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") - c.Request().Header.Set(HeaderXForwardedHost, "google1.com") + c.Context().Request.SetRequestURI("http://google.com/test") + c.Context().Request.Header.Set(HeaderXForwardedHost, "google1.com") require.Equal(t, "google1.com", c.Host()) app.ReleaseCtx(c) } @@ -1546,8 +1546,8 @@ func Test_Ctx_Host_UntrustedProxyRange(t *testing.T) { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"1.0.0.0/30"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") - c.Request().Header.Set(HeaderXForwardedHost, "google1.com") + c.Context().Request.SetRequestURI("http://google.com/test") + c.Context().Request.Header.Set(HeaderXForwardedHost, "google1.com") require.Equal(t, "google.com", c.Host()) app.ReleaseCtx(c) } @@ -1556,7 +1556,7 @@ func Test_Ctx_Host_UntrustedProxyRange(t *testing.T) { func Benchmark_Ctx_Host(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") + c.Context().Request.SetRequestURI("http://google.com/test") var host string b.ReportAllocs() b.ResetTimer() @@ -1663,10 +1663,10 @@ func Test_Ctx_Hostname(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") + c.Context().Request.SetRequestURI("http://google.com/test") require.Equal(t, "google.com", c.Hostname()) - c.Request().SetRequestURI("http://google.com:8080/test") + c.Context().Request.SetRequestURI("http://google.com:8080/test") require.Equal(t, "google.com", c.Hostname()) } @@ -1674,7 +1674,7 @@ func Test_Ctx_Hostname(t *testing.T) { func Benchmark_Ctx_Hostname(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com:8080/test") + c.Context().Request.SetRequestURI("http://google.com:8080/test") var hostname string b.ReportAllocs() b.ResetTimer() @@ -1685,8 +1685,8 @@ func Benchmark_Ctx_Hostname(b *testing.B) { { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.8.0.0", "0.8.0.1"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") - c.Request().Header.Set(HeaderXForwardedHost, "google1.com") + c.Context().Request.SetRequestURI("http://google.com/test") + c.Context().Request.Header.Set(HeaderXForwardedHost, "google1.com") require.Equal(b, "google.com", hostname) app.ReleaseCtx(c) } @@ -1698,8 +1698,8 @@ func Test_Ctx_Hostname_TrustedProxy(t *testing.T) { { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0", "0.8.0.1"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") - c.Request().Header.Set(HeaderXForwardedHost, "google1.com") + c.Context().Request.SetRequestURI("http://google.com/test") + c.Context().Request.Header.Set(HeaderXForwardedHost, "google1.com") require.Equal(t, "google1.com", c.Hostname()) app.ReleaseCtx(c) } @@ -1711,8 +1711,8 @@ func Test_Ctx_Hostname_TrustedProxy_Multiple(t *testing.T) { { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0", "0.8.0.1"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") - c.Request().Header.Set(HeaderXForwardedHost, "google1.com, google2.com") + c.Context().Request.SetRequestURI("http://google.com/test") + c.Context().Request.Header.Set(HeaderXForwardedHost, "google1.com, google2.com") require.Equal(t, "google1.com", c.Hostname()) app.ReleaseCtx(c) } @@ -1724,8 +1724,8 @@ func Test_Ctx_Hostname_TrustedProxyRange(t *testing.T) { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0/30"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") - c.Request().Header.Set(HeaderXForwardedHost, "google1.com") + c.Context().Request.SetRequestURI("http://google.com/test") + c.Context().Request.Header.Set(HeaderXForwardedHost, "google1.com") require.Equal(t, "google1.com", c.Hostname()) app.ReleaseCtx(c) } @@ -1736,8 +1736,8 @@ func Test_Ctx_Hostname_UntrustedProxyRange(t *testing.T) { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"1.0.0.0/30"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://google.com/test") - c.Request().Header.Set(HeaderXForwardedHost, "google1.com") + c.Context().Request.SetRequestURI("http://google.com/test") + c.Context().Request.Header.Set(HeaderXForwardedHost, "google1.com") require.Equal(t, "google.com", c.Hostname()) app.ReleaseCtx(c) } @@ -1780,7 +1780,7 @@ func Test_Ctx_IP(t *testing.T) { require.Equal(t, "0.0.0.0", c.IP()) // X-Forwarded-For is set, but it is ignored because proxyHeader is not set - c.Request().Header.Set(HeaderXForwardedFor, "0.0.0.1") + c.Context().Request.Header.Set(HeaderXForwardedFor, "0.0.0.1") require.Equal(t, "0.0.0.0", c.IP()) } @@ -1795,23 +1795,23 @@ func Test_Ctx_IP_ProxyHeader(t *testing.T) { app := New(Config{ProxyHeader: proxyHeaderName}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(proxyHeaderName, "0.0.0.1") + c.Context().Request.Header.Set(proxyHeaderName, "0.0.0.1") require.Equal(t, "0.0.0.1", c.IP()) // without IP validation we return the full string - c.Request().Header.Set(proxyHeaderName, "0.0.0.1, 0.0.0.2") + c.Context().Request.Header.Set(proxyHeaderName, "0.0.0.1, 0.0.0.2") require.Equal(t, "0.0.0.1, 0.0.0.2", c.IP()) // without IP validation we return invalid IPs - c.Request().Header.Set(proxyHeaderName, "invalid, 0.0.0.2, 0.0.0.3") + c.Context().Request.Header.Set(proxyHeaderName, "invalid, 0.0.0.2, 0.0.0.3") require.Equal(t, "invalid, 0.0.0.2, 0.0.0.3", c.IP()) // when proxy header is enabled but the value is empty, without IP validation we return an empty string - c.Request().Header.Set(proxyHeaderName, "") + c.Context().Request.Header.Set(proxyHeaderName, "") require.Equal(t, "", c.IP()) // without IP validation we return an invalid IP - c.Request().Header.Set(proxyHeaderName, "not-valid-ip") + c.Context().Request.Header.Set(proxyHeaderName, "not-valid-ip") require.Equal(t, "not-valid-ip", c.IP()) } } @@ -1828,23 +1828,23 @@ func Test_Ctx_IP_ProxyHeader_With_IP_Validation(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) // when proxy header & validation is enabled and the value is a valid IP, we return it - c.Request().Header.Set(proxyHeaderName, "0.0.0.1") + c.Context().Request.Header.Set(proxyHeaderName, "0.0.0.1") require.Equal(t, "0.0.0.1", c.IP()) // when proxy header & validation is enabled and the value is a list of IPs, we return the first valid IP - c.Request().Header.Set(proxyHeaderName, "0.0.0.1, 0.0.0.2") + c.Context().Request.Header.Set(proxyHeaderName, "0.0.0.1, 0.0.0.2") require.Equal(t, "0.0.0.1", c.IP()) - c.Request().Header.Set(proxyHeaderName, "invalid, 0.0.0.2, 0.0.0.3") + c.Context().Request.Header.Set(proxyHeaderName, "invalid, 0.0.0.2, 0.0.0.3") require.Equal(t, "0.0.0.2", c.IP()) // when proxy header & validation is enabled but the value is empty, we will ignore the header - c.Request().Header.Set(proxyHeaderName, "") + c.Context().Request.Header.Set(proxyHeaderName, "") require.Equal(t, "0.0.0.0", c.IP()) // when proxy header & validation is enabled but the value is not an IP, we will ignore the header // and return the IP of the caller - c.Request().Header.Set(proxyHeaderName, "not-valid-ip") + c.Context().Request.Header.Set(proxyHeaderName, "not-valid-ip") require.Equal(t, "0.0.0.0", c.IP()) } } @@ -1854,7 +1854,7 @@ func Test_Ctx_IP_UntrustedProxy(t *testing.T) { t.Parallel() app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.8.0.1"}, ProxyHeader: HeaderXForwardedFor}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "0.0.0.1") + c.Context().Request.Header.Set(HeaderXForwardedFor, "0.0.0.1") require.Equal(t, "0.0.0.0", c.IP()) } @@ -1863,7 +1863,7 @@ func Test_Ctx_IP_TrustedProxy(t *testing.T) { t.Parallel() app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0"}, ProxyHeader: HeaderXForwardedFor}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "0.0.0.1") + c.Context().Request.Header.Set(HeaderXForwardedFor, "0.0.0.1") require.Equal(t, "0.0.0.1", c.IP()) } @@ -1874,33 +1874,33 @@ func Test_Ctx_IPs(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) // normal happy path test case - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, 127.0.0.2, 127.0.0.3") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1, 127.0.0.2, 127.0.0.3") require.Equal(t, []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}, c.IPs()) // inconsistent space formatting - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1,127.0.0.2 ,127.0.0.3") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1,127.0.0.2 ,127.0.0.3") require.Equal(t, []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}, c.IPs()) // invalid IPs are allowed to be returned - c.Request().Header.Set(HeaderXForwardedFor, "invalid, 127.0.0.1, 127.0.0.2") + c.Context().Request.Header.Set(HeaderXForwardedFor, "invalid, 127.0.0.1, 127.0.0.2") require.Equal(t, []string{"invalid", "127.0.0.1", "127.0.0.2"}, c.IPs()) - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.2") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.2") require.Equal(t, []string{"127.0.0.1", "invalid", "127.0.0.2"}, c.IPs()) // ensure that the ordering of IPs in the header is maintained - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.3, 127.0.0.1, 127.0.0.2") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.3, 127.0.0.1, 127.0.0.2") require.Equal(t, []string{"127.0.0.3", "127.0.0.1", "127.0.0.2"}, c.IPs()) // ensure for IPv6 - c.Request().Header.Set(HeaderXForwardedFor, "9396:9549:b4f7:8ed0:4791:1330:8c06:e62d, invalid, 2345:0425:2CA1::0567:5673:23b5") + c.Context().Request.Header.Set(HeaderXForwardedFor, "9396:9549:b4f7:8ed0:4791:1330:8c06:e62d, invalid, 2345:0425:2CA1::0567:5673:23b5") require.Equal(t, []string{"9396:9549:b4f7:8ed0:4791:1330:8c06:e62d", "invalid", "2345:0425:2CA1::0567:5673:23b5"}, c.IPs()) // empty header - c.Request().Header.Set(HeaderXForwardedFor, "") + c.Context().Request.Header.Set(HeaderXForwardedFor, "") require.Empty(t, c.IPs()) // missing header - c.Request() + c.Req() require.Empty(t, c.IPs()) } @@ -1910,33 +1910,33 @@ func Test_Ctx_IPs_With_IP_Validation(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) // normal happy path test case - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, 127.0.0.2, 127.0.0.3") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1, 127.0.0.2, 127.0.0.3") require.Equal(t, []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}, c.IPs()) // inconsistent space formatting - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1,127.0.0.2 ,127.0.0.3") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1,127.0.0.2 ,127.0.0.3") require.Equal(t, []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}, c.IPs()) // invalid IPs are in the header - c.Request().Header.Set(HeaderXForwardedFor, "invalid, 127.0.0.1, 127.0.0.2") + c.Context().Request.Header.Set(HeaderXForwardedFor, "invalid, 127.0.0.1, 127.0.0.2") require.Equal(t, []string{"127.0.0.1", "127.0.0.2"}, c.IPs()) - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.2") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.2") require.Equal(t, []string{"127.0.0.1", "127.0.0.2"}, c.IPs()) // ensure that the ordering of IPs in the header is maintained - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.3, 127.0.0.1, 127.0.0.2") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.3, 127.0.0.1, 127.0.0.2") require.Equal(t, []string{"127.0.0.3", "127.0.0.1", "127.0.0.2"}, c.IPs()) // ensure for IPv6 - c.Request().Header.Set(HeaderXForwardedFor, "f037:825e:eadb:1b7b:1667:6f0a:5356:f604, invalid, 9396:9549:b4f7:8ed0:4791:1330:8c06:e62d") + c.Context().Request.Header.Set(HeaderXForwardedFor, "f037:825e:eadb:1b7b:1667:6f0a:5356:f604, invalid, 9396:9549:b4f7:8ed0:4791:1330:8c06:e62d") require.Equal(t, []string{"f037:825e:eadb:1b7b:1667:6f0a:5356:f604", "9396:9549:b4f7:8ed0:4791:1330:8c06:e62d"}, c.IPs()) // empty header - c.Request().Header.Set(HeaderXForwardedFor, "") + c.Context().Request.Header.Set(HeaderXForwardedFor, "") require.Empty(t, c.IPs()) // missing header - c.Request() + c.Req() require.Empty(t, c.IPs()) } @@ -1944,7 +1944,7 @@ func Test_Ctx_IPs_With_IP_Validation(t *testing.T) { func Benchmark_Ctx_IPs(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.1") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.1") var res []string b.ReportAllocs() b.ResetTimer() @@ -1958,7 +1958,7 @@ func Benchmark_Ctx_IPs_v6(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) - c.Request().Header.Set(HeaderXForwardedFor, "f037:825e:eadb:1b7b:1667:6f0a:5356:f604, invalid, 2345:0425:2CA1::0567:5673:23b5") + c.Context().Request.Header.Set(HeaderXForwardedFor, "f037:825e:eadb:1b7b:1667:6f0a:5356:f604, invalid, 2345:0425:2CA1::0567:5673:23b5") var res []string b.ReportAllocs() b.ResetTimer() @@ -1971,7 +1971,7 @@ func Benchmark_Ctx_IPs_v6(b *testing.B) { func Benchmark_Ctx_IPs_With_IP_Validation(b *testing.B) { app := New(Config{EnableIPValidation: true}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.1") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.1") var res []string b.ReportAllocs() b.ResetTimer() @@ -1985,7 +1985,7 @@ func Benchmark_Ctx_IPs_v6_With_IP_Validation(b *testing.B) { app := New(Config{EnableIPValidation: true}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) - c.Request().Header.Set(HeaderXForwardedFor, "2345:0425:2CA1:0000:0000:0567:5673:23b5, invalid, 2345:0425:2CA1::0567:5673:23b5") + c.Context().Request.Header.Set(HeaderXForwardedFor, "2345:0425:2CA1:0000:0000:0567:5673:23b5, invalid, 2345:0425:2CA1::0567:5673:23b5") var res []string b.ReportAllocs() b.ResetTimer() @@ -1998,7 +1998,7 @@ func Benchmark_Ctx_IPs_v6_With_IP_Validation(b *testing.B) { func Benchmark_Ctx_IP_With_ProxyHeader(b *testing.B) { app := New(Config{ProxyHeader: HeaderXForwardedFor}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1") var res string b.ReportAllocs() b.ResetTimer() @@ -2011,7 +2011,7 @@ func Benchmark_Ctx_IP_With_ProxyHeader(b *testing.B) { func Benchmark_Ctx_IP_With_ProxyHeader_and_IP_Validation(b *testing.B) { app := New(Config{ProxyHeader: HeaderXForwardedFor, EnableIPValidation: true}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1") var res string b.ReportAllocs() b.ResetTimer() @@ -2024,7 +2024,7 @@ func Benchmark_Ctx_IP_With_ProxyHeader_and_IP_Validation(b *testing.B) { func Benchmark_Ctx_IP(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request() + c.Req() var res string b.ReportAllocs() b.ResetTimer() @@ -2040,7 +2040,7 @@ func Test_Ctx_Is(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderContentType, MIMETextHTML+"; boundary=something") + c.Context().Request.Header.Set(HeaderContentType, MIMETextHTML+"; boundary=something") require.True(t, c.Is(".html")) require.True(t, c.Is("html")) require.False(t, c.Is("json")) @@ -2048,22 +2048,22 @@ func Test_Ctx_Is(t *testing.T) { require.False(t, c.Is("")) require.False(t, c.Is(".foooo")) - c.Request().Header.Set(HeaderContentType, MIMEApplicationJSONCharsetUTF8) + c.Context().Request.Header.Set(HeaderContentType, MIMEApplicationJSONCharsetUTF8) require.False(t, c.Is("html")) require.True(t, c.Is("json")) require.True(t, c.Is(".json")) - c.Request().Header.Set(HeaderContentType, " application/json;charset=UTF-8") + c.Context().Request.Header.Set(HeaderContentType, " application/json;charset=UTF-8") require.False(t, c.Is("html")) require.True(t, c.Is("json")) require.True(t, c.Is(".json")) - c.Request().Header.Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8) + c.Context().Request.Header.Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8) require.False(t, c.Is("html")) require.True(t, c.Is("xml")) require.True(t, c.Is(".xml")) - c.Request().Header.Set(HeaderContentType, MIMETextPlain) + c.Context().Request.Header.Set(HeaderContentType, MIMETextPlain) require.False(t, c.Is("html")) require.True(t, c.Is("txt")) require.True(t, c.Is(".txt")) @@ -2074,7 +2074,7 @@ func Benchmark_Ctx_Is(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderContentType, MIMEApplicationJSON) + c.Context().Request.Header.Set(HeaderContentType, MIMEApplicationJSON) var res bool b.ReportAllocs() b.ResetTimer() @@ -2311,7 +2311,7 @@ func Test_Ctx_OriginalURL(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.SetRequestURI("http://google.com/test?search=demo") + c.Context().Request.Header.SetRequestURI("http://google.com/test?search=demo") require.Equal(t, "http://google.com/test?search=demo", c.OriginalURL()) } @@ -2393,12 +2393,12 @@ func Benchmark_Ctx_Params(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.route = &Route{ + c.req.route = &Route{ Params: []string{ "param1", "param2", "param3", "param4", }, } - c.values = [maxParams]string{ + c.req.values = [maxParams]string{ "john", "doe", "is", "awesome", } var res string @@ -2446,7 +2446,7 @@ func Test_Ctx_Protocol(t *testing.T) { require.Equal(t, "HTTP/1.1", c.Protocol()) - c.Request().Header.SetProtocol("HTTP/2") + c.Context().Request.Header.SetProtocol("HTTP/2") require.Equal(t, "HTTP/2", c.Protocol()) } @@ -2474,30 +2474,31 @@ func Test_Ctx_Scheme(t *testing.T) { freq.Request.Header.Set("X-Forwarded", "invalid") c := app.AcquireCtx(freq) + defer app.ReleaseCtx(c) - c.Request().Header.Set(HeaderXForwardedProto, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXForwardedProto, schemeHTTPS) require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedProtocol, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXForwardedProtocol, schemeHTTPS) require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedProto, "https, http") + c.Context().Request.Header.Set(HeaderXForwardedProto, "https, http") require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedProtocol, "https, http") + c.Context().Request.Header.Set(HeaderXForwardedProtocol, "https, http") require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedSsl, "on") + c.Context().Request.Header.Set(HeaderXForwardedSsl, "on") require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXUrlScheme, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXUrlScheme, schemeHTTPS) require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() require.Equal(t, schemeHTTP, c.Scheme()) } @@ -2522,21 +2523,21 @@ func Test_Ctx_Scheme_TrustedProxy(t *testing.T) { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedProto, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXForwardedProto, schemeHTTPS) require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedProtocol, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXForwardedProtocol, schemeHTTPS) require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedSsl, "on") + c.Context().Request.Header.Set(HeaderXForwardedSsl, "on") require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXUrlScheme, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXUrlScheme, schemeHTTPS) require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() require.Equal(t, schemeHTTP, c.Scheme()) } @@ -2547,21 +2548,21 @@ func Test_Ctx_Scheme_TrustedProxyRange(t *testing.T) { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0/30"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedProto, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXForwardedProto, schemeHTTPS) require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedProtocol, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXForwardedProtocol, schemeHTTPS) require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedSsl, "on") + c.Context().Request.Header.Set(HeaderXForwardedSsl, "on") require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXUrlScheme, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXUrlScheme, schemeHTTPS) require.Equal(t, schemeHTTPS, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() require.Equal(t, schemeHTTP, c.Scheme()) } @@ -2572,21 +2573,21 @@ func Test_Ctx_Scheme_UntrustedProxyRange(t *testing.T) { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"1.1.1.1/30"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedProto, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXForwardedProto, schemeHTTPS) require.Equal(t, schemeHTTP, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedProtocol, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXForwardedProtocol, schemeHTTPS) require.Equal(t, schemeHTTP, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedSsl, "on") + c.Context().Request.Header.Set(HeaderXForwardedSsl, "on") require.Equal(t, schemeHTTP, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXUrlScheme, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXUrlScheme, schemeHTTPS) require.Equal(t, schemeHTTP, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() require.Equal(t, schemeHTTP, c.Scheme()) } @@ -2597,21 +2598,21 @@ func Test_Ctx_Scheme_UnTrustedProxy(t *testing.T) { app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.8.0.1"}}) c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedProto, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXForwardedProto, schemeHTTPS) require.Equal(t, schemeHTTP, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedProtocol, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXForwardedProtocol, schemeHTTPS) require.Equal(t, schemeHTTP, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXForwardedSsl, "on") + c.Context().Request.Header.Set(HeaderXForwardedSsl, "on") require.Equal(t, schemeHTTP, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() - c.Request().Header.Set(HeaderXUrlScheme, schemeHTTPS) + c.Context().Request.Header.Set(HeaderXUrlScheme, schemeHTTPS) require.Equal(t, schemeHTTP, c.Scheme()) - c.Request().Header.Reset() + c.Context().Request.Header.Reset() require.Equal(t, schemeHTTP, c.Scheme()) } @@ -2621,8 +2622,9 @@ func Test_Ctx_Query(t *testing.T) { t.Parallel() app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) + defer app.ReleaseCtx(c) - c.Request().URI().SetQueryString("search=john&age=20") + c.Context().URI().SetQueryString("search=john&age=20") require.Equal(t, "john", c.Query("search")) require.Equal(t, "20", c.Query("age")) require.Equal(t, "default", c.Query("unknown", "default")) @@ -2637,7 +2639,7 @@ func Test_Ctx_Query(t *testing.T) { func Benchmark_Ctx_Query(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().URI().SetQueryString("search=john&age=8") + c.Context().URI().SetQueryString("search=john&age=8") var res string b.ReportAllocs() b.ResetTimer() @@ -2654,7 +2656,7 @@ func Test_Ctx_Range(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}) testRange := func(header string, ranges ...RangeSet) { - c.Request().Header.Set(HeaderRange, header) + c.Context().Request.Header.Set(HeaderRange, header) result, err := c.Range(1000) if len(ranges) == 0 { require.Error(t, err) @@ -2700,7 +2702,7 @@ func Benchmark_Ctx_Range(b *testing.B) { for _, tc := range testCases { b.Run(tc.str, func(b *testing.B) { - c.Request().Header.Set(HeaderRange, tc.str) + c.Context().Request.Header.Set(HeaderRange, tc.str) var ( result Range err error @@ -2862,10 +2864,10 @@ func Test_Ctx_Subdomains(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().URI().SetHost("john.doe.is.awesome.google.com") + c.Context().URI().SetHost("john.doe.is.awesome.google.com") require.Equal(t, []string{"john", "doe"}, c.Subdomains(4)) - c.Request().URI().SetHost("localhost:3000") + c.Context().URI().SetHost("localhost:3000") require.Equal(t, []string{"localhost:3000"}, c.Subdomains()) } @@ -2874,7 +2876,7 @@ func Benchmark_Ctx_Subdomains(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetRequestURI("http://john.doe.google.com") + c.Context().Request.SetRequestURI("http://john.doe.google.com") var res []string b.ReportAllocs() b.ResetTimer() @@ -2890,12 +2892,12 @@ func Test_Ctx_ClearCookie(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderCookie, "john=doe") + c.Context().Request.Header.Set(HeaderCookie, "john=doe") c.ClearCookie("john") require.True(t, strings.HasPrefix(string(c.Response().Header.Peek(HeaderSetCookie)), "john=; expires=")) - c.Request().Header.Set(HeaderCookie, "test1=dummy") - c.Request().Header.Set(HeaderCookie, "test2=dummy") + c.Context().Request.Header.Set(HeaderCookie, "test1=dummy") + c.Context().Request.Header.Set(HeaderCookie, "test2=dummy") c.ClearCookie() require.Contains(t, string(c.Response().Header.Peek(HeaderSetCookie)), "test1=; expires=") require.Contains(t, string(c.Response().Header.Peek(HeaderSetCookie)), "test2=; expires=") @@ -2961,7 +2963,7 @@ func Test_Ctx_SendFile(t *testing.T) { // test not modified c = app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderIfModifiedSince, fI.ModTime().Format(time.RFC1123)) + c.Context().Request.Header.Set(HeaderIfModifiedSince, fI.ModTime().Format(time.RFC1123)) err = c.SendFile("ctx.go") // check expectation require.NoError(t, err) @@ -4161,7 +4163,7 @@ func Test_Ctx_XHR(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXRequestedWith, "XMLHttpRequest") + c.Context().Request.Header.Set(HeaderXRequestedWith, "XMLHttpRequest") require.True(t, c.XHR()) } @@ -4170,7 +4172,7 @@ func Benchmark_Ctx_XHR(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXRequestedWith, "XMLHttpRequest") + c.Context().Request.Header.Set(HeaderXRequestedWith, "XMLHttpRequest") var equal bool b.ReportAllocs() b.ResetTimer() @@ -4203,9 +4205,9 @@ func Test_Ctx_Queries(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().SetBody([]byte(``)) - c.Request().Header.SetContentType("") - c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1&field1=value1&field1=value2&field2=value3&list_a=1&list_a=2&list_a=3&list_b[]=1&list_b[]=2&list_b[]=3&list_c=1,2,3") + c.Context().Request.SetBody([]byte(``)) + c.Context().Request.Header.SetContentType("") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1&field1=value1&field1=value2&field2=value3&list_a=1&list_a=2&list_a=3&list_b[]=1&list_b[]=2&list_b[]=3&list_c=1,2,3") queries := c.Queries() require.Equal(t, "1", queries["id"]) @@ -4220,7 +4222,7 @@ func Test_Ctx_Queries(t *testing.T) { require.Equal(t, "3", queries["list_b[]"]) require.Equal(t, "1,2,3", queries["list_c"]) - c.Request().URI().SetQueryString("filters.author.name=John&filters.category.name=Technology&filters[customer][name]=Alice&filters[status]=pending") + c.Context().URI().SetQueryString("filters.author.name=John&filters.category.name=Technology&filters[customer][name]=Alice&filters[status]=pending") queries = c.Queries() require.Equal(t, "John", queries["filters.author.name"]) @@ -4228,7 +4230,7 @@ func Test_Ctx_Queries(t *testing.T) { require.Equal(t, "Alice", queries["filters[customer][name]"]) require.Equal(t, "pending", queries["filters[status]"]) - c.Request().URI().SetQueryString("tags=apple,orange,banana&filters[tags]=apple,orange,banana&filters[category][name]=fruits&filters.tags=apple,orange,banana&filters.category.name=fruits") + c.Context().URI().SetQueryString("tags=apple,orange,banana&filters[tags]=apple,orange,banana&filters[category][name]=fruits&filters.tags=apple,orange,banana&filters.category.name=fruits") queries = c.Queries() require.Equal(t, "apple,orange,banana", queries["tags"]) @@ -4237,7 +4239,7 @@ func Test_Ctx_Queries(t *testing.T) { require.Equal(t, "apple,orange,banana", queries["filters.tags"]) require.Equal(t, "fruits", queries["filters.category.name"]) - c.Request().URI().SetQueryString("filters[tags][0]=apple&filters[tags][1]=orange&filters[tags][2]=banana&filters[category][name]=fruits") + c.Context().URI().SetQueryString("filters[tags][0]=apple&filters[tags][1]=orange&filters[tags][2]=banana&filters[category][name]=fruits") queries = c.Queries() require.Equal(t, "apple", queries["filters[tags][0]"]) @@ -4253,7 +4255,7 @@ func Benchmark_Ctx_Queries(b *testing.B) { b.ReportAllocs() b.ResetTimer() - c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1") + c.Context().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1") var queries map[string]string for n := 0; n < b.N; n++ { @@ -4352,7 +4354,7 @@ func Test_Ctx_IsFromLocal_X_Forwarded(t *testing.T) { { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1") + c.Context().Request.Header.Set(HeaderXForwardedFor, "127.0.0.1") defer app.ReleaseCtx(c) require.False(t, c.IsFromLocal()) } @@ -4360,7 +4362,7 @@ func Test_Ctx_IsFromLocal_X_Forwarded(t *testing.T) { { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "::1") + c.Context().Request.Header.Set(HeaderXForwardedFor, "::1") defer app.ReleaseCtx(c) require.False(t, c.IsFromLocal()) } @@ -4368,7 +4370,7 @@ func Test_Ctx_IsFromLocal_X_Forwarded(t *testing.T) { { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "0:0:0:0:0:0:0:1") + c.Context().Request.Header.Set(HeaderXForwardedFor, "0:0:0:0:0:0:0:1") defer app.ReleaseCtx(c) require.False(t, c.IsFromLocal()) } @@ -4376,7 +4378,7 @@ func Test_Ctx_IsFromLocal_X_Forwarded(t *testing.T) { { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderXForwardedFor, "93.46.8.90") + c.Context().Request.Header.Set(HeaderXForwardedFor, "93.46.8.90") require.False(t, c.IsFromLocal()) } @@ -4458,7 +4460,7 @@ func Test_Ctx_IsFromLocal_RemoteAddr(t *testing.T) { func Test_Ctx_extractIPsFromHeader(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - 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") + c.Context().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] require.Equal(t, "42.118.81.169", res) @@ -4469,7 +4471,7 @@ func Test_Ctx_extractIPsFromHeader_EnableValidateIp(t *testing.T) { app := New() app.config.EnableIPValidation = true c := app.AcquireCtx(&fasthttp.RequestCtx{}) - 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") + c.Context().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] require.Equal(t, "42.118.81.169", res) @@ -4524,11 +4526,11 @@ func Test_Ctx_GetReqHeaders(t *testing.T) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - 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") + c.Context().Request.Header.Set("test", "Hello, World πŸ‘‹!") + c.Context().Request.Header.Set("foo", "bar") + c.Context().Request.Header.Set("multi", "one") + c.Context().Request.Header.Add("multi", "two") + c.Context().Request.Header.Set(HeaderContentType, "application/json") require.Equal(t, map[string][]string{ "Content-Type": {"application/json"}, @@ -4542,9 +4544,9 @@ func Benchmark_Ctx_GetReqHeaders(b *testing.B) { app := New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set("test", "Hello, World πŸ‘‹!") - c.Request().Header.Set("foo", "bar") - c.Request().Header.Set(HeaderContentType, "application/json") + c.Context().Request.Header.Set("test", "Hello, World πŸ‘‹!") + c.Context().Request.Header.Set("foo", "bar") + c.Context().Request.Header.Set(HeaderContentType, "application/json") b.ReportAllocs() b.ResetTimer() diff --git a/middleware/adaptor/adaptor.go b/middleware/adaptor/adaptor.go index 82059cf1580..e2a1cfcacd0 100644 --- a/middleware/adaptor/adaptor.go +++ b/middleware/adaptor/adaptor.go @@ -84,13 +84,13 @@ func HTTPMiddleware(mw func(http.Handler) http.Handler) fiber.Handler { nextHandler := http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { next = true // Convert again in case request may modify by middleware - c.Request().Header.SetMethod(r.Method) - c.Request().SetRequestURI(r.RequestURI) - c.Request().SetHost(r.Host) - c.Request().Header.SetHost(r.Host) + c.Context().Request.Header.SetMethod(r.Method) + c.Context().Request.SetRequestURI(r.RequestURI) + c.Context().Request.SetHost(r.Host) + c.Context().Request.Header.SetHost(r.Host) for key, val := range r.Header { for _, v := range val { - c.Request().Header.Set(key, v) + c.Context().Request.Header.Set(key, v) } } CopyContextToFiberContext(r.Context(), c.Context()) diff --git a/middleware/adaptor/adaptor_test.go b/middleware/adaptor/adaptor_test.go index a14ea606691..a7dd8f722d4 100644 --- a/middleware/adaptor/adaptor_test.go +++ b/middleware/adaptor/adaptor_test.go @@ -242,7 +242,7 @@ func testFiberToHandlerFunc(t *testing.T, checkDefaultPort bool, app ...*fiber.A require.Equal(t, expectedRequestURI, string(c.Context().RequestURI()), "RequestURI") require.Equal(t, expectedContentLength, c.Context().Request.Header.ContentLength(), "ContentLength") require.Equal(t, expectedHost, c.Hostname(), "Host") - require.Equal(t, expectedHost, string(c.Request().Header.Host()), "Host") + require.Equal(t, expectedHost, c.Get(fiber.HeaderHost), "Host") require.Equal(t, "http://"+expectedHost, c.BaseURL(), "BaseURL") require.Equal(t, expectedRemoteAddr, c.Context().RemoteAddr().String(), "RemoteAddr") diff --git a/middleware/csrf/csrf_test.go b/middleware/csrf/csrf_test.go index 70f7f032eee..4efe1a13fa2 100644 --- a/middleware/csrf/csrf_test.go +++ b/middleware/csrf/csrf_test.go @@ -88,7 +88,7 @@ func Test_CSRF_WithSession(t *testing.T) { // the session string is no longer be 123 newSessionIDString := sess.ID() - app.AcquireCtx(ctx).Request().Header.SetCookie("_session", newSessionIDString) + app.AcquireCtx(ctx).Context().Request.Header.SetCookie("_session", newSessionIDString) // middleware config config := Config{ @@ -221,7 +221,7 @@ func Test_CSRF_ExpiredToken_WithSession(t *testing.T) { // get session id newSessionIDString := sess.ID() - app.AcquireCtx(ctx).Request().Header.SetCookie("_session", newSessionIDString) + app.AcquireCtx(ctx).Context().Request.Header.SetCookie("_session", newSessionIDString) // middleware config config := Config{ @@ -1089,7 +1089,7 @@ func Test_CSRF_DeleteToken_WithSession(t *testing.T) { // the session string is no longer be 123 newSessionIDString := sess.ID() - app.AcquireCtx(ctx).Request().Header.SetCookie("_session", newSessionIDString) + app.AcquireCtx(ctx).Context().Request.Header.SetCookie("_session", newSessionIDString) // middleware config config := Config{ diff --git a/middleware/encryptcookie/encryptcookie.go b/middleware/encryptcookie/encryptcookie.go index 5faffcc69d8..6f905168cd7 100644 --- a/middleware/encryptcookie/encryptcookie.go +++ b/middleware/encryptcookie/encryptcookie.go @@ -18,14 +18,14 @@ func New(config ...Config) fiber.Handler { } // Decrypt request cookies - c.Request().Header.VisitAllCookie(func(key, value []byte) { + c.Context().Request.Header.VisitAllCookie(func(key, value []byte) { keyString := string(key) if !isDisabled(keyString, cfg.Except) { decryptedValue, err := cfg.Decryptor(string(value), cfg.Key) if err != nil { - c.Request().Header.SetCookieBytesKV(key, nil) + c.Context().Request.Header.SetCookieBytesKV(key, nil) } else { - c.Request().Header.SetCookie(string(key), decryptedValue) + c.Context().Request.Header.SetCookie(string(key), decryptedValue) } } }) diff --git a/middleware/etag/etag.go b/middleware/etag/etag.go index 2a2c0ae161a..312e557887f 100644 --- a/middleware/etag/etag.go +++ b/middleware/etag/etag.go @@ -65,7 +65,7 @@ func New(config ...Config) fiber.Handler { etag := bb.Bytes() // Get ETag header from request - clientEtag := c.Request().Header.Peek(fiber.HeaderIfNoneMatch) + clientEtag := c.Context().Request.Header.Peek(fiber.HeaderIfNoneMatch) // Check if client's ETag is weak if bytes.HasPrefix(clientEtag, weakPrefix) { diff --git a/middleware/etag/etag_test.go b/middleware/etag/etag_test.go index 9769639cb19..74c6ac45d4d 100644 --- a/middleware/etag/etag_test.go +++ b/middleware/etag/etag_test.go @@ -1,7 +1,6 @@ package etag import ( - "bytes" "io" "net/http/httptest" "testing" @@ -208,7 +207,7 @@ func testETagCustomEtag(t *testing.T, headerIfNoneMatch, matched bool) { //nolin app.Get("/", func(c fiber.Ctx) error { c.Set(fiber.HeaderETag, `"custom"`) - if bytes.Equal(c.Request().Header.Peek(fiber.HeaderIfNoneMatch), []byte(`"custom"`)) { + if c.Get(fiber.HeaderIfNoneMatch) == `"custom"` { return c.SendStatus(fiber.StatusNotModified) } return c.SendString("Hello, World!") @@ -249,7 +248,7 @@ func Test_ETag_CustomEtagPut(t *testing.T) { app.Put("/", func(c fiber.Ctx) error { c.Set(fiber.HeaderETag, `"custom"`) - if !bytes.Equal(c.Request().Header.Peek(fiber.HeaderIfMatch), []byte(`"custom"`)) { + if c.Get(fiber.HeaderIfMatch) != `"custom"` { return c.SendStatus(fiber.StatusPreconditionFailed) } return c.SendString("Hello, World!") diff --git a/middleware/filesystem/filesystem.go b/middleware/filesystem/filesystem.go index 62d4f4f6bb8..0a0393bec45 100644 --- a/middleware/filesystem/filesystem.go +++ b/middleware/filesystem/filesystem.go @@ -234,7 +234,7 @@ func New(config ...Config) fiber.Handler { return nil } if method == fiber.MethodHead { - c.Request().ResetBody() + c.Context().Request.ResetBody() // Fasthttp should skipbody by default if HEAD? c.Response().SkipBody = true c.Response().Header.SetContentLength(contentLength) @@ -309,7 +309,7 @@ func SendFile(c fiber.Ctx, filesystem fs.FS, path string) error { return nil } if method == fiber.MethodHead { - c.Request().ResetBody() + c.Context().Request.ResetBody() // Fasthttp should skipbody by default if HEAD? c.Response().SkipBody = true c.Response().Header.SetContentLength(contentLength) diff --git a/middleware/logger/tags.go b/middleware/logger/tags.go index 8d147fd05dd..cf1b49ff844 100644 --- a/middleware/logger/tags.go +++ b/middleware/logger/tags.go @@ -87,7 +87,7 @@ func createTagMap(cfg *Config) map[string]LogFunc { return output.Write(c.Body()) }, TagBytesReceived: func(output Buffer, c fiber.Ctx, _ *Data, _ string) (int, error) { - return appendInt(output, len(c.Request().Body())) + return appendInt(output, len(c.Req().Body())) }, TagBytesSent: func(output Buffer, c fiber.Ctx, _ *Data, _ string) (int, error) { if c.Response().Header.ContentLength() < 0 { @@ -114,7 +114,7 @@ func createTagMap(cfg *Config) map[string]LogFunc { return output.Write([]byte(strings.Join(reqHeaders, "&"))) }, TagQueryStringParams: func(output Buffer, c fiber.Ctx, _ *Data, _ string) (int, error) { - return output.WriteString(c.Request().URI().QueryArgs().String()) + return output.WriteString(c.Context().URI().QueryArgs().String()) }, TagBlack: func(output Buffer, c fiber.Ctx, _ *Data, _ string) (int, error) { diff --git a/middleware/proxy/proxy.go b/middleware/proxy/proxy.go index 9dad5d55238..746ee7ab8d4 100644 --- a/middleware/proxy/proxy.go +++ b/middleware/proxy/proxy.go @@ -64,7 +64,7 @@ func Balancer(config Config) fiber.Handler { } // Set request and response - req := c.Request() + req := &c.Context().Request res := c.Response() // Don't proxy "Connection" header @@ -172,7 +172,7 @@ func doAction( lock.RUnlock() } - req := c.Request() + req := &c.Context().Request res := c.Response() originalURL := utils.CopyString(c.OriginalURL()) defer req.SetRequestURI(originalURL) @@ -205,7 +205,7 @@ func getScheme(uri []byte) []byte { // This method will return an fiber.Handler func DomainForward(hostname, addr string, clients ...*fasthttp.Client) fiber.Handler { return func(c fiber.Ctx) error { - host := string(c.Request().Host()) + host := string(c.Context().Host()) if host == hostname { return Do(c, addr+c.OriginalURL(), clients...) } @@ -246,7 +246,7 @@ func BalancerForward(servers []string, clients ...*fasthttp.Client) fiber.Handle if !strings.HasPrefix(server, "http") { server = "http://" + server } - c.Request().Header.Add("X-Real-IP", c.IP()) + c.Context().Request.Header.Add("X-Real-IP", c.IP()) return Do(c, server+c.OriginalURL(), clients...) } } diff --git a/middleware/proxy/proxy_test.go b/middleware/proxy/proxy_test.go index 713488a52b8..7f10273d57f 100644 --- a/middleware/proxy/proxy_test.go +++ b/middleware/proxy/proxy_test.go @@ -362,7 +362,7 @@ func Test_Proxy_Modify_Request(t *testing.T) { t.Parallel() _, addr := createProxyTestServerIPv4(t, func(c fiber.Ctx) error { - b := c.Request().Body() + b := c.Req().Body() return c.SendString(string(b)) }) @@ -370,7 +370,7 @@ func Test_Proxy_Modify_Request(t *testing.T) { app.Use(Balancer(Config{ Servers: []string{addr}, ModifyRequest: func(c fiber.Ctx) error { - c.Request().SetBody([]byte("modified request")) + c.Context().Request.SetBody([]byte("modified request")) return nil }, })) diff --git a/middleware/session/session.go b/middleware/session/session.go index c2573439688..259d062c3e5 100644 --- a/middleware/session/session.go +++ b/middleware/session/session.go @@ -215,7 +215,7 @@ func (s *Session) SetExpiry(exp time.Duration) { func (s *Session) setSession() { if s.config.source == SourceHeader { - s.ctx.Request().Header.SetBytesV(s.config.sessionName, []byte(s.id)) + s.ctx.Context().Request.Header.SetBytesV(s.config.sessionName, []byte(s.id)) s.ctx.Response().Header.SetBytesV(s.config.sessionName, []byte(s.id)) } else { fcookie := fasthttp.AcquireCookie() @@ -247,10 +247,10 @@ func (s *Session) setSession() { func (s *Session) delSession() { if s.config.source == SourceHeader { - s.ctx.Request().Header.Del(s.config.sessionName) + s.ctx.Context().Request.Header.Del(s.config.sessionName) s.ctx.Response().Header.Del(s.config.sessionName) } else { - s.ctx.Request().Header.DelCookie(s.config.sessionName) + s.ctx.Context().Request.Header.DelCookie(s.config.sessionName) s.ctx.Response().Header.DelCookie(s.config.sessionName) fcookie := fasthttp.AcquireCookie() diff --git a/middleware/session/session_test.go b/middleware/session/session_test.go index 02bd52d4e2a..b3172262896 100644 --- a/middleware/session/session_test.go +++ b/middleware/session/session_test.go @@ -25,7 +25,7 @@ func Test_Session(t *testing.T) { defer app.ReleaseCtx(ctx) // set session - ctx.Request().Header.SetCookie(store.sessionName, "123") + ctx.Context().Request.Header.SetCookie(store.sessionName, "123") // get session sess, err := store.Get(ctx) @@ -86,7 +86,7 @@ func Test_Session(t *testing.T) { defer app.ReleaseCtx(ctx) // request the server with the old session - ctx.Request().Header.SetCookie(store.sessionName, id) + ctx.Context().Request.Header.SetCookie(store.sessionName, id) sess, err = store.Get(ctx) require.NoError(t, err) require.False(t, sess.Fresh()) @@ -108,7 +108,7 @@ func Test_Session_Types(t *testing.T) { defer app.ReleaseCtx(ctx) // set cookie - ctx.Request().Header.SetCookie(store.sessionName, "123") + ctx.Context().Request.Header.SetCookie(store.sessionName, "123") // get session sess, err := store.Get(ctx) @@ -117,7 +117,7 @@ func Test_Session_Types(t *testing.T) { // the session string is no longer be 123 newSessionIDString := sess.ID() - ctx.Request().Header.SetCookie(store.sessionName, newSessionIDString) + ctx.Context().Request.Header.SetCookie(store.sessionName, newSessionIDString) type User struct { Name string @@ -279,7 +279,7 @@ func Test_Session_Store_Reset(t *testing.T) { require.True(t, sess.Fresh()) // set value & save sess.Set("hello", "world") - ctx.Request().Header.SetCookie(store.sessionName, sess.ID()) + ctx.Context().Request.Header.SetCookie(store.sessionName, sess.ID()) require.NoError(t, sess.Save()) // reset store @@ -338,7 +338,7 @@ func Test_Session_Save(t *testing.T) { err = sess.Save() require.NoError(t, err) require.Equal(t, store.getSessionID(ctx), string(ctx.Response().Header.Peek(store.sessionName))) - require.Equal(t, store.getSessionID(ctx), string(ctx.Request().Header.Peek(store.sessionName))) + require.Equal(t, store.getSessionID(ctx), ctx.Get(store.sessionName)) }) } @@ -435,7 +435,7 @@ func Test_Session_Destroy(t *testing.T) { err = sess.Destroy() require.NoError(t, err) require.Equal(t, "", string(ctx.Response().Header.Peek(store.sessionName))) - require.Equal(t, "", string(ctx.Request().Header.Peek(store.sessionName))) + require.Equal(t, "", ctx.Get(store.sessionName)) }) } @@ -509,7 +509,7 @@ func Test_Session_Deletes_Single_Key(t *testing.T) { sess, err := store.Get(ctx) require.NoError(t, err) - ctx.Request().Header.SetCookie(store.sessionName, sess.ID()) + ctx.Context().Request.Header.SetCookie(store.sessionName, sess.ID()) sess.Set("id", "1") require.NoError(t, sess.Save()) @@ -556,7 +556,7 @@ func Test_Session_Reset(t *testing.T) { require.NoError(t, err) // set cookie - ctx.Request().Header.SetCookie(store.sessionName, originalSessionUUIDString) + ctx.Context().Request.Header.SetCookie(store.sessionName, originalSessionUUIDString) // as the session is in the storage, session.fresh should be false acquiredSession, err := store.Get(ctx) @@ -586,7 +586,7 @@ func Test_Session_Reset(t *testing.T) { // Check that the session id is not in the header or cookie anymore require.Equal(t, "", string(ctx.Response().Header.Peek(store.sessionName))) - require.Equal(t, "", string(ctx.Request().Header.Peek(store.sessionName))) + require.Equal(t, "", ctx.Get(store.sessionName)) }) } @@ -616,7 +616,7 @@ func Test_Session_Regenerate(t *testing.T) { require.NoError(t, err) // set cookie - ctx.Request().Header.SetCookie(store.sessionName, originalSessionUUIDString) + ctx.Context().Request.Header.SetCookie(store.sessionName, originalSessionUUIDString) // as the session is in the storage, session.fresh should be false acquiredSession, err := store.Get(ctx) @@ -639,7 +639,7 @@ func Benchmark_Session(b *testing.B) { app, store := fiber.New(), New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) - c.Request().Header.SetCookie(store.sessionName, "12356789") + c.Context().Request.Header.SetCookie(store.sessionName, "12356789") b.ReportAllocs() b.ResetTimer() @@ -657,7 +657,7 @@ func Benchmark_Session(b *testing.B) { }) c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) - c.Request().Header.SetCookie(store.sessionName, "12356789") + c.Context().Request.Header.SetCookie(store.sessionName, "12356789") b.ReportAllocs() b.ResetTimer() @@ -678,7 +678,7 @@ func Benchmark_Session_Parallel(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.SetCookie(store.sessionName, "12356789") + c.Context().Request.Header.SetCookie(store.sessionName, "12356789") sess, _ := store.Get(c) //nolint:errcheck // We're inside a benchmark sess.Set("john", "doe") @@ -698,7 +698,7 @@ func Benchmark_Session_Parallel(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.SetCookie(store.sessionName, "12356789") + c.Context().Request.Header.SetCookie(store.sessionName, "12356789") sess, _ := store.Get(c) //nolint:errcheck // We're inside a benchmark sess.Set("john", "doe") @@ -715,7 +715,7 @@ func Benchmark_Session_Asserted(b *testing.B) { app, store := fiber.New(), New() c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) - c.Request().Header.SetCookie(store.sessionName, "12356789") + c.Context().Request.Header.SetCookie(store.sessionName, "12356789") b.ReportAllocs() b.ResetTimer() @@ -735,7 +735,7 @@ func Benchmark_Session_Asserted(b *testing.B) { }) c := app.AcquireCtx(&fasthttp.RequestCtx{}) defer app.ReleaseCtx(c) - c.Request().Header.SetCookie(store.sessionName, "12356789") + c.Context().Request.Header.SetCookie(store.sessionName, "12356789") b.ReportAllocs() b.ResetTimer() @@ -758,7 +758,7 @@ func Benchmark_Session_Asserted_Parallel(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.SetCookie(store.sessionName, "12356789") + c.Context().Request.Header.SetCookie(store.sessionName, "12356789") sess, err := store.Get(c) require.NoError(b, err) @@ -779,7 +779,7 @@ func Benchmark_Session_Asserted_Parallel(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.SetCookie(store.sessionName, "12356789") + c.Context().Request.Header.SetCookie(store.sessionName, "12356789") sess, err := store.Get(c) require.NoError(b, err) diff --git a/middleware/session/store.go b/middleware/session/store.go index dbca801808a..e480164efb7 100644 --- a/middleware/session/store.go +++ b/middleware/session/store.go @@ -105,7 +105,7 @@ func (s *Store) getSessionID(c fiber.Ctx) string { } if s.source == SourceHeader { - id = string(c.Request().Header.Peek(s.sessionName)) + id = string(c.Context().Request.Header.Peek(s.sessionName)) if len(id) > 0 { return id } diff --git a/middleware/session/store_test.go b/middleware/session/store_test.go index 13738278998..b50ab364608 100644 --- a/middleware/session/store_test.go +++ b/middleware/session/store_test.go @@ -25,7 +25,7 @@ func Test_Store_getSessionID(t *testing.T) { ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) // set cookie - ctx.Request().Header.SetCookie(store.sessionName, expectedID) + ctx.Context().Request.Header.SetCookie(store.sessionName, expectedID) require.Equal(t, expectedID, store.getSessionID(ctx)) }) @@ -40,7 +40,7 @@ func Test_Store_getSessionID(t *testing.T) { ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) // set header - ctx.Request().Header.Set(store.sessionName, expectedID) + ctx.Context().Request.Header.Set(store.sessionName, expectedID) require.Equal(t, expectedID, store.getSessionID(ctx)) }) @@ -55,7 +55,7 @@ func Test_Store_getSessionID(t *testing.T) { ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) // set url parameter - ctx.Request().SetRequestURI(fmt.Sprintf("/path?%s=%s", store.sessionName, expectedID)) + ctx.Context().Request.SetRequestURI(fmt.Sprintf("/path?%s=%s", store.sessionName, expectedID)) require.Equal(t, expectedID, store.getSessionID(ctx)) }) @@ -76,7 +76,7 @@ func Test_Store_Get(t *testing.T) { ctx := app.AcquireCtx(&fasthttp.RequestCtx{}) // set cookie - ctx.Request().Header.SetCookie(store.sessionName, unexpectedID) + ctx.Context().Request.Header.SetCookie(store.sessionName, unexpectedID) acquiredSession, err := store.Get(ctx) require.NoError(t, err) diff --git a/redirect_test.go b/redirect_test.go index dd5e4b27152..c69e0548d71 100644 --- a/redirect_test.go +++ b/redirect_test.go @@ -161,7 +161,7 @@ func Test_Redirect_Back_WithReferer(t *testing.T) { }).Name("back") c := app.AcquireCtx(&fasthttp.RequestCtx{}) - c.Request().Header.Set(HeaderReferer, "/back") + c.Context().Request.Header.Set(HeaderReferer, "/back") err := c.Redirect().Back("/") require.NoError(t, err) require.Equal(t, 302, c.Response().StatusCode()) @@ -202,8 +202,9 @@ func Test_Redirect_Route_WithOldInput(t *testing.T) { }).Name("user") c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed + defer app.ReleaseCtx(c) - c.Request().URI().SetQueryString("id=1&name=tom") + c.Context().URI().SetQueryString("id=1&name=tom") err := c.Redirect().With("success", "1").With("message", "test").WithInput().Route("user") require.NoError(t, err) require.Equal(t, 302, c.Response().StatusCode()) @@ -231,7 +232,7 @@ func Test_Redirect_setFlash(t *testing.T) { c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") + c.Context().Request.Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") c.Redirect().setFlash() @@ -429,7 +430,7 @@ func Benchmark_Redirect_setFlash(b *testing.B) { c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") + c.Context().Request.Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") b.ReportAllocs() b.ResetTimer() @@ -458,7 +459,7 @@ func Benchmark_Redirect_Messages(b *testing.B) { c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") + c.Context().Request.Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") c.Redirect().setFlash() var msgs map[string]string @@ -483,7 +484,7 @@ func Benchmark_Redirect_OldInputs(b *testing.B) { c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") + c.Context().Request.Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") c.Redirect().setFlash() var oldInputs map[string]string @@ -508,7 +509,7 @@ func Benchmark_Redirect_Message(b *testing.B) { c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") + c.Context().Request.Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") c.Redirect().setFlash() var msg string @@ -533,7 +534,7 @@ func Benchmark_Redirect_OldInput(b *testing.B) { c := app.AcquireCtx(&fasthttp.RequestCtx{}).(*DefaultCtx) //nolint:errcheck, forcetypeassert // not needed - c.Request().Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") + c.Context().Request.Header.Set(HeaderCookie, "fiber_flash=success:1,message:test,old_input_data_name:tom,old_input_data_id:1") c.Redirect().setFlash() var input string diff --git a/request.go b/request.go new file mode 100644 index 00000000000..f719425a2aa --- /dev/null +++ b/request.go @@ -0,0 +1,701 @@ +package fiber + +import ( + "bytes" + "net/http" + "strings" + + "github.com/gofiber/utils/v2" + "github.com/valyala/fasthttp" +) + +type Request struct { + app *App // Reference to the parent App. + ctx Ctx // Reference to the parent Ctx. + fasthttp *fasthttp.Request // Reference to the underlying fasthttp.Request object. + route *Route // Reference to *Route + path string // HTTP path with the modifications by the configuration -> string copy from pathBuffer + pathBuffer []byte // HTTP path buffer + detectionPath string // Route detection path -> string copy from detectionPathBuffer + detectionPathBuffer []byte // HTTP detectionPath buffer + treePath string // Path for the search in the tree + pathOriginal string // Original HTTP path + values [maxParams]string // Route parameter values + baseURI string // Memoized base HTTP URI of the current request. + method string // HTTP method + methodINT int // HTTP method INT equivalent +} + +// Accepts checks if the specified extensions or content types are acceptable. +func (r *Request) Accepts(offers ...string) string { + return getOffer(r.fasthttp.Header.Peek(HeaderAccept), acceptsOfferType, offers...) +} + +// AcceptsCharsets checks if the specified charset is acceptable. +func (r *Request) AcceptsCharsets(offers ...string) string { + return getOffer(r.fasthttp.Header.Peek(HeaderAcceptCharset), acceptsOffer, offers...) +} + +// AcceptsEncodings checks if the specified encoding is acceptable. +func (r *Request) AcceptsEncodings(offers ...string) string { + return getOffer(r.fasthttp.Header.Peek(HeaderAcceptEncoding), acceptsOffer, offers...) +} + +// AcceptsLanguages checks if the specified language is acceptable. +func (r *Request) AcceptsLanguages(offers ...string) string { + return getOffer(r.fasthttp.Header.Peek(HeaderAcceptLanguage), acceptsOffer, offers...) +} + +func (r *Request) App() *App { + return r.app +} + +// 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 (r *Request) Method(override ...string) string { + if len(override) == 0 { + // Nothing to override, just return current method from context + return r.method + } + + method := utils.ToUpper(override[0]) + mINT := r.app.methodInt(method) + if mINT == -1 { + // Provided override does not valid HTTP method, no override, return current method + return r.method + } + + r.method = method + r.methodINT = mINT + return r.method +} + +// OriginalURL contains the original request URL. +// Returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting to use the value outside the Handler. +func (r *Request) OriginalURL() string { + return r.app.getString(r.fasthttp.Header.RequestURI()) +} + +// BaseURL returns (protocol + host + base path). +func (r *Request) BaseURL() string { + // TODO: Could be improved: 53.8 ns/op 32 B/op 1 allocs/op + // Should work like https://codeigniter.com/user_guide/helpers/url_helper.html + if r.baseURI != "" { + return r.baseURI + } + r.baseURI = r.Scheme() + "://" + r.Host() + return r.baseURI +} + +// Path returns the path part of the request URL. +// Optionally, you could override the path. +func (r *Request) Path(override ...string) string { + if len(override) != 0 && r.path != override[0] { + // Set new path to context + r.pathOriginal = override[0] + + // Set new path to request context + r.fasthttp.URI().SetPath(r.pathOriginal) + // Prettify path + r.configDependentPaths() + } + return r.path +} + +// configDependentPaths set paths for route recognition and prepared paths for the user, +// here the features for caseSensitive, decoded paths, strict paths are evaluated +func (r *Request) configDependentPaths() { + r.pathBuffer = append(r.pathBuffer[0:0], r.pathOriginal...) + // If UnescapePath enabled, we decode the path and save it for the framework user + if r.app.config.UnescapePath { + r.pathBuffer = fasthttp.AppendUnquotedArg(r.pathBuffer[:0], r.pathBuffer) + } + r.path = r.app.getString(r.pathBuffer) + + // another path is specified which is for routing recognition only + // use the path that was changed by the previous configuration flags + r.detectionPathBuffer = append(r.detectionPathBuffer[0:0], r.pathBuffer...) + // If CaseSensitive is disabled, we lowercase the original path + if !r.app.config.CaseSensitive { + r.detectionPathBuffer = utils.ToLowerBytes(r.detectionPathBuffer) + } + // If StrictRouting is disabled, we strip all trailing slashes + if !r.app.config.StrictRouting && len(r.detectionPathBuffer) > 1 && r.detectionPathBuffer[len(r.detectionPathBuffer)-1] == '/' { + r.detectionPathBuffer = bytes.TrimRight(r.detectionPathBuffer, "/") + } + r.detectionPath = r.app.getString(r.detectionPathBuffer) + + // Define the path for dividing routes into areas for fast tree detection, so that fewer routes need to be traversed, + // since the first three characters area select a list of routes + r.treePath = r.treePath[0:0] + const maxDetectionPaths = 3 + if len(r.detectionPath) >= maxDetectionPaths { + r.treePath = r.detectionPath[:maxDetectionPaths] + } +} + +// Protocol returns the HTTP protocol of request: HTTP/1.1 and HTTP/2. +func (r *Request) Protocol() string { + return r.app.getString(r.fasthttp.Header.Protocol()) +} + +// Scheme contains the request protocol string: http or https for TLS requests. +// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. +func (r *Request) Scheme() string { + if string(r.fasthttp.URI().Scheme()) == "https" { + return schemeHTTPS + } + if !r.ctx.IsProxyTrusted() { + return schemeHTTP + } + + scheme := schemeHTTP + const lenXHeaderName = 12 + r.fasthttp.Header.VisitAll(func(key, val []byte) { + if len(key) < lenXHeaderName { + return // Neither "X-Forwarded-" nor "X-Url-Scheme" + } + switch { + case bytes.HasPrefix(key, []byte("X-Forwarded-")): + if string(key) == HeaderXForwardedProto || + string(key) == HeaderXForwardedProtocol { + v := r.app.getString(val) + commaPos := strings.IndexByte(v, ',') + if commaPos != -1 { + scheme = v[:commaPos] + } else { + scheme = v + } + } else if string(key) == HeaderXForwardedSsl && string(val) == "on" { + scheme = schemeHTTPS + } + + case string(key) == HeaderXUrlScheme: + scheme = r.app.getString(val) + } + }) + return scheme +} + +// Host contains the host derived from the X-Forwarded-Host or Host HTTP header. +// Returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting instead. +// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. +func (r *Request) Host() string { + if r.ctx.IsProxyTrusted() { + if host := r.Get(HeaderXForwardedHost); len(host) > 0 { + commaPos := strings.Index(host, ",") + if commaPos != -1 { + return host[:commaPos] + } + return host + } + } + return r.app.getString(r.fasthttp.URI().Host()) +} + +// Hostname contains the hostname derived from the X-Forwarded-Host or Host HTTP header using the r.Host() method. +// Returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting instead. +// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. +func (r *Request) Hostname() string { + addr, _ := parseAddr(r.Host()) + + return addr +} + +// IP returns the remote IP address of the request. +// If ProxyHeader and IP Validation is configured, it will parse that header and return the first valid IP address. +// Please use Config.EnableTrustedProxyCheck to prevent header spoofing, in case when your app is behind the proxy. +func (r *Request) IP() string { + if r.ctx.IsProxyTrusted() && len(r.app.config.ProxyHeader) > 0 { + return r.extractIPFromHeader(r.app.config.ProxyHeader) + } + + return r.ctx.Context().RemoteIP().String() +} + +// extractIPFromHeader will attempt to pull the real client IP from the given header when IP validation is enabled. +// currently, it will return the first valid IP address in header. +// when IP validation is disabled, it will simply return the value of the header without any inspection. +// Implementation is almost the same as in extractIPsFromHeader, but without allocation of []string. +func (r *Request) extractIPFromHeader(header string) string { + if r.app.config.EnableIPValidation { + headerValue := r.Get(header) + + i := 0 + j := -1 + + iploop: + for { + var v4, v6 bool + + // Manually splitting string without allocating slice, working with parts directly + i, j = j+1, j+2 + + if j > len(headerValue) { + break + } + + for j < len(headerValue) && headerValue[j] != ',' { + if headerValue[j] == ':' { + v6 = true + } else if headerValue[j] == '.' { + v4 = true + } + j++ + } + + for i < j && headerValue[i] == ' ' { + i++ + } + + s := strings.TrimRight(headerValue[i:j], " ") + + if r.app.config.EnableIPValidation { + if (!v6 && !v4) || (v6 && !utils.IsIPv6(s)) || (v4 && !utils.IsIPv4(s)) { + continue iploop + } + } + + return s + } + + return r.ctx.Context().RemoteIP().String() + } + + // default behavior if IP validation is not enabled is just to return whatever value is + // in the proxy header. Even if it is empty or invalid + return r.Get(r.app.config.ProxyHeader) +} + +// IPs returns a string slice of IP addresses specified in the X-Forwarded-For request header. +// When IP validation is enabled, only valid IPs are returned. +func (r *Request) IPs() []string { + return r.extractIPsFromHeader(HeaderXForwardedFor) +} + +// extractIPsFromHeader will return a slice of IPs it found given a header name in the order they appear. +// When IP validation is enabled, any invalid IPs will be omitted. +func (r *Request) extractIPsFromHeader(header string) []string { + // TODO: Reuse the c.extractIPFromHeader func somehow in here + + headerValue := r.Get(header) + + // We can't know how many IPs we will return, but we will try to guess with this constant division. + // Counting ',' makes function slower for about 50ns in general case. + const maxEstimatedCount = 8 + estimatedCount := len(headerValue) / maxEstimatedCount + if estimatedCount > maxEstimatedCount { + estimatedCount = maxEstimatedCount // Avoid big allocation on big header + } + + ipsFound := make([]string, 0, estimatedCount) + + i := 0 + j := -1 + +iploop: + for { + var v4, v6 bool + + // Manually splitting string without allocating slice, working with parts directly + i, j = j+1, j+2 + + if j > len(headerValue) { + break + } + + for j < len(headerValue) && headerValue[j] != ',' { + if headerValue[j] == ':' { + v6 = true + } else if headerValue[j] == '.' { + v4 = true + } + j++ + } + + for i < j && (headerValue[i] == ' ' || headerValue[i] == ',') { + i++ + } + + s := strings.TrimRight(headerValue[i:j], " ") + + if r.app.config.EnableIPValidation { + // Skip validation if IP is clearly not IPv4/IPv6, otherwise validate without allocations + if (!v6 && !v4) || (v6 && !utils.IsIPv6(s)) || (v4 && !utils.IsIPv4(s)) { + continue iploop + } + } + + ipsFound = append(ipsFound, s) + } + + return ipsFound +} + +// Is returns the matching content type, +// if the incoming request's Content-Type HTTP header field matches the MIME type specified by the type parameter +func (r *Request) Is(extension string) bool { + extensionHeader := utils.GetMIME(extension) + if extensionHeader == "" { + return false + } + + return strings.HasPrefix( + strings.TrimLeft(utils.UnsafeString(r.fasthttp.Header.ContentType()), " "), + extensionHeader, + ) +} + +// 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 (r *Request) BodyRaw() []byte { + if r.app.config.Immutable { + return utils.CopyBytes(r.fasthttp.Body()) + } + return r.fasthttp.Body() +} + +// 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 (r *Request) Body() []byte { + var ( + err error + body, originalBody []byte + headerEncoding string + encodingOrder = []string{"", "", ""} + ) + + // faster than peek + r.fasthttp.Header.VisitAll(func(key, value []byte) { + if r.app.getString(key) == HeaderContentEncoding { + headerEncoding = r.app.getString(value) + } + }) + + // 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 { + if r.app.config.Immutable { + return utils.CopyBytes(r.fasthttp.Body()) + } + return r.fasthttp.Body() + } + + var decodesRealized uint8 + body, decodesRealized, err = r.tryDecodeBodyInOrder(&originalBody, encodingOrder) + + // Ensure that the body will be the original + if originalBody != nil && decodesRealized > 0 { + r.fasthttp.SetBodyRaw(originalBody) + } + if err != nil { + return []byte(err.Error()) + } + + if r.app.config.Immutable { + return utils.CopyBytes(body) + } + return body +} + +func (r *Request) 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 = r.fasthttp.BodyGunzip() + case StrBr, StrBrotli: + body, err = r.fasthttp.BodyUnbrotli() + case StrDeflate: + body, err = r.fasthttp.BodyInflate() + default: + decodesRealized-- + if len(encodings) == 1 { + body = r.fasthttp.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 := r.fasthttp.Body() + *originalBody = make([]byte, len(tempBody)) + copy(*originalBody, tempBody) + } + r.fasthttp.SetBodyRaw(body) + } + } + + return body, decodesRealized, nil +} + +// Get returns the HTTP request header specified by field. +// Field names are case-insensitive +// Returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting instead. +func (r *Request) Get(key string, defaultValue ...string) string { + return defaultString(r.app.getString(r.fasthttp.Header.Peek(key)), defaultValue) +} + +// Cookies are used for getting a cookie value by key. +// Defaults to the empty string "" if the cookie doesn't exist. +// If a default value is given, it will return that value if the cookie doesn't exist. +// The returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting to use the value outside the Handler. +func (r *Request) Cookies(key string, defaultValue ...string) string { + return defaultString(r.app.getString(r.fasthttp.Header.Cookie(key)), defaultValue) +} + +// Fresh returns true when the response is still β€œfresh” in the client's cache, +// otherwise false is returned to indicate that the client cache is now stale +// and the full response should be sent. +// When a client sends the Cache-Control: no-cache request header to indicate an end-to-end +// reload request, this module will return false to make handling these requests transparent. +// https://github.com/jshttp/fresh/blob/10e0471669dbbfbfd8de65bc6efac2ddd0bfa057/index.js#L33 +func (r *Request) Fresh() bool { + // fields + modifiedSince := r.Get(HeaderIfModifiedSince) + noneMatch := r.Get(HeaderIfNoneMatch) + + // unconditional request + if modifiedSince == "" && noneMatch == "" { + return false + } + + // Always return stale when Cache-Control: no-cache + // to support end-to-end reload requests + // https://tools.ietf.org/html/rfc2616#section-14.9.4 + cacheControl := r.Get(HeaderCacheControl) + if cacheControl != "" && isNoCache(cacheControl) { + return false + } + + // if-none-match + if noneMatch != "" && noneMatch != "*" { + etag := r.app.getString(r.ctx.Response().Header.Peek(HeaderETag)) + if etag == "" { + return false + } + if r.app.isEtagStale(etag, r.app.getBytes(noneMatch)) { + return false + } + + if modifiedSince != "" { + lastModified := r.app.getString(r.ctx.Response().Header.Peek(HeaderLastModified)) + if lastModified != "" { + lastModifiedTime, err := http.ParseTime(lastModified) + if err != nil { + return false + } + modifiedSinceTime, err := http.ParseTime(modifiedSince) + if err != nil { + return false + } + return lastModifiedTime.Before(modifiedSinceTime) + } + } + } + return true +} + +// Secure returns whether a secure connection was established. +func (r *Request) Secure() bool { + return r.Protocol() == schemeHTTPS +} + +// Stale is the opposite of [Request.Fresh] and returns true when the response +// to this request is no longer "fresh" in the client's cache. +func (r *Request) Stale() bool { + return !r.Fresh() +} + +// Subdomains returns a string slice of subdomains in the domain name of the request. +// The subdomain offset, which defaults to 2, is used for determining the beginning of the subdomain segments. +func (r *Request) Subdomains(offset ...int) []string { + o := 2 + if len(offset) > 0 { + o = offset[0] + } + subdomains := strings.Split(r.Host(), ".") + l := len(subdomains) - o + // Check index to avoid slice bounds out of range panic + if l < 0 { + l = len(subdomains) + } + subdomains = subdomains[:l] + return subdomains +} + +// XHR returns a Boolean property, that is true, if the request's X-Requested-With header field is XMLHttpRequest, +// indicating that the request was issued by a client library (such as jQuery). +func (r *Request) XHR() bool { + return utils.EqualFold(r.Get(HeaderXRequestedWith), "xmlhttprequest") +} + +// Params is used to get the route parameters. +// Defaults to empty string "" if the param doesn't exist. +// If a default value is given, it will return that value if the param doesn't exist. +// Returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting to use the value outside the Handler. +func (r *Request) Params(key string, defaultValue ...string) string { + if key == "*" || key == "+" { + key += "1" + } + for i := range r.route.Params { + if len(key) != len(r.route.Params[i]) { + continue + } + if r.route.Params[i] == key || (!r.app.config.CaseSensitive && utils.EqualFold(r.route.Params[i], key)) { + // in case values are not here + if len(r.values) <= i || len(r.values[i]) == 0 { + break + } + return r.values[i] + } + } + return defaultString("", defaultValue) +} + +// Query returns the query string parameter in the url. +// Defaults to empty string "" if the query doesn't exist. +// If a default value is given, it will return that value if the query doesn't exist. +// Returned value is only valid within the handler. Do not store any references. +// Make copies or use the Immutable setting to use the value outside the Handler. +func (r *Request) Query(key string, defaultValue ...string) string { + query := r.app.getString(r.fasthttp.URI().QueryArgs().Peek(key)) + return defaultString(query, defaultValue) +} + +// Queries returns a map of query parameters and their values. +// +// GET /?name=alex&wanna_cake=2&id= +// Queries()["name"] == "alex" +// Queries()["wanna_cake"] == "2" +// Queries()["id"] == "" +// +// GET /?field1=value1&field1=value2&field2=value3 +// Queries()["field1"] == "value2" +// Queries()["field2"] == "value3" +// +// GET /?list_a=1&list_a=2&list_a=3&list_b[]=1&list_b[]=2&list_b[]=3&list_c=1,2,3 +// Queries()["list_a"] == "3" +// Queries()["list_b[]"] == "3" +// Queries()["list_c"] == "1,2,3" +// +// GET /api/search?filters.author.name=John&filters.category.name=Technology&filters[customer][name]=Alice&filters[status]=pending +// Queries()["filters.author.name"] == "John" +// Queries()["filters.category.name"] == "Technology" +// Queries()["filters[customer][name]"] == "Alice" +// Queries()["filters[status]"] == "pending" +func (r *Request) Queries() map[string]string { + m := make(map[string]string, r.fasthttp.URI().QueryArgs().Len()) + r.fasthttp.URI().QueryArgs().VisitAll(func(key, value []byte) { + m[r.app.getString(key)] = r.app.getString(value) + }) + return m +} + +// Range returns a struct containing the type and a slice of ranges. +func (r *Request) Range(size int) (Range, error) { + var ( + rangeData Range + ranges string + ) + rangeStr := r.Get(HeaderRange) + + i := strings.IndexByte(rangeStr, '=') + if i == -1 || strings.Contains(rangeStr[i+1:], "=") { + return rangeData, ErrRangeMalformed + } + rangeData.Type = rangeStr[:i] + ranges = rangeStr[i+1:] + + var ( + singleRange string + moreRanges = ranges + ) + for moreRanges != "" { + singleRange = moreRanges + if i := strings.IndexByte(moreRanges, ','); i >= 0 { + singleRange = moreRanges[:i] + moreRanges = moreRanges[i+1:] + } else { + moreRanges = "" + } + + var ( + startStr, endStr string + i int + ) + if i = strings.IndexByte(singleRange, '-'); i == -1 { + return rangeData, ErrRangeMalformed + } + startStr = singleRange[:i] + endStr = singleRange[i+1:] + + start, startErr := fasthttp.ParseUint(utils.UnsafeBytes(startStr)) + end, endErr := fasthttp.ParseUint(utils.UnsafeBytes(endStr)) + if startErr != nil { // -nnn + start = size - end + end = size - 1 + } else if endErr != nil { // nnn- + end = size - 1 + } + if end > size-1 { // limit last-byte-pos to current length + end = size - 1 + } + if start > end || start < 0 { + continue + } + rangeData.Ranges = append(rangeData.Ranges, struct { + Start int + End int + }{ + start, + end, + }) + } + if len(rangeData.Ranges) < 1 { + return rangeData, ErrRangeUnsatisfiable + } + + return rangeData, nil +} + +// Route returns the matched Route struct. +func (r *Request) Route() *Route { + if r.route == nil { + // Fallback for fasthttp error handler + return &Route{ + path: r.pathOriginal, + Path: r.pathOriginal, + Method: r.method, + Handlers: make([]Handler, 0), + Params: make([]string, 0), + } + } + return r.route +} diff --git a/router.go b/router.go index f65b4ece908..3e31822ab25 100644 --- a/router.go +++ b/router.go @@ -150,9 +150,9 @@ func (app *App) nextCustom(c CustomCtx) (bool, error) { //nolint: unparam // boo func (app *App) next(c *DefaultCtx) (bool, error) { // Get stack length - tree, ok := app.treeStack[c.methodINT][c.treePath] + tree, ok := app.treeStack[c.req.methodINT][c.req.treePath] if !ok { - tree = app.treeStack[c.methodINT][""] + tree = app.treeStack[c.req.methodINT][""] } lenTree := len(tree) - 1 @@ -172,13 +172,13 @@ func (app *App) next(c *DefaultCtx) (bool, error) { } // Check if it matches the request path - match = route.match(c.detectionPath, c.path, &c.values) + match = route.match(c.req.detectionPath, c.req.path, &c.req.values) if !match { // No match, next route continue } // Pass route reference and param values - c.route = route + c.req.route = route // Non use handler matched if !c.matched && !route.use { @@ -194,7 +194,7 @@ func (app *App) next(c *DefaultCtx) (bool, error) { } // If c.Next() does not match, return 404 - err := NewError(StatusNotFound, "Cannot "+c.method+" "+html.EscapeString(c.pathOriginal)) + err := NewError(StatusNotFound, "Cannot "+c.req.method+" "+html.EscapeString(c.req.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 @@ -227,7 +227,7 @@ func (app *App) requestHandler(rctx *fasthttp.RequestCtx) { } // check flash messages - if strings.Contains(utils.UnsafeString(c.Request().Header.RawHeaders()), FlashCookieName) { + if strings.Contains(utils.UnsafeString(c.Context().Request.Header.RawHeaders()), FlashCookieName) { c.Redirect().setFlash() }