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