github.com/boomhut/fiber/v2@v2.0.0-20230603160335-b65c856e57d3/ctx_test.go (about)

     1  // ⚡️ Fiber is an Express inspired web framework written in Go with ☕️
     2  // 🤖 Github Repository: https://github.com/gofiber/fiber
     3  // 📌 API Documentation: https://docs.gofiber.io
     4  
     5  //nolint:bodyclose // Much easier to just ignore memory leaks in tests
     6  package fiber
     7  
     8  import (
     9  	"bufio"
    10  	"bytes"
    11  	"compress/gzip"
    12  	"context"
    13  	"crypto/tls"
    14  	"encoding/xml"
    15  	"errors"
    16  	"fmt"
    17  	"io"
    18  	"mime/multipart"
    19  	"net/http/httptest"
    20  	"net/url"
    21  	"os"
    22  	"path/filepath"
    23  	"reflect"
    24  	"strconv"
    25  	"strings"
    26  	"testing"
    27  	"text/template"
    28  	"time"
    29  
    30  	"github.com/boomhut/fiber/v2/internal/storage/memory"
    31  	"github.com/boomhut/fiber/v2/utils"
    32  
    33  	"github.com/valyala/bytebufferpool"
    34  	"github.com/valyala/fasthttp"
    35  )
    36  
    37  // go test -run Test_Ctx_Accepts
    38  func Test_Ctx_Accepts(t *testing.T) {
    39  	t.Parallel()
    40  	app := New()
    41  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
    42  	defer app.ReleaseCtx(c)
    43  	c.Request().Header.Set(HeaderAccept, "text/html,application/xhtml+xml,application/xml;q=0.9")
    44  	utils.AssertEqual(t, "", c.Accepts(""))
    45  	utils.AssertEqual(t, "", c.Accepts())
    46  	utils.AssertEqual(t, ".xml", c.Accepts(".xml"))
    47  	utils.AssertEqual(t, "", c.Accepts(".john"))
    48  
    49  	c.Request().Header.Set(HeaderAccept, "text/*, application/json")
    50  	utils.AssertEqual(t, "html", c.Accepts("html"))
    51  	utils.AssertEqual(t, "text/html", c.Accepts("text/html"))
    52  	utils.AssertEqual(t, "json", c.Accepts("json", "text"))
    53  	utils.AssertEqual(t, "application/json", c.Accepts("application/json"))
    54  	utils.AssertEqual(t, "", c.Accepts("image/png"))
    55  	utils.AssertEqual(t, "", c.Accepts("png"))
    56  
    57  	c.Request().Header.Set(HeaderAccept, "text/html, application/json")
    58  	utils.AssertEqual(t, "text/*", c.Accepts("text/*"))
    59  
    60  	c.Request().Header.Set(HeaderAccept, "*/*")
    61  	utils.AssertEqual(t, "html", c.Accepts("html"))
    62  }
    63  
    64  // go test -v -run=^$ -bench=Benchmark_Ctx_Accepts -benchmem -count=4
    65  func Benchmark_Ctx_Accepts(b *testing.B) {
    66  	app := New()
    67  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
    68  	defer app.ReleaseCtx(c)
    69  	acceptHeader := "text/html,application/xhtml+xml,application/xml;q=0.9"
    70  	c.Request().Header.Set("Accept", acceptHeader)
    71  	acceptValues := [][]string{
    72  		{".xml"},
    73  		{"json", "xml"},
    74  		{"application/json", "application/xml"},
    75  	}
    76  	expectedResults := []string{".xml", "xml", "application/xml"}
    77  
    78  	for i := 0; i < len(acceptValues); i++ {
    79  		b.Run(fmt.Sprintf("run-%#v", acceptValues[i]), func(bb *testing.B) {
    80  			var res string
    81  			bb.ReportAllocs()
    82  			bb.ResetTimer()
    83  
    84  			for n := 0; n < bb.N; n++ {
    85  				res = c.Accepts(acceptValues[i]...)
    86  			}
    87  			utils.AssertEqual(bb, expectedResults[i], res)
    88  		})
    89  	}
    90  }
    91  
    92  // go test -run Test_Ctx_Accepts_EmptyAccept
    93  func Test_Ctx_Accepts_EmptyAccept(t *testing.T) {
    94  	t.Parallel()
    95  	app := New()
    96  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
    97  	defer app.ReleaseCtx(c)
    98  	utils.AssertEqual(t, ".forwarded", c.Accepts(".forwarded"))
    99  }
   100  
   101  // go test -run Test_Ctx_Accepts_Wildcard
   102  func Test_Ctx_Accepts_Wildcard(t *testing.T) {
   103  	t.Parallel()
   104  	app := New()
   105  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   106  	defer app.ReleaseCtx(c)
   107  	c.Request().Header.Set(HeaderAccept, "*/*;q=0.9")
   108  	utils.AssertEqual(t, "html", c.Accepts("html"))
   109  	utils.AssertEqual(t, "foo", c.Accepts("foo"))
   110  	utils.AssertEqual(t, ".bar", c.Accepts(".bar"))
   111  	c.Request().Header.Set(HeaderAccept, "text/html,application/*;q=0.9")
   112  	utils.AssertEqual(t, "xml", c.Accepts("xml"))
   113  }
   114  
   115  // go test -run Test_Ctx_AcceptsCharsets
   116  func Test_Ctx_AcceptsCharsets(t *testing.T) {
   117  	t.Parallel()
   118  	app := New()
   119  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   120  	defer app.ReleaseCtx(c)
   121  	c.Request().Header.Set(HeaderAcceptCharset, "utf-8, iso-8859-1;q=0.5")
   122  	utils.AssertEqual(t, "utf-8", c.AcceptsCharsets("utf-8"))
   123  }
   124  
   125  // go test -v -run=^$ -bench=Benchmark_Ctx_AcceptsCharsets -benchmem -count=4
   126  func Benchmark_Ctx_AcceptsCharsets(b *testing.B) {
   127  	app := New()
   128  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   129  	defer app.ReleaseCtx(c)
   130  	c.Request().Header.Set("Accept-Charset", "utf-8, iso-8859-1;q=0.5")
   131  	var res string
   132  	b.ReportAllocs()
   133  	b.ResetTimer()
   134  	for n := 0; n < b.N; n++ {
   135  		res = c.AcceptsCharsets("utf-8")
   136  	}
   137  	utils.AssertEqual(b, "utf-8", res)
   138  }
   139  
   140  // go test -run Test_Ctx_AcceptsEncodings
   141  func Test_Ctx_AcceptsEncodings(t *testing.T) {
   142  	t.Parallel()
   143  	app := New()
   144  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   145  	defer app.ReleaseCtx(c)
   146  	c.Request().Header.Set(HeaderAcceptEncoding, "deflate, gzip;q=1.0, *;q=0.5")
   147  	utils.AssertEqual(t, "gzip", c.AcceptsEncodings("gzip"))
   148  	utils.AssertEqual(t, "abc", c.AcceptsEncodings("abc"))
   149  }
   150  
   151  // go test -v -run=^$ -bench=Benchmark_Ctx_AcceptsEncodings -benchmem -count=4
   152  func Benchmark_Ctx_AcceptsEncodings(b *testing.B) {
   153  	app := New()
   154  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   155  	defer app.ReleaseCtx(c)
   156  	c.Request().Header.Set(HeaderAcceptEncoding, "deflate, gzip;q=1.0, *;q=0.5")
   157  	var res string
   158  	b.ReportAllocs()
   159  	b.ResetTimer()
   160  	for n := 0; n < b.N; n++ {
   161  		res = c.AcceptsEncodings("gzip")
   162  	}
   163  	utils.AssertEqual(b, "gzip", res)
   164  }
   165  
   166  // go test -run Test_Ctx_AcceptsLanguages
   167  func Test_Ctx_AcceptsLanguages(t *testing.T) {
   168  	t.Parallel()
   169  	app := New()
   170  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   171  	defer app.ReleaseCtx(c)
   172  	c.Request().Header.Set(HeaderAcceptLanguage, "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5")
   173  	utils.AssertEqual(t, "fr", c.AcceptsLanguages("fr"))
   174  }
   175  
   176  // go test -v -run=^$ -bench=Benchmark_Ctx_AcceptsLanguages -benchmem -count=4
   177  func Benchmark_Ctx_AcceptsLanguages(b *testing.B) {
   178  	app := New()
   179  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   180  	defer app.ReleaseCtx(c)
   181  	c.Request().Header.Set(HeaderAcceptLanguage, "fr-CH, fr;q=0.9, en;q=0.8, de;q=0.7, *;q=0.5")
   182  	var res string
   183  	b.ReportAllocs()
   184  	b.ResetTimer()
   185  	for n := 0; n < b.N; n++ {
   186  		res = c.AcceptsLanguages("fr")
   187  	}
   188  	utils.AssertEqual(b, "fr", res)
   189  }
   190  
   191  // go test -run Test_Ctx_App
   192  func Test_Ctx_App(t *testing.T) {
   193  	t.Parallel()
   194  	app := New()
   195  	app.config.BodyLimit = 1000
   196  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   197  	defer app.ReleaseCtx(c)
   198  	utils.AssertEqual(t, 1000, c.App().config.BodyLimit)
   199  }
   200  
   201  // go test -run Test_Ctx_Append
   202  func Test_Ctx_Append(t *testing.T) {
   203  	t.Parallel()
   204  	app := New()
   205  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   206  	defer app.ReleaseCtx(c)
   207  	c.Append("X-Test", "Hello")
   208  	c.Append("X-Test", "World")
   209  	c.Append("X-Test", "Hello", "World")
   210  	// similar value in the middle
   211  	c.Append("X2-Test", "World")
   212  	c.Append("X2-Test", "XHello")
   213  	c.Append("X2-Test", "Hello", "World")
   214  	// similar value at the start
   215  	c.Append("X3-Test", "XHello")
   216  	c.Append("X3-Test", "World")
   217  	c.Append("X3-Test", "Hello", "World")
   218  	// try it with multiple similar values
   219  	c.Append("X4-Test", "XHello")
   220  	c.Append("X4-Test", "Hello")
   221  	c.Append("X4-Test", "HelloZ")
   222  	c.Append("X4-Test", "YHello")
   223  	c.Append("X4-Test", "Hello")
   224  	c.Append("X4-Test", "YHello")
   225  	c.Append("X4-Test", "HelloZ")
   226  	c.Append("X4-Test", "XHello")
   227  	// without append value
   228  	c.Append("X-Custom-Header")
   229  
   230  	utils.AssertEqual(t, "Hello, World", string(c.Response().Header.Peek("X-Test")))
   231  	utils.AssertEqual(t, "World, XHello, Hello", string(c.Response().Header.Peek("X2-Test")))
   232  	utils.AssertEqual(t, "XHello, World, Hello", string(c.Response().Header.Peek("X3-Test")))
   233  	utils.AssertEqual(t, "XHello, Hello, HelloZ, YHello", string(c.Response().Header.Peek("X4-Test")))
   234  	utils.AssertEqual(t, "", string(c.Response().Header.Peek("x-custom-header")))
   235  }
   236  
   237  // go test -v -run=^$ -bench=Benchmark_Ctx_Append -benchmem -count=4
   238  func Benchmark_Ctx_Append(b *testing.B) {
   239  	app := New()
   240  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   241  	defer app.ReleaseCtx(c)
   242  	b.ReportAllocs()
   243  	b.ResetTimer()
   244  	for n := 0; n < b.N; n++ {
   245  		c.Append("X-Custom-Header", "Hello")
   246  		c.Append("X-Custom-Header", "World")
   247  		c.Append("X-Custom-Header", "Hello")
   248  	}
   249  	utils.AssertEqual(b, "Hello, World", app.getString(c.Response().Header.Peek("X-Custom-Header")))
   250  }
   251  
   252  // go test -run Test_Ctx_Attachment
   253  func Test_Ctx_Attachment(t *testing.T) {
   254  	t.Parallel()
   255  	app := New()
   256  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   257  	defer app.ReleaseCtx(c)
   258  	// empty
   259  	c.Attachment()
   260  	utils.AssertEqual(t, `attachment`, string(c.Response().Header.Peek(HeaderContentDisposition)))
   261  	// real filename
   262  	c.Attachment("./static/img/logo.png")
   263  	utils.AssertEqual(t, `attachment; filename="logo.png"`, string(c.Response().Header.Peek(HeaderContentDisposition)))
   264  	utils.AssertEqual(t, "image/png", string(c.Response().Header.Peek(HeaderContentType)))
   265  	// check quoting
   266  	c.Attachment("another document.pdf\"\r\nBla: \"fasel")
   267  	utils.AssertEqual(t, `attachment; filename="another+document.pdf%22%0D%0ABla%3A+%22fasel"`, string(c.Response().Header.Peek(HeaderContentDisposition)))
   268  }
   269  
   270  // go test -v -run=^$ -bench=Benchmark_Ctx_Attachment -benchmem -count=4
   271  func Benchmark_Ctx_Attachment(b *testing.B) {
   272  	app := New()
   273  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   274  	defer app.ReleaseCtx(c)
   275  	b.ReportAllocs()
   276  	b.ResetTimer()
   277  	for n := 0; n < b.N; n++ {
   278  		// example with quote params
   279  		c.Attachment("another document.pdf\"\r\nBla: \"fasel")
   280  	}
   281  	utils.AssertEqual(b, `attachment; filename="another+document.pdf%22%0D%0ABla%3A+%22fasel"`, string(c.Response().Header.Peek(HeaderContentDisposition)))
   282  }
   283  
   284  // go test -run Test_Ctx_BaseURL
   285  func Test_Ctx_BaseURL(t *testing.T) {
   286  	t.Parallel()
   287  	app := New()
   288  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   289  	defer app.ReleaseCtx(c)
   290  	c.Request().SetRequestURI("http://google.com/test")
   291  	utils.AssertEqual(t, "http://google.com", c.BaseURL())
   292  	// Check cache
   293  	utils.AssertEqual(t, "http://google.com", c.BaseURL())
   294  }
   295  
   296  // go test -v -run=^$ -bench=Benchmark_Ctx_BaseURL -benchmem
   297  func Benchmark_Ctx_BaseURL(b *testing.B) {
   298  	app := New()
   299  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   300  	defer app.ReleaseCtx(c)
   301  	c.Request().SetHost("google.com:1337")
   302  	c.Request().URI().SetPath("/haha/oke/lol")
   303  	var res string
   304  	b.ReportAllocs()
   305  	b.ResetTimer()
   306  	for n := 0; n < b.N; n++ {
   307  		res = c.BaseURL()
   308  	}
   309  	utils.AssertEqual(b, "http://google.com:1337", res)
   310  }
   311  
   312  // go test -run Test_Ctx_Body
   313  func Test_Ctx_Body(t *testing.T) {
   314  	t.Parallel()
   315  	app := New()
   316  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   317  	defer app.ReleaseCtx(c)
   318  	c.Request().SetBody([]byte("john=doe"))
   319  	utils.AssertEqual(t, []byte("john=doe"), c.Body())
   320  }
   321  
   322  // go test -run Test_Ctx_Body_With_Compression
   323  func Test_Ctx_Body_With_Compression(t *testing.T) {
   324  	t.Parallel()
   325  	app := New()
   326  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   327  	defer app.ReleaseCtx(c)
   328  	c.Request().Header.Set("Content-Encoding", "gzip")
   329  	var b bytes.Buffer
   330  	gz := gzip.NewWriter(&b)
   331  	_, err := gz.Write([]byte("john=doe"))
   332  	utils.AssertEqual(t, nil, err)
   333  	err = gz.Flush()
   334  	utils.AssertEqual(t, nil, err)
   335  	err = gz.Close()
   336  	utils.AssertEqual(t, nil, err)
   337  	c.Request().SetBody(b.Bytes())
   338  	utils.AssertEqual(t, []byte("john=doe"), c.Body())
   339  }
   340  
   341  // go test -v -run=^$ -bench=Benchmark_Ctx_Body_With_Compression -benchmem -count=4
   342  func Benchmark_Ctx_Body_With_Compression(b *testing.B) {
   343  	app := New()
   344  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   345  	defer app.ReleaseCtx(c)
   346  	c.Request().Header.Set("Content-Encoding", "gzip")
   347  	var buf bytes.Buffer
   348  	gz := gzip.NewWriter(&buf)
   349  	_, err := gz.Write([]byte("john=doe"))
   350  	utils.AssertEqual(b, nil, err)
   351  	err = gz.Flush()
   352  	utils.AssertEqual(b, nil, err)
   353  	err = gz.Close()
   354  	utils.AssertEqual(b, nil, err)
   355  
   356  	c.Request().SetBody(buf.Bytes())
   357  
   358  	for i := 0; i < b.N; i++ {
   359  		_ = c.Body()
   360  	}
   361  
   362  	utils.AssertEqual(b, []byte("john=doe"), c.Body())
   363  }
   364  
   365  // go test -run Test_Ctx_BodyParser
   366  func Test_Ctx_BodyParser(t *testing.T) {
   367  	t.Parallel()
   368  	app := New()
   369  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   370  	defer app.ReleaseCtx(c)
   371  
   372  	type Demo struct {
   373  		Name string `json:"name" xml:"name" form:"name" query:"name"`
   374  	}
   375  
   376  	{
   377  		var gzipJSON bytes.Buffer
   378  		w := gzip.NewWriter(&gzipJSON)
   379  		_, err := w.Write([]byte(`{"name":"john"}`))
   380  		utils.AssertEqual(t, nil, err)
   381  		err = w.Close()
   382  		utils.AssertEqual(t, nil, err)
   383  
   384  		c.Request().Header.SetContentType(MIMEApplicationJSON)
   385  		c.Request().Header.Set(HeaderContentEncoding, "gzip")
   386  		c.Request().SetBody(gzipJSON.Bytes())
   387  		c.Request().Header.SetContentLength(len(gzipJSON.Bytes()))
   388  		d := new(Demo)
   389  		utils.AssertEqual(t, nil, c.BodyParser(d))
   390  		utils.AssertEqual(t, "john", d.Name)
   391  		c.Request().Header.Del(HeaderContentEncoding)
   392  	}
   393  
   394  	testDecodeParser := func(contentType, body string) {
   395  		c.Request().Header.SetContentType(contentType)
   396  		c.Request().SetBody([]byte(body))
   397  		c.Request().Header.SetContentLength(len(body))
   398  		d := new(Demo)
   399  		utils.AssertEqual(t, nil, c.BodyParser(d))
   400  		utils.AssertEqual(t, "john", d.Name)
   401  	}
   402  
   403  	testDecodeParser(MIMEApplicationJSON, `{"name":"john"}`)
   404  	testDecodeParser(MIMEApplicationXML, `<Demo><name>john</name></Demo>`)
   405  	testDecodeParser(MIMEApplicationForm, "name=john")
   406  	testDecodeParser(MIMEMultipartForm+`;boundary="b"`, "--b\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\njohn\r\n--b--")
   407  
   408  	testDecodeParserError := func(contentType, body string) {
   409  		c.Request().Header.SetContentType(contentType)
   410  		c.Request().SetBody([]byte(body))
   411  		c.Request().Header.SetContentLength(len(body))
   412  		utils.AssertEqual(t, false, c.BodyParser(nil) == nil)
   413  	}
   414  
   415  	testDecodeParserError("invalid-content-type", "")
   416  	testDecodeParserError(MIMEMultipartForm+`;boundary="b"`, "--b")
   417  
   418  	type CollectionQuery struct {
   419  		Data []Demo `query:"data"`
   420  	}
   421  
   422  	c.Request().Reset()
   423  	c.Request().Header.SetContentType(MIMEApplicationForm)
   424  	c.Request().SetBody([]byte("data[0][name]=john&data[1][name]=doe"))
   425  	c.Request().Header.SetContentLength(len(c.Body()))
   426  	cq := new(CollectionQuery)
   427  	utils.AssertEqual(t, nil, c.BodyParser(cq))
   428  	utils.AssertEqual(t, 2, len(cq.Data))
   429  	utils.AssertEqual(t, "john", cq.Data[0].Name)
   430  	utils.AssertEqual(t, "doe", cq.Data[1].Name)
   431  
   432  	c.Request().Reset()
   433  	c.Request().Header.SetContentType(MIMEApplicationForm)
   434  	c.Request().SetBody([]byte("data.0.name=john&data.1.name=doe"))
   435  	c.Request().Header.SetContentLength(len(c.Body()))
   436  	cq = new(CollectionQuery)
   437  	utils.AssertEqual(t, nil, c.BodyParser(cq))
   438  	utils.AssertEqual(t, 2, len(cq.Data))
   439  	utils.AssertEqual(t, "john", cq.Data[0].Name)
   440  	utils.AssertEqual(t, "doe", cq.Data[1].Name)
   441  }
   442  
   443  func Test_Ctx_ParamParser(t *testing.T) {
   444  	t.Parallel()
   445  	app := New()
   446  	app.Get("/test1/:userId/role/:roleId", func(ctx *Ctx) error {
   447  		type Demo struct {
   448  			UserID uint `params:"userId"`
   449  			RoleID uint `params:"roleId"`
   450  		}
   451  		d := new(Demo)
   452  		if err := ctx.ParamsParser(d); err != nil {
   453  			t.Fatal(err)
   454  		}
   455  		utils.AssertEqual(t, uint(111), d.UserID)
   456  		utils.AssertEqual(t, uint(222), d.RoleID)
   457  		return nil
   458  	})
   459  	_, err := app.Test(httptest.NewRequest(MethodGet, "/test1/111/role/222", nil))
   460  	utils.AssertEqual(t, nil, err)
   461  
   462  	_, err = app.Test(httptest.NewRequest(MethodGet, "/test2/111/role/222", nil))
   463  	utils.AssertEqual(t, nil, err)
   464  }
   465  
   466  // go test -run Test_Ctx_BodyParser_WithSetParserDecoder
   467  func Test_Ctx_BodyParser_WithSetParserDecoder(t *testing.T) {
   468  	t.Parallel()
   469  	type CustomTime time.Time
   470  
   471  	timeConverter := func(value string) reflect.Value {
   472  		if v, err := time.Parse("2006-01-02", value); err == nil {
   473  			return reflect.ValueOf(v)
   474  		}
   475  		return reflect.Value{}
   476  	}
   477  
   478  	customTime := ParserType{
   479  		Customtype: CustomTime{},
   480  		Converter:  timeConverter,
   481  	}
   482  
   483  	SetParserDecoder(ParserConfig{
   484  		IgnoreUnknownKeys: true,
   485  		ParserType:        []ParserType{customTime},
   486  		ZeroEmpty:         true,
   487  		SetAliasTag:       "form",
   488  	})
   489  
   490  	app := New()
   491  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   492  	defer app.ReleaseCtx(c)
   493  
   494  	type Demo struct {
   495  		Date  CustomTime `form:"date"`
   496  		Title string     `form:"title"`
   497  		Body  string     `form:"body"`
   498  	}
   499  
   500  	testDecodeParser := func(contentType, body string) {
   501  		c.Request().Header.SetContentType(contentType)
   502  		c.Request().SetBody([]byte(body))
   503  		c.Request().Header.SetContentLength(len(body))
   504  		d := Demo{
   505  			Title: "Existing title",
   506  			Body:  "Existing Body",
   507  		}
   508  		utils.AssertEqual(t, nil, c.BodyParser(&d))
   509  		date := fmt.Sprintf("%v", d.Date)
   510  		utils.AssertEqual(t, "{0 63743587200 <nil>}", date)
   511  		utils.AssertEqual(t, "", d.Title)
   512  		utils.AssertEqual(t, "New Body", d.Body)
   513  	}
   514  
   515  	testDecodeParser(MIMEApplicationForm, "date=2020-12-15&title=&body=New Body")
   516  	testDecodeParser(MIMEMultipartForm+`; boundary="b"`, "--b\r\nContent-Disposition: form-data; name=\"date\"\r\n\r\n2020-12-15\r\n--b\r\nContent-Disposition: form-data; name=\"title\"\r\n\r\n\r\n--b\r\nContent-Disposition: form-data; name=\"body\"\r\n\r\nNew Body\r\n--b--")
   517  }
   518  
   519  // go test -v -run=^$ -bench=Benchmark_Ctx_BodyParser_JSON -benchmem -count=4
   520  func Benchmark_Ctx_BodyParser_JSON(b *testing.B) {
   521  	app := New()
   522  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   523  	defer app.ReleaseCtx(c)
   524  	type Demo struct {
   525  		Name string `json:"name"`
   526  	}
   527  	body := []byte(`{"name":"john"}`)
   528  	c.Request().SetBody(body)
   529  	c.Request().Header.SetContentType(MIMEApplicationJSON)
   530  	c.Request().Header.SetContentLength(len(body))
   531  	d := new(Demo)
   532  
   533  	b.ReportAllocs()
   534  	b.ResetTimer()
   535  
   536  	for n := 0; n < b.N; n++ {
   537  		_ = c.BodyParser(d) //nolint:errcheck // It is fine to ignore the error here as we check it once further below
   538  	}
   539  	utils.AssertEqual(b, nil, c.BodyParser(d))
   540  	utils.AssertEqual(b, "john", d.Name)
   541  }
   542  
   543  // go test -v -run=^$ -bench=Benchmark_Ctx_BodyParser_XML -benchmem -count=4
   544  func Benchmark_Ctx_BodyParser_XML(b *testing.B) {
   545  	app := New()
   546  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   547  	defer app.ReleaseCtx(c)
   548  	type Demo struct {
   549  		Name string `xml:"name"`
   550  	}
   551  	body := []byte("<Demo><name>john</name></Demo>")
   552  	c.Request().SetBody(body)
   553  	c.Request().Header.SetContentType(MIMEApplicationXML)
   554  	c.Request().Header.SetContentLength(len(body))
   555  	d := new(Demo)
   556  
   557  	b.ReportAllocs()
   558  	b.ResetTimer()
   559  
   560  	for n := 0; n < b.N; n++ {
   561  		_ = c.BodyParser(d) //nolint:errcheck // It is fine to ignore the error here as we check it once further below
   562  	}
   563  	utils.AssertEqual(b, nil, c.BodyParser(d))
   564  	utils.AssertEqual(b, "john", d.Name)
   565  }
   566  
   567  // go test -v -run=^$ -bench=Benchmark_Ctx_BodyParser_Form -benchmem -count=4
   568  func Benchmark_Ctx_BodyParser_Form(b *testing.B) {
   569  	app := New()
   570  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   571  	defer app.ReleaseCtx(c)
   572  	type Demo struct {
   573  		Name string `form:"name"`
   574  	}
   575  	body := []byte("name=john")
   576  	c.Request().SetBody(body)
   577  	c.Request().Header.SetContentType(MIMEApplicationForm)
   578  	c.Request().Header.SetContentLength(len(body))
   579  	d := new(Demo)
   580  
   581  	b.ReportAllocs()
   582  	b.ResetTimer()
   583  
   584  	for n := 0; n < b.N; n++ {
   585  		_ = c.BodyParser(d) //nolint:errcheck // It is fine to ignore the error here as we check it once further below
   586  	}
   587  	utils.AssertEqual(b, nil, c.BodyParser(d))
   588  	utils.AssertEqual(b, "john", d.Name)
   589  }
   590  
   591  // go test -v -run=^$ -bench=Benchmark_Ctx_BodyParser_MultipartForm -benchmem -count=4
   592  func Benchmark_Ctx_BodyParser_MultipartForm(b *testing.B) {
   593  	app := New()
   594  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   595  	defer app.ReleaseCtx(c)
   596  	type Demo struct {
   597  		Name string `form:"name"`
   598  	}
   599  
   600  	body := []byte("--b\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\njohn\r\n--b--")
   601  	c.Request().SetBody(body)
   602  	c.Request().Header.SetContentType(MIMEMultipartForm + `;boundary="b"`)
   603  	c.Request().Header.SetContentLength(len(body))
   604  	d := new(Demo)
   605  
   606  	b.ReportAllocs()
   607  	b.ResetTimer()
   608  
   609  	for n := 0; n < b.N; n++ {
   610  		_ = c.BodyParser(d) //nolint:errcheck // It is fine to ignore the error here as we check it once further below
   611  	}
   612  	utils.AssertEqual(b, nil, c.BodyParser(d))
   613  	utils.AssertEqual(b, "john", d.Name)
   614  }
   615  
   616  // go test -run Test_Ctx_Context
   617  func Test_Ctx_Context(t *testing.T) {
   618  	t.Parallel()
   619  	app := New()
   620  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   621  	defer app.ReleaseCtx(c)
   622  
   623  	utils.AssertEqual(t, "*fasthttp.RequestCtx", fmt.Sprintf("%T", c.Context()))
   624  }
   625  
   626  // go test -run Test_Ctx_UserContext
   627  func Test_Ctx_UserContext(t *testing.T) {
   628  	app := New()
   629  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   630  	defer app.ReleaseCtx(c)
   631  
   632  	t.Run("Nil_Context", func(t *testing.T) {
   633  		ctx := c.UserContext()
   634  		utils.AssertEqual(t, ctx, context.Background())
   635  	})
   636  	t.Run("ValueContext", func(t *testing.T) {
   637  		testKey := struct{}{}
   638  		testValue := "Test Value"
   639  		ctx := context.WithValue(context.Background(), testKey, testValue)
   640  		utils.AssertEqual(t, testValue, ctx.Value(testKey))
   641  	})
   642  }
   643  
   644  // go test -run Test_Ctx_SetUserContext
   645  func Test_Ctx_SetUserContext(t *testing.T) {
   646  	t.Parallel()
   647  	app := New()
   648  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   649  	defer app.ReleaseCtx(c)
   650  
   651  	testKey := struct{}{}
   652  	testValue := "Test Value"
   653  	ctx := context.WithValue(context.Background(), testKey, testValue)
   654  	c.SetUserContext(ctx)
   655  	utils.AssertEqual(t, testValue, c.UserContext().Value(testKey))
   656  }
   657  
   658  // go test -run Test_Ctx_UserContext_Multiple_Requests
   659  func Test_Ctx_UserContext_Multiple_Requests(t *testing.T) {
   660  	t.Parallel()
   661  	testKey := struct{}{}
   662  	testValue := "foobar-value"
   663  
   664  	app := New()
   665  	app.Get("/", func(c *Ctx) error {
   666  		ctx := c.UserContext()
   667  
   668  		if ctx.Value(testKey) != nil {
   669  			return c.SendStatus(StatusInternalServerError)
   670  		}
   671  
   672  		input := utils.CopyString(c.Query("input", "NO_VALUE"))
   673  		ctx = context.WithValue(ctx, testKey, fmt.Sprintf("%s_%s", testValue, input))
   674  		c.SetUserContext(ctx)
   675  
   676  		return c.Status(StatusOK).SendString(fmt.Sprintf("resp_%s_returned", input))
   677  	})
   678  
   679  	// Consecutive Requests
   680  	for i := 1; i <= 10; i++ {
   681  		t.Run(fmt.Sprintf("request_%d", i), func(t *testing.T) {
   682  			resp, err := app.Test(httptest.NewRequest(MethodGet, fmt.Sprintf("/?input=%d", i), nil))
   683  
   684  			utils.AssertEqual(t, nil, err, "Unexpected error from response")
   685  			utils.AssertEqual(t, StatusOK, resp.StatusCode, "context.Context returned from c.UserContext() is reused")
   686  
   687  			b, err := io.ReadAll(resp.Body)
   688  			utils.AssertEqual(t, nil, err, "Unexpected error from reading response body")
   689  			utils.AssertEqual(t, fmt.Sprintf("resp_%d_returned", i), string(b), "response text incorrect")
   690  		})
   691  	}
   692  }
   693  
   694  // go test -run Test_Ctx_Cookie
   695  func Test_Ctx_Cookie(t *testing.T) {
   696  	t.Parallel()
   697  	app := New()
   698  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   699  	defer app.ReleaseCtx(c)
   700  	expire := time.Now().Add(24 * time.Hour)
   701  	var dst []byte
   702  	dst = expire.In(time.UTC).AppendFormat(dst, time.RFC1123)
   703  	httpdate := strings.ReplaceAll(string(dst), "UTC", "GMT")
   704  	cookie := &Cookie{
   705  		Name:    "username",
   706  		Value:   "john",
   707  		Expires: expire,
   708  		// SameSite: CookieSameSiteStrictMode, // default is "lax"
   709  	}
   710  	c.Cookie(cookie)
   711  	expect := "username=john; expires=" + httpdate + "; path=/; SameSite=Lax"
   712  	utils.AssertEqual(t, expect, string(c.Response().Header.Peek(HeaderSetCookie)))
   713  
   714  	expect = "username=john; expires=" + httpdate + "; path=/"
   715  	cookie.SameSite = CookieSameSiteDisabled
   716  	c.Cookie(cookie)
   717  	utils.AssertEqual(t, expect, string(c.Response().Header.Peek(HeaderSetCookie)))
   718  
   719  	expect = "username=john; expires=" + httpdate + "; path=/; SameSite=Strict"
   720  	cookie.SameSite = CookieSameSiteStrictMode
   721  	c.Cookie(cookie)
   722  	utils.AssertEqual(t, expect, string(c.Response().Header.Peek(HeaderSetCookie)))
   723  
   724  	expect = "username=john; expires=" + httpdate + "; path=/; secure; SameSite=None"
   725  	cookie.Secure = true
   726  	cookie.SameSite = CookieSameSiteNoneMode
   727  	c.Cookie(cookie)
   728  	utils.AssertEqual(t, expect, string(c.Response().Header.Peek(HeaderSetCookie)))
   729  
   730  	expect = "username=john; path=/; secure; SameSite=None"
   731  	// should remove expires and max-age headers
   732  	cookie.SessionOnly = true
   733  	cookie.Expires = expire
   734  	cookie.MaxAge = 10000
   735  	c.Cookie(cookie)
   736  	utils.AssertEqual(t, expect, string(c.Response().Header.Peek(HeaderSetCookie)))
   737  
   738  	expect = "username=john; path=/; secure; SameSite=None"
   739  	// should remove expires and max-age headers when no expire and no MaxAge (default time)
   740  	cookie.SessionOnly = false
   741  	cookie.Expires = time.Time{}
   742  	cookie.MaxAge = 0
   743  	c.Cookie(cookie)
   744  	utils.AssertEqual(t, expect, string(c.Response().Header.Peek(HeaderSetCookie)))
   745  }
   746  
   747  // go test -v -run=^$ -bench=Benchmark_Ctx_Cookie -benchmem -count=4
   748  func Benchmark_Ctx_Cookie(b *testing.B) {
   749  	app := New()
   750  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   751  	defer app.ReleaseCtx(c)
   752  	b.ReportAllocs()
   753  	b.ResetTimer()
   754  	for n := 0; n < b.N; n++ {
   755  		c.Cookie(&Cookie{
   756  			Name:  "John",
   757  			Value: "Doe",
   758  		})
   759  	}
   760  	utils.AssertEqual(b, "John=Doe; path=/; SameSite=Lax", app.getString(c.Response().Header.Peek("Set-Cookie")))
   761  }
   762  
   763  // go test -run Test_Ctx_Cookies
   764  func Test_Ctx_Cookies(t *testing.T) {
   765  	t.Parallel()
   766  	app := New()
   767  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   768  	defer app.ReleaseCtx(c)
   769  	c.Request().Header.Set("Cookie", "john=doe")
   770  	utils.AssertEqual(t, "doe", c.Cookies("john"))
   771  	utils.AssertEqual(t, "default", c.Cookies("unknown", "default"))
   772  }
   773  
   774  // go test -run Test_Ctx_Format
   775  func Test_Ctx_Format(t *testing.T) {
   776  	t.Parallel()
   777  	app := New()
   778  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   779  	defer app.ReleaseCtx(c)
   780  	c.Request().Header.Set(HeaderAccept, MIMETextPlain)
   781  	err := c.Format([]byte("Hello, World!"))
   782  	utils.AssertEqual(t, nil, err)
   783  	utils.AssertEqual(t, "Hello, World!", string(c.Response().Body()))
   784  
   785  	c.Request().Header.Set(HeaderAccept, MIMETextHTML)
   786  	err = c.Format("Hello, World!")
   787  	utils.AssertEqual(t, nil, err)
   788  	utils.AssertEqual(t, "<p>Hello, World!</p>", string(c.Response().Body()))
   789  
   790  	c.Request().Header.Set(HeaderAccept, MIMEApplicationJSON)
   791  	err = c.Format("Hello, World!")
   792  	utils.AssertEqual(t, nil, err)
   793  	utils.AssertEqual(t, `"Hello, World!"`, string(c.Response().Body()))
   794  
   795  	c.Request().Header.Set(HeaderAccept, MIMETextPlain)
   796  	err = c.Format(complex(1, 1))
   797  	utils.AssertEqual(t, nil, err)
   798  	utils.AssertEqual(t, "(1+1i)", string(c.Response().Body()))
   799  
   800  	c.Request().Header.Set(HeaderAccept, MIMEApplicationXML)
   801  	err = c.Format("Hello, World!")
   802  	utils.AssertEqual(t, nil, err)
   803  	utils.AssertEqual(t, `<string>Hello, World!</string>`, string(c.Response().Body()))
   804  
   805  	err = c.Format(complex(1, 1))
   806  	utils.AssertEqual(t, true, err != nil)
   807  
   808  	c.Request().Header.Set(HeaderAccept, MIMETextPlain)
   809  	err = c.Format(Map{})
   810  	utils.AssertEqual(t, nil, err)
   811  	utils.AssertEqual(t, "map[]", string(c.Response().Body()))
   812  
   813  	type broken string
   814  	c.Request().Header.Set(HeaderAccept, "broken/accept")
   815  	err = c.Format(broken("Hello, World!"))
   816  	utils.AssertEqual(t, nil, err)
   817  	utils.AssertEqual(t, `Hello, World!`, string(c.Response().Body()))
   818  }
   819  
   820  // go test -v -run=^$ -bench=Benchmark_Ctx_Format -benchmem -count=4
   821  func Benchmark_Ctx_Format(b *testing.B) {
   822  	app := New()
   823  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   824  	defer app.ReleaseCtx(c)
   825  	c.Request().Header.Set("Accept", "text/plain")
   826  	b.ReportAllocs()
   827  	b.ResetTimer()
   828  
   829  	var err error
   830  	for n := 0; n < b.N; n++ {
   831  		err = c.Format("Hello, World!")
   832  	}
   833  
   834  	utils.AssertEqual(b, nil, err)
   835  	utils.AssertEqual(b, `Hello, World!`, string(c.Response().Body()))
   836  }
   837  
   838  // go test -v -run=^$ -bench=Benchmark_Ctx_Format_HTML -benchmem -count=4
   839  func Benchmark_Ctx_Format_HTML(b *testing.B) {
   840  	app := New()
   841  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   842  	defer app.ReleaseCtx(c)
   843  	c.Request().Header.Set("Accept", "text/html")
   844  	b.ReportAllocs()
   845  	b.ResetTimer()
   846  
   847  	var err error
   848  	for n := 0; n < b.N; n++ {
   849  		err = c.Format("Hello, World!")
   850  	}
   851  
   852  	utils.AssertEqual(b, nil, err)
   853  	utils.AssertEqual(b, "<p>Hello, World!</p>", string(c.Response().Body()))
   854  }
   855  
   856  // go test -v -run=^$ -bench=Benchmark_Ctx_Format_JSON -benchmem -count=4
   857  func Benchmark_Ctx_Format_JSON(b *testing.B) {
   858  	app := New()
   859  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   860  	defer app.ReleaseCtx(c)
   861  	c.Request().Header.Set("Accept", "application/json")
   862  	b.ReportAllocs()
   863  	b.ResetTimer()
   864  
   865  	var err error
   866  	for n := 0; n < b.N; n++ {
   867  		err = c.Format("Hello, World!")
   868  	}
   869  
   870  	utils.AssertEqual(b, nil, err)
   871  	utils.AssertEqual(b, `"Hello, World!"`, string(c.Response().Body()))
   872  }
   873  
   874  // go test -v -run=^$ -bench=Benchmark_Ctx_Format_XML -benchmem -count=4
   875  func Benchmark_Ctx_Format_XML(b *testing.B) {
   876  	app := New()
   877  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   878  	defer app.ReleaseCtx(c)
   879  	c.Request().Header.Set("Accept", "application/xml")
   880  	b.ReportAllocs()
   881  	b.ResetTimer()
   882  
   883  	var err error
   884  	for n := 0; n < b.N; n++ {
   885  		err = c.Format("Hello, World!")
   886  	}
   887  
   888  	utils.AssertEqual(b, nil, err)
   889  	utils.AssertEqual(b, `<string>Hello, World!</string>`, string(c.Response().Body()))
   890  }
   891  
   892  // go test -run Test_Ctx_FormFile
   893  func Test_Ctx_FormFile(t *testing.T) {
   894  	// TODO: We should clean this up
   895  	t.Parallel()
   896  	app := New()
   897  
   898  	app.Post("/test", func(c *Ctx) error {
   899  		fh, err := c.FormFile("file")
   900  		utils.AssertEqual(t, nil, err)
   901  		utils.AssertEqual(t, "test", fh.Filename)
   902  
   903  		f, err := fh.Open()
   904  		utils.AssertEqual(t, nil, err)
   905  		defer func() {
   906  			utils.AssertEqual(t, nil, f.Close())
   907  		}()
   908  
   909  		b := new(bytes.Buffer)
   910  		_, err = io.Copy(b, f)
   911  		utils.AssertEqual(t, nil, err)
   912  		utils.AssertEqual(t, "hello world", b.String())
   913  		return nil
   914  	})
   915  
   916  	body := &bytes.Buffer{}
   917  	writer := multipart.NewWriter(body)
   918  
   919  	ioWriter, err := writer.CreateFormFile("file", "test")
   920  	utils.AssertEqual(t, nil, err)
   921  
   922  	_, err = ioWriter.Write([]byte("hello world"))
   923  	utils.AssertEqual(t, nil, err)
   924  	utils.AssertEqual(t, nil, writer.Close())
   925  
   926  	req := httptest.NewRequest(MethodPost, "/test", body)
   927  	req.Header.Set(HeaderContentType, writer.FormDataContentType())
   928  	req.Header.Set(HeaderContentLength, strconv.Itoa(len(body.Bytes())))
   929  
   930  	resp, err := app.Test(req)
   931  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   932  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   933  }
   934  
   935  // go test -run Test_Ctx_FormValue
   936  func Test_Ctx_FormValue(t *testing.T) {
   937  	t.Parallel()
   938  	app := New()
   939  
   940  	app.Post("/test", func(c *Ctx) error {
   941  		utils.AssertEqual(t, "john", c.FormValue("name"))
   942  		return nil
   943  	})
   944  
   945  	body := &bytes.Buffer{}
   946  	writer := multipart.NewWriter(body)
   947  	utils.AssertEqual(t, nil, writer.WriteField("name", "john"))
   948  	utils.AssertEqual(t, nil, writer.Close())
   949  
   950  	req := httptest.NewRequest(MethodPost, "/test", body)
   951  	req.Header.Set("Content-Type", fmt.Sprintf("multipart/form-data; boundary=%s", writer.Boundary()))
   952  	req.Header.Set("Content-Length", strconv.Itoa(len(body.Bytes())))
   953  
   954  	resp, err := app.Test(req)
   955  	utils.AssertEqual(t, nil, err, "app.Test(req)")
   956  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
   957  }
   958  
   959  // go test -v -run=^$ -bench=Benchmark_Ctx_Fresh_StaleEtag -benchmem -count=4
   960  func Benchmark_Ctx_Fresh_StaleEtag(b *testing.B) {
   961  	app := New()
   962  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   963  	defer app.ReleaseCtx(c)
   964  
   965  	for n := 0; n < b.N; n++ {
   966  		c.Request().Header.Set(HeaderIfNoneMatch, "a, b, c, d")
   967  		c.Request().Header.Set(HeaderCacheControl, "c")
   968  		c.Fresh()
   969  
   970  		c.Request().Header.Set(HeaderIfNoneMatch, "a, b, c, d")
   971  		c.Request().Header.Set(HeaderCacheControl, "e")
   972  		c.Fresh()
   973  	}
   974  }
   975  
   976  // go test -run Test_Ctx_Fresh
   977  func Test_Ctx_Fresh(t *testing.T) {
   978  	t.Parallel()
   979  	app := New()
   980  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
   981  	defer app.ReleaseCtx(c)
   982  	utils.AssertEqual(t, false, c.Fresh())
   983  
   984  	c.Request().Header.Set(HeaderIfNoneMatch, "*")
   985  	c.Request().Header.Set(HeaderCacheControl, "no-cache")
   986  	utils.AssertEqual(t, false, c.Fresh())
   987  
   988  	c.Request().Header.Set(HeaderIfNoneMatch, "*")
   989  	c.Request().Header.Set(HeaderCacheControl, ",no-cache,")
   990  	utils.AssertEqual(t, false, c.Fresh())
   991  
   992  	c.Request().Header.Set(HeaderIfNoneMatch, "*")
   993  	c.Request().Header.Set(HeaderCacheControl, "aa,no-cache,")
   994  	utils.AssertEqual(t, false, c.Fresh())
   995  
   996  	c.Request().Header.Set(HeaderIfNoneMatch, "*")
   997  	c.Request().Header.Set(HeaderCacheControl, ",no-cache,bb")
   998  	utils.AssertEqual(t, false, c.Fresh())
   999  
  1000  	c.Request().Header.Set(HeaderIfNoneMatch, "675af34563dc-tr34")
  1001  	c.Request().Header.Set(HeaderCacheControl, "public")
  1002  	utils.AssertEqual(t, false, c.Fresh())
  1003  
  1004  	c.Request().Header.Set(HeaderIfNoneMatch, "a, b")
  1005  	c.Response().Header.Set(HeaderETag, "c")
  1006  	utils.AssertEqual(t, false, c.Fresh())
  1007  
  1008  	c.Response().Header.Set(HeaderETag, "a")
  1009  	utils.AssertEqual(t, true, c.Fresh())
  1010  
  1011  	c.Request().Header.Set(HeaderIfModifiedSince, "xxWed, 21 Oct 2015 07:28:00 GMT")
  1012  	c.Response().Header.Set(HeaderLastModified, "xxWed, 21 Oct 2015 07:28:00 GMT")
  1013  	utils.AssertEqual(t, false, c.Fresh())
  1014  
  1015  	c.Response().Header.Set(HeaderLastModified, "Wed, 21 Oct 2015 07:28:00 GMT")
  1016  	utils.AssertEqual(t, false, c.Fresh())
  1017  
  1018  	c.Request().Header.Set(HeaderIfModifiedSince, "Wed, 21 Oct 2015 07:28:00 GMT")
  1019  	utils.AssertEqual(t, false, c.Fresh())
  1020  }
  1021  
  1022  // go test -v -run=^$ -bench=Benchmark_Ctx_Fresh_WithNoCache -benchmem -count=4
  1023  func Benchmark_Ctx_Fresh_WithNoCache(b *testing.B) {
  1024  	app := New()
  1025  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1026  	defer app.ReleaseCtx(c)
  1027  
  1028  	c.Request().Header.Set(HeaderIfNoneMatch, "*")
  1029  	c.Request().Header.Set(HeaderCacheControl, "no-cache")
  1030  	for n := 0; n < b.N; n++ {
  1031  		c.Fresh()
  1032  	}
  1033  }
  1034  
  1035  // go test -run Test_Ctx_Get
  1036  func Test_Ctx_Get(t *testing.T) {
  1037  	t.Parallel()
  1038  	app := New()
  1039  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1040  	defer app.ReleaseCtx(c)
  1041  	c.Request().Header.Set(HeaderAcceptCharset, "utf-8, iso-8859-1;q=0.5")
  1042  	c.Request().Header.Set(HeaderReferer, "Monster")
  1043  	utils.AssertEqual(t, "utf-8, iso-8859-1;q=0.5", c.Get(HeaderAcceptCharset))
  1044  	utils.AssertEqual(t, "Monster", c.Get(HeaderReferer))
  1045  	utils.AssertEqual(t, "default", c.Get("unknown", "default"))
  1046  }
  1047  
  1048  // go test -run Test_Ctx_IsProxyTrusted
  1049  func Test_Ctx_IsProxyTrusted(t *testing.T) {
  1050  	t.Parallel()
  1051  
  1052  	{
  1053  		app := New()
  1054  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1055  		defer app.ReleaseCtx(c)
  1056  		utils.AssertEqual(t, true, c.IsProxyTrusted())
  1057  	}
  1058  	{
  1059  		app := New(Config{
  1060  			EnableTrustedProxyCheck: false,
  1061  		})
  1062  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1063  		defer app.ReleaseCtx(c)
  1064  		utils.AssertEqual(t, true, c.IsProxyTrusted())
  1065  	}
  1066  
  1067  	{
  1068  		app := New(Config{
  1069  			EnableTrustedProxyCheck: true,
  1070  		})
  1071  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1072  		defer app.ReleaseCtx(c)
  1073  		utils.AssertEqual(t, false, c.IsProxyTrusted())
  1074  	}
  1075  	{
  1076  		app := New(Config{
  1077  			EnableTrustedProxyCheck: true,
  1078  
  1079  			TrustedProxies: []string{},
  1080  		})
  1081  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1082  		defer app.ReleaseCtx(c)
  1083  		utils.AssertEqual(t, false, c.IsProxyTrusted())
  1084  	}
  1085  	{
  1086  		app := New(Config{
  1087  			EnableTrustedProxyCheck: true,
  1088  
  1089  			TrustedProxies: []string{
  1090  				"127.0.0.1",
  1091  			},
  1092  		})
  1093  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1094  		defer app.ReleaseCtx(c)
  1095  		utils.AssertEqual(t, false, c.IsProxyTrusted())
  1096  	}
  1097  	{
  1098  		app := New(Config{
  1099  			EnableTrustedProxyCheck: true,
  1100  
  1101  			TrustedProxies: []string{
  1102  				"127.0.0.1/8",
  1103  			},
  1104  		})
  1105  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1106  		defer app.ReleaseCtx(c)
  1107  		utils.AssertEqual(t, false, c.IsProxyTrusted())
  1108  	}
  1109  	{
  1110  		app := New(Config{
  1111  			EnableTrustedProxyCheck: true,
  1112  
  1113  			TrustedProxies: []string{
  1114  				"0.0.0.0",
  1115  			},
  1116  		})
  1117  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1118  		defer app.ReleaseCtx(c)
  1119  		utils.AssertEqual(t, true, c.IsProxyTrusted())
  1120  	}
  1121  	{
  1122  		app := New(Config{
  1123  			EnableTrustedProxyCheck: true,
  1124  
  1125  			TrustedProxies: []string{
  1126  				"0.0.0.1/31",
  1127  			},
  1128  		})
  1129  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1130  		defer app.ReleaseCtx(c)
  1131  		utils.AssertEqual(t, true, c.IsProxyTrusted())
  1132  	}
  1133  	{
  1134  		app := New(Config{
  1135  			EnableTrustedProxyCheck: true,
  1136  
  1137  			TrustedProxies: []string{
  1138  				"0.0.0.1/31junk",
  1139  			},
  1140  		})
  1141  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1142  		defer app.ReleaseCtx(c)
  1143  		utils.AssertEqual(t, false, c.IsProxyTrusted())
  1144  	}
  1145  }
  1146  
  1147  // go test -run Test_Ctx_Hostname
  1148  func Test_Ctx_Hostname(t *testing.T) {
  1149  	t.Parallel()
  1150  	app := New()
  1151  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1152  	defer app.ReleaseCtx(c)
  1153  	c.Request().SetRequestURI("http://google.com/test")
  1154  	utils.AssertEqual(t, "google.com", c.Hostname())
  1155  }
  1156  
  1157  // go test -run Test_Ctx_Hostname_Untrusted
  1158  func Test_Ctx_Hostname_UntrustedProxy(t *testing.T) {
  1159  	t.Parallel()
  1160  	// Don't trust any proxy
  1161  	{
  1162  		app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{}})
  1163  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1164  		c.Request().SetRequestURI("http://google.com/test")
  1165  		c.Request().Header.Set(HeaderXForwardedHost, "google1.com")
  1166  		utils.AssertEqual(t, "google.com", c.Hostname())
  1167  		app.ReleaseCtx(c)
  1168  	}
  1169  	// Trust to specific proxy list
  1170  	{
  1171  		app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.8.0.0", "0.8.0.1"}})
  1172  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1173  		c.Request().SetRequestURI("http://google.com/test")
  1174  		c.Request().Header.Set(HeaderXForwardedHost, "google1.com")
  1175  		utils.AssertEqual(t, "google.com", c.Hostname())
  1176  		app.ReleaseCtx(c)
  1177  	}
  1178  }
  1179  
  1180  // go test -run Test_Ctx_Hostname_Trusted
  1181  func Test_Ctx_Hostname_TrustedProxy(t *testing.T) {
  1182  	t.Parallel()
  1183  	{
  1184  		app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0", "0.8.0.1"}})
  1185  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1186  		c.Request().SetRequestURI("http://google.com/test")
  1187  		c.Request().Header.Set(HeaderXForwardedHost, "google1.com")
  1188  		utils.AssertEqual(t, "google1.com", c.Hostname())
  1189  		app.ReleaseCtx(c)
  1190  	}
  1191  }
  1192  
  1193  // go test -run Test_Ctx_Hostname_Trusted_Multiple
  1194  func Test_Ctx_Hostname_TrustedProxy_Multiple(t *testing.T) {
  1195  	t.Parallel()
  1196  	{
  1197  		app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0", "0.8.0.1"}})
  1198  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1199  		c.Request().SetRequestURI("http://google.com/test")
  1200  		c.Request().Header.Set(HeaderXForwardedHost, "google1.com, google2.com")
  1201  		utils.AssertEqual(t, "google1.com", c.Hostname())
  1202  		app.ReleaseCtx(c)
  1203  	}
  1204  }
  1205  
  1206  // go test -run Test_Ctx_Hostname_UntrustedProxyRange
  1207  func Test_Ctx_Hostname_TrustedProxyRange(t *testing.T) {
  1208  	t.Parallel()
  1209  
  1210  	app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0/30"}})
  1211  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1212  	c.Request().SetRequestURI("http://google.com/test")
  1213  	c.Request().Header.Set(HeaderXForwardedHost, "google1.com")
  1214  	utils.AssertEqual(t, "google1.com", c.Hostname())
  1215  	app.ReleaseCtx(c)
  1216  }
  1217  
  1218  // go test -run Test_Ctx_Hostname_UntrustedProxyRange
  1219  func Test_Ctx_Hostname_UntrustedProxyRange(t *testing.T) {
  1220  	t.Parallel()
  1221  
  1222  	app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"1.0.0.0/30"}})
  1223  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1224  	c.Request().SetRequestURI("http://google.com/test")
  1225  	c.Request().Header.Set(HeaderXForwardedHost, "google1.com")
  1226  	utils.AssertEqual(t, "google.com", c.Hostname())
  1227  	app.ReleaseCtx(c)
  1228  }
  1229  
  1230  // go test -run Test_Ctx_Port
  1231  func Test_Ctx_Port(t *testing.T) {
  1232  	t.Parallel()
  1233  	app := New()
  1234  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1235  	defer app.ReleaseCtx(c)
  1236  	utils.AssertEqual(t, "0", c.Port())
  1237  }
  1238  
  1239  // go test -run Test_Ctx_PortInHandler
  1240  func Test_Ctx_PortInHandler(t *testing.T) {
  1241  	t.Parallel()
  1242  	app := New()
  1243  
  1244  	app.Get("/port", func(c *Ctx) error {
  1245  		return c.SendString(c.Port())
  1246  	})
  1247  
  1248  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/port", nil))
  1249  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1250  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1251  
  1252  	body, err := io.ReadAll(resp.Body)
  1253  	utils.AssertEqual(t, nil, err)
  1254  	utils.AssertEqual(t, "0", string(body))
  1255  }
  1256  
  1257  // go test -run Test_Ctx_IP
  1258  func Test_Ctx_IP(t *testing.T) {
  1259  	t.Parallel()
  1260  
  1261  	app := New()
  1262  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1263  	defer app.ReleaseCtx(c)
  1264  
  1265  	// default behavior will return the remote IP from the stack
  1266  	utils.AssertEqual(t, "0.0.0.0", c.IP())
  1267  
  1268  	// X-Forwarded-For is set, but it is ignored because proxyHeader is not set
  1269  	c.Request().Header.Set(HeaderXForwardedFor, "0.0.0.1")
  1270  	utils.AssertEqual(t, "0.0.0.0", c.IP())
  1271  }
  1272  
  1273  // go test -run Test_Ctx_IP_ProxyHeader
  1274  func Test_Ctx_IP_ProxyHeader(t *testing.T) {
  1275  	t.Parallel()
  1276  
  1277  	// make sure that the same behavior exists for different proxy header names
  1278  	proxyHeaderNames := []string{"Real-Ip", HeaderXForwardedFor}
  1279  
  1280  	for _, proxyHeaderName := range proxyHeaderNames {
  1281  		app := New(Config{ProxyHeader: proxyHeaderName})
  1282  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1283  
  1284  		c.Request().Header.Set(proxyHeaderName, "0.0.0.1")
  1285  		utils.AssertEqual(t, "0.0.0.1", c.IP())
  1286  
  1287  		// without IP validation we return the full string
  1288  		c.Request().Header.Set(proxyHeaderName, "0.0.0.1, 0.0.0.2")
  1289  		utils.AssertEqual(t, "0.0.0.1, 0.0.0.2", c.IP())
  1290  
  1291  		// without IP validation we return invalid IPs
  1292  		c.Request().Header.Set(proxyHeaderName, "invalid, 0.0.0.2, 0.0.0.3")
  1293  		utils.AssertEqual(t, "invalid, 0.0.0.2, 0.0.0.3", c.IP())
  1294  
  1295  		// when proxy header is enabled but the value is empty, without IP validation we return an empty string
  1296  		c.Request().Header.Set(proxyHeaderName, "")
  1297  		utils.AssertEqual(t, "", c.IP())
  1298  
  1299  		// without IP validation we return an invalid IP
  1300  		c.Request().Header.Set(proxyHeaderName, "not-valid-ip")
  1301  		utils.AssertEqual(t, "not-valid-ip", c.IP())
  1302  
  1303  		app.ReleaseCtx(c)
  1304  	}
  1305  }
  1306  
  1307  // go test -run Test_Ctx_IP_ProxyHeader
  1308  func Test_Ctx_IP_ProxyHeader_With_IP_Validation(t *testing.T) {
  1309  	t.Parallel()
  1310  
  1311  	// make sure that the same behavior exists for different proxy header names
  1312  	proxyHeaderNames := []string{"Real-Ip", HeaderXForwardedFor}
  1313  
  1314  	for _, proxyHeaderName := range proxyHeaderNames {
  1315  		app := New(Config{EnableIPValidation: true, ProxyHeader: proxyHeaderName})
  1316  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1317  
  1318  		// when proxy header & validation is enabled and the value is a valid IP, we return it
  1319  		c.Request().Header.Set(proxyHeaderName, "0.0.0.1")
  1320  		utils.AssertEqual(t, "0.0.0.1", c.IP())
  1321  
  1322  		// when proxy header & validation is enabled and the value is a list of IPs, we return the first valid IP
  1323  		c.Request().Header.Set(proxyHeaderName, "0.0.0.1, 0.0.0.2")
  1324  		utils.AssertEqual(t, "0.0.0.1", c.IP())
  1325  
  1326  		c.Request().Header.Set(proxyHeaderName, "invalid, 0.0.0.2, 0.0.0.3")
  1327  		utils.AssertEqual(t, "0.0.0.2", c.IP())
  1328  
  1329  		// when proxy header & validation is enabled but the value is empty, we will ignore the header
  1330  		c.Request().Header.Set(proxyHeaderName, "")
  1331  		utils.AssertEqual(t, "0.0.0.0", c.IP())
  1332  
  1333  		// when proxy header & validation is enabled but the value is not an IP, we will ignore the header
  1334  		// and return the IP of the caller
  1335  		c.Request().Header.Set(proxyHeaderName, "not-valid-ip")
  1336  		utils.AssertEqual(t, "0.0.0.0", c.IP())
  1337  
  1338  		app.ReleaseCtx(c)
  1339  	}
  1340  }
  1341  
  1342  // go test -run Test_Ctx_IP_UntrustedProxy
  1343  func Test_Ctx_IP_UntrustedProxy(t *testing.T) {
  1344  	t.Parallel()
  1345  	app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.8.0.1"}, ProxyHeader: HeaderXForwardedFor})
  1346  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1347  	c.Request().Header.Set(HeaderXForwardedFor, "0.0.0.1")
  1348  	defer app.ReleaseCtx(c)
  1349  	utils.AssertEqual(t, "0.0.0.0", c.IP())
  1350  }
  1351  
  1352  // go test -run Test_Ctx_IP_TrustedProxy
  1353  func Test_Ctx_IP_TrustedProxy(t *testing.T) {
  1354  	t.Parallel()
  1355  	app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0"}, ProxyHeader: HeaderXForwardedFor})
  1356  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1357  	c.Request().Header.Set(HeaderXForwardedFor, "0.0.0.1")
  1358  	defer app.ReleaseCtx(c)
  1359  	utils.AssertEqual(t, "0.0.0.1", c.IP())
  1360  }
  1361  
  1362  // go test -run Test_Ctx_IPs  -parallel
  1363  func Test_Ctx_IPs(t *testing.T) {
  1364  	t.Parallel()
  1365  	app := New()
  1366  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1367  	defer app.ReleaseCtx(c)
  1368  
  1369  	// normal happy path test case
  1370  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, 127.0.0.2, 127.0.0.3")
  1371  	utils.AssertEqual(t, []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}, c.IPs())
  1372  
  1373  	// inconsistent space formatting
  1374  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1,127.0.0.2  ,127.0.0.3")
  1375  	utils.AssertEqual(t, []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}, c.IPs())
  1376  
  1377  	// invalid IPs are allowed to be returned
  1378  	c.Request().Header.Set(HeaderXForwardedFor, "invalid, 127.0.0.1, 127.0.0.2")
  1379  	utils.AssertEqual(t, []string{"invalid", "127.0.0.1", "127.0.0.2"}, c.IPs())
  1380  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.2")
  1381  	utils.AssertEqual(t, []string{"127.0.0.1", "invalid", "127.0.0.2"}, c.IPs())
  1382  
  1383  	// ensure that the ordering of IPs in the header is maintained
  1384  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.3, 127.0.0.1, 127.0.0.2")
  1385  	utils.AssertEqual(t, []string{"127.0.0.3", "127.0.0.1", "127.0.0.2"}, c.IPs())
  1386  
  1387  	// ensure for IPv6
  1388  	c.Request().Header.Set(HeaderXForwardedFor, "9396:9549:b4f7:8ed0:4791:1330:8c06:e62d, invalid, 2345:0425:2CA1::0567:5673:23b5")
  1389  	utils.AssertEqual(t, []string{"9396:9549:b4f7:8ed0:4791:1330:8c06:e62d", "invalid", "2345:0425:2CA1::0567:5673:23b5"}, c.IPs())
  1390  
  1391  	// empty header
  1392  	c.Request().Header.Set(HeaderXForwardedFor, "")
  1393  	utils.AssertEqual(t, 0, len(c.IPs()))
  1394  
  1395  	// missing header
  1396  	c.Request()
  1397  	utils.AssertEqual(t, 0, len(c.IPs()))
  1398  }
  1399  
  1400  func Test_Ctx_IPs_With_IP_Validation(t *testing.T) {
  1401  	t.Parallel()
  1402  	app := New(Config{EnableIPValidation: true})
  1403  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1404  	defer app.ReleaseCtx(c)
  1405  
  1406  	// normal happy path test case
  1407  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, 127.0.0.2, 127.0.0.3")
  1408  	utils.AssertEqual(t, []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}, c.IPs())
  1409  
  1410  	// inconsistent space formatting
  1411  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1,127.0.0.2  ,127.0.0.3")
  1412  	utils.AssertEqual(t, []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}, c.IPs())
  1413  
  1414  	// invalid IPs are in the header
  1415  	c.Request().Header.Set(HeaderXForwardedFor, "invalid, 127.0.0.1, 127.0.0.2")
  1416  	utils.AssertEqual(t, []string{"127.0.0.1", "127.0.0.2"}, c.IPs())
  1417  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.2")
  1418  	utils.AssertEqual(t, []string{"127.0.0.1", "127.0.0.2"}, c.IPs())
  1419  
  1420  	// ensure that the ordering of IPs in the header is maintained
  1421  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.3, 127.0.0.1, 127.0.0.2")
  1422  	utils.AssertEqual(t, []string{"127.0.0.3", "127.0.0.1", "127.0.0.2"}, c.IPs())
  1423  
  1424  	// ensure for IPv6
  1425  	c.Request().Header.Set(HeaderXForwardedFor, "f037:825e:eadb:1b7b:1667:6f0a:5356:f604, invalid, 9396:9549:b4f7:8ed0:4791:1330:8c06:e62d")
  1426  	utils.AssertEqual(t, []string{"f037:825e:eadb:1b7b:1667:6f0a:5356:f604", "9396:9549:b4f7:8ed0:4791:1330:8c06:e62d"}, c.IPs())
  1427  
  1428  	// empty header
  1429  	c.Request().Header.Set(HeaderXForwardedFor, "")
  1430  	utils.AssertEqual(t, 0, len(c.IPs()))
  1431  
  1432  	// missing header
  1433  	c.Request()
  1434  	utils.AssertEqual(t, 0, len(c.IPs()))
  1435  }
  1436  
  1437  // go test -v -run=^$ -bench=Benchmark_Ctx_IPs -benchmem -count=4
  1438  func Benchmark_Ctx_IPs(b *testing.B) {
  1439  	app := New()
  1440  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1441  	defer app.ReleaseCtx(c)
  1442  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.1")
  1443  	var res []string
  1444  	b.ReportAllocs()
  1445  	b.ResetTimer()
  1446  	for n := 0; n < b.N; n++ {
  1447  		res = c.IPs()
  1448  	}
  1449  	utils.AssertEqual(b, []string{"127.0.0.1", "invalid", "127.0.0.1"}, res)
  1450  }
  1451  
  1452  func Benchmark_Ctx_IPs_v6(b *testing.B) {
  1453  	app := New()
  1454  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1455  	defer app.ReleaseCtx(c)
  1456  	c.Request().Header.Set(HeaderXForwardedFor, "f037:825e:eadb:1b7b:1667:6f0a:5356:f604, invalid, 2345:0425:2CA1::0567:5673:23b5")
  1457  	var res []string
  1458  	b.ReportAllocs()
  1459  	b.ResetTimer()
  1460  	for n := 0; n < b.N; n++ {
  1461  		res = c.IPs()
  1462  	}
  1463  	utils.AssertEqual(b, []string{"f037:825e:eadb:1b7b:1667:6f0a:5356:f604", "invalid", "2345:0425:2CA1::0567:5673:23b5"}, res)
  1464  }
  1465  
  1466  func Benchmark_Ctx_IPs_With_IP_Validation(b *testing.B) {
  1467  	app := New(Config{EnableIPValidation: true})
  1468  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1469  	defer app.ReleaseCtx(c)
  1470  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1, invalid, 127.0.0.1")
  1471  	var res []string
  1472  	b.ReportAllocs()
  1473  	b.ResetTimer()
  1474  	for n := 0; n < b.N; n++ {
  1475  		res = c.IPs()
  1476  	}
  1477  	utils.AssertEqual(b, []string{"127.0.0.1", "127.0.0.1"}, res)
  1478  }
  1479  
  1480  func Benchmark_Ctx_IPs_v6_With_IP_Validation(b *testing.B) {
  1481  	app := New(Config{EnableIPValidation: true})
  1482  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1483  	defer app.ReleaseCtx(c)
  1484  	c.Request().Header.Set(HeaderXForwardedFor, "2345:0425:2CA1:0000:0000:0567:5673:23b5, invalid, 2345:0425:2CA1::0567:5673:23b5")
  1485  	var res []string
  1486  	b.ReportAllocs()
  1487  	b.ResetTimer()
  1488  	for n := 0; n < b.N; n++ {
  1489  		res = c.IPs()
  1490  	}
  1491  	utils.AssertEqual(b, []string{"2345:0425:2CA1:0000:0000:0567:5673:23b5", "2345:0425:2CA1::0567:5673:23b5"}, res)
  1492  }
  1493  
  1494  func Benchmark_Ctx_IP_With_ProxyHeader(b *testing.B) {
  1495  	app := New(Config{ProxyHeader: HeaderXForwardedFor})
  1496  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1497  	defer app.ReleaseCtx(c)
  1498  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1")
  1499  	var res string
  1500  	b.ReportAllocs()
  1501  	b.ResetTimer()
  1502  	for n := 0; n < b.N; n++ {
  1503  		res = c.IP()
  1504  	}
  1505  	utils.AssertEqual(b, "127.0.0.1", res)
  1506  }
  1507  
  1508  func Benchmark_Ctx_IP_With_ProxyHeader_and_IP_Validation(b *testing.B) {
  1509  	app := New(Config{ProxyHeader: HeaderXForwardedFor, EnableIPValidation: true})
  1510  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1511  	defer app.ReleaseCtx(c)
  1512  	c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1")
  1513  	var res string
  1514  	b.ReportAllocs()
  1515  	b.ResetTimer()
  1516  	for n := 0; n < b.N; n++ {
  1517  		res = c.IP()
  1518  	}
  1519  	utils.AssertEqual(b, "127.0.0.1", res)
  1520  }
  1521  
  1522  func Benchmark_Ctx_IP(b *testing.B) {
  1523  	app := New()
  1524  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1525  	defer app.ReleaseCtx(c)
  1526  	c.Request()
  1527  	var res string
  1528  	b.ReportAllocs()
  1529  	b.ResetTimer()
  1530  	for n := 0; n < b.N; n++ {
  1531  		res = c.IP()
  1532  	}
  1533  	utils.AssertEqual(b, "0.0.0.0", res)
  1534  }
  1535  
  1536  // go test -run Test_Ctx_Is
  1537  func Test_Ctx_Is(t *testing.T) {
  1538  	t.Parallel()
  1539  	app := New()
  1540  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1541  	defer app.ReleaseCtx(c)
  1542  	c.Request().Header.Set(HeaderContentType, MIMETextHTML+"; boundary=something")
  1543  	utils.AssertEqual(t, true, c.Is(".html"))
  1544  	utils.AssertEqual(t, true, c.Is("html"))
  1545  	utils.AssertEqual(t, false, c.Is("json"))
  1546  	utils.AssertEqual(t, false, c.Is(".json"))
  1547  	utils.AssertEqual(t, false, c.Is(""))
  1548  	utils.AssertEqual(t, false, c.Is(".foooo"))
  1549  
  1550  	c.Request().Header.Set(HeaderContentType, MIMEApplicationJSONCharsetUTF8)
  1551  	utils.AssertEqual(t, false, c.Is("html"))
  1552  	utils.AssertEqual(t, true, c.Is("json"))
  1553  	utils.AssertEqual(t, true, c.Is(".json"))
  1554  
  1555  	c.Request().Header.Set(HeaderContentType, " application/json;charset=UTF-8")
  1556  	utils.AssertEqual(t, false, c.Is("html"))
  1557  	utils.AssertEqual(t, true, c.Is("json"))
  1558  	utils.AssertEqual(t, true, c.Is(".json"))
  1559  
  1560  	c.Request().Header.Set(HeaderContentType, MIMEApplicationXMLCharsetUTF8)
  1561  	utils.AssertEqual(t, false, c.Is("html"))
  1562  	utils.AssertEqual(t, true, c.Is("xml"))
  1563  	utils.AssertEqual(t, true, c.Is(".xml"))
  1564  
  1565  	c.Request().Header.Set(HeaderContentType, MIMETextPlain)
  1566  	utils.AssertEqual(t, false, c.Is("html"))
  1567  	utils.AssertEqual(t, true, c.Is("txt"))
  1568  	utils.AssertEqual(t, true, c.Is(".txt"))
  1569  }
  1570  
  1571  // go test -v -run=^$ -bench=Benchmark_Ctx_Is -benchmem -count=4
  1572  func Benchmark_Ctx_Is(b *testing.B) {
  1573  	app := New()
  1574  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1575  	defer app.ReleaseCtx(c)
  1576  	c.Request().Header.Set(HeaderContentType, MIMEApplicationJSON)
  1577  	var res bool
  1578  	b.ReportAllocs()
  1579  	b.ResetTimer()
  1580  	for n := 0; n < b.N; n++ {
  1581  		_ = c.Is(".json")
  1582  		res = c.Is("json")
  1583  	}
  1584  	utils.AssertEqual(b, true, res)
  1585  }
  1586  
  1587  // go test -run Test_Ctx_Locals
  1588  func Test_Ctx_Locals(t *testing.T) {
  1589  	t.Parallel()
  1590  	app := New()
  1591  	app.Use(func(c *Ctx) error {
  1592  		c.Locals("john", "doe")
  1593  		return c.Next()
  1594  	})
  1595  	app.Get("/test", func(c *Ctx) error {
  1596  		utils.AssertEqual(t, "doe", c.Locals("john"))
  1597  		return nil
  1598  	})
  1599  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/test", nil))
  1600  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1601  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1602  }
  1603  
  1604  // go test -run Test_Ctx_Method
  1605  func Test_Ctx_Method(t *testing.T) {
  1606  	t.Parallel()
  1607  	fctx := &fasthttp.RequestCtx{}
  1608  	fctx.Request.Header.SetMethod(MethodGet)
  1609  	app := New()
  1610  	c := app.AcquireCtx(fctx)
  1611  	defer app.ReleaseCtx(c)
  1612  	utils.AssertEqual(t, MethodGet, c.Method())
  1613  	c.Method(MethodPost)
  1614  	utils.AssertEqual(t, MethodPost, c.Method())
  1615  
  1616  	c.Method("MethodInvalid")
  1617  	utils.AssertEqual(t, MethodPost, c.Method())
  1618  }
  1619  
  1620  // go test -run Test_Ctx_ClientHelloInfo
  1621  func Test_Ctx_ClientHelloInfo(t *testing.T) {
  1622  	t.Parallel()
  1623  	app := New()
  1624  	app.Get("/ServerName", func(c *Ctx) error {
  1625  		result := c.ClientHelloInfo()
  1626  		if result != nil {
  1627  			return c.SendString(result.ServerName)
  1628  		}
  1629  
  1630  		return c.SendString("ClientHelloInfo is nil")
  1631  	})
  1632  	app.Get("/SignatureSchemes", func(c *Ctx) error {
  1633  		result := c.ClientHelloInfo()
  1634  		if result != nil {
  1635  			return c.JSON(result.SignatureSchemes)
  1636  		}
  1637  
  1638  		return c.SendString("ClientHelloInfo is nil")
  1639  	})
  1640  	app.Get("/SupportedVersions", func(c *Ctx) error {
  1641  		result := c.ClientHelloInfo()
  1642  		if result != nil {
  1643  			return c.JSON(result.SupportedVersions)
  1644  		}
  1645  
  1646  		return c.SendString("ClientHelloInfo is nil")
  1647  	})
  1648  
  1649  	// Test without TLS handler
  1650  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/ServerName", nil))
  1651  	utils.AssertEqual(t, nil, err)
  1652  	body, err := io.ReadAll(resp.Body)
  1653  	utils.AssertEqual(t, nil, err)
  1654  	utils.AssertEqual(t, []byte("ClientHelloInfo is nil"), body)
  1655  
  1656  	// Test with TLS Handler
  1657  	const (
  1658  		pssWithSHA256 = 0x0804
  1659  		versionTLS13  = 0x0304
  1660  	)
  1661  	app.tlsHandler = &TLSHandler{clientHelloInfo: &tls.ClientHelloInfo{
  1662  		ServerName:        "example.golang",
  1663  		SignatureSchemes:  []tls.SignatureScheme{pssWithSHA256},
  1664  		SupportedVersions: []uint16{versionTLS13},
  1665  	}}
  1666  
  1667  	// Test ServerName
  1668  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/ServerName", nil))
  1669  	utils.AssertEqual(t, nil, err)
  1670  	body, err = io.ReadAll(resp.Body)
  1671  	utils.AssertEqual(t, nil, err)
  1672  	utils.AssertEqual(t, []byte("example.golang"), body)
  1673  
  1674  	// Test SignatureSchemes
  1675  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/SignatureSchemes", nil))
  1676  	utils.AssertEqual(t, nil, err)
  1677  	body, err = io.ReadAll(resp.Body)
  1678  	utils.AssertEqual(t, nil, err)
  1679  	utils.AssertEqual(t, "["+strconv.Itoa(pssWithSHA256)+"]", string(body))
  1680  
  1681  	// Test SupportedVersions
  1682  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/SupportedVersions", nil))
  1683  	utils.AssertEqual(t, nil, err)
  1684  	body, err = io.ReadAll(resp.Body)
  1685  	utils.AssertEqual(t, nil, err)
  1686  	utils.AssertEqual(t, "["+strconv.Itoa(versionTLS13)+"]", string(body))
  1687  }
  1688  
  1689  // go test -run Test_Ctx_InvalidMethod
  1690  func Test_Ctx_InvalidMethod(t *testing.T) {
  1691  	t.Parallel()
  1692  	app := New()
  1693  	app.Get("/", func(c *Ctx) error {
  1694  		return nil
  1695  	})
  1696  
  1697  	fctx := &fasthttp.RequestCtx{}
  1698  	fctx.Request.Header.SetMethod("InvalidMethod")
  1699  	fctx.Request.SetRequestURI("/")
  1700  
  1701  	app.Handler()(fctx)
  1702  
  1703  	utils.AssertEqual(t, 400, fctx.Response.StatusCode())
  1704  	utils.AssertEqual(t, []byte("Invalid http method"), fctx.Response.Body())
  1705  }
  1706  
  1707  // go test -run Test_Ctx_MultipartForm
  1708  func Test_Ctx_MultipartForm(t *testing.T) {
  1709  	t.Parallel()
  1710  	app := New()
  1711  
  1712  	app.Post("/test", func(c *Ctx) error {
  1713  		result, err := c.MultipartForm()
  1714  		utils.AssertEqual(t, nil, err)
  1715  		utils.AssertEqual(t, "john", result.Value["name"][0])
  1716  		return nil
  1717  	})
  1718  
  1719  	body := &bytes.Buffer{}
  1720  	writer := multipart.NewWriter(body)
  1721  	utils.AssertEqual(t, nil, writer.WriteField("name", "john"))
  1722  	utils.AssertEqual(t, nil, writer.Close())
  1723  
  1724  	req := httptest.NewRequest(MethodPost, "/test", body)
  1725  	req.Header.Set(HeaderContentType, fmt.Sprintf("multipart/form-data; boundary=%s", writer.Boundary()))
  1726  	req.Header.Set(HeaderContentLength, strconv.Itoa(len(body.Bytes())))
  1727  
  1728  	resp, err := app.Test(req)
  1729  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1730  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1731  }
  1732  
  1733  // go test -v -run=^$ -bench=Benchmark_Ctx_MultipartForm -benchmem -count=4
  1734  func Benchmark_Ctx_MultipartForm(b *testing.B) {
  1735  	app := New()
  1736  
  1737  	app.Post("/", func(c *Ctx) error {
  1738  		_, err := c.MultipartForm()
  1739  		return err
  1740  	})
  1741  
  1742  	c := &fasthttp.RequestCtx{}
  1743  
  1744  	body := []byte("--b\r\nContent-Disposition: form-data; name=\"name\"\r\n\r\njohn\r\n--b--")
  1745  	c.Request.SetBody(body)
  1746  	c.Request.Header.SetContentType(MIMEMultipartForm + `;boundary="b"`)
  1747  	c.Request.Header.SetContentLength(len(body))
  1748  
  1749  	h := app.Handler()
  1750  
  1751  	b.ReportAllocs()
  1752  	b.ResetTimer()
  1753  
  1754  	for n := 0; n < b.N; n++ {
  1755  		h(c)
  1756  	}
  1757  }
  1758  
  1759  // go test -run Test_Ctx_OriginalURL
  1760  func Test_Ctx_OriginalURL(t *testing.T) {
  1761  	t.Parallel()
  1762  	app := New()
  1763  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1764  	defer app.ReleaseCtx(c)
  1765  	c.Request().Header.SetRequestURI("http://google.com/test?search=demo")
  1766  	utils.AssertEqual(t, "http://google.com/test?search=demo", c.OriginalURL())
  1767  }
  1768  
  1769  // go test -race -run Test_Ctx_Params
  1770  func Test_Ctx_Params(t *testing.T) {
  1771  	t.Parallel()
  1772  	app := New()
  1773  	app.Get("/test/:user", func(c *Ctx) error {
  1774  		utils.AssertEqual(t, "john", c.Params("user"))
  1775  		return nil
  1776  	})
  1777  	app.Get("/test2/*", func(c *Ctx) error {
  1778  		utils.AssertEqual(t, "im/a/cookie", c.Params("*"))
  1779  		return nil
  1780  	})
  1781  	app.Get("/test3/*/blafasel/*", func(c *Ctx) error {
  1782  		utils.AssertEqual(t, "1111", c.Params("*1"))
  1783  		utils.AssertEqual(t, "2222", c.Params("*2"))
  1784  		utils.AssertEqual(t, "1111", c.Params("*"))
  1785  		return nil
  1786  	})
  1787  	app.Get("/test4/:optional?", func(c *Ctx) error {
  1788  		utils.AssertEqual(t, "", c.Params("optional"))
  1789  		return nil
  1790  	})
  1791  	app.Get("/test5/:id/:Id", func(c *Ctx) error {
  1792  		utils.AssertEqual(t, "first", c.Params("id"))
  1793  		utils.AssertEqual(t, "first", c.Params("Id"))
  1794  		return nil
  1795  	})
  1796  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/test/john", nil))
  1797  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1798  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1799  
  1800  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test2/im/a/cookie", nil))
  1801  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1802  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1803  
  1804  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test3/1111/blafasel/2222", nil))
  1805  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1806  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1807  
  1808  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test4", nil))
  1809  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1810  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1811  
  1812  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test5/first/second", nil))
  1813  	utils.AssertEqual(t, nil, err)
  1814  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1815  }
  1816  
  1817  func Test_Ctx_Params_Case_Sensitive(t *testing.T) {
  1818  	t.Parallel()
  1819  	app := New(Config{CaseSensitive: true})
  1820  	app.Get("/test/:User", func(c *Ctx) error {
  1821  		utils.AssertEqual(t, "john", c.Params("User"))
  1822  		utils.AssertEqual(t, "", c.Params("user"))
  1823  		return nil
  1824  	})
  1825  	app.Get("/test2/:id/:Id", func(c *Ctx) error {
  1826  		utils.AssertEqual(t, "first", c.Params("id"))
  1827  		utils.AssertEqual(t, "second", c.Params("Id"))
  1828  		return nil
  1829  	})
  1830  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/test/john", nil))
  1831  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1832  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1833  
  1834  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test2/first/second", nil))
  1835  	utils.AssertEqual(t, nil, err)
  1836  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1837  }
  1838  
  1839  // go test -race -run Test_Ctx_AllParams
  1840  func Test_Ctx_AllParams(t *testing.T) {
  1841  	t.Parallel()
  1842  	app := New()
  1843  	app.Get("/test/:user", func(c *Ctx) error {
  1844  		utils.AssertEqual(t, map[string]string{"user": "john"}, c.AllParams())
  1845  		return nil
  1846  	})
  1847  	app.Get("/test2/*", func(c *Ctx) error {
  1848  		utils.AssertEqual(t, map[string]string{"*1": "im/a/cookie"}, c.AllParams())
  1849  		return nil
  1850  	})
  1851  	app.Get("/test3/*/blafasel/*", func(c *Ctx) error {
  1852  		utils.AssertEqual(t, map[string]string{"*1": "1111", "*2": "2222"}, c.AllParams())
  1853  		return nil
  1854  	})
  1855  	app.Get("/test4/:optional?", func(c *Ctx) error {
  1856  		utils.AssertEqual(t, map[string]string{"optional": ""}, c.AllParams())
  1857  		return nil
  1858  	})
  1859  
  1860  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/test/john", nil))
  1861  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1862  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1863  
  1864  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test2/im/a/cookie", nil))
  1865  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1866  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1867  
  1868  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test3/1111/blafasel/2222", nil))
  1869  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1870  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1871  
  1872  	resp, err = app.Test(httptest.NewRequest(MethodGet, "/test4", nil))
  1873  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1874  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1875  }
  1876  
  1877  // go test -v -run=^$ -bench=Benchmark_Ctx_Params -benchmem -count=4
  1878  func Benchmark_Ctx_Params(b *testing.B) {
  1879  	app := New()
  1880  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1881  	defer app.ReleaseCtx(c)
  1882  	c.route = &Route{
  1883  		Params: []string{
  1884  			"param1", "param2", "param3", "param4",
  1885  		},
  1886  	}
  1887  	c.values = [maxParams]string{
  1888  		"john", "doe", "is", "awesome",
  1889  	}
  1890  	var res string
  1891  	b.ReportAllocs()
  1892  	b.ResetTimer()
  1893  	for n := 0; n < b.N; n++ {
  1894  		_ = c.Params("param1")
  1895  		_ = c.Params("param2")
  1896  		_ = c.Params("param3")
  1897  		res = c.Params("param4")
  1898  	}
  1899  	utils.AssertEqual(b, "awesome", res)
  1900  }
  1901  
  1902  // go test -v -run=^$ -bench=Benchmark_Ctx_AllParams -benchmem -count=4
  1903  func Benchmark_Ctx_AllParams(b *testing.B) {
  1904  	app := New()
  1905  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1906  	defer app.ReleaseCtx(c)
  1907  	c.route = &Route{
  1908  		Params: []string{
  1909  			"param1", "param2", "param3", "param4",
  1910  		},
  1911  	}
  1912  	c.values = [maxParams]string{
  1913  		"john", "doe", "is", "awesome",
  1914  	}
  1915  	var res map[string]string
  1916  	b.ReportAllocs()
  1917  	b.ResetTimer()
  1918  	for n := 0; n < b.N; n++ {
  1919  		res = c.AllParams()
  1920  	}
  1921  	utils.AssertEqual(
  1922  		b,
  1923  		map[string]string{
  1924  			"param1": "john",
  1925  			"param2": "doe",
  1926  			"param3": "is",
  1927  			"param4": "awesome",
  1928  		},
  1929  		res,
  1930  	)
  1931  }
  1932  
  1933  // go test -v -run=^$ -bench=Benchmark_Ctx_ParamsParse -benchmem -count=4
  1934  func Benchmark_Ctx_ParamsParse(b *testing.B) {
  1935  	app := New()
  1936  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  1937  	defer app.ReleaseCtx(c)
  1938  	c.route = &Route{
  1939  		Params: []string{
  1940  			"param1", "param2", "param3", "param4",
  1941  		},
  1942  	}
  1943  	c.values = [maxParams]string{
  1944  		"john", "doe", "is", "awesome",
  1945  	}
  1946  	var res struct {
  1947  		Param1 string `params:"param1"`
  1948  		Param2 string `params:"param2"`
  1949  		Param3 string `params:"param3"`
  1950  		Param4 string `params:"param4"`
  1951  	}
  1952  	b.ReportAllocs()
  1953  	b.ResetTimer()
  1954  
  1955  	var err error
  1956  	for n := 0; n < b.N; n++ {
  1957  		err = c.ParamsParser(&res)
  1958  	}
  1959  
  1960  	utils.AssertEqual(b, nil, err)
  1961  	utils.AssertEqual(b, "john", res.Param1)
  1962  	utils.AssertEqual(b, "doe", res.Param2)
  1963  	utils.AssertEqual(b, "is", res.Param3)
  1964  	utils.AssertEqual(b, "awesome", res.Param4)
  1965  }
  1966  
  1967  // go test -run Test_Ctx_Path
  1968  func Test_Ctx_Path(t *testing.T) {
  1969  	t.Parallel()
  1970  	app := New(Config{UnescapePath: true})
  1971  	app.Get("/test/:user", func(c *Ctx) error {
  1972  		utils.AssertEqual(t, "/Test/John", c.Path())
  1973  		// not strict && case insensitive
  1974  		utils.AssertEqual(t, "/ABC/", c.Path("/ABC/"))
  1975  		utils.AssertEqual(t, "/test/john/", c.Path("/test/john/"))
  1976  		return nil
  1977  	})
  1978  
  1979  	// test with special chars
  1980  	app.Get("/specialChars/:name", func(c *Ctx) error {
  1981  		utils.AssertEqual(t, "/specialChars/créer", c.Path())
  1982  		// unescape is also working if you set the path afterwards
  1983  		utils.AssertEqual(t, "/اختبار/", c.Path("/%D8%A7%D8%AE%D8%AA%D8%A8%D8%A7%D8%B1/"))
  1984  		return nil
  1985  	})
  1986  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/specialChars/cr%C3%A9er", nil))
  1987  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  1988  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  1989  }
  1990  
  1991  // go test -run Test_Ctx_Protocol
  1992  func Test_Ctx_Protocol(t *testing.T) {
  1993  	t.Parallel()
  1994  	app := New()
  1995  
  1996  	freq := &fasthttp.RequestCtx{}
  1997  	freq.Request.Header.Set("X-Forwarded", "invalid")
  1998  
  1999  	c := app.AcquireCtx(freq)
  2000  	defer app.ReleaseCtx(c)
  2001  	c.Request().Header.Set(HeaderXForwardedProto, schemeHTTPS)
  2002  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2003  	c.Request().Header.Reset()
  2004  
  2005  	c.Request().Header.Set(HeaderXForwardedProtocol, schemeHTTPS)
  2006  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2007  	c.Request().Header.Reset()
  2008  
  2009  	c.Request().Header.Set(HeaderXForwardedProto, "https, http")
  2010  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2011  	c.Request().Header.Reset()
  2012  
  2013  	c.Request().Header.Set(HeaderXForwardedProtocol, "https, http")
  2014  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2015  	c.Request().Header.Reset()
  2016  
  2017  	c.Request().Header.Set(HeaderXForwardedSsl, "on")
  2018  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2019  	c.Request().Header.Reset()
  2020  
  2021  	c.Request().Header.Set(HeaderXUrlScheme, schemeHTTPS)
  2022  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2023  	c.Request().Header.Reset()
  2024  
  2025  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2026  }
  2027  
  2028  // go test -v -run=^$ -bench=Benchmark_Ctx_Protocol -benchmem -count=4
  2029  func Benchmark_Ctx_Protocol(b *testing.B) {
  2030  	app := New()
  2031  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2032  	defer app.ReleaseCtx(c)
  2033  	var res string
  2034  	b.ReportAllocs()
  2035  	b.ResetTimer()
  2036  	for n := 0; n < b.N; n++ {
  2037  		res = c.Protocol()
  2038  	}
  2039  	utils.AssertEqual(b, schemeHTTP, res)
  2040  }
  2041  
  2042  // go test -run Test_Ctx_Protocol_TrustedProxy
  2043  func Test_Ctx_Protocol_TrustedProxy(t *testing.T) {
  2044  	t.Parallel()
  2045  	app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0"}})
  2046  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2047  	defer app.ReleaseCtx(c)
  2048  
  2049  	c.Request().Header.Set(HeaderXForwardedProto, schemeHTTPS)
  2050  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2051  	c.Request().Header.Reset()
  2052  
  2053  	c.Request().Header.Set(HeaderXForwardedProtocol, schemeHTTPS)
  2054  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2055  	c.Request().Header.Reset()
  2056  
  2057  	c.Request().Header.Set(HeaderXForwardedSsl, "on")
  2058  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2059  	c.Request().Header.Reset()
  2060  
  2061  	c.Request().Header.Set(HeaderXUrlScheme, schemeHTTPS)
  2062  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2063  	c.Request().Header.Reset()
  2064  
  2065  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2066  }
  2067  
  2068  // go test -run Test_Ctx_Protocol_TrustedProxyRange
  2069  func Test_Ctx_Protocol_TrustedProxyRange(t *testing.T) {
  2070  	t.Parallel()
  2071  	app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.0.0.0/30"}})
  2072  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2073  	defer app.ReleaseCtx(c)
  2074  
  2075  	c.Request().Header.Set(HeaderXForwardedProto, schemeHTTPS)
  2076  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2077  	c.Request().Header.Reset()
  2078  
  2079  	c.Request().Header.Set(HeaderXForwardedProtocol, schemeHTTPS)
  2080  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2081  	c.Request().Header.Reset()
  2082  
  2083  	c.Request().Header.Set(HeaderXForwardedSsl, "on")
  2084  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2085  	c.Request().Header.Reset()
  2086  
  2087  	c.Request().Header.Set(HeaderXUrlScheme, schemeHTTPS)
  2088  	utils.AssertEqual(t, schemeHTTPS, c.Protocol())
  2089  	c.Request().Header.Reset()
  2090  
  2091  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2092  }
  2093  
  2094  // go test -run Test_Ctx_Protocol_UntrustedProxyRange
  2095  func Test_Ctx_Protocol_UntrustedProxyRange(t *testing.T) {
  2096  	t.Parallel()
  2097  	app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"1.1.1.1/30"}})
  2098  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2099  	defer app.ReleaseCtx(c)
  2100  
  2101  	c.Request().Header.Set(HeaderXForwardedProto, schemeHTTPS)
  2102  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2103  	c.Request().Header.Reset()
  2104  
  2105  	c.Request().Header.Set(HeaderXForwardedProtocol, schemeHTTPS)
  2106  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2107  	c.Request().Header.Reset()
  2108  
  2109  	c.Request().Header.Set(HeaderXForwardedSsl, "on")
  2110  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2111  	c.Request().Header.Reset()
  2112  
  2113  	c.Request().Header.Set(HeaderXUrlScheme, schemeHTTPS)
  2114  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2115  	c.Request().Header.Reset()
  2116  
  2117  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2118  }
  2119  
  2120  // go test -run Test_Ctx_Protocol_UnTrustedProxy
  2121  func Test_Ctx_Protocol_UnTrustedProxy(t *testing.T) {
  2122  	t.Parallel()
  2123  	app := New(Config{EnableTrustedProxyCheck: true, TrustedProxies: []string{"0.8.0.1"}})
  2124  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2125  	defer app.ReleaseCtx(c)
  2126  
  2127  	c.Request().Header.Set(HeaderXForwardedProto, schemeHTTPS)
  2128  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2129  	c.Request().Header.Reset()
  2130  
  2131  	c.Request().Header.Set(HeaderXForwardedProtocol, schemeHTTPS)
  2132  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2133  	c.Request().Header.Reset()
  2134  
  2135  	c.Request().Header.Set(HeaderXForwardedSsl, "on")
  2136  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2137  	c.Request().Header.Reset()
  2138  
  2139  	c.Request().Header.Set(HeaderXUrlScheme, schemeHTTPS)
  2140  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2141  	c.Request().Header.Reset()
  2142  
  2143  	utils.AssertEqual(t, schemeHTTP, c.Protocol())
  2144  }
  2145  
  2146  // go test -run Test_Ctx_Query
  2147  func Test_Ctx_Query(t *testing.T) {
  2148  	t.Parallel()
  2149  	app := New()
  2150  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2151  	defer app.ReleaseCtx(c)
  2152  	c.Request().URI().SetQueryString("search=john&age=20&id=")
  2153  	utils.AssertEqual(t, "john", c.Query("search"))
  2154  	utils.AssertEqual(t, "20", c.Query("age"))
  2155  	utils.AssertEqual(t, "default", c.Query("unknown", "default"))
  2156  }
  2157  
  2158  func Test_Ctx_QueryInt(t *testing.T) {
  2159  	t.Parallel()
  2160  	app := New()
  2161  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2162  	defer app.ReleaseCtx(c)
  2163  	c.Request().URI().SetQueryString("search=john&age=20&id=")
  2164  
  2165  	utils.AssertEqual(t, 0, c.QueryInt("foo"))
  2166  	utils.AssertEqual(t, 20, c.QueryInt("age", 12))
  2167  	utils.AssertEqual(t, 0, c.QueryInt("search"))
  2168  	utils.AssertEqual(t, 1, c.QueryInt("search", 1))
  2169  	utils.AssertEqual(t, 0, c.QueryInt("id"))
  2170  	utils.AssertEqual(t, 2, c.QueryInt("id", 2))
  2171  }
  2172  
  2173  func Test_Ctx_QueryBool(t *testing.T) {
  2174  	t.Parallel()
  2175  	app := New()
  2176  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2177  	defer app.ReleaseCtx(c)
  2178  	c.Request().URI().SetQueryString("name=alex&want_pizza=false&id=")
  2179  
  2180  	utils.AssertEqual(t, false, c.QueryBool("want_pizza"))
  2181  	utils.AssertEqual(t, false, c.QueryBool("want_pizza", true))
  2182  	utils.AssertEqual(t, false, c.QueryBool("name"))
  2183  	utils.AssertEqual(t, true, c.QueryBool("name", true))
  2184  	utils.AssertEqual(t, false, c.QueryBool("id"))
  2185  	utils.AssertEqual(t, true, c.QueryBool("id", true))
  2186  }
  2187  
  2188  func Test_Ctx_QueryFloat(t *testing.T) {
  2189  	t.Parallel()
  2190  	app := New()
  2191  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2192  	defer app.ReleaseCtx(c)
  2193  	c.Request().URI().SetQueryString("name=alex&amount=32.23&id=")
  2194  
  2195  	utils.AssertEqual(t, 32.23, c.QueryFloat("amount"))
  2196  	utils.AssertEqual(t, 32.23, c.QueryFloat("amount", 3.123))
  2197  	utils.AssertEqual(t, 87.123, c.QueryFloat("name", 87.123))
  2198  	utils.AssertEqual(t, float64(0), c.QueryFloat("name"))
  2199  	utils.AssertEqual(t, 12.87, c.QueryFloat("id", 12.87))
  2200  	utils.AssertEqual(t, float64(0), c.QueryFloat("id"))
  2201  }
  2202  
  2203  // go test -run Test_Ctx_Range
  2204  func Test_Ctx_Range(t *testing.T) {
  2205  	t.Parallel()
  2206  	app := New()
  2207  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2208  	defer app.ReleaseCtx(c)
  2209  
  2210  	var (
  2211  		result Range
  2212  		err    error
  2213  	)
  2214  
  2215  	_, err = c.Range(1000)
  2216  	utils.AssertEqual(t, true, err != nil)
  2217  
  2218  	c.Request().Header.Set(HeaderRange, "bytes=500")
  2219  	_, err = c.Range(1000)
  2220  	utils.AssertEqual(t, true, err != nil)
  2221  
  2222  	c.Request().Header.Set(HeaderRange, "bytes=500=")
  2223  	_, err = c.Range(1000)
  2224  	utils.AssertEqual(t, true, err != nil)
  2225  
  2226  	c.Request().Header.Set(HeaderRange, "bytes=500-300")
  2227  	_, err = c.Range(1000)
  2228  	utils.AssertEqual(t, true, err != nil)
  2229  
  2230  	testRange := func(header string, start, end int) {
  2231  		c.Request().Header.Set(HeaderRange, header)
  2232  		result, err = c.Range(1000)
  2233  		utils.AssertEqual(t, nil, err)
  2234  		utils.AssertEqual(t, "bytes", result.Type)
  2235  		utils.AssertEqual(t, start, result.Ranges[0].Start)
  2236  		utils.AssertEqual(t, end, result.Ranges[0].End)
  2237  	}
  2238  
  2239  	testRange("bytes=a-700", 300, 999)
  2240  	testRange("bytes=500-b", 500, 999)
  2241  	testRange("bytes=500-1000", 500, 999)
  2242  	testRange("bytes=500-700", 500, 700)
  2243  }
  2244  
  2245  // go test -run Test_Ctx_Route
  2246  func Test_Ctx_Route(t *testing.T) {
  2247  	t.Parallel()
  2248  	app := New()
  2249  	app.Get("/test", func(c *Ctx) error {
  2250  		utils.AssertEqual(t, "/test", c.Route().Path)
  2251  		return nil
  2252  	})
  2253  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/test", nil))
  2254  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  2255  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  2256  
  2257  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2258  	defer app.ReleaseCtx(c)
  2259  
  2260  	utils.AssertEqual(t, "/", c.Route().Path)
  2261  	utils.AssertEqual(t, MethodGet, c.Route().Method)
  2262  	utils.AssertEqual(t, 0, len(c.Route().Handlers))
  2263  }
  2264  
  2265  // go test -run Test_Ctx_RouteNormalized
  2266  func Test_Ctx_RouteNormalized(t *testing.T) {
  2267  	t.Parallel()
  2268  	app := New()
  2269  	app.Get("/test", func(c *Ctx) error {
  2270  		utils.AssertEqual(t, "/test", c.Route().Path)
  2271  		return nil
  2272  	})
  2273  	resp, err := app.Test(httptest.NewRequest(MethodGet, "//test", nil))
  2274  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  2275  	utils.AssertEqual(t, StatusNotFound, resp.StatusCode, "Status code")
  2276  }
  2277  
  2278  // go test -run Test_Ctx_SaveFile
  2279  func Test_Ctx_SaveFile(t *testing.T) {
  2280  	// TODO We should clean this up
  2281  	t.Parallel()
  2282  	app := New()
  2283  
  2284  	app.Post("/test", func(c *Ctx) error {
  2285  		fh, err := c.FormFile("file")
  2286  		utils.AssertEqual(t, nil, err)
  2287  
  2288  		tempFile, err := os.CreateTemp(os.TempDir(), "test-")
  2289  		utils.AssertEqual(t, nil, err)
  2290  
  2291  		defer func(file *os.File) {
  2292  			err := file.Close()
  2293  			utils.AssertEqual(t, nil, err)
  2294  			err = os.Remove(file.Name())
  2295  			utils.AssertEqual(t, nil, err)
  2296  		}(tempFile)
  2297  		err = c.SaveFile(fh, tempFile.Name())
  2298  		utils.AssertEqual(t, nil, err)
  2299  
  2300  		bs, err := os.ReadFile(tempFile.Name())
  2301  		utils.AssertEqual(t, nil, err)
  2302  		utils.AssertEqual(t, "hello world", string(bs))
  2303  		return nil
  2304  	})
  2305  
  2306  	body := &bytes.Buffer{}
  2307  	writer := multipart.NewWriter(body)
  2308  
  2309  	ioWriter, err := writer.CreateFormFile("file", "test")
  2310  	utils.AssertEqual(t, nil, err)
  2311  
  2312  	_, err = ioWriter.Write([]byte("hello world"))
  2313  	utils.AssertEqual(t, nil, err)
  2314  	utils.AssertEqual(t, nil, writer.Close())
  2315  
  2316  	req := httptest.NewRequest(MethodPost, "/test", body)
  2317  	req.Header.Set("Content-Type", writer.FormDataContentType())
  2318  	req.Header.Set("Content-Length", strconv.Itoa(len(body.Bytes())))
  2319  
  2320  	resp, err := app.Test(req)
  2321  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  2322  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  2323  }
  2324  
  2325  // go test -run Test_Ctx_SaveFileToStorage
  2326  func Test_Ctx_SaveFileToStorage(t *testing.T) {
  2327  	t.Parallel()
  2328  	app := New()
  2329  	storage := memory.New()
  2330  
  2331  	app.Post("/test", func(c *Ctx) error {
  2332  		fh, err := c.FormFile("file")
  2333  		utils.AssertEqual(t, nil, err)
  2334  
  2335  		err = c.SaveFileToStorage(fh, "test", storage)
  2336  		utils.AssertEqual(t, nil, err)
  2337  
  2338  		file, err := storage.Get("test")
  2339  		utils.AssertEqual(t, []byte("hello world"), file)
  2340  		utils.AssertEqual(t, nil, err)
  2341  
  2342  		err = storage.Delete("test")
  2343  		utils.AssertEqual(t, nil, err)
  2344  
  2345  		return nil
  2346  	})
  2347  
  2348  	body := &bytes.Buffer{}
  2349  	writer := multipart.NewWriter(body)
  2350  
  2351  	ioWriter, err := writer.CreateFormFile("file", "test")
  2352  	utils.AssertEqual(t, nil, err)
  2353  
  2354  	_, err = ioWriter.Write([]byte("hello world"))
  2355  	utils.AssertEqual(t, nil, err)
  2356  	utils.AssertEqual(t, nil, writer.Close())
  2357  
  2358  	req := httptest.NewRequest(MethodPost, "/test", body)
  2359  	req.Header.Set("Content-Type", writer.FormDataContentType())
  2360  	req.Header.Set("Content-Length", strconv.Itoa(len(body.Bytes())))
  2361  
  2362  	resp, err := app.Test(req)
  2363  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  2364  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  2365  }
  2366  
  2367  // go test -run Test_Ctx_Secure
  2368  func Test_Ctx_Secure(t *testing.T) {
  2369  	t.Parallel()
  2370  	app := New()
  2371  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2372  	defer app.ReleaseCtx(c)
  2373  	// TODO Add TLS conn
  2374  	utils.AssertEqual(t, false, c.Secure())
  2375  }
  2376  
  2377  // go test -run Test_Ctx_Stale
  2378  func Test_Ctx_Stale(t *testing.T) {
  2379  	t.Parallel()
  2380  	app := New()
  2381  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2382  	defer app.ReleaseCtx(c)
  2383  	utils.AssertEqual(t, true, c.Stale())
  2384  }
  2385  
  2386  // go test -run Test_Ctx_Subdomains
  2387  func Test_Ctx_Subdomains(t *testing.T) {
  2388  	t.Parallel()
  2389  	app := New()
  2390  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2391  	defer app.ReleaseCtx(c)
  2392  	c.Request().URI().SetHost("john.doe.is.awesome.google.com")
  2393  	utils.AssertEqual(t, []string{"john", "doe"}, c.Subdomains(4))
  2394  
  2395  	c.Request().URI().SetHost("localhost:3000")
  2396  	utils.AssertEqual(t, []string{"localhost:3000"}, c.Subdomains())
  2397  }
  2398  
  2399  // go test -v -run=^$ -bench=Benchmark_Ctx_Subdomains -benchmem -count=4
  2400  func Benchmark_Ctx_Subdomains(b *testing.B) {
  2401  	app := New()
  2402  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2403  	defer app.ReleaseCtx(c)
  2404  	c.Request().SetRequestURI("http://john.doe.google.com")
  2405  	var res []string
  2406  	b.ReportAllocs()
  2407  	b.ResetTimer()
  2408  	for n := 0; n < b.N; n++ {
  2409  		res = c.Subdomains()
  2410  	}
  2411  	utils.AssertEqual(b, []string{"john", "doe"}, res)
  2412  }
  2413  
  2414  // go test -run Test_Ctx_ClearCookie
  2415  func Test_Ctx_ClearCookie(t *testing.T) {
  2416  	t.Parallel()
  2417  	app := New()
  2418  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2419  	defer app.ReleaseCtx(c)
  2420  	c.Request().Header.Set(HeaderCookie, "john=doe")
  2421  	c.ClearCookie("john")
  2422  	utils.AssertEqual(t, true, strings.HasPrefix(string(c.Response().Header.Peek(HeaderSetCookie)), "john=; expires="))
  2423  
  2424  	c.Request().Header.Set(HeaderCookie, "test1=dummy")
  2425  	c.Request().Header.Set(HeaderCookie, "test2=dummy")
  2426  	c.ClearCookie()
  2427  	utils.AssertEqual(t, true, strings.Contains(string(c.Response().Header.Peek(HeaderSetCookie)), "test1=; expires="))
  2428  	utils.AssertEqual(t, true, strings.Contains(string(c.Response().Header.Peek(HeaderSetCookie)), "test2=; expires="))
  2429  }
  2430  
  2431  // go test -race -run Test_Ctx_Download
  2432  func Test_Ctx_Download(t *testing.T) {
  2433  	t.Parallel()
  2434  	app := New()
  2435  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2436  	defer app.ReleaseCtx(c)
  2437  
  2438  	utils.AssertEqual(t, nil, c.Download("ctx.go", "Awesome File!"))
  2439  
  2440  	f, err := os.Open("./ctx.go")
  2441  	utils.AssertEqual(t, nil, err)
  2442  	defer func() {
  2443  		utils.AssertEqual(t, nil, f.Close())
  2444  	}()
  2445  
  2446  	expect, err := io.ReadAll(f)
  2447  	utils.AssertEqual(t, nil, err)
  2448  	utils.AssertEqual(t, expect, c.Response().Body())
  2449  	utils.AssertEqual(t, `attachment; filename="Awesome+File%21"`, string(c.Response().Header.Peek(HeaderContentDisposition)))
  2450  
  2451  	utils.AssertEqual(t, nil, c.Download("ctx.go"))
  2452  	utils.AssertEqual(t, `attachment; filename="ctx.go"`, string(c.Response().Header.Peek(HeaderContentDisposition)))
  2453  }
  2454  
  2455  // go test -race -run Test_Ctx_SendFile
  2456  func Test_Ctx_SendFile(t *testing.T) {
  2457  	t.Parallel()
  2458  	app := New()
  2459  
  2460  	// fetch file content
  2461  	f, err := os.Open("./ctx.go")
  2462  	utils.AssertEqual(t, nil, err)
  2463  	defer func() {
  2464  		utils.AssertEqual(t, nil, f.Close())
  2465  	}()
  2466  	expectFileContent, err := io.ReadAll(f)
  2467  	utils.AssertEqual(t, nil, err)
  2468  	// fetch file info for the not modified test case
  2469  	fI, err := os.Stat("./ctx.go")
  2470  	utils.AssertEqual(t, nil, err)
  2471  
  2472  	// simple test case
  2473  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2474  	err = c.SendFile("ctx.go")
  2475  	// check expectation
  2476  	utils.AssertEqual(t, nil, err)
  2477  	utils.AssertEqual(t, expectFileContent, c.Response().Body())
  2478  	utils.AssertEqual(t, StatusOK, c.Response().StatusCode())
  2479  	app.ReleaseCtx(c)
  2480  
  2481  	// test with custom error code
  2482  	c = app.AcquireCtx(&fasthttp.RequestCtx{})
  2483  	err = c.Status(StatusInternalServerError).SendFile("ctx.go")
  2484  	// check expectation
  2485  	utils.AssertEqual(t, nil, err)
  2486  	utils.AssertEqual(t, expectFileContent, c.Response().Body())
  2487  	utils.AssertEqual(t, StatusInternalServerError, c.Response().StatusCode())
  2488  	app.ReleaseCtx(c)
  2489  
  2490  	// test not modified
  2491  	c = app.AcquireCtx(&fasthttp.RequestCtx{})
  2492  	c.Request().Header.Set(HeaderIfModifiedSince, fI.ModTime().Format(time.RFC1123))
  2493  	err = c.SendFile("ctx.go")
  2494  	// check expectation
  2495  	utils.AssertEqual(t, nil, err)
  2496  	utils.AssertEqual(t, StatusNotModified, c.Response().StatusCode())
  2497  	utils.AssertEqual(t, []byte(nil), c.Response().Body())
  2498  	app.ReleaseCtx(c)
  2499  }
  2500  
  2501  // go test -race -run Test_Ctx_SendFile_404
  2502  func Test_Ctx_SendFile_404(t *testing.T) {
  2503  	t.Parallel()
  2504  	app := New()
  2505  	app.Get("/", func(c *Ctx) error {
  2506  		err := c.SendFile(filepath.FromSlash("john_dow.go/"))
  2507  		utils.AssertEqual(t, false, err == nil)
  2508  		return err
  2509  	})
  2510  
  2511  	resp, err := app.Test(httptest.NewRequest(MethodGet, "/", nil))
  2512  	utils.AssertEqual(t, nil, err)
  2513  	utils.AssertEqual(t, StatusNotFound, resp.StatusCode)
  2514  }
  2515  
  2516  // go test -race -run Test_Ctx_SendFile_Immutable
  2517  func Test_Ctx_SendFile_Immutable(t *testing.T) {
  2518  	t.Parallel()
  2519  	app := New()
  2520  	var endpointsForTest []string
  2521  	addEndpoint := func(file, endpoint string) {
  2522  		endpointsForTest = append(endpointsForTest, endpoint)
  2523  		app.Get(endpoint, func(c *Ctx) error {
  2524  			if err := c.SendFile(file); err != nil {
  2525  				utils.AssertEqual(t, nil, err)
  2526  				return err
  2527  			}
  2528  			return c.SendStatus(200)
  2529  		})
  2530  	}
  2531  
  2532  	// relative paths
  2533  	addEndpoint("./.github/index.html", "/relativeWithDot")
  2534  	addEndpoint(filepath.FromSlash("./.github/index.html"), "/relativeOSWithDot")
  2535  	addEndpoint(".github/index.html", "/relative")
  2536  	addEndpoint(filepath.FromSlash(".github/index.html"), "/relativeOS")
  2537  
  2538  	// absolute paths
  2539  	if path, err := filepath.Abs(".github/index.html"); err != nil {
  2540  		utils.AssertEqual(t, nil, err)
  2541  	} else {
  2542  		addEndpoint(path, "/absolute")
  2543  		addEndpoint(filepath.FromSlash(path), "/absoluteOS") // os related
  2544  	}
  2545  
  2546  	for _, endpoint := range endpointsForTest {
  2547  		t.Run(endpoint, func(t *testing.T) {
  2548  			// 1st try
  2549  			resp, err := app.Test(httptest.NewRequest(MethodGet, endpoint, nil))
  2550  			utils.AssertEqual(t, nil, err)
  2551  			utils.AssertEqual(t, StatusOK, resp.StatusCode)
  2552  			// 2nd try
  2553  			resp, err = app.Test(httptest.NewRequest(MethodGet, endpoint, nil))
  2554  			utils.AssertEqual(t, nil, err)
  2555  			utils.AssertEqual(t, StatusOK, resp.StatusCode)
  2556  		})
  2557  	}
  2558  }
  2559  
  2560  // go test -race -run Test_Ctx_SendFile_RestoreOriginalURL
  2561  func Test_Ctx_SendFile_RestoreOriginalURL(t *testing.T) {
  2562  	t.Parallel()
  2563  	app := New()
  2564  	app.Get("/", func(c *Ctx) error {
  2565  		originalURL := utils.CopyString(c.OriginalURL())
  2566  		err := c.SendFile("ctx.go")
  2567  		utils.AssertEqual(t, originalURL, c.OriginalURL())
  2568  		return err
  2569  	})
  2570  
  2571  	_, err1 := app.Test(httptest.NewRequest(MethodGet, "/?test=true", nil))
  2572  	// second request required to confirm with zero allocation
  2573  	_, err2 := app.Test(httptest.NewRequest(MethodGet, "/?test=true", nil))
  2574  
  2575  	utils.AssertEqual(t, nil, err1)
  2576  	utils.AssertEqual(t, nil, err2)
  2577  }
  2578  
  2579  // go test -run Test_Ctx_JSON
  2580  func Test_Ctx_JSON(t *testing.T) {
  2581  	t.Parallel()
  2582  	app := New()
  2583  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2584  	defer app.ReleaseCtx(c)
  2585  
  2586  	utils.AssertEqual(t, true, c.JSON(complex(1, 1)) != nil)
  2587  
  2588  	err := c.JSON(Map{ // map has no order
  2589  		"Name": "Grame",
  2590  		"Age":  20,
  2591  	})
  2592  	utils.AssertEqual(t, nil, err)
  2593  	utils.AssertEqual(t, `{"Age":20,"Name":"Grame"}`, string(c.Response().Body()))
  2594  	utils.AssertEqual(t, "application/json", string(c.Response().Header.Peek("content-type")))
  2595  
  2596  	testEmpty := func(v interface{}, r string) {
  2597  		err := c.JSON(v)
  2598  		utils.AssertEqual(t, nil, err)
  2599  		utils.AssertEqual(t, r, string(c.Response().Body()))
  2600  	}
  2601  
  2602  	testEmpty(nil, "null")
  2603  	testEmpty("", `""`)
  2604  	testEmpty(0, "0")
  2605  	testEmpty([]int{}, "[]")
  2606  }
  2607  
  2608  // go test -run=^$ -bench=Benchmark_Ctx_JSON -benchmem -count=4
  2609  func Benchmark_Ctx_JSON(b *testing.B) {
  2610  	app := New()
  2611  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2612  	defer app.ReleaseCtx(c)
  2613  	type SomeStruct struct {
  2614  		Name string
  2615  		Age  uint8
  2616  	}
  2617  	data := SomeStruct{
  2618  		Name: "Grame",
  2619  		Age:  20,
  2620  	}
  2621  	var err error
  2622  	b.ReportAllocs()
  2623  	b.ResetTimer()
  2624  	for n := 0; n < b.N; n++ {
  2625  		err = c.JSON(data)
  2626  	}
  2627  	utils.AssertEqual(b, nil, err)
  2628  	utils.AssertEqual(b, `{"Name":"Grame","Age":20}`, string(c.Response().Body()))
  2629  }
  2630  
  2631  // go test -run Test_Ctx_JSONP
  2632  func Test_Ctx_JSONP(t *testing.T) {
  2633  	t.Parallel()
  2634  	app := New()
  2635  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2636  	defer app.ReleaseCtx(c)
  2637  
  2638  	utils.AssertEqual(t, true, c.JSONP(complex(1, 1)) != nil)
  2639  
  2640  	err := c.JSONP(Map{
  2641  		"Name": "Grame",
  2642  		"Age":  20,
  2643  	})
  2644  	utils.AssertEqual(t, nil, err)
  2645  	utils.AssertEqual(t, `callback({"Age":20,"Name":"Grame"});`, string(c.Response().Body()))
  2646  	utils.AssertEqual(t, "text/javascript; charset=utf-8", string(c.Response().Header.Peek("content-type")))
  2647  
  2648  	err = c.JSONP(Map{
  2649  		"Name": "Grame",
  2650  		"Age":  20,
  2651  	}, "john")
  2652  	utils.AssertEqual(t, nil, err)
  2653  	utils.AssertEqual(t, `john({"Age":20,"Name":"Grame"});`, string(c.Response().Body()))
  2654  	utils.AssertEqual(t, "text/javascript; charset=utf-8", string(c.Response().Header.Peek("content-type")))
  2655  }
  2656  
  2657  // go test -v  -run=^$ -bench=Benchmark_Ctx_JSONP -benchmem -count=4
  2658  func Benchmark_Ctx_JSONP(b *testing.B) {
  2659  	app := New()
  2660  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2661  	defer app.ReleaseCtx(c)
  2662  	type SomeStruct struct {
  2663  		Name string
  2664  		Age  uint8
  2665  	}
  2666  	data := SomeStruct{
  2667  		Name: "Grame",
  2668  		Age:  20,
  2669  	}
  2670  	callback := "emit"
  2671  	var err error
  2672  	b.ReportAllocs()
  2673  	b.ResetTimer()
  2674  	for n := 0; n < b.N; n++ {
  2675  		err = c.JSONP(data, callback)
  2676  	}
  2677  	utils.AssertEqual(b, nil, err)
  2678  	utils.AssertEqual(b, `emit({"Name":"Grame","Age":20});`, string(c.Response().Body()))
  2679  }
  2680  
  2681  // go test -run Test_Ctx_XML
  2682  func Test_Ctx_XML(t *testing.T) {
  2683  	t.Parallel()
  2684  	app := New()
  2685  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2686  	defer app.ReleaseCtx(c)
  2687  
  2688  	utils.AssertEqual(t, true, c.JSON(complex(1, 1)) != nil)
  2689  
  2690  	type xmlResult struct {
  2691  		XMLName xml.Name `xml:"Users"`
  2692  		Names   []string `xml:"Names"`
  2693  		Ages    []int    `xml:"Ages"`
  2694  	}
  2695  
  2696  	err := c.XML(xmlResult{
  2697  		Names: []string{"Grame", "John"},
  2698  		Ages:  []int{1, 12, 20},
  2699  	})
  2700  	utils.AssertEqual(t, nil, err)
  2701  	utils.AssertEqual(t, `<Users><Names>Grame</Names><Names>John</Names><Ages>1</Ages><Ages>12</Ages><Ages>20</Ages></Users>`, string(c.Response().Body()))
  2702  	utils.AssertEqual(t, "application/xml", string(c.Response().Header.Peek("content-type")))
  2703  
  2704  	testEmpty := func(v interface{}, r string) {
  2705  		err := c.XML(v)
  2706  		utils.AssertEqual(t, nil, err)
  2707  		utils.AssertEqual(t, r, string(c.Response().Body()))
  2708  	}
  2709  
  2710  	testEmpty(nil, "")
  2711  	testEmpty("", `<string></string>`)
  2712  	testEmpty(0, "<int>0</int>")
  2713  	testEmpty([]int{}, "")
  2714  }
  2715  
  2716  // go test -run=^$ -bench=Benchmark_Ctx_XML -benchmem -count=4
  2717  func Benchmark_Ctx_XML(b *testing.B) {
  2718  	app := New()
  2719  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2720  	defer app.ReleaseCtx(c)
  2721  	type SomeStruct struct {
  2722  		Name string `xml:"Name"`
  2723  		Age  uint8  `xml:"Age"`
  2724  	}
  2725  	data := SomeStruct{
  2726  		Name: "Grame",
  2727  		Age:  20,
  2728  	}
  2729  	var err error
  2730  	b.ReportAllocs()
  2731  	b.ResetTimer()
  2732  	for n := 0; n < b.N; n++ {
  2733  		err = c.XML(data)
  2734  	}
  2735  
  2736  	utils.AssertEqual(b, nil, err)
  2737  	utils.AssertEqual(b, `<SomeStruct><Name>Grame</Name><Age>20</Age></SomeStruct>`, string(c.Response().Body()))
  2738  }
  2739  
  2740  // go test -run Test_Ctx_Links
  2741  func Test_Ctx_Links(t *testing.T) {
  2742  	t.Parallel()
  2743  	app := New()
  2744  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2745  	defer app.ReleaseCtx(c)
  2746  
  2747  	c.Links()
  2748  	utils.AssertEqual(t, "", string(c.Response().Header.Peek(HeaderLink)))
  2749  
  2750  	c.Links(
  2751  		"http://api.example.com/users?page=2", "next",
  2752  		"http://api.example.com/users?page=5", "last",
  2753  	)
  2754  	utils.AssertEqual(t, `<http://api.example.com/users?page=2>; rel="next",<http://api.example.com/users?page=5>; rel="last"`, string(c.Response().Header.Peek(HeaderLink)))
  2755  }
  2756  
  2757  // go test -v  -run=^$ -bench=Benchmark_Ctx_Links -benchmem -count=4
  2758  func Benchmark_Ctx_Links(b *testing.B) {
  2759  	app := New()
  2760  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2761  	defer app.ReleaseCtx(c)
  2762  	b.ReportAllocs()
  2763  	b.ResetTimer()
  2764  	for n := 0; n < b.N; n++ {
  2765  		c.Links(
  2766  			"http://api.example.com/users?page=2", "next",
  2767  			"http://api.example.com/users?page=5", "last",
  2768  		)
  2769  	}
  2770  }
  2771  
  2772  // go test -run Test_Ctx_Location
  2773  func Test_Ctx_Location(t *testing.T) {
  2774  	t.Parallel()
  2775  	app := New()
  2776  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2777  	defer app.ReleaseCtx(c)
  2778  	c.Location("http://example.com")
  2779  	utils.AssertEqual(t, "http://example.com", string(c.Response().Header.Peek(HeaderLocation)))
  2780  }
  2781  
  2782  // go test -run Test_Ctx_Next
  2783  func Test_Ctx_Next(t *testing.T) {
  2784  	t.Parallel()
  2785  	app := New()
  2786  	app.Use("/", func(c *Ctx) error {
  2787  		return c.Next()
  2788  	})
  2789  	app.Get("/test", func(c *Ctx) error {
  2790  		c.Set("X-Next-Result", "Works")
  2791  		return nil
  2792  	})
  2793  	resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/test", nil))
  2794  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  2795  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  2796  	utils.AssertEqual(t, "Works", resp.Header.Get("X-Next-Result"))
  2797  }
  2798  
  2799  // go test -run Test_Ctx_Next_Error
  2800  func Test_Ctx_Next_Error(t *testing.T) {
  2801  	t.Parallel()
  2802  	app := New()
  2803  	app.Use("/", func(c *Ctx) error {
  2804  		c.Set("X-Next-Result", "Works")
  2805  		return ErrNotFound
  2806  	})
  2807  
  2808  	resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/test", nil))
  2809  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  2810  	utils.AssertEqual(t, StatusNotFound, resp.StatusCode, "Status code")
  2811  	utils.AssertEqual(t, "Works", resp.Header.Get("X-Next-Result"))
  2812  }
  2813  
  2814  // go test -run Test_Ctx_Redirect
  2815  func Test_Ctx_Redirect(t *testing.T) {
  2816  	t.Parallel()
  2817  	app := New()
  2818  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2819  	defer app.ReleaseCtx(c)
  2820  
  2821  	err := c.Redirect("http://default.com")
  2822  	utils.AssertEqual(t, nil, err)
  2823  	utils.AssertEqual(t, 302, c.Response().StatusCode())
  2824  	utils.AssertEqual(t, "http://default.com", string(c.Response().Header.Peek(HeaderLocation)))
  2825  
  2826  	err = c.Redirect("http://example.com", 301)
  2827  	utils.AssertEqual(t, nil, err)
  2828  	utils.AssertEqual(t, 301, c.Response().StatusCode())
  2829  	utils.AssertEqual(t, "http://example.com", string(c.Response().Header.Peek(HeaderLocation)))
  2830  }
  2831  
  2832  // go test -run Test_Ctx_RedirectToRouteWithParams
  2833  func Test_Ctx_RedirectToRouteWithParams(t *testing.T) {
  2834  	t.Parallel()
  2835  	app := New()
  2836  	app.Get("/user/:name", func(c *Ctx) error {
  2837  		return c.JSON(c.Params("name"))
  2838  	}).Name("user")
  2839  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2840  	defer app.ReleaseCtx(c)
  2841  
  2842  	err := c.RedirectToRoute("user", Map{
  2843  		"name": "fiber",
  2844  	})
  2845  	utils.AssertEqual(t, nil, err)
  2846  	utils.AssertEqual(t, 302, c.Response().StatusCode())
  2847  	utils.AssertEqual(t, "/user/fiber", string(c.Response().Header.Peek(HeaderLocation)))
  2848  }
  2849  
  2850  // go test -run Test_Ctx_RedirectToRouteWithParams
  2851  func Test_Ctx_RedirectToRouteWithQueries(t *testing.T) {
  2852  	t.Parallel()
  2853  	app := New()
  2854  	app.Get("/user/:name", func(c *Ctx) error {
  2855  		return c.JSON(c.Params("name"))
  2856  	}).Name("user")
  2857  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2858  	defer app.ReleaseCtx(c)
  2859  
  2860  	err := c.RedirectToRoute("user", Map{
  2861  		"name":    "fiber",
  2862  		"queries": map[string]string{"data[0][name]": "john", "data[0][age]": "10", "test": "doe"},
  2863  	})
  2864  	utils.AssertEqual(t, nil, err)
  2865  	utils.AssertEqual(t, 302, c.Response().StatusCode())
  2866  	// analysis of query parameters with url parsing, since a map pass is always randomly ordered
  2867  	location, err := url.Parse(string(c.Response().Header.Peek(HeaderLocation)))
  2868  	utils.AssertEqual(t, nil, err, "url.Parse(location)")
  2869  	utils.AssertEqual(t, "/user/fiber", location.Path)
  2870  	utils.AssertEqual(t, url.Values{"data[0][name]": []string{"john"}, "data[0][age]": []string{"10"}, "test": []string{"doe"}}, location.Query())
  2871  }
  2872  
  2873  // go test -run Test_Ctx_RedirectToRouteWithOptionalParams
  2874  func Test_Ctx_RedirectToRouteWithOptionalParams(t *testing.T) {
  2875  	t.Parallel()
  2876  	app := New()
  2877  	app.Get("/user/:name?", func(c *Ctx) error {
  2878  		return c.JSON(c.Params("name"))
  2879  	}).Name("user")
  2880  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2881  	defer app.ReleaseCtx(c)
  2882  
  2883  	err := c.RedirectToRoute("user", Map{
  2884  		"name": "fiber",
  2885  	})
  2886  	utils.AssertEqual(t, nil, err)
  2887  	utils.AssertEqual(t, 302, c.Response().StatusCode())
  2888  	utils.AssertEqual(t, "/user/fiber", string(c.Response().Header.Peek(HeaderLocation)))
  2889  }
  2890  
  2891  // go test -run Test_Ctx_RedirectToRouteWithOptionalParamsWithoutValue
  2892  func Test_Ctx_RedirectToRouteWithOptionalParamsWithoutValue(t *testing.T) {
  2893  	t.Parallel()
  2894  	app := New()
  2895  	app.Get("/user/:name?", func(c *Ctx) error {
  2896  		return c.JSON(c.Params("name"))
  2897  	}).Name("user")
  2898  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2899  	defer app.ReleaseCtx(c)
  2900  
  2901  	err := c.RedirectToRoute("user", Map{})
  2902  	utils.AssertEqual(t, nil, err)
  2903  	utils.AssertEqual(t, 302, c.Response().StatusCode())
  2904  	utils.AssertEqual(t, "/user/", string(c.Response().Header.Peek(HeaderLocation)))
  2905  }
  2906  
  2907  // go test -run Test_Ctx_RedirectToRouteWithGreedyParameters
  2908  func Test_Ctx_RedirectToRouteWithGreedyParameters(t *testing.T) {
  2909  	t.Parallel()
  2910  	app := New()
  2911  	app.Get("/user/+", func(c *Ctx) error {
  2912  		return c.JSON(c.Params("+"))
  2913  	}).Name("user")
  2914  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2915  	defer app.ReleaseCtx(c)
  2916  
  2917  	err := c.RedirectToRoute("user", Map{
  2918  		"+": "test/routes",
  2919  	})
  2920  	utils.AssertEqual(t, nil, err)
  2921  	utils.AssertEqual(t, 302, c.Response().StatusCode())
  2922  	utils.AssertEqual(t, "/user/test/routes", string(c.Response().Header.Peek(HeaderLocation)))
  2923  }
  2924  
  2925  // go test -run Test_Ctx_RedirectBack
  2926  func Test_Ctx_RedirectBack(t *testing.T) {
  2927  	t.Parallel()
  2928  	app := New()
  2929  	app.Get("/", func(c *Ctx) error {
  2930  		return c.JSON("Home")
  2931  	}).Name("home")
  2932  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2933  	defer app.ReleaseCtx(c)
  2934  	err := c.RedirectBack("/")
  2935  	utils.AssertEqual(t, nil, err)
  2936  	utils.AssertEqual(t, 302, c.Response().StatusCode())
  2937  	utils.AssertEqual(t, "/", string(c.Response().Header.Peek(HeaderLocation)))
  2938  }
  2939  
  2940  // go test -run Test_Ctx_RedirectBackWithReferer
  2941  func Test_Ctx_RedirectBackWithReferer(t *testing.T) {
  2942  	t.Parallel()
  2943  	app := New()
  2944  	app.Get("/", func(c *Ctx) error {
  2945  		return c.JSON("Home")
  2946  	}).Name("home")
  2947  	app.Get("/back", func(c *Ctx) error {
  2948  		return c.JSON("Back")
  2949  	}).Name("back")
  2950  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2951  	defer app.ReleaseCtx(c)
  2952  	c.Request().Header.Set(HeaderReferer, "/back")
  2953  	err := c.RedirectBack("/")
  2954  	utils.AssertEqual(t, nil, err)
  2955  	utils.AssertEqual(t, 302, c.Response().StatusCode())
  2956  	utils.AssertEqual(t, "/back", c.Get(HeaderReferer))
  2957  	utils.AssertEqual(t, "/back", string(c.Response().Header.Peek(HeaderLocation)))
  2958  }
  2959  
  2960  // go test -run Test_Ctx_Render
  2961  func Test_Ctx_Render(t *testing.T) {
  2962  	t.Parallel()
  2963  	app := New()
  2964  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2965  	defer app.ReleaseCtx(c)
  2966  	err := c.Render("./.github/testdata/index.tmpl", Map{
  2967  		"Title": "Hello, World!",
  2968  	})
  2969  	utils.AssertEqual(t, nil, err)
  2970  
  2971  	buf := bytebufferpool.Get()
  2972  	_, _ = buf.WriteString("overwrite") //nolint:errcheck // This will never fail
  2973  	defer bytebufferpool.Put(buf)
  2974  
  2975  	utils.AssertEqual(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))
  2976  
  2977  	err = c.Render("./.github/testdata/template-non-exists.html", nil)
  2978  	utils.AssertEqual(t, false, err == nil)
  2979  
  2980  	err = c.Render("./.github/testdata/template-invalid.html", nil)
  2981  	utils.AssertEqual(t, false, err == nil)
  2982  }
  2983  
  2984  func Test_Ctx_RenderWithoutLocals(t *testing.T) {
  2985  	t.Parallel()
  2986  	app := New(Config{
  2987  		PassLocalsToViews: false,
  2988  	})
  2989  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  2990  
  2991  	c.Locals("Title", "Hello, World!")
  2992  	defer app.ReleaseCtx(c)
  2993  	err := c.Render("./.github/testdata/index.tmpl", Map{})
  2994  	utils.AssertEqual(t, nil, err)
  2995  
  2996  	buf := bytebufferpool.Get()
  2997  	_, _ = buf.WriteString("overwrite") //nolint:errcheck // This will never fail
  2998  	defer bytebufferpool.Put(buf)
  2999  
  3000  	utils.AssertEqual(t, "<h1><no value></h1>", string(c.Response().Body()))
  3001  }
  3002  
  3003  func Test_Ctx_RenderWithLocals(t *testing.T) {
  3004  	t.Parallel()
  3005  	app := New(Config{
  3006  		PassLocalsToViews: true,
  3007  	})
  3008  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3009  
  3010  	c.Locals("Title", "Hello, World!")
  3011  	defer app.ReleaseCtx(c)
  3012  	err := c.Render("./.github/testdata/index.tmpl", Map{})
  3013  	utils.AssertEqual(t, nil, err)
  3014  
  3015  	buf := bytebufferpool.Get()
  3016  	_, _ = buf.WriteString("overwrite") //nolint:errcheck // This will never fail
  3017  	defer bytebufferpool.Put(buf)
  3018  
  3019  	utils.AssertEqual(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))
  3020  }
  3021  
  3022  func Test_Ctx_RenderWithBind(t *testing.T) {
  3023  	t.Parallel()
  3024  
  3025  	app := New()
  3026  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3027  
  3028  	err := c.Bind(Map{
  3029  		"Title": "Hello, World!",
  3030  	})
  3031  	utils.AssertEqual(t, nil, err)
  3032  	defer app.ReleaseCtx(c)
  3033  	err = c.Render("./.github/testdata/index.tmpl", Map{})
  3034  	utils.AssertEqual(t, nil, err)
  3035  
  3036  	buf := bytebufferpool.Get()
  3037  	_, _ = buf.WriteString("overwrite") //nolint:errcheck // This will never fail
  3038  	defer bytebufferpool.Put(buf)
  3039  
  3040  	utils.AssertEqual(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))
  3041  }
  3042  
  3043  func Test_Ctx_RenderWithOverwrittenBind(t *testing.T) {
  3044  	t.Parallel()
  3045  	app := New()
  3046  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3047  
  3048  	err := c.Bind(Map{
  3049  		"Title": "Hello, World!",
  3050  	})
  3051  	utils.AssertEqual(t, nil, err)
  3052  	defer app.ReleaseCtx(c)
  3053  	err = c.Render("./.github/testdata/index.tmpl", Map{
  3054  		"Title": "Hello from Fiber!",
  3055  	})
  3056  	utils.AssertEqual(t, nil, err)
  3057  
  3058  	buf := bytebufferpool.Get()
  3059  	_, _ = buf.WriteString("overwrite") //nolint:errcheck // This will never fail
  3060  	defer bytebufferpool.Put(buf)
  3061  
  3062  	utils.AssertEqual(t, "<h1>Hello from Fiber!</h1>", string(c.Response().Body()))
  3063  }
  3064  
  3065  func Test_Ctx_RenderWithBindLocals(t *testing.T) {
  3066  	t.Parallel()
  3067  	app := New(Config{
  3068  		PassLocalsToViews: true,
  3069  	})
  3070  
  3071  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3072  
  3073  	err := c.Bind(Map{
  3074  		"Title": "Hello, World!",
  3075  	})
  3076  	utils.AssertEqual(t, nil, err)
  3077  
  3078  	c.Locals("Summary", "Test")
  3079  	defer app.ReleaseCtx(c)
  3080  
  3081  	err = c.Render("./.github/testdata/template.tmpl", Map{})
  3082  	utils.AssertEqual(t, nil, err)
  3083  
  3084  	utils.AssertEqual(t, "<h1>Hello, World! Test</h1>", string(c.Response().Body()))
  3085  }
  3086  
  3087  func Test_Ctx_RenderWithLocalsAndBinding(t *testing.T) {
  3088  	t.Parallel()
  3089  	engine := &testTemplateEngine{}
  3090  	err := engine.Load()
  3091  	utils.AssertEqual(t, nil, err)
  3092  	app := New(Config{
  3093  		PassLocalsToViews: true,
  3094  		Views:             engine,
  3095  	})
  3096  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3097  
  3098  	c.Locals("Title", "This is a test.")
  3099  	defer app.ReleaseCtx(c)
  3100  
  3101  	err = c.Render("index.tmpl", Map{
  3102  		"Title": "Hello, World!",
  3103  	})
  3104  	utils.AssertEqual(t, nil, err)
  3105  
  3106  	utils.AssertEqual(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))
  3107  }
  3108  
  3109  func Benchmark_Ctx_RenderWithLocalsAndBinding(b *testing.B) {
  3110  	engine := &testTemplateEngine{}
  3111  	err := engine.Load()
  3112  	utils.AssertEqual(b, nil, err)
  3113  	utils.AssertEqual(b, nil, err)
  3114  	app := New(Config{
  3115  		PassLocalsToViews: true,
  3116  		Views:             engine,
  3117  	})
  3118  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3119  
  3120  	err = c.Bind(Map{
  3121  		"Title": "Hello, World!",
  3122  	})
  3123  	utils.AssertEqual(b, nil, err)
  3124  	c.Locals("Summary", "Test")
  3125  
  3126  	defer app.ReleaseCtx(c)
  3127  
  3128  	b.ReportAllocs()
  3129  	b.ResetTimer()
  3130  
  3131  	for n := 0; n < b.N; n++ {
  3132  		err = c.Render("template.tmpl", Map{})
  3133  	}
  3134  	utils.AssertEqual(b, nil, err)
  3135  
  3136  	utils.AssertEqual(b, "<h1>Hello, World! Test</h1>", string(c.Response().Body()))
  3137  }
  3138  
  3139  func Benchmark_Ctx_RedirectToRoute(b *testing.B) {
  3140  	app := New()
  3141  	app.Get("/user/:name", func(c *Ctx) error {
  3142  		return c.JSON(c.Params("name"))
  3143  	}).Name("user")
  3144  
  3145  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3146  	defer app.ReleaseCtx(c)
  3147  
  3148  	b.ReportAllocs()
  3149  	b.ResetTimer()
  3150  
  3151  	var err error
  3152  	for n := 0; n < b.N; n++ {
  3153  		err = c.RedirectToRoute("user", Map{
  3154  			"name": "fiber",
  3155  		})
  3156  	}
  3157  	utils.AssertEqual(b, nil, err)
  3158  
  3159  	utils.AssertEqual(b, 302, c.Response().StatusCode())
  3160  	utils.AssertEqual(b, "/user/fiber", string(c.Response().Header.Peek(HeaderLocation)))
  3161  }
  3162  
  3163  func Benchmark_Ctx_RedirectToRouteWithQueries(b *testing.B) {
  3164  	app := New()
  3165  	app.Get("/user/:name", func(c *Ctx) error {
  3166  		return c.JSON(c.Params("name"))
  3167  	}).Name("user")
  3168  
  3169  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3170  	defer app.ReleaseCtx(c)
  3171  
  3172  	b.ReportAllocs()
  3173  	b.ResetTimer()
  3174  
  3175  	var err error
  3176  	for n := 0; n < b.N; n++ {
  3177  		err = c.RedirectToRoute("user", Map{
  3178  			"name":    "fiber",
  3179  			"queries": map[string]string{"a": "a", "b": "b"},
  3180  		})
  3181  	}
  3182  	utils.AssertEqual(b, nil, err)
  3183  
  3184  	utils.AssertEqual(b, 302, c.Response().StatusCode())
  3185  	// analysis of query parameters with url parsing, since a map pass is always randomly ordered
  3186  	location, err := url.Parse(string(c.Response().Header.Peek(HeaderLocation)))
  3187  	utils.AssertEqual(b, nil, err, "url.Parse(location)")
  3188  	utils.AssertEqual(b, "/user/fiber", location.Path)
  3189  	utils.AssertEqual(b, url.Values{"a": []string{"a"}, "b": []string{"b"}}, location.Query())
  3190  }
  3191  
  3192  func Benchmark_Ctx_RenderLocals(b *testing.B) {
  3193  	engine := &testTemplateEngine{}
  3194  	err := engine.Load()
  3195  	utils.AssertEqual(b, nil, err)
  3196  	app := New(Config{
  3197  		PassLocalsToViews: true,
  3198  	})
  3199  	app.config.Views = engine
  3200  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3201  
  3202  	c.Locals("Title", "Hello, World!")
  3203  
  3204  	defer app.ReleaseCtx(c)
  3205  
  3206  	b.ReportAllocs()
  3207  	b.ResetTimer()
  3208  
  3209  	for n := 0; n < b.N; n++ {
  3210  		err = c.Render("index.tmpl", Map{})
  3211  	}
  3212  	utils.AssertEqual(b, nil, err)
  3213  
  3214  	utils.AssertEqual(b, "<h1>Hello, World!</h1>", string(c.Response().Body()))
  3215  }
  3216  
  3217  func Benchmark_Ctx_RenderBind(b *testing.B) {
  3218  	engine := &testTemplateEngine{}
  3219  	err := engine.Load()
  3220  	utils.AssertEqual(b, nil, err)
  3221  	app := New()
  3222  	app.config.Views = engine
  3223  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3224  
  3225  	err = c.Bind(Map{
  3226  		"Title": "Hello, World!",
  3227  	})
  3228  	utils.AssertEqual(b, nil, err)
  3229  
  3230  	defer app.ReleaseCtx(c)
  3231  
  3232  	b.ReportAllocs()
  3233  	b.ResetTimer()
  3234  
  3235  	for n := 0; n < b.N; n++ {
  3236  		err = c.Render("index.tmpl", Map{})
  3237  	}
  3238  	utils.AssertEqual(b, nil, err)
  3239  
  3240  	utils.AssertEqual(b, "<h1>Hello, World!</h1>", string(c.Response().Body()))
  3241  }
  3242  
  3243  // go test -run Test_Ctx_RestartRouting
  3244  func Test_Ctx_RestartRouting(t *testing.T) {
  3245  	t.Parallel()
  3246  	app := New()
  3247  	calls := 0
  3248  	app.Get("/", func(c *Ctx) error {
  3249  		calls++
  3250  		if calls < 3 {
  3251  			return c.RestartRouting()
  3252  		}
  3253  		return nil
  3254  	})
  3255  	resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/", nil))
  3256  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  3257  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  3258  	utils.AssertEqual(t, 3, calls, "Number of calls")
  3259  }
  3260  
  3261  // go test -run Test_Ctx_RestartRoutingWithChangedPath
  3262  func Test_Ctx_RestartRoutingWithChangedPath(t *testing.T) {
  3263  	t.Parallel()
  3264  	app := New()
  3265  	var executedOldHandler, executedNewHandler bool
  3266  
  3267  	app.Get("/old", func(c *Ctx) error {
  3268  		c.Path("/new")
  3269  		return c.RestartRouting()
  3270  	})
  3271  	app.Get("/old", func(c *Ctx) error {
  3272  		executedOldHandler = true
  3273  		return nil
  3274  	})
  3275  	app.Get("/new", func(c *Ctx) error {
  3276  		executedNewHandler = true
  3277  		return nil
  3278  	})
  3279  
  3280  	resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/old", nil))
  3281  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  3282  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  3283  	utils.AssertEqual(t, false, executedOldHandler, "Executed old handler")
  3284  	utils.AssertEqual(t, true, executedNewHandler, "Executed new handler")
  3285  }
  3286  
  3287  // go test -run Test_Ctx_RestartRoutingWithChangedPathAnd404
  3288  func Test_Ctx_RestartRoutingWithChangedPathAndCatchAll(t *testing.T) {
  3289  	t.Parallel()
  3290  	app := New()
  3291  	app.Get("/new", func(c *Ctx) error {
  3292  		return nil
  3293  	})
  3294  	app.Use(func(c *Ctx) error {
  3295  		c.Path("/new")
  3296  		// c.Next() would fail this test as a 404 is returned from the next handler
  3297  		return c.RestartRouting()
  3298  	})
  3299  	app.Use(func(c *Ctx) error {
  3300  		return ErrNotFound
  3301  	})
  3302  
  3303  	resp, err := app.Test(httptest.NewRequest(MethodGet, "http://example.com/old", nil))
  3304  	utils.AssertEqual(t, nil, err, "app.Test(req)")
  3305  	utils.AssertEqual(t, StatusOK, resp.StatusCode, "Status code")
  3306  }
  3307  
  3308  type testTemplateEngine struct {
  3309  	templates *template.Template
  3310  	path      string
  3311  }
  3312  
  3313  func (t *testTemplateEngine) Render(w io.Writer, name string, bind interface{}, layout ...string) error {
  3314  	if len(layout) == 0 {
  3315  		if err := t.templates.ExecuteTemplate(w, name, bind); err != nil {
  3316  			return fmt.Errorf("failed to execute template without layout: %w", err)
  3317  		}
  3318  		return nil
  3319  	}
  3320  	if err := t.templates.ExecuteTemplate(w, name, bind); err != nil {
  3321  		return fmt.Errorf("failed to execute template: %w", err)
  3322  	}
  3323  	if err := t.templates.ExecuteTemplate(w, layout[0], bind); err != nil {
  3324  		return fmt.Errorf("failed to execute template with layout: %w", err)
  3325  	}
  3326  	return nil
  3327  }
  3328  
  3329  func (t *testTemplateEngine) Load() error {
  3330  	if t.path == "" {
  3331  		t.path = "testdata"
  3332  	}
  3333  	t.templates = template.Must(template.ParseGlob("./.github/" + t.path + "/*.tmpl"))
  3334  	return nil
  3335  }
  3336  
  3337  // go test -run Test_Ctx_Render_Engine
  3338  func Test_Ctx_Render_Engine(t *testing.T) {
  3339  	t.Parallel()
  3340  	engine := &testTemplateEngine{}
  3341  	utils.AssertEqual(t, nil, engine.Load())
  3342  	app := New()
  3343  	app.config.Views = engine
  3344  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3345  	defer app.ReleaseCtx(c)
  3346  	err := c.Render("index.tmpl", Map{
  3347  		"Title": "Hello, World!",
  3348  	})
  3349  	utils.AssertEqual(t, nil, err)
  3350  	utils.AssertEqual(t, "<h1>Hello, World!</h1>", string(c.Response().Body()))
  3351  }
  3352  
  3353  // go test -run Test_Ctx_Render_Engine_With_View_Layout
  3354  func Test_Ctx_Render_Engine_With_View_Layout(t *testing.T) {
  3355  	t.Parallel()
  3356  	engine := &testTemplateEngine{}
  3357  	utils.AssertEqual(t, nil, engine.Load())
  3358  	app := New(Config{ViewsLayout: "main.tmpl"})
  3359  	app.config.Views = engine
  3360  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3361  	defer app.ReleaseCtx(c)
  3362  	err := c.Render("index.tmpl", Map{
  3363  		"Title": "Hello, World!",
  3364  	})
  3365  	utils.AssertEqual(t, nil, err)
  3366  	utils.AssertEqual(t, "<h1>Hello, World!</h1><h1>I'm main</h1>", string(c.Response().Body()))
  3367  }
  3368  
  3369  // go test -v -run=^$ -bench=Benchmark_Ctx_Render_Engine -benchmem -count=4
  3370  func Benchmark_Ctx_Render_Engine(b *testing.B) {
  3371  	engine := &testTemplateEngine{}
  3372  	err := engine.Load()
  3373  	utils.AssertEqual(b, nil, err)
  3374  	app := New()
  3375  	app.config.Views = engine
  3376  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3377  	defer app.ReleaseCtx(c)
  3378  	b.ReportAllocs()
  3379  	b.ResetTimer()
  3380  	for n := 0; n < b.N; n++ {
  3381  		err = c.Render("index.tmpl", Map{
  3382  			"Title": "Hello, World!",
  3383  		})
  3384  	}
  3385  	utils.AssertEqual(b, nil, err)
  3386  	utils.AssertEqual(b, "<h1>Hello, World!</h1>", string(c.Response().Body()))
  3387  }
  3388  
  3389  // go test -v -run=^$ -bench=Benchmark_Ctx_Get_Location_From_Route -benchmem -count=4
  3390  func Benchmark_Ctx_Get_Location_From_Route(b *testing.B) {
  3391  	app := New()
  3392  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3393  	defer app.ReleaseCtx(c)
  3394  	app.Get("/user/:name", func(c *Ctx) error {
  3395  		return c.SendString(c.Params("name"))
  3396  	}).Name("User")
  3397  
  3398  	var err error
  3399  	var location string
  3400  	for n := 0; n < b.N; n++ {
  3401  		location, err = c.getLocationFromRoute(app.GetRoute("User"), Map{"name": "fiber"})
  3402  	}
  3403  	utils.AssertEqual(b, "/user/fiber", location)
  3404  	utils.AssertEqual(b, nil, err)
  3405  }
  3406  
  3407  // go test -run Test_Ctx_Get_Location_From_Route_name
  3408  func Test_Ctx_Get_Location_From_Route_name(t *testing.T) {
  3409  	t.Parallel()
  3410  
  3411  	t.Run("case insensitive", func(t *testing.T) {
  3412  		t.Parallel()
  3413  		app := New()
  3414  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3415  		defer app.ReleaseCtx(c)
  3416  		app.Get("/user/:name", func(c *Ctx) error {
  3417  			return c.SendString(c.Params("name"))
  3418  		}).Name("User")
  3419  
  3420  		location, err := c.GetRouteURL("User", Map{"name": "fiber"})
  3421  		utils.AssertEqual(t, nil, err)
  3422  		utils.AssertEqual(t, "/user/fiber", location)
  3423  
  3424  		location, err = c.GetRouteURL("User", Map{"Name": "fiber"})
  3425  		utils.AssertEqual(t, nil, err)
  3426  		utils.AssertEqual(t, "/user/fiber", location)
  3427  	})
  3428  
  3429  	t.Run("case sensitive", func(t *testing.T) {
  3430  		t.Parallel()
  3431  		app := New(Config{CaseSensitive: true})
  3432  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3433  		defer app.ReleaseCtx(c)
  3434  		app.Get("/user/:name", func(c *Ctx) error {
  3435  			return c.SendString(c.Params("name"))
  3436  		}).Name("User")
  3437  
  3438  		location, err := c.GetRouteURL("User", Map{"name": "fiber"})
  3439  		utils.AssertEqual(t, nil, err)
  3440  		utils.AssertEqual(t, "/user/fiber", location)
  3441  
  3442  		location, err = c.GetRouteURL("User", Map{"Name": "fiber"})
  3443  		utils.AssertEqual(t, nil, err)
  3444  		utils.AssertEqual(t, "/user/", location)
  3445  	})
  3446  }
  3447  
  3448  // go test -run Test_Ctx_Get_Location_From_Route_name_Optional_greedy
  3449  func Test_Ctx_Get_Location_From_Route_name_Optional_greedy(t *testing.T) {
  3450  	t.Parallel()
  3451  	app := New()
  3452  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3453  	defer app.ReleaseCtx(c)
  3454  	app.Get("/:phone/*/send/*", func(c *Ctx) error {
  3455  		return c.SendString("Phone: " + c.Params("phone") + "\nFirst Param: " + c.Params("*1") + "\nSecond Param: " + c.Params("*2"))
  3456  	}).Name("SendSms")
  3457  
  3458  	location, err := c.GetRouteURL("SendSms", Map{
  3459  		"phone": "23456789",
  3460  		"*1":    "sms",
  3461  		"*2":    "test-msg",
  3462  	})
  3463  	utils.AssertEqual(t, nil, err)
  3464  	utils.AssertEqual(t, "/23456789/sms/send/test-msg", location)
  3465  }
  3466  
  3467  // go test -run Test_Ctx_Get_Location_From_Route_name_Optional_greedy_one_param
  3468  func Test_Ctx_Get_Location_From_Route_name_Optional_greedy_one_param(t *testing.T) {
  3469  	t.Parallel()
  3470  	app := New()
  3471  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3472  	defer app.ReleaseCtx(c)
  3473  	app.Get("/:phone/*/send", func(c *Ctx) error {
  3474  		return c.SendString("Phone: " + c.Params("phone") + "\nFirst Param: " + c.Params("*1"))
  3475  	}).Name("SendSms")
  3476  
  3477  	location, err := c.GetRouteURL("SendSms", Map{
  3478  		"phone": "23456789",
  3479  		"*":     "sms",
  3480  	})
  3481  	utils.AssertEqual(t, nil, err)
  3482  	utils.AssertEqual(t, "/23456789/sms/send", location)
  3483  }
  3484  
  3485  type errorTemplateEngine struct{}
  3486  
  3487  func (errorTemplateEngine) Render(_ io.Writer, _ string, _ interface{}, _ ...string) error {
  3488  	return errors.New("errorTemplateEngine")
  3489  }
  3490  
  3491  func (errorTemplateEngine) Load() error { return nil }
  3492  
  3493  // go test -run Test_Ctx_Render_Engine_Error
  3494  func Test_Ctx_Render_Engine_Error(t *testing.T) {
  3495  	t.Parallel()
  3496  	app := New()
  3497  	app.config.Views = errorTemplateEngine{}
  3498  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3499  	defer app.ReleaseCtx(c)
  3500  	err := c.Render("index.tmpl", nil)
  3501  	utils.AssertEqual(t, false, err == nil)
  3502  }
  3503  
  3504  // go test -run Test_Ctx_Render_Go_Template
  3505  func Test_Ctx_Render_Go_Template(t *testing.T) {
  3506  	t.Parallel()
  3507  	file, err := os.CreateTemp(os.TempDir(), "fiber")
  3508  	utils.AssertEqual(t, nil, err)
  3509  	defer func() {
  3510  		err := os.Remove(file.Name())
  3511  		utils.AssertEqual(t, nil, err)
  3512  	}()
  3513  
  3514  	_, err = file.Write([]byte("template"))
  3515  	utils.AssertEqual(t, nil, err)
  3516  
  3517  	err = file.Close()
  3518  	utils.AssertEqual(t, nil, err)
  3519  
  3520  	app := New()
  3521  
  3522  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3523  	defer app.ReleaseCtx(c)
  3524  
  3525  	err = c.Render(file.Name(), nil)
  3526  	utils.AssertEqual(t, nil, err)
  3527  	utils.AssertEqual(t, "template", string(c.Response().Body()))
  3528  }
  3529  
  3530  // go test -run Test_Ctx_Send
  3531  func Test_Ctx_Send(t *testing.T) {
  3532  	t.Parallel()
  3533  	app := New()
  3534  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3535  	defer app.ReleaseCtx(c)
  3536  	utils.AssertEqual(t, nil, c.Send([]byte("Hello, World")))
  3537  	utils.AssertEqual(t, nil, c.Send([]byte("Don't crash please")))
  3538  	utils.AssertEqual(t, nil, c.Send([]byte("1337")))
  3539  	utils.AssertEqual(t, "1337", string(c.Response().Body()))
  3540  }
  3541  
  3542  // go test -v  -run=^$ -bench=Benchmark_Ctx_Send -benchmem -count=4
  3543  func Benchmark_Ctx_Send(b *testing.B) {
  3544  	app := New()
  3545  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3546  	defer app.ReleaseCtx(c)
  3547  	byt := []byte("Hello, World!")
  3548  	b.ReportAllocs()
  3549  	b.ResetTimer()
  3550  
  3551  	var err error
  3552  	for n := 0; n < b.N; n++ {
  3553  		err = c.Send(byt)
  3554  	}
  3555  	utils.AssertEqual(b, nil, err)
  3556  	utils.AssertEqual(b, "Hello, World!", string(c.Response().Body()))
  3557  }
  3558  
  3559  // go test -run Test_Ctx_SendStatus
  3560  func Test_Ctx_SendStatus(t *testing.T) {
  3561  	t.Parallel()
  3562  	app := New()
  3563  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3564  	defer app.ReleaseCtx(c)
  3565  	err := c.SendStatus(415)
  3566  	utils.AssertEqual(t, nil, err)
  3567  	utils.AssertEqual(t, 415, c.Response().StatusCode())
  3568  	utils.AssertEqual(t, "Unsupported Media Type", string(c.Response().Body()))
  3569  }
  3570  
  3571  // go test -run Test_Ctx_SendString
  3572  func Test_Ctx_SendString(t *testing.T) {
  3573  	t.Parallel()
  3574  	app := New()
  3575  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3576  	defer app.ReleaseCtx(c)
  3577  	err := c.SendString("Don't crash please")
  3578  	utils.AssertEqual(t, nil, err)
  3579  	utils.AssertEqual(t, "Don't crash please", string(c.Response().Body()))
  3580  }
  3581  
  3582  // go test -run Test_Ctx_SendStream
  3583  func Test_Ctx_SendStream(t *testing.T) {
  3584  	t.Parallel()
  3585  	app := New()
  3586  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3587  	defer app.ReleaseCtx(c)
  3588  
  3589  	err := c.SendStream(bytes.NewReader([]byte("Don't crash please")))
  3590  	utils.AssertEqual(t, nil, err)
  3591  	utils.AssertEqual(t, "Don't crash please", string(c.Response().Body()))
  3592  
  3593  	err = c.SendStream(bytes.NewReader([]byte("Don't crash please")), len([]byte("Don't crash please")))
  3594  	utils.AssertEqual(t, nil, err)
  3595  	utils.AssertEqual(t, "Don't crash please", string(c.Response().Body()))
  3596  
  3597  	err = c.SendStream(bufio.NewReader(bytes.NewReader([]byte("Hello bufio"))))
  3598  	utils.AssertEqual(t, nil, err)
  3599  	utils.AssertEqual(t, "Hello bufio", string(c.Response().Body()))
  3600  }
  3601  
  3602  // go test -run Test_Ctx_Set
  3603  func Test_Ctx_Set(t *testing.T) {
  3604  	t.Parallel()
  3605  	app := New()
  3606  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3607  	defer app.ReleaseCtx(c)
  3608  	c.Set("X-1", "1")
  3609  	c.Set("X-2", "2")
  3610  	c.Set("X-3", "3")
  3611  	c.Set("X-3", "1337")
  3612  	utils.AssertEqual(t, "1", string(c.Response().Header.Peek("x-1")))
  3613  	utils.AssertEqual(t, "2", string(c.Response().Header.Peek("x-2")))
  3614  	utils.AssertEqual(t, "1337", string(c.Response().Header.Peek("x-3")))
  3615  }
  3616  
  3617  // go test -run Test_Ctx_Set_Splitter
  3618  func Test_Ctx_Set_Splitter(t *testing.T) {
  3619  	t.Parallel()
  3620  	app := New()
  3621  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3622  	defer app.ReleaseCtx(c)
  3623  
  3624  	c.Set("Location", "foo\r\nSet-Cookie:%20SESSIONID=MaliciousValue\r\n")
  3625  	h := string(c.Response().Header.Peek("Location"))
  3626  	utils.AssertEqual(t, false, strings.Contains(h, "\r\n"), h)
  3627  
  3628  	c.Set("Location", "foo\nSet-Cookie:%20SESSIONID=MaliciousValue\n")
  3629  	h = string(c.Response().Header.Peek("Location"))
  3630  	utils.AssertEqual(t, false, strings.Contains(h, "\n"), h)
  3631  }
  3632  
  3633  // go test -v  -run=^$ -bench=Benchmark_Ctx_Set -benchmem -count=4
  3634  func Benchmark_Ctx_Set(b *testing.B) {
  3635  	app := New()
  3636  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3637  	defer app.ReleaseCtx(c)
  3638  	val := "1431-15132-3423"
  3639  	b.ReportAllocs()
  3640  	b.ResetTimer()
  3641  	for n := 0; n < b.N; n++ {
  3642  		c.Set(HeaderXRequestID, val)
  3643  	}
  3644  }
  3645  
  3646  // go test -run Test_Ctx_Status
  3647  func Test_Ctx_Status(t *testing.T) {
  3648  	t.Parallel()
  3649  	app := New()
  3650  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3651  	defer app.ReleaseCtx(c)
  3652  	c.Status(400)
  3653  	utils.AssertEqual(t, 400, c.Response().StatusCode())
  3654  	err := c.Status(415).Send([]byte("Hello, World"))
  3655  	utils.AssertEqual(t, nil, err)
  3656  	utils.AssertEqual(t, 415, c.Response().StatusCode())
  3657  	utils.AssertEqual(t, "Hello, World", string(c.Response().Body()))
  3658  }
  3659  
  3660  // go test -run Test_Ctx_Type
  3661  func Test_Ctx_Type(t *testing.T) {
  3662  	t.Parallel()
  3663  	app := New()
  3664  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3665  	defer app.ReleaseCtx(c)
  3666  	c.Type(".json")
  3667  	utils.AssertEqual(t, "application/json", string(c.Response().Header.Peek("Content-Type")))
  3668  
  3669  	c.Type("json", "utf-8")
  3670  	utils.AssertEqual(t, "application/json; charset=utf-8", string(c.Response().Header.Peek("Content-Type")))
  3671  
  3672  	c.Type(".html")
  3673  	utils.AssertEqual(t, "text/html", string(c.Response().Header.Peek("Content-Type")))
  3674  
  3675  	c.Type("html", "utf-8")
  3676  	utils.AssertEqual(t, "text/html; charset=utf-8", string(c.Response().Header.Peek("Content-Type")))
  3677  }
  3678  
  3679  // go test -v  -run=^$ -bench=Benchmark_Ctx_Type -benchmem -count=4
  3680  func Benchmark_Ctx_Type(b *testing.B) {
  3681  	app := New()
  3682  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3683  	defer app.ReleaseCtx(c)
  3684  	b.ReportAllocs()
  3685  	b.ResetTimer()
  3686  	for n := 0; n < b.N; n++ {
  3687  		c.Type(".json")
  3688  		c.Type("json")
  3689  	}
  3690  }
  3691  
  3692  // go test -v  -run=^$ -bench=Benchmark_Ctx_Type_Charset -benchmem -count=4
  3693  func Benchmark_Ctx_Type_Charset(b *testing.B) {
  3694  	app := New()
  3695  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3696  	defer app.ReleaseCtx(c)
  3697  	b.ReportAllocs()
  3698  	b.ResetTimer()
  3699  	for n := 0; n < b.N; n++ {
  3700  		c.Type(".json", "utf-8")
  3701  		c.Type("json", "utf-8")
  3702  	}
  3703  }
  3704  
  3705  // go test -run Test_Ctx_Vary
  3706  func Test_Ctx_Vary(t *testing.T) {
  3707  	t.Parallel()
  3708  	app := New()
  3709  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3710  	defer app.ReleaseCtx(c)
  3711  	c.Vary("Origin")
  3712  	c.Vary("User-Agent")
  3713  	c.Vary("Accept-Encoding", "Accept")
  3714  	utils.AssertEqual(t, "Origin, User-Agent, Accept-Encoding, Accept", string(c.Response().Header.Peek("Vary")))
  3715  }
  3716  
  3717  // go test -v  -run=^$ -bench=Benchmark_Ctx_Vary -benchmem -count=4
  3718  func Benchmark_Ctx_Vary(b *testing.B) {
  3719  	app := New()
  3720  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3721  	defer app.ReleaseCtx(c)
  3722  	b.ReportAllocs()
  3723  	b.ResetTimer()
  3724  	for n := 0; n < b.N; n++ {
  3725  		c.Vary("Origin", "User-Agent")
  3726  	}
  3727  }
  3728  
  3729  // go test -run Test_Ctx_Write
  3730  func Test_Ctx_Write(t *testing.T) {
  3731  	t.Parallel()
  3732  	app := New()
  3733  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3734  	defer app.ReleaseCtx(c)
  3735  	_, err := c.Write([]byte("Hello, "))
  3736  	utils.AssertEqual(t, nil, err)
  3737  	_, err = c.Write([]byte("World!"))
  3738  	utils.AssertEqual(t, nil, err)
  3739  	utils.AssertEqual(t, "Hello, World!", string(c.Response().Body()))
  3740  }
  3741  
  3742  // go test -v -run=^$ -bench=Benchmark_Ctx_Write -benchmem -count=4
  3743  func Benchmark_Ctx_Write(b *testing.B) {
  3744  	app := New()
  3745  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3746  	defer app.ReleaseCtx(c)
  3747  	byt := []byte("Hello, World!")
  3748  	b.ReportAllocs()
  3749  	b.ResetTimer()
  3750  
  3751  	var err error
  3752  	for n := 0; n < b.N; n++ {
  3753  		_, err = c.Write(byt)
  3754  	}
  3755  	utils.AssertEqual(b, nil, err)
  3756  }
  3757  
  3758  // go test -run Test_Ctx_Writef
  3759  func Test_Ctx_Writef(t *testing.T) {
  3760  	t.Parallel()
  3761  	app := New()
  3762  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3763  	defer app.ReleaseCtx(c)
  3764  	world := "World!"
  3765  	_, err := c.Writef("Hello, %s", world)
  3766  	utils.AssertEqual(t, nil, err)
  3767  	utils.AssertEqual(t, "Hello, World!", string(c.Response().Body()))
  3768  }
  3769  
  3770  // go test -v -run=^$ -bench=Benchmark_Ctx_Writef -benchmem -count=4
  3771  func Benchmark_Ctx_Writef(b *testing.B) {
  3772  	app := New()
  3773  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3774  	defer app.ReleaseCtx(c)
  3775  	world := "World!"
  3776  	b.ReportAllocs()
  3777  	b.ResetTimer()
  3778  
  3779  	var err error
  3780  	for n := 0; n < b.N; n++ {
  3781  		_, err = c.Writef("Hello, %s", world)
  3782  	}
  3783  	utils.AssertEqual(b, nil, err)
  3784  }
  3785  
  3786  // go test -run Test_Ctx_WriteString
  3787  func Test_Ctx_WriteString(t *testing.T) {
  3788  	t.Parallel()
  3789  	app := New()
  3790  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3791  	defer app.ReleaseCtx(c)
  3792  	_, err := c.WriteString("Hello, ")
  3793  	utils.AssertEqual(t, nil, err)
  3794  	_, err = c.WriteString("World!")
  3795  	utils.AssertEqual(t, nil, err)
  3796  	utils.AssertEqual(t, "Hello, World!", string(c.Response().Body()))
  3797  }
  3798  
  3799  // go test -run Test_Ctx_XHR
  3800  func Test_Ctx_XHR(t *testing.T) {
  3801  	t.Parallel()
  3802  	app := New()
  3803  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3804  	defer app.ReleaseCtx(c)
  3805  	c.Request().Header.Set(HeaderXRequestedWith, "XMLHttpRequest")
  3806  	utils.AssertEqual(t, true, c.XHR())
  3807  }
  3808  
  3809  // go test -run=^$ -bench=Benchmark_Ctx_XHR -benchmem -count=4
  3810  func Benchmark_Ctx_XHR(b *testing.B) {
  3811  	app := New()
  3812  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3813  	defer app.ReleaseCtx(c)
  3814  	c.Request().Header.Set(HeaderXRequestedWith, "XMLHttpRequest")
  3815  	var equal bool
  3816  	b.ReportAllocs()
  3817  	b.ResetTimer()
  3818  	for n := 0; n < b.N; n++ {
  3819  		equal = c.XHR()
  3820  	}
  3821  	utils.AssertEqual(b, true, equal)
  3822  }
  3823  
  3824  // go test -v  -run=^$ -bench=Benchmark_Ctx_SendString_B -benchmem -count=4
  3825  func Benchmark_Ctx_SendString_B(b *testing.B) {
  3826  	app := New()
  3827  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3828  	defer app.ReleaseCtx(c)
  3829  	body := "Hello, world!"
  3830  	b.ReportAllocs()
  3831  	b.ResetTimer()
  3832  
  3833  	var err error
  3834  	for n := 0; n < b.N; n++ {
  3835  		err = c.SendString(body)
  3836  	}
  3837  	utils.AssertEqual(b, nil, err)
  3838  	utils.AssertEqual(b, []byte("Hello, world!"), c.Response().Body())
  3839  }
  3840  
  3841  // go test -run Test_Ctx_QueryParser -v
  3842  func Test_Ctx_QueryParser(t *testing.T) {
  3843  	t.Parallel()
  3844  	app := New()
  3845  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3846  	defer app.ReleaseCtx(c)
  3847  	type Query struct {
  3848  		ID    int
  3849  		Name  string
  3850  		Hobby []string
  3851  	}
  3852  	c.Request().SetBody([]byte(``))
  3853  	c.Request().Header.SetContentType("")
  3854  	c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football")
  3855  	q := new(Query)
  3856  	utils.AssertEqual(t, nil, c.QueryParser(q))
  3857  	utils.AssertEqual(t, 2, len(q.Hobby))
  3858  
  3859  	c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football")
  3860  	q = new(Query)
  3861  	utils.AssertEqual(t, nil, c.QueryParser(q))
  3862  	utils.AssertEqual(t, 2, len(q.Hobby))
  3863  
  3864  	c.Request().URI().SetQueryString("id=1&name=tom&hobby=scoccer&hobby=basketball,football")
  3865  	q = new(Query)
  3866  	utils.AssertEqual(t, nil, c.QueryParser(q))
  3867  	utils.AssertEqual(t, 3, len(q.Hobby))
  3868  
  3869  	empty := new(Query)
  3870  	c.Request().URI().SetQueryString("")
  3871  	utils.AssertEqual(t, nil, c.QueryParser(empty))
  3872  	utils.AssertEqual(t, 0, len(empty.Hobby))
  3873  
  3874  	type Query2 struct {
  3875  		Bool            bool
  3876  		ID              int
  3877  		Name            string
  3878  		Hobby           string
  3879  		FavouriteDrinks []string
  3880  		Empty           []string
  3881  		Alloc           []string
  3882  		No              []int64
  3883  	}
  3884  
  3885  	c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1")
  3886  	q2 := new(Query2)
  3887  	q2.Bool = true
  3888  	q2.Name = "hello world"
  3889  	utils.AssertEqual(t, nil, c.QueryParser(q2))
  3890  	utils.AssertEqual(t, "basketball,football", q2.Hobby)
  3891  	utils.AssertEqual(t, true, q2.Bool)
  3892  	utils.AssertEqual(t, "tom", q2.Name) // check value get overwritten
  3893  	utils.AssertEqual(t, []string{"milo", "coke", "pepsi"}, q2.FavouriteDrinks)
  3894  	var nilSlice []string
  3895  	utils.AssertEqual(t, nilSlice, q2.Empty)
  3896  	utils.AssertEqual(t, []string{""}, q2.Alloc)
  3897  	utils.AssertEqual(t, []int64{1}, q2.No)
  3898  
  3899  	type RequiredQuery struct {
  3900  		Name string `query:"name,required"`
  3901  	}
  3902  	rq := new(RequiredQuery)
  3903  	c.Request().URI().SetQueryString("")
  3904  	utils.AssertEqual(t, "failed to decode: name is empty", c.QueryParser(rq).Error())
  3905  
  3906  	type ArrayQuery struct {
  3907  		Data []string
  3908  	}
  3909  	aq := new(ArrayQuery)
  3910  	c.Request().URI().SetQueryString("data[]=john&data[]=doe")
  3911  	utils.AssertEqual(t, nil, c.QueryParser(aq))
  3912  	utils.AssertEqual(t, 2, len(aq.Data))
  3913  }
  3914  
  3915  // go test -run Test_Ctx_QueryParser_WithSetParserDecoder -v
  3916  func Test_Ctx_QueryParser_WithSetParserDecoder(t *testing.T) {
  3917  	t.Parallel()
  3918  	type NonRFCTime time.Time
  3919  
  3920  	nonRFCConverter := func(value string) reflect.Value {
  3921  		if v, err := time.Parse("2006-01-02", value); err == nil {
  3922  			return reflect.ValueOf(v)
  3923  		}
  3924  		return reflect.Value{}
  3925  	}
  3926  
  3927  	nonRFCTime := ParserType{
  3928  		Customtype: NonRFCTime{},
  3929  		Converter:  nonRFCConverter,
  3930  	}
  3931  
  3932  	SetParserDecoder(ParserConfig{
  3933  		IgnoreUnknownKeys: true,
  3934  		ParserType:        []ParserType{nonRFCTime},
  3935  		ZeroEmpty:         true,
  3936  		SetAliasTag:       "query",
  3937  	})
  3938  
  3939  	app := New()
  3940  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3941  	defer app.ReleaseCtx(c)
  3942  
  3943  	type NonRFCTimeInput struct {
  3944  		Date  NonRFCTime `query:"date"`
  3945  		Title string     `query:"title"`
  3946  		Body  string     `query:"body"`
  3947  	}
  3948  
  3949  	c.Request().SetBody([]byte(``))
  3950  	c.Request().Header.SetContentType("")
  3951  	q := new(NonRFCTimeInput)
  3952  
  3953  	c.Request().URI().SetQueryString("date=2021-04-10&title=CustomDateTest&Body=October")
  3954  	utils.AssertEqual(t, nil, c.QueryParser(q))
  3955  	utils.AssertEqual(t, "CustomDateTest", q.Title)
  3956  	date := fmt.Sprintf("%v", q.Date)
  3957  	utils.AssertEqual(t, "{0 63753609600 <nil>}", date)
  3958  	utils.AssertEqual(t, "October", q.Body)
  3959  
  3960  	c.Request().URI().SetQueryString("date=2021-04-10&title&Body=October")
  3961  	q = &NonRFCTimeInput{
  3962  		Title: "Existing title",
  3963  		Body:  "Existing Body",
  3964  	}
  3965  	utils.AssertEqual(t, nil, c.QueryParser(q))
  3966  	utils.AssertEqual(t, "", q.Title)
  3967  }
  3968  
  3969  // go test -run Test_Ctx_QueryParser_Schema -v
  3970  func Test_Ctx_QueryParser_Schema(t *testing.T) {
  3971  	t.Parallel()
  3972  	app := New()
  3973  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  3974  	defer app.ReleaseCtx(c)
  3975  	type Query1 struct {
  3976  		Name   string `query:"name,required"`
  3977  		Nested struct {
  3978  			Age int `query:"age"`
  3979  		} `query:"nested,required"`
  3980  	}
  3981  	c.Request().SetBody([]byte(``))
  3982  	c.Request().Header.SetContentType("")
  3983  	c.Request().URI().SetQueryString("name=tom&nested.age=10")
  3984  	q := new(Query1)
  3985  	utils.AssertEqual(t, nil, c.QueryParser(q))
  3986  
  3987  	c.Request().URI().SetQueryString("namex=tom&nested.age=10")
  3988  	q = new(Query1)
  3989  	utils.AssertEqual(t, "failed to decode: name is empty", c.QueryParser(q).Error())
  3990  
  3991  	c.Request().URI().SetQueryString("name=tom&nested.agex=10")
  3992  	q = new(Query1)
  3993  	utils.AssertEqual(t, nil, c.QueryParser(q))
  3994  
  3995  	c.Request().URI().SetQueryString("name=tom&test.age=10")
  3996  	q = new(Query1)
  3997  	utils.AssertEqual(t, "failed to decode: nested is empty", c.QueryParser(q).Error())
  3998  
  3999  	type Query2 struct {
  4000  		Name   string `query:"name"`
  4001  		Nested struct {
  4002  			Age int `query:"age,required"`
  4003  		} `query:"nested"`
  4004  	}
  4005  	c.Request().URI().SetQueryString("name=tom&nested.age=10")
  4006  	q2 := new(Query2)
  4007  	utils.AssertEqual(t, nil, c.QueryParser(q2))
  4008  
  4009  	c.Request().URI().SetQueryString("nested.age=10")
  4010  	q2 = new(Query2)
  4011  	utils.AssertEqual(t, nil, c.QueryParser(q2))
  4012  
  4013  	c.Request().URI().SetQueryString("nested.agex=10")
  4014  	q2 = new(Query2)
  4015  	utils.AssertEqual(t, "failed to decode: nested.age is empty", c.QueryParser(q2).Error())
  4016  
  4017  	c.Request().URI().SetQueryString("nested.agex=10")
  4018  	q2 = new(Query2)
  4019  	utils.AssertEqual(t, "failed to decode: nested.age is empty", c.QueryParser(q2).Error())
  4020  
  4021  	type Node struct {
  4022  		Value int   `query:"val,required"`
  4023  		Next  *Node `query:"next,required"`
  4024  	}
  4025  	c.Request().URI().SetQueryString("val=1&next.val=3")
  4026  	n := new(Node)
  4027  	utils.AssertEqual(t, nil, c.QueryParser(n))
  4028  	utils.AssertEqual(t, 1, n.Value)
  4029  	utils.AssertEqual(t, 3, n.Next.Value)
  4030  
  4031  	c.Request().URI().SetQueryString("next.val=2")
  4032  	n = new(Node)
  4033  	utils.AssertEqual(t, "failed to decode: val is empty", c.QueryParser(n).Error())
  4034  
  4035  	c.Request().URI().SetQueryString("val=3&next.value=2")
  4036  	n = new(Node)
  4037  	n.Next = new(Node)
  4038  	utils.AssertEqual(t, nil, c.QueryParser(n))
  4039  	utils.AssertEqual(t, 3, n.Value)
  4040  	utils.AssertEqual(t, 0, n.Next.Value)
  4041  
  4042  	type Person struct {
  4043  		Name string `query:"name"`
  4044  		Age  int    `query:"age"`
  4045  	}
  4046  
  4047  	type CollectionQuery struct {
  4048  		Data []Person `query:"data"`
  4049  	}
  4050  
  4051  	c.Request().URI().SetQueryString("data[0][name]=john&data[0][age]=10&data[1][name]=doe&data[1][age]=12")
  4052  	cq := new(CollectionQuery)
  4053  	utils.AssertEqual(t, nil, c.QueryParser(cq))
  4054  	utils.AssertEqual(t, 2, len(cq.Data))
  4055  	utils.AssertEqual(t, "john", cq.Data[0].Name)
  4056  	utils.AssertEqual(t, 10, cq.Data[0].Age)
  4057  	utils.AssertEqual(t, "doe", cq.Data[1].Name)
  4058  	utils.AssertEqual(t, 12, cq.Data[1].Age)
  4059  
  4060  	c.Request().URI().SetQueryString("data.0.name=john&data.0.age=10&data.1.name=doe&data.1.age=12")
  4061  	cq = new(CollectionQuery)
  4062  	utils.AssertEqual(t, nil, c.QueryParser(cq))
  4063  	utils.AssertEqual(t, 2, len(cq.Data))
  4064  	utils.AssertEqual(t, "john", cq.Data[0].Name)
  4065  	utils.AssertEqual(t, 10, cq.Data[0].Age)
  4066  	utils.AssertEqual(t, "doe", cq.Data[1].Name)
  4067  	utils.AssertEqual(t, 12, cq.Data[1].Age)
  4068  }
  4069  
  4070  // go test -run Test_Ctx_ReqHeaderParser -v
  4071  func Test_Ctx_ReqHeaderParser(t *testing.T) {
  4072  	t.Parallel()
  4073  	app := New()
  4074  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4075  	defer app.ReleaseCtx(c)
  4076  	type Header struct {
  4077  		ID    int
  4078  		Name  string
  4079  		Hobby []string
  4080  	}
  4081  	c.Request().SetBody([]byte(``))
  4082  	c.Request().Header.SetContentType("")
  4083  
  4084  	c.Request().Header.Add("id", "1")
  4085  	c.Request().Header.Add("Name", "John Doe")
  4086  	c.Request().Header.Add("Hobby", "golang,fiber")
  4087  	q := new(Header)
  4088  	utils.AssertEqual(t, nil, c.ReqHeaderParser(q))
  4089  	utils.AssertEqual(t, 2, len(q.Hobby))
  4090  
  4091  	c.Request().Header.Del("hobby")
  4092  	c.Request().Header.Add("Hobby", "golang,fiber,go")
  4093  	q = new(Header)
  4094  	utils.AssertEqual(t, nil, c.ReqHeaderParser(q))
  4095  	utils.AssertEqual(t, 3, len(q.Hobby))
  4096  
  4097  	empty := new(Header)
  4098  	c.Request().Header.Del("hobby")
  4099  	utils.AssertEqual(t, nil, c.QueryParser(empty))
  4100  	utils.AssertEqual(t, 0, len(empty.Hobby))
  4101  
  4102  	type Header2 struct {
  4103  		Bool            bool
  4104  		ID              int
  4105  		Name            string
  4106  		Hobby           string
  4107  		FavouriteDrinks []string
  4108  		Empty           []string
  4109  		Alloc           []string
  4110  		No              []int64
  4111  	}
  4112  
  4113  	c.Request().Header.Add("id", "2")
  4114  	c.Request().Header.Add("Name", "Jane Doe")
  4115  	c.Request().Header.Del("hobby")
  4116  	c.Request().Header.Add("Hobby", "go,fiber")
  4117  	c.Request().Header.Add("favouriteDrinks", "milo,coke,pepsi")
  4118  	c.Request().Header.Add("alloc", "")
  4119  	c.Request().Header.Add("no", "1")
  4120  
  4121  	h2 := new(Header2)
  4122  	h2.Bool = true
  4123  	h2.Name = "hello world"
  4124  	utils.AssertEqual(t, nil, c.ReqHeaderParser(h2))
  4125  	utils.AssertEqual(t, "go,fiber", h2.Hobby)
  4126  	utils.AssertEqual(t, true, h2.Bool)
  4127  	utils.AssertEqual(t, "Jane Doe", h2.Name) // check value get overwritten
  4128  	utils.AssertEqual(t, []string{"milo", "coke", "pepsi"}, h2.FavouriteDrinks)
  4129  	var nilSlice []string
  4130  	utils.AssertEqual(t, nilSlice, h2.Empty)
  4131  	utils.AssertEqual(t, []string{""}, h2.Alloc)
  4132  	utils.AssertEqual(t, []int64{1}, h2.No)
  4133  
  4134  	type RequiredHeader struct {
  4135  		Name string `reqHeader:"name,required"`
  4136  	}
  4137  	rh := new(RequiredHeader)
  4138  	c.Request().Header.Del("name")
  4139  	utils.AssertEqual(t, "failed to decode: name is empty", c.ReqHeaderParser(rh).Error())
  4140  }
  4141  
  4142  // go test -run Test_Ctx_ReqHeaderParser_WithSetParserDecoder -v
  4143  func Test_Ctx_ReqHeaderParser_WithSetParserDecoder(t *testing.T) {
  4144  	t.Parallel()
  4145  	type NonRFCTime time.Time
  4146  
  4147  	nonRFCConverter := func(value string) reflect.Value {
  4148  		if v, err := time.Parse("2006-01-02", value); err == nil {
  4149  			return reflect.ValueOf(v)
  4150  		}
  4151  		return reflect.Value{}
  4152  	}
  4153  
  4154  	nonRFCTime := ParserType{
  4155  		Customtype: NonRFCTime{},
  4156  		Converter:  nonRFCConverter,
  4157  	}
  4158  
  4159  	SetParserDecoder(ParserConfig{
  4160  		IgnoreUnknownKeys: true,
  4161  		ParserType:        []ParserType{nonRFCTime},
  4162  		ZeroEmpty:         true,
  4163  		SetAliasTag:       "req",
  4164  	})
  4165  
  4166  	app := New()
  4167  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4168  	defer app.ReleaseCtx(c)
  4169  
  4170  	type NonRFCTimeInput struct {
  4171  		Date  NonRFCTime `req:"date"`
  4172  		Title string     `req:"title"`
  4173  		Body  string     `req:"body"`
  4174  	}
  4175  
  4176  	c.Request().SetBody([]byte(``))
  4177  	c.Request().Header.SetContentType("")
  4178  	r := new(NonRFCTimeInput)
  4179  
  4180  	c.Request().Header.Add("Date", "2021-04-10")
  4181  	c.Request().Header.Add("Title", "CustomDateTest")
  4182  	c.Request().Header.Add("Body", "October")
  4183  
  4184  	utils.AssertEqual(t, nil, c.ReqHeaderParser(r))
  4185  	utils.AssertEqual(t, "CustomDateTest", r.Title)
  4186  	date := fmt.Sprintf("%v", r.Date)
  4187  	utils.AssertEqual(t, "{0 63753609600 <nil>}", date)
  4188  	utils.AssertEqual(t, "October", r.Body)
  4189  
  4190  	c.Request().Header.Add("Title", "")
  4191  	r = &NonRFCTimeInput{
  4192  		Title: "Existing title",
  4193  		Body:  "Existing Body",
  4194  	}
  4195  	utils.AssertEqual(t, nil, c.ReqHeaderParser(r))
  4196  	utils.AssertEqual(t, "", r.Title)
  4197  }
  4198  
  4199  // go test -run Test_Ctx_ReqHeaderParser_Schema -v
  4200  func Test_Ctx_ReqHeaderParser_Schema(t *testing.T) {
  4201  	t.Parallel()
  4202  	app := New()
  4203  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4204  	defer app.ReleaseCtx(c)
  4205  	type Header1 struct {
  4206  		Name   string `reqHeader:"Name,required"`
  4207  		Nested struct {
  4208  			Age int `reqHeader:"Age"`
  4209  		} `reqHeader:"Nested,required"`
  4210  	}
  4211  	c.Request().SetBody([]byte(``))
  4212  	c.Request().Header.SetContentType("")
  4213  
  4214  	c.Request().Header.Add("Name", "tom")
  4215  	c.Request().Header.Add("Nested.Age", "10")
  4216  	q := new(Header1)
  4217  	utils.AssertEqual(t, nil, c.ReqHeaderParser(q))
  4218  
  4219  	c.Request().Header.Del("Name")
  4220  	q = new(Header1)
  4221  	utils.AssertEqual(t, "failed to decode: Name is empty", c.ReqHeaderParser(q).Error())
  4222  
  4223  	c.Request().Header.Add("Name", "tom")
  4224  	c.Request().Header.Del("Nested.Age")
  4225  	c.Request().Header.Add("Nested.Agex", "10")
  4226  	q = new(Header1)
  4227  	utils.AssertEqual(t, nil, c.ReqHeaderParser(q))
  4228  
  4229  	c.Request().Header.Del("Nested.Agex")
  4230  	q = new(Header1)
  4231  	utils.AssertEqual(t, "failed to decode: Nested is empty", c.ReqHeaderParser(q).Error())
  4232  
  4233  	c.Request().Header.Del("Nested.Agex")
  4234  	c.Request().Header.Del("Name")
  4235  
  4236  	type Header2 struct {
  4237  		Name   string `reqHeader:"Name"`
  4238  		Nested struct {
  4239  			Age int `reqHeader:"age,required"`
  4240  		} `reqHeader:"Nested"`
  4241  	}
  4242  
  4243  	c.Request().Header.Add("Name", "tom")
  4244  	c.Request().Header.Add("Nested.Age", "10")
  4245  
  4246  	h2 := new(Header2)
  4247  	utils.AssertEqual(t, nil, c.ReqHeaderParser(h2))
  4248  
  4249  	c.Request().Header.Del("Name")
  4250  	h2 = new(Header2)
  4251  	utils.AssertEqual(t, nil, c.ReqHeaderParser(h2))
  4252  
  4253  	c.Request().Header.Del("Name")
  4254  	c.Request().Header.Del("Nested.Age")
  4255  	c.Request().Header.Add("Nested.Agex", "10")
  4256  	h2 = new(Header2)
  4257  	utils.AssertEqual(t, "failed to decode: Nested.age is empty", c.ReqHeaderParser(h2).Error())
  4258  
  4259  	type Node struct {
  4260  		Value int   `reqHeader:"Val,required"`
  4261  		Next  *Node `reqHeader:"Next,required"`
  4262  	}
  4263  	c.Request().Header.Add("Val", "1")
  4264  	c.Request().Header.Add("Next.Val", "3")
  4265  	n := new(Node)
  4266  	utils.AssertEqual(t, nil, c.ReqHeaderParser(n))
  4267  	utils.AssertEqual(t, 1, n.Value)
  4268  	utils.AssertEqual(t, 3, n.Next.Value)
  4269  
  4270  	c.Request().Header.Del("Val")
  4271  	n = new(Node)
  4272  	utils.AssertEqual(t, "failed to decode: Val is empty", c.ReqHeaderParser(n).Error())
  4273  
  4274  	c.Request().Header.Add("Val", "3")
  4275  	c.Request().Header.Del("Next.Val")
  4276  	c.Request().Header.Add("Next.Value", "2")
  4277  	n = new(Node)
  4278  	n.Next = new(Node)
  4279  	utils.AssertEqual(t, nil, c.ReqHeaderParser(n))
  4280  	utils.AssertEqual(t, 3, n.Value)
  4281  	utils.AssertEqual(t, 0, n.Next.Value)
  4282  }
  4283  
  4284  func Test_Ctx_EqualFieldType(t *testing.T) {
  4285  	t.Parallel()
  4286  	var out int
  4287  	utils.AssertEqual(t, false, equalFieldType(&out, reflect.Int, "key"))
  4288  
  4289  	var dummy struct{ f string }
  4290  	utils.AssertEqual(t, false, equalFieldType(&dummy, reflect.String, "key"))
  4291  
  4292  	var dummy2 struct{ f string }
  4293  	utils.AssertEqual(t, false, equalFieldType(&dummy2, reflect.String, "f"))
  4294  
  4295  	var user struct {
  4296  		Name    string
  4297  		Address string `query:"address"`
  4298  		Age     int    `query:"AGE"`
  4299  	}
  4300  	utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "name"))
  4301  	utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Name"))
  4302  	utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "address"))
  4303  	utils.AssertEqual(t, true, equalFieldType(&user, reflect.String, "Address"))
  4304  	utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "AGE"))
  4305  	utils.AssertEqual(t, true, equalFieldType(&user, reflect.Int, "age"))
  4306  }
  4307  
  4308  // go test -v  -run=^$ -bench=Benchmark_Ctx_QueryParser -benchmem -count=4
  4309  func Benchmark_Ctx_QueryParser(b *testing.B) {
  4310  	app := New()
  4311  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4312  	defer app.ReleaseCtx(c)
  4313  	type Query struct {
  4314  		ID    int
  4315  		Name  string
  4316  		Hobby []string
  4317  	}
  4318  	c.Request().SetBody([]byte(``))
  4319  	c.Request().Header.SetContentType("")
  4320  	c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football")
  4321  	q := new(Query)
  4322  	b.ReportAllocs()
  4323  	b.ResetTimer()
  4324  
  4325  	var err error
  4326  	for n := 0; n < b.N; n++ {
  4327  		err = c.QueryParser(q)
  4328  	}
  4329  	utils.AssertEqual(b, nil, err)
  4330  	utils.AssertEqual(b, nil, c.QueryParser(q))
  4331  }
  4332  
  4333  // go test -v  -run=^$ -bench=Benchmark_Ctx_parseQuery -benchmem -count=4
  4334  func Benchmark_Ctx_parseQuery(b *testing.B) {
  4335  	app := New()
  4336  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4337  	defer app.ReleaseCtx(c)
  4338  	type Person struct {
  4339  		Name string `query:"name"`
  4340  		Age  int    `query:"age"`
  4341  	}
  4342  
  4343  	type CollectionQuery struct {
  4344  		Data []Person `query:"data"`
  4345  	}
  4346  
  4347  	c.Request().SetBody([]byte(``))
  4348  	c.Request().Header.SetContentType("")
  4349  	c.Request().URI().SetQueryString("data[0][name]=john&data[0][age]=10")
  4350  	cq := new(CollectionQuery)
  4351  
  4352  	b.ReportAllocs()
  4353  	b.ResetTimer()
  4354  
  4355  	var err error
  4356  	for n := 0; n < b.N; n++ {
  4357  		err = c.QueryParser(cq)
  4358  	}
  4359  
  4360  	utils.AssertEqual(b, nil, err)
  4361  	utils.AssertEqual(b, nil, c.QueryParser(cq))
  4362  }
  4363  
  4364  // go test -v  -run=^$ -bench=Benchmark_Ctx_QueryParser_Comma -benchmem -count=4
  4365  func Benchmark_Ctx_QueryParser_Comma(b *testing.B) {
  4366  	app := New()
  4367  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4368  	defer app.ReleaseCtx(c)
  4369  	type Query struct {
  4370  		ID    int
  4371  		Name  string
  4372  		Hobby []string
  4373  	}
  4374  	c.Request().SetBody([]byte(``))
  4375  	c.Request().Header.SetContentType("")
  4376  	// c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball&hobby=football")
  4377  	c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football")
  4378  	q := new(Query)
  4379  	b.ReportAllocs()
  4380  	b.ResetTimer()
  4381  
  4382  	var err error
  4383  	for n := 0; n < b.N; n++ {
  4384  		err = c.QueryParser(q)
  4385  	}
  4386  	utils.AssertEqual(b, nil, err)
  4387  	utils.AssertEqual(b, nil, c.QueryParser(q))
  4388  }
  4389  
  4390  // go test -v  -run=^$ -bench=Benchmark_Ctx_ReqHeaderParser -benchmem -count=4
  4391  func Benchmark_Ctx_ReqHeaderParser(b *testing.B) {
  4392  	app := New()
  4393  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4394  	defer app.ReleaseCtx(c)
  4395  	type ReqHeader struct {
  4396  		ID    int
  4397  		Name  string
  4398  		Hobby []string
  4399  	}
  4400  	c.Request().SetBody([]byte(``))
  4401  	c.Request().Header.SetContentType("")
  4402  
  4403  	c.Request().Header.Add("id", "1")
  4404  	c.Request().Header.Add("Name", "John Doe")
  4405  	c.Request().Header.Add("Hobby", "golang,fiber")
  4406  
  4407  	q := new(ReqHeader)
  4408  	b.ReportAllocs()
  4409  	b.ResetTimer()
  4410  
  4411  	var err error
  4412  	for n := 0; n < b.N; n++ {
  4413  		err = c.ReqHeaderParser(q)
  4414  	}
  4415  	utils.AssertEqual(b, nil, err)
  4416  	utils.AssertEqual(b, nil, c.ReqHeaderParser(q))
  4417  }
  4418  
  4419  // go test -run Test_Ctx_BodyStreamWriter
  4420  func Test_Ctx_BodyStreamWriter(t *testing.T) {
  4421  	t.Parallel()
  4422  	ctx := &fasthttp.RequestCtx{}
  4423  
  4424  	ctx.SetBodyStreamWriter(func(w *bufio.Writer) {
  4425  		fmt.Fprintf(w, "body writer line 1\n")
  4426  		if err := w.Flush(); err != nil {
  4427  			t.Errorf("unexpected error: %s", err)
  4428  		}
  4429  		fmt.Fprintf(w, "body writer line 2\n")
  4430  	})
  4431  	if !ctx.IsBodyStream() {
  4432  		t.Fatal("IsBodyStream must return true")
  4433  	}
  4434  
  4435  	s := ctx.Response.String()
  4436  	br := bufio.NewReader(bytes.NewBufferString(s))
  4437  	var resp fasthttp.Response
  4438  	if err := resp.Read(br); err != nil {
  4439  		t.Fatalf("Error when reading response: %s", err)
  4440  	}
  4441  	body := string(resp.Body())
  4442  	expectedBody := "body writer line 1\nbody writer line 2\n"
  4443  	if body != expectedBody {
  4444  		t.Fatalf("unexpected body: %q. Expecting %q", body, expectedBody)
  4445  	}
  4446  }
  4447  
  4448  // go test -v  -run=^$ -bench=Benchmark_Ctx_BodyStreamWriter -benchmem -count=4
  4449  func Benchmark_Ctx_BodyStreamWriter(b *testing.B) {
  4450  	ctx := &fasthttp.RequestCtx{}
  4451  	user := []byte(`{"name":"john"}`)
  4452  	b.ReportAllocs()
  4453  	b.ResetTimer()
  4454  
  4455  	var err error
  4456  	for n := 0; n < b.N; n++ {
  4457  		ctx.ResetBody()
  4458  		ctx.SetBodyStreamWriter(func(w *bufio.Writer) {
  4459  			for i := 0; i < 10; i++ {
  4460  				_, err = w.Write(user)
  4461  				if err := w.Flush(); err != nil {
  4462  					return
  4463  				}
  4464  			}
  4465  		})
  4466  	}
  4467  	utils.AssertEqual(b, nil, err)
  4468  }
  4469  
  4470  func Test_Ctx_String(t *testing.T) {
  4471  	t.Parallel()
  4472  	app := New()
  4473  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4474  	defer app.ReleaseCtx(c)
  4475  
  4476  	utils.AssertEqual(t, "#0000000000000000 - 0.0.0.0:0 <-> 0.0.0.0:0 - GET http:///", c.String())
  4477  }
  4478  
  4479  func TestCtx_ParamsInt(t *testing.T) {
  4480  	// Create a test context and set some strings (or params)
  4481  	// create a fake app to be used within this test
  4482  	t.Parallel()
  4483  	app := New()
  4484  
  4485  	// Create some test endpoints
  4486  
  4487  	// For the user id I will use the number 1111, so I should be able to get the number
  4488  	// 1111 from the Ctx
  4489  	app.Get("/test/:user", func(c *Ctx) error {
  4490  		// utils.AssertEqual(t, "john", c.Params("user"))
  4491  
  4492  		num, err := c.ParamsInt("user")
  4493  
  4494  		// Check the number matches
  4495  		if num != 1111 {
  4496  			t.Fatalf("Expected number 1111 from the path, got %d", num)
  4497  		}
  4498  
  4499  		// Check no errors are returned, because we want NO errors in this one
  4500  		if err != nil {
  4501  			t.Fatalf("Expected nil error for 1111 test, got " + err.Error())
  4502  		}
  4503  
  4504  		return nil
  4505  	})
  4506  
  4507  	// In this test case, there will be a bad request where the expected number is NOT
  4508  	// a number in the path
  4509  	app.Get("/testnoint/:user", func(c *Ctx) error {
  4510  		// utils.AssertEqual(t, "john", c.Params("user"))
  4511  
  4512  		num, err := c.ParamsInt("user")
  4513  
  4514  		// Check the number matches
  4515  		if num != 0 {
  4516  			t.Fatalf("Expected number 0 from the path, got %d", num)
  4517  		}
  4518  
  4519  		// Check an error is returned, because we want NO errors in this one
  4520  		if err == nil {
  4521  			t.Fatal("Expected non nil error for bad req test, got nil")
  4522  		}
  4523  
  4524  		return nil
  4525  	})
  4526  
  4527  	// For the user id I will use the number 2222, so I should be able to get the number
  4528  	// 2222 from the Ctx even when the default value is specified
  4529  	app.Get("/testignoredefault/:user", func(c *Ctx) error {
  4530  		// utils.AssertEqual(t, "john", c.Params("user"))
  4531  
  4532  		num, err := c.ParamsInt("user", 1111)
  4533  
  4534  		// Check the number matches
  4535  		if num != 2222 {
  4536  			t.Fatalf("Expected number 2222 from the path, got %d", num)
  4537  		}
  4538  
  4539  		// Check no errors are returned, because we want NO errors in this one
  4540  		if err != nil {
  4541  			t.Fatalf("Expected nil error for 2222 test, got " + err.Error())
  4542  		}
  4543  
  4544  		return nil
  4545  	})
  4546  
  4547  	// In this test case, there will be a bad request where the expected number is NOT
  4548  	// a number in the path, default value of 1111 should be used instead
  4549  	app.Get("/testdefault/:user", func(c *Ctx) error {
  4550  		// utils.AssertEqual(t, "john", c.Params("user"))
  4551  
  4552  		num, err := c.ParamsInt("user", 1111)
  4553  
  4554  		// Check the number matches
  4555  		if num != 1111 {
  4556  			t.Fatalf("Expected number 1111 from the path, got %d", num)
  4557  		}
  4558  
  4559  		// Check an error is returned, because we want NO errors in this one
  4560  		if err != nil {
  4561  			t.Fatalf("Expected nil error for 1111 test, got " + err.Error())
  4562  		}
  4563  
  4564  		return nil
  4565  	})
  4566  
  4567  	_, err := app.Test(httptest.NewRequest(MethodGet, "/test/1111", nil))
  4568  	utils.AssertEqual(t, nil, err)
  4569  
  4570  	_, err = app.Test(httptest.NewRequest(MethodGet, "/testnoint/xd", nil))
  4571  	utils.AssertEqual(t, nil, err)
  4572  
  4573  	_, err = app.Test(httptest.NewRequest(MethodGet, "/testignoredefault/2222", nil))
  4574  	utils.AssertEqual(t, nil, err)
  4575  
  4576  	_, err = app.Test(httptest.NewRequest(MethodGet, "/testdefault/xd", nil))
  4577  	utils.AssertEqual(t, nil, err)
  4578  }
  4579  
  4580  // go test -run Test_Ctx_GetRespHeader
  4581  func Test_Ctx_GetRespHeader(t *testing.T) {
  4582  	t.Parallel()
  4583  	app := New()
  4584  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4585  	defer app.ReleaseCtx(c)
  4586  
  4587  	c.Set("test", "Hello, World 👋!")
  4588  	c.Response().Header.Set(HeaderContentType, "application/json")
  4589  	utils.AssertEqual(t, c.GetRespHeader("test"), "Hello, World 👋!")
  4590  	utils.AssertEqual(t, c.GetRespHeader(HeaderContentType), "application/json")
  4591  }
  4592  
  4593  // go test -run Test_Ctx_GetRespHeaders
  4594  func Test_Ctx_GetRespHeaders(t *testing.T) {
  4595  	t.Parallel()
  4596  	app := New()
  4597  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4598  	defer app.ReleaseCtx(c)
  4599  
  4600  	c.Set("test", "Hello, World 👋!")
  4601  	c.Set("foo", "bar")
  4602  	c.Response().Header.Set(HeaderContentType, "application/json")
  4603  
  4604  	utils.AssertEqual(t, c.GetRespHeaders(), map[string]string{
  4605  		"Content-Type": "application/json",
  4606  		"Foo":          "bar",
  4607  		"Test":         "Hello, World 👋!",
  4608  	})
  4609  }
  4610  
  4611  // go test -run Test_Ctx_GetReqHeaders
  4612  func Test_Ctx_GetReqHeaders(t *testing.T) {
  4613  	t.Parallel()
  4614  	app := New()
  4615  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4616  	defer app.ReleaseCtx(c)
  4617  
  4618  	c.Request().Header.Set("test", "Hello, World 👋!")
  4619  	c.Request().Header.Set("foo", "bar")
  4620  	c.Request().Header.Set(HeaderContentType, "application/json")
  4621  
  4622  	utils.AssertEqual(t, c.GetReqHeaders(), map[string]string{
  4623  		"Content-Type": "application/json",
  4624  		"Foo":          "bar",
  4625  		"Test":         "Hello, World 👋!",
  4626  	})
  4627  }
  4628  
  4629  // go test -run Test_Ctx_IsFromLocal
  4630  func Test_Ctx_IsFromLocal(t *testing.T) {
  4631  	t.Parallel()
  4632  	// Test "0.0.0.0", "127.0.0.1" and "::1".
  4633  	{
  4634  		app := New()
  4635  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4636  		defer app.ReleaseCtx(c)
  4637  		utils.AssertEqual(t, true, c.IsFromLocal())
  4638  	}
  4639  	// This is a test for "0.0.0.0"
  4640  	{
  4641  		app := New()
  4642  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4643  		c.Request().Header.Set(HeaderXForwardedFor, "0.0.0.0")
  4644  		defer app.ReleaseCtx(c)
  4645  		utils.AssertEqual(t, true, c.IsFromLocal())
  4646  	}
  4647  
  4648  	// This is a test for "127.0.0.1"
  4649  	{
  4650  		app := New()
  4651  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4652  		c.Request().Header.Set(HeaderXForwardedFor, "127.0.0.1")
  4653  		defer app.ReleaseCtx(c)
  4654  		utils.AssertEqual(t, true, c.IsFromLocal())
  4655  	}
  4656  
  4657  	// This is a test for "localhost"
  4658  	{
  4659  		app := New()
  4660  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4661  		defer app.ReleaseCtx(c)
  4662  		utils.AssertEqual(t, true, c.IsFromLocal())
  4663  	}
  4664  
  4665  	// This is testing "::1", it is the compressed format IPV6 loopback address 0:0:0:0:0:0:0:1.
  4666  	// It is the equivalent of the IPV4 address 127.0.0.1.
  4667  	{
  4668  		app := New()
  4669  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4670  		c.Request().Header.Set(HeaderXForwardedFor, "::1")
  4671  		defer app.ReleaseCtx(c)
  4672  		utils.AssertEqual(t, true, c.IsFromLocal())
  4673  	}
  4674  
  4675  	{
  4676  		app := New()
  4677  		c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4678  		c.Request().Header.Set(HeaderXForwardedFor, "93.46.8.90")
  4679  		defer app.ReleaseCtx(c)
  4680  		utils.AssertEqual(t, false, c.IsFromLocal())
  4681  	}
  4682  }
  4683  
  4684  // go test -run Test_Ctx_RepeatParserWithSameStruct -v
  4685  func Test_Ctx_RepeatParserWithSameStruct(t *testing.T) {
  4686  	t.Parallel()
  4687  	app := New()
  4688  	c := app.AcquireCtx(&fasthttp.RequestCtx{})
  4689  	defer app.ReleaseCtx(c)
  4690  
  4691  	type Request struct {
  4692  		QueryParam  string `query:"query_param"`
  4693  		HeaderParam string `reqHeader:"header_param"`
  4694  		BodyParam   string `json:"body_param" xml:"body_param" form:"body_param"`
  4695  	}
  4696  
  4697  	r := new(Request)
  4698  
  4699  	c.Request().URI().SetQueryString("query_param=query_param")
  4700  	utils.AssertEqual(t, nil, c.QueryParser(r))
  4701  	utils.AssertEqual(t, "query_param", r.QueryParam)
  4702  
  4703  	c.Request().Header.Add("header_param", "header_param")
  4704  	utils.AssertEqual(t, nil, c.ReqHeaderParser(r))
  4705  	utils.AssertEqual(t, "header_param", r.HeaderParam)
  4706  
  4707  	var gzipJSON bytes.Buffer
  4708  	w := gzip.NewWriter(&gzipJSON)
  4709  	_, _ = w.Write([]byte(`{"body_param":"body_param"}`)) //nolint:errcheck // This will never fail
  4710  	err := w.Close()
  4711  	utils.AssertEqual(t, nil, err)
  4712  	c.Request().Header.SetContentType(MIMEApplicationJSON)
  4713  	c.Request().Header.Set(HeaderContentEncoding, "gzip")
  4714  	c.Request().SetBody(gzipJSON.Bytes())
  4715  	c.Request().Header.SetContentLength(len(gzipJSON.Bytes()))
  4716  	utils.AssertEqual(t, nil, c.BodyParser(r))
  4717  	utils.AssertEqual(t, "body_param", r.BodyParam)
  4718  	c.Request().Header.Del(HeaderContentEncoding)
  4719  
  4720  	testDecodeParser := func(contentType, body string) {
  4721  		c.Request().Header.SetContentType(contentType)
  4722  		c.Request().SetBody([]byte(body))
  4723  		c.Request().Header.SetContentLength(len(body))
  4724  		utils.AssertEqual(t, nil, c.BodyParser(r))
  4725  		utils.AssertEqual(t, "body_param", r.BodyParam)
  4726  	}
  4727  
  4728  	testDecodeParser(MIMEApplicationJSON, `{"body_param":"body_param"}`)
  4729  	testDecodeParser(MIMEApplicationXML, `<Demo><body_param>body_param</body_param></Demo>`)
  4730  	testDecodeParser(MIMEApplicationForm, "body_param=body_param")
  4731  	testDecodeParser(MIMEMultipartForm+`;boundary="b"`, "--b\r\nContent-Disposition: form-data; name=\"body_param\"\r\n\r\nbody_param\r\n--b--")
  4732  }