github.com/gofiber/fiber/v2@v2.47.0/client_test.go (about)

     1  //nolint:wrapcheck // We must not wrap errors in tests
     2  package fiber
     3  
     4  import (
     5  	"bytes"
     6  	"crypto/tls"
     7  	"encoding/base64"
     8  	"encoding/json"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"mime/multipart"
    13  	"net"
    14  	"os"
    15  	"path/filepath"
    16  	"regexp"
    17  	"strings"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/gofiber/fiber/v2/internal/tlstest"
    22  	"github.com/gofiber/fiber/v2/utils"
    23  
    24  	"github.com/valyala/fasthttp/fasthttputil"
    25  )
    26  
    27  func Test_Client_Invalid_URL(t *testing.T) {
    28  	t.Parallel()
    29  
    30  	ln := fasthttputil.NewInmemoryListener()
    31  
    32  	app := New(Config{DisableStartupMessage: true})
    33  
    34  	app.Get("/", func(c *Ctx) error {
    35  		return c.SendString(c.Hostname())
    36  	})
    37  
    38  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
    39  
    40  	a := Get("http://example.com\r\n\r\nGET /\r\n\r\n")
    41  
    42  	a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
    43  
    44  	_, body, errs := a.String()
    45  
    46  	utils.AssertEqual(t, "", body)
    47  	utils.AssertEqual(t, 1, len(errs))
    48  	utils.AssertEqual(t, "missing required Host header in request", errs[0].Error())
    49  }
    50  
    51  func Test_Client_Unsupported_Protocol(t *testing.T) {
    52  	t.Parallel()
    53  
    54  	a := Get("ftp://example.com")
    55  
    56  	_, body, errs := a.String()
    57  
    58  	utils.AssertEqual(t, "", body)
    59  	utils.AssertEqual(t, 1, len(errs))
    60  	utils.AssertEqual(t, `unsupported protocol "ftp". http and https are supported`,
    61  		errs[0].Error())
    62  }
    63  
    64  func Test_Client_Get(t *testing.T) {
    65  	t.Parallel()
    66  
    67  	ln := fasthttputil.NewInmemoryListener()
    68  
    69  	app := New(Config{DisableStartupMessage: true})
    70  
    71  	app.Get("/", func(c *Ctx) error {
    72  		return c.SendString(c.Hostname())
    73  	})
    74  
    75  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
    76  
    77  	for i := 0; i < 5; i++ {
    78  		a := Get("http://example.com")
    79  
    80  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
    81  
    82  		code, body, errs := a.String()
    83  
    84  		utils.AssertEqual(t, StatusOK, code)
    85  		utils.AssertEqual(t, "example.com", body)
    86  		utils.AssertEqual(t, 0, len(errs))
    87  	}
    88  }
    89  
    90  func Test_Client_Head(t *testing.T) {
    91  	t.Parallel()
    92  
    93  	ln := fasthttputil.NewInmemoryListener()
    94  
    95  	app := New(Config{DisableStartupMessage: true})
    96  
    97  	app.Get("/", func(c *Ctx) error {
    98  		return c.SendString(c.Hostname())
    99  	})
   100  
   101  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   102  
   103  	for i := 0; i < 5; i++ {
   104  		a := Head("http://example.com")
   105  
   106  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   107  
   108  		code, body, errs := a.String()
   109  
   110  		utils.AssertEqual(t, StatusOK, code)
   111  		utils.AssertEqual(t, "", body)
   112  		utils.AssertEqual(t, 0, len(errs))
   113  	}
   114  }
   115  
   116  func Test_Client_Post(t *testing.T) {
   117  	t.Parallel()
   118  
   119  	ln := fasthttputil.NewInmemoryListener()
   120  
   121  	app := New(Config{DisableStartupMessage: true})
   122  
   123  	app.Post("/", func(c *Ctx) error {
   124  		return c.Status(StatusCreated).
   125  			SendString(c.FormValue("foo"))
   126  	})
   127  
   128  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   129  
   130  	for i := 0; i < 5; i++ {
   131  		args := AcquireArgs()
   132  
   133  		args.Set("foo", "bar")
   134  
   135  		a := Post("http://example.com").
   136  			Form(args)
   137  
   138  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   139  
   140  		code, body, errs := a.String()
   141  
   142  		utils.AssertEqual(t, StatusCreated, code)
   143  		utils.AssertEqual(t, "bar", body)
   144  		utils.AssertEqual(t, 0, len(errs))
   145  
   146  		ReleaseArgs(args)
   147  	}
   148  }
   149  
   150  func Test_Client_Put(t *testing.T) {
   151  	t.Parallel()
   152  
   153  	ln := fasthttputil.NewInmemoryListener()
   154  
   155  	app := New(Config{DisableStartupMessage: true})
   156  
   157  	app.Put("/", func(c *Ctx) error {
   158  		return c.SendString(c.FormValue("foo"))
   159  	})
   160  
   161  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   162  
   163  	for i := 0; i < 5; i++ {
   164  		args := AcquireArgs()
   165  
   166  		args.Set("foo", "bar")
   167  
   168  		a := Put("http://example.com").
   169  			Form(args)
   170  
   171  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   172  
   173  		code, body, errs := a.String()
   174  
   175  		utils.AssertEqual(t, StatusOK, code)
   176  		utils.AssertEqual(t, "bar", body)
   177  		utils.AssertEqual(t, 0, len(errs))
   178  
   179  		ReleaseArgs(args)
   180  	}
   181  }
   182  
   183  func Test_Client_Patch(t *testing.T) {
   184  	t.Parallel()
   185  
   186  	ln := fasthttputil.NewInmemoryListener()
   187  
   188  	app := New(Config{DisableStartupMessage: true})
   189  
   190  	app.Patch("/", func(c *Ctx) error {
   191  		return c.SendString(c.FormValue("foo"))
   192  	})
   193  
   194  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   195  
   196  	for i := 0; i < 5; i++ {
   197  		args := AcquireArgs()
   198  
   199  		args.Set("foo", "bar")
   200  
   201  		a := Patch("http://example.com").
   202  			Form(args)
   203  
   204  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   205  
   206  		code, body, errs := a.String()
   207  
   208  		utils.AssertEqual(t, StatusOK, code)
   209  		utils.AssertEqual(t, "bar", body)
   210  		utils.AssertEqual(t, 0, len(errs))
   211  
   212  		ReleaseArgs(args)
   213  	}
   214  }
   215  
   216  func Test_Client_Delete(t *testing.T) {
   217  	t.Parallel()
   218  
   219  	ln := fasthttputil.NewInmemoryListener()
   220  
   221  	app := New(Config{DisableStartupMessage: true})
   222  
   223  	app.Delete("/", func(c *Ctx) error {
   224  		return c.Status(StatusNoContent).
   225  			SendString("deleted")
   226  	})
   227  
   228  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   229  
   230  	for i := 0; i < 5; i++ {
   231  		args := AcquireArgs()
   232  
   233  		a := Delete("http://example.com")
   234  
   235  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   236  
   237  		code, body, errs := a.String()
   238  
   239  		utils.AssertEqual(t, StatusNoContent, code)
   240  		utils.AssertEqual(t, "", body)
   241  		utils.AssertEqual(t, 0, len(errs))
   242  
   243  		ReleaseArgs(args)
   244  	}
   245  }
   246  
   247  func Test_Client_UserAgent(t *testing.T) {
   248  	t.Parallel()
   249  
   250  	ln := fasthttputil.NewInmemoryListener()
   251  
   252  	app := New(Config{DisableStartupMessage: true})
   253  
   254  	app.Get("/", func(c *Ctx) error {
   255  		return c.Send(c.Request().Header.UserAgent())
   256  	})
   257  
   258  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   259  
   260  	t.Run("default", func(t *testing.T) {
   261  		t.Parallel()
   262  		for i := 0; i < 5; i++ {
   263  			a := Get("http://example.com")
   264  
   265  			a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   266  
   267  			code, body, errs := a.String()
   268  
   269  			utils.AssertEqual(t, StatusOK, code)
   270  			utils.AssertEqual(t, defaultUserAgent, body)
   271  			utils.AssertEqual(t, 0, len(errs))
   272  		}
   273  	})
   274  
   275  	t.Run("custom", func(t *testing.T) {
   276  		t.Parallel()
   277  		for i := 0; i < 5; i++ {
   278  			c := AcquireClient()
   279  			c.UserAgent = "ua"
   280  
   281  			a := c.Get("http://example.com")
   282  
   283  			a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   284  
   285  			code, body, errs := a.String()
   286  
   287  			utils.AssertEqual(t, StatusOK, code)
   288  			utils.AssertEqual(t, "ua", body)
   289  			utils.AssertEqual(t, 0, len(errs))
   290  			ReleaseClient(c)
   291  		}
   292  	})
   293  }
   294  
   295  func Test_Client_Agent_Set_Or_Add_Headers(t *testing.T) {
   296  	t.Parallel()
   297  	handler := func(c *Ctx) error {
   298  		c.Request().Header.VisitAll(func(key, value []byte) {
   299  			if k := string(key); k == "K1" || k == "K2" {
   300  				_, err := c.Write(key)
   301  				utils.AssertEqual(t, nil, err)
   302  				_, err = c.Write(value)
   303  				utils.AssertEqual(t, nil, err)
   304  			}
   305  		})
   306  		return nil
   307  	}
   308  
   309  	wrapAgent := func(a *Agent) {
   310  		a.Set("k1", "v1").
   311  			SetBytesK([]byte("k1"), "v1").
   312  			SetBytesV("k1", []byte("v1")).
   313  			AddBytesK([]byte("k1"), "v11").
   314  			AddBytesV("k1", []byte("v22")).
   315  			AddBytesKV([]byte("k1"), []byte("v33")).
   316  			SetBytesKV([]byte("k2"), []byte("v2")).
   317  			Add("k2", "v22")
   318  	}
   319  
   320  	testAgent(t, handler, wrapAgent, "K1v1K1v11K1v22K1v33K2v2K2v22")
   321  }
   322  
   323  func Test_Client_Agent_Connection_Close(t *testing.T) {
   324  	t.Parallel()
   325  	handler := func(c *Ctx) error {
   326  		if c.Request().Header.ConnectionClose() {
   327  			return c.SendString("close")
   328  		}
   329  		return c.SendString("not close")
   330  	}
   331  
   332  	wrapAgent := func(a *Agent) {
   333  		a.ConnectionClose()
   334  	}
   335  
   336  	testAgent(t, handler, wrapAgent, "close")
   337  }
   338  
   339  func Test_Client_Agent_UserAgent(t *testing.T) {
   340  	t.Parallel()
   341  	handler := func(c *Ctx) error {
   342  		return c.Send(c.Request().Header.UserAgent())
   343  	}
   344  
   345  	wrapAgent := func(a *Agent) {
   346  		a.UserAgent("ua").
   347  			UserAgentBytes([]byte("ua"))
   348  	}
   349  
   350  	testAgent(t, handler, wrapAgent, "ua")
   351  }
   352  
   353  func Test_Client_Agent_Cookie(t *testing.T) {
   354  	t.Parallel()
   355  	handler := func(c *Ctx) error {
   356  		return c.SendString(
   357  			c.Cookies("k1") + c.Cookies("k2") + c.Cookies("k3") + c.Cookies("k4"))
   358  	}
   359  
   360  	wrapAgent := func(a *Agent) {
   361  		a.Cookie("k1", "v1").
   362  			CookieBytesK([]byte("k2"), "v2").
   363  			CookieBytesKV([]byte("k2"), []byte("v2")).
   364  			Cookies("k3", "v3", "k4", "v4").
   365  			CookiesBytesKV([]byte("k3"), []byte("v3"), []byte("k4"), []byte("v4"))
   366  	}
   367  
   368  	testAgent(t, handler, wrapAgent, "v1v2v3v4")
   369  }
   370  
   371  func Test_Client_Agent_Referer(t *testing.T) {
   372  	t.Parallel()
   373  	handler := func(c *Ctx) error {
   374  		return c.Send(c.Request().Header.Referer())
   375  	}
   376  
   377  	wrapAgent := func(a *Agent) {
   378  		a.Referer("http://referer.com").
   379  			RefererBytes([]byte("http://referer.com"))
   380  	}
   381  
   382  	testAgent(t, handler, wrapAgent, "http://referer.com")
   383  }
   384  
   385  func Test_Client_Agent_ContentType(t *testing.T) {
   386  	t.Parallel()
   387  	handler := func(c *Ctx) error {
   388  		return c.Send(c.Request().Header.ContentType())
   389  	}
   390  
   391  	wrapAgent := func(a *Agent) {
   392  		a.ContentType("custom-type").
   393  			ContentTypeBytes([]byte("custom-type"))
   394  	}
   395  
   396  	testAgent(t, handler, wrapAgent, "custom-type")
   397  }
   398  
   399  func Test_Client_Agent_Host(t *testing.T) {
   400  	t.Parallel()
   401  
   402  	ln := fasthttputil.NewInmemoryListener()
   403  
   404  	app := New(Config{DisableStartupMessage: true})
   405  
   406  	app.Get("/", func(c *Ctx) error {
   407  		return c.SendString(c.Hostname())
   408  	})
   409  
   410  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   411  
   412  	a := Get("http://1.1.1.1:8080").
   413  		Host("example.com").
   414  		HostBytes([]byte("example.com"))
   415  
   416  	utils.AssertEqual(t, "1.1.1.1:8080", a.HostClient.Addr)
   417  
   418  	a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   419  
   420  	code, body, errs := a.String()
   421  
   422  	utils.AssertEqual(t, StatusOK, code)
   423  	utils.AssertEqual(t, "example.com", body)
   424  	utils.AssertEqual(t, 0, len(errs))
   425  }
   426  
   427  func Test_Client_Agent_QueryString(t *testing.T) {
   428  	t.Parallel()
   429  	handler := func(c *Ctx) error {
   430  		return c.Send(c.Request().URI().QueryString())
   431  	}
   432  
   433  	wrapAgent := func(a *Agent) {
   434  		a.QueryString("foo=bar&bar=baz").
   435  			QueryStringBytes([]byte("foo=bar&bar=baz"))
   436  	}
   437  
   438  	testAgent(t, handler, wrapAgent, "foo=bar&bar=baz")
   439  }
   440  
   441  func Test_Client_Agent_BasicAuth(t *testing.T) {
   442  	t.Parallel()
   443  	handler := func(c *Ctx) error {
   444  		// Get authorization header
   445  		auth := c.Get(HeaderAuthorization)
   446  		// Decode the header contents
   447  		raw, err := base64.StdEncoding.DecodeString(auth[6:])
   448  		utils.AssertEqual(t, nil, err)
   449  
   450  		return c.Send(raw)
   451  	}
   452  
   453  	wrapAgent := func(a *Agent) {
   454  		a.BasicAuth("foo", "bar").
   455  			BasicAuthBytes([]byte("foo"), []byte("bar"))
   456  	}
   457  
   458  	testAgent(t, handler, wrapAgent, "foo:bar")
   459  }
   460  
   461  func Test_Client_Agent_BodyString(t *testing.T) {
   462  	t.Parallel()
   463  	handler := func(c *Ctx) error {
   464  		return c.Send(c.Request().Body())
   465  	}
   466  
   467  	wrapAgent := func(a *Agent) {
   468  		a.BodyString("foo=bar&bar=baz")
   469  	}
   470  
   471  	testAgent(t, handler, wrapAgent, "foo=bar&bar=baz")
   472  }
   473  
   474  func Test_Client_Agent_Body(t *testing.T) {
   475  	t.Parallel()
   476  	handler := func(c *Ctx) error {
   477  		return c.Send(c.Request().Body())
   478  	}
   479  
   480  	wrapAgent := func(a *Agent) {
   481  		a.Body([]byte("foo=bar&bar=baz"))
   482  	}
   483  
   484  	testAgent(t, handler, wrapAgent, "foo=bar&bar=baz")
   485  }
   486  
   487  func Test_Client_Agent_BodyStream(t *testing.T) {
   488  	t.Parallel()
   489  	handler := func(c *Ctx) error {
   490  		return c.Send(c.Request().Body())
   491  	}
   492  
   493  	wrapAgent := func(a *Agent) {
   494  		a.BodyStream(strings.NewReader("body stream"), -1)
   495  	}
   496  
   497  	testAgent(t, handler, wrapAgent, "body stream")
   498  }
   499  
   500  func Test_Client_Agent_Custom_Response(t *testing.T) {
   501  	t.Parallel()
   502  
   503  	ln := fasthttputil.NewInmemoryListener()
   504  
   505  	app := New(Config{DisableStartupMessage: true})
   506  
   507  	app.Get("/", func(c *Ctx) error {
   508  		return c.SendString("custom")
   509  	})
   510  
   511  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   512  
   513  	for i := 0; i < 5; i++ {
   514  		a := AcquireAgent()
   515  		resp := AcquireResponse()
   516  
   517  		req := a.Request()
   518  		req.Header.SetMethod(MethodGet)
   519  		req.SetRequestURI("http://example.com")
   520  
   521  		utils.AssertEqual(t, nil, a.Parse())
   522  
   523  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   524  
   525  		code, body, errs := a.SetResponse(resp).
   526  			String()
   527  
   528  		utils.AssertEqual(t, StatusOK, code)
   529  		utils.AssertEqual(t, "custom", body)
   530  		utils.AssertEqual(t, "custom", string(resp.Body()))
   531  		utils.AssertEqual(t, 0, len(errs))
   532  
   533  		ReleaseResponse(resp)
   534  	}
   535  }
   536  
   537  func Test_Client_Agent_Dest(t *testing.T) {
   538  	t.Parallel()
   539  
   540  	ln := fasthttputil.NewInmemoryListener()
   541  
   542  	app := New(Config{DisableStartupMessage: true})
   543  
   544  	app.Get("/", func(c *Ctx) error {
   545  		return c.SendString("dest")
   546  	})
   547  
   548  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   549  
   550  	t.Run("small dest", func(t *testing.T) {
   551  		t.Parallel()
   552  		dest := []byte("de")
   553  
   554  		a := Get("http://example.com")
   555  
   556  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   557  
   558  		code, body, errs := a.Dest(dest[:0]).String()
   559  
   560  		utils.AssertEqual(t, StatusOK, code)
   561  		utils.AssertEqual(t, "dest", body)
   562  		utils.AssertEqual(t, "de", string(dest))
   563  		utils.AssertEqual(t, 0, len(errs))
   564  	})
   565  
   566  	t.Run("enough dest", func(t *testing.T) {
   567  		t.Parallel()
   568  		dest := []byte("foobar")
   569  
   570  		a := Get("http://example.com")
   571  
   572  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   573  
   574  		code, body, errs := a.Dest(dest[:0]).String()
   575  
   576  		utils.AssertEqual(t, StatusOK, code)
   577  		utils.AssertEqual(t, "dest", body)
   578  		utils.AssertEqual(t, "destar", string(dest))
   579  		utils.AssertEqual(t, 0, len(errs))
   580  	})
   581  }
   582  
   583  // readErrorConn is a struct for testing retryIf
   584  type readErrorConn struct {
   585  	net.Conn
   586  }
   587  
   588  func (*readErrorConn) Read(_ []byte) (int, error) {
   589  	return 0, fmt.Errorf("error")
   590  }
   591  
   592  func (*readErrorConn) Write(p []byte) (int, error) {
   593  	return len(p), nil
   594  }
   595  
   596  func (*readErrorConn) Close() error {
   597  	return nil
   598  }
   599  
   600  func (*readErrorConn) LocalAddr() net.Addr {
   601  	return nil
   602  }
   603  
   604  func (*readErrorConn) RemoteAddr() net.Addr {
   605  	return nil
   606  }
   607  
   608  func Test_Client_Agent_RetryIf(t *testing.T) {
   609  	t.Parallel()
   610  
   611  	ln := fasthttputil.NewInmemoryListener()
   612  
   613  	app := New(Config{DisableStartupMessage: true})
   614  
   615  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   616  
   617  	a := Post("http://example.com").
   618  		RetryIf(func(req *Request) bool {
   619  			return true
   620  		})
   621  	dialsCount := 0
   622  	a.HostClient.Dial = func(addr string) (net.Conn, error) {
   623  		dialsCount++
   624  		switch dialsCount {
   625  		case 1:
   626  			return &readErrorConn{}, nil
   627  		case 2:
   628  			return &readErrorConn{}, nil
   629  		case 3:
   630  			return &readErrorConn{}, nil
   631  		case 4:
   632  			return ln.Dial()
   633  		default:
   634  			t.Fatalf("unexpected number of dials: %d", dialsCount)
   635  		}
   636  		panic("unreachable")
   637  	}
   638  
   639  	_, _, errs := a.String()
   640  	utils.AssertEqual(t, dialsCount, 4)
   641  	utils.AssertEqual(t, 0, len(errs))
   642  }
   643  
   644  func Test_Client_Agent_Json(t *testing.T) {
   645  	t.Parallel()
   646  	handler := func(c *Ctx) error {
   647  		utils.AssertEqual(t, MIMEApplicationJSON, string(c.Request().Header.ContentType()))
   648  
   649  		return c.Send(c.Request().Body())
   650  	}
   651  
   652  	wrapAgent := func(a *Agent) {
   653  		a.JSON(data{Success: true})
   654  	}
   655  
   656  	testAgent(t, handler, wrapAgent, `{"success":true}`)
   657  }
   658  
   659  func Test_Client_Agent_Json_Error(t *testing.T) {
   660  	t.Parallel()
   661  	a := Get("http://example.com").
   662  		JSONEncoder(json.Marshal).
   663  		JSON(complex(1, 1))
   664  
   665  	_, body, errs := a.String()
   666  
   667  	utils.AssertEqual(t, "", body)
   668  	utils.AssertEqual(t, 1, len(errs))
   669  	utils.AssertEqual(t, "json: unsupported type: complex128", errs[0].Error())
   670  }
   671  
   672  func Test_Client_Agent_XML(t *testing.T) {
   673  	t.Parallel()
   674  	handler := func(c *Ctx) error {
   675  		utils.AssertEqual(t, MIMEApplicationXML, string(c.Request().Header.ContentType()))
   676  
   677  		return c.Send(c.Request().Body())
   678  	}
   679  
   680  	wrapAgent := func(a *Agent) {
   681  		a.XML(data{Success: true})
   682  	}
   683  
   684  	testAgent(t, handler, wrapAgent, "<data><success>true</success></data>")
   685  }
   686  
   687  func Test_Client_Agent_XML_Error(t *testing.T) {
   688  	t.Parallel()
   689  	a := Get("http://example.com").
   690  		XML(complex(1, 1))
   691  
   692  	_, body, errs := a.String()
   693  
   694  	utils.AssertEqual(t, "", body)
   695  	utils.AssertEqual(t, 1, len(errs))
   696  	utils.AssertEqual(t, "xml: unsupported type: complex128", errs[0].Error())
   697  }
   698  
   699  func Test_Client_Agent_Form(t *testing.T) {
   700  	t.Parallel()
   701  	handler := func(c *Ctx) error {
   702  		utils.AssertEqual(t, MIMEApplicationForm, string(c.Request().Header.ContentType()))
   703  
   704  		return c.Send(c.Request().Body())
   705  	}
   706  
   707  	args := AcquireArgs()
   708  
   709  	args.Set("foo", "bar")
   710  
   711  	wrapAgent := func(a *Agent) {
   712  		a.Form(args)
   713  	}
   714  
   715  	testAgent(t, handler, wrapAgent, "foo=bar")
   716  
   717  	ReleaseArgs(args)
   718  }
   719  
   720  func Test_Client_Agent_MultipartForm(t *testing.T) {
   721  	t.Parallel()
   722  
   723  	ln := fasthttputil.NewInmemoryListener()
   724  
   725  	app := New(Config{DisableStartupMessage: true})
   726  
   727  	app.Post("/", func(c *Ctx) error {
   728  		utils.AssertEqual(t, "multipart/form-data; boundary=myBoundary", c.Get(HeaderContentType))
   729  
   730  		mf, err := c.MultipartForm()
   731  		utils.AssertEqual(t, nil, err)
   732  		utils.AssertEqual(t, "bar", mf.Value["foo"][0])
   733  
   734  		return c.Send(c.Request().Body())
   735  	})
   736  
   737  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   738  
   739  	args := AcquireArgs()
   740  
   741  	args.Set("foo", "bar")
   742  
   743  	a := Post("http://example.com").
   744  		Boundary("myBoundary").
   745  		MultipartForm(args)
   746  
   747  	a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   748  
   749  	code, body, errs := a.String()
   750  
   751  	utils.AssertEqual(t, StatusOK, code)
   752  	utils.AssertEqual(t, "--myBoundary\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n--myBoundary--\r\n", body)
   753  	utils.AssertEqual(t, 0, len(errs))
   754  	ReleaseArgs(args)
   755  }
   756  
   757  func Test_Client_Agent_MultipartForm_Errors(t *testing.T) {
   758  	t.Parallel()
   759  
   760  	a := AcquireAgent()
   761  	a.mw = &errorMultipartWriter{}
   762  
   763  	args := AcquireArgs()
   764  	args.Set("foo", "bar")
   765  
   766  	ff1 := &FormFile{"", "name1", []byte("content"), false}
   767  	ff2 := &FormFile{"", "name2", []byte("content"), false}
   768  	a.FileData(ff1, ff2).
   769  		MultipartForm(args)
   770  
   771  	utils.AssertEqual(t, 4, len(a.errs))
   772  	ReleaseArgs(args)
   773  }
   774  
   775  func Test_Client_Agent_MultipartForm_SendFiles(t *testing.T) {
   776  	t.Parallel()
   777  
   778  	ln := fasthttputil.NewInmemoryListener()
   779  
   780  	app := New(Config{DisableStartupMessage: true})
   781  
   782  	app.Post("/", func(c *Ctx) error {
   783  		utils.AssertEqual(t, "multipart/form-data; boundary=myBoundary", c.Get(HeaderContentType))
   784  
   785  		fh1, err := c.FormFile("field1")
   786  		utils.AssertEqual(t, nil, err)
   787  		utils.AssertEqual(t, fh1.Filename, "name")
   788  		buf := make([]byte, fh1.Size)
   789  		f, err := fh1.Open()
   790  		utils.AssertEqual(t, nil, err)
   791  		defer func() {
   792  			err := f.Close()
   793  			utils.AssertEqual(t, nil, err)
   794  		}()
   795  		_, err = f.Read(buf)
   796  		utils.AssertEqual(t, nil, err)
   797  		utils.AssertEqual(t, "form file", string(buf))
   798  
   799  		fh2, err := c.FormFile("index")
   800  		utils.AssertEqual(t, nil, err)
   801  		checkFormFile(t, fh2, ".github/testdata/index.html")
   802  
   803  		fh3, err := c.FormFile("file3")
   804  		utils.AssertEqual(t, nil, err)
   805  		checkFormFile(t, fh3, ".github/testdata/index.tmpl")
   806  
   807  		return c.SendString("multipart form files")
   808  	})
   809  
   810  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   811  
   812  	for i := 0; i < 5; i++ {
   813  		ff := AcquireFormFile()
   814  		ff.Fieldname = "field1"
   815  		ff.Name = "name"
   816  		ff.Content = []byte("form file")
   817  
   818  		a := Post("http://example.com").
   819  			Boundary("myBoundary").
   820  			FileData(ff).
   821  			SendFiles(".github/testdata/index.html", "index", ".github/testdata/index.tmpl").
   822  			MultipartForm(nil)
   823  
   824  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   825  
   826  		code, body, errs := a.String()
   827  
   828  		utils.AssertEqual(t, StatusOK, code)
   829  		utils.AssertEqual(t, "multipart form files", body)
   830  		utils.AssertEqual(t, 0, len(errs))
   831  
   832  		ReleaseFormFile(ff)
   833  	}
   834  }
   835  
   836  func checkFormFile(t *testing.T, fh *multipart.FileHeader, filename string) {
   837  	t.Helper()
   838  
   839  	basename := filepath.Base(filename)
   840  	utils.AssertEqual(t, fh.Filename, basename)
   841  
   842  	b1, err := os.ReadFile(filename) //nolint:gosec // We're in a test so reading user-provided files by name is fine
   843  	utils.AssertEqual(t, nil, err)
   844  
   845  	b2 := make([]byte, fh.Size)
   846  	f, err := fh.Open()
   847  	utils.AssertEqual(t, nil, err)
   848  	defer func() {
   849  		err := f.Close()
   850  		utils.AssertEqual(t, nil, err)
   851  	}()
   852  	_, err = f.Read(b2)
   853  	utils.AssertEqual(t, nil, err)
   854  	utils.AssertEqual(t, b1, b2)
   855  }
   856  
   857  func Test_Client_Agent_Multipart_Random_Boundary(t *testing.T) {
   858  	t.Parallel()
   859  
   860  	a := Post("http://example.com").
   861  		MultipartForm(nil)
   862  
   863  	reg := regexp.MustCompile(`multipart/form-data; boundary=\w{30}`)
   864  
   865  	utils.AssertEqual(t, true, reg.Match(a.req.Header.Peek(HeaderContentType)))
   866  }
   867  
   868  func Test_Client_Agent_Multipart_Invalid_Boundary(t *testing.T) {
   869  	t.Parallel()
   870  
   871  	a := Post("http://example.com").
   872  		Boundary("*").
   873  		MultipartForm(nil)
   874  
   875  	utils.AssertEqual(t, 1, len(a.errs))
   876  	utils.AssertEqual(t, "mime: invalid boundary character", a.errs[0].Error())
   877  }
   878  
   879  func Test_Client_Agent_SendFile_Error(t *testing.T) {
   880  	t.Parallel()
   881  
   882  	a := Post("http://example.com").
   883  		SendFile("non-exist-file!", "")
   884  
   885  	utils.AssertEqual(t, 1, len(a.errs))
   886  	utils.AssertEqual(t, true, strings.Contains(a.errs[0].Error(), "open non-exist-file!"))
   887  }
   888  
   889  func Test_Client_Debug(t *testing.T) {
   890  	t.Parallel()
   891  	handler := func(c *Ctx) error {
   892  		return c.SendString("debug")
   893  	}
   894  
   895  	var output bytes.Buffer
   896  
   897  	wrapAgent := func(a *Agent) {
   898  		a.Debug(&output)
   899  	}
   900  
   901  	testAgent(t, handler, wrapAgent, "debug", 1)
   902  
   903  	str := output.String()
   904  
   905  	utils.AssertEqual(t, true, strings.Contains(str, "Connected to example.com(InmemoryListener)"))
   906  	utils.AssertEqual(t, true, strings.Contains(str, "GET / HTTP/1.1"))
   907  	utils.AssertEqual(t, true, strings.Contains(str, "User-Agent: fiber"))
   908  	utils.AssertEqual(t, true, strings.Contains(str, "Host: example.com\r\n\r\n"))
   909  	utils.AssertEqual(t, true, strings.Contains(str, "HTTP/1.1 200 OK"))
   910  	utils.AssertEqual(t, true, strings.Contains(str, "Content-Type: text/plain; charset=utf-8\r\nContent-Length: 5\r\n\r\ndebug"))
   911  }
   912  
   913  func Test_Client_Agent_Timeout(t *testing.T) {
   914  	t.Parallel()
   915  
   916  	ln := fasthttputil.NewInmemoryListener()
   917  
   918  	app := New(Config{DisableStartupMessage: true})
   919  
   920  	app.Get("/", func(c *Ctx) error {
   921  		time.Sleep(time.Millisecond * 200)
   922  		return c.SendString("timeout")
   923  	})
   924  
   925  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   926  
   927  	a := Get("http://example.com").
   928  		Timeout(time.Millisecond * 50)
   929  
   930  	a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   931  
   932  	_, body, errs := a.String()
   933  
   934  	utils.AssertEqual(t, "", body)
   935  	utils.AssertEqual(t, 1, len(errs))
   936  	utils.AssertEqual(t, "timeout", errs[0].Error())
   937  }
   938  
   939  func Test_Client_Agent_Reuse(t *testing.T) {
   940  	t.Parallel()
   941  
   942  	ln := fasthttputil.NewInmemoryListener()
   943  
   944  	app := New(Config{DisableStartupMessage: true})
   945  
   946  	app.Get("/", func(c *Ctx) error {
   947  		return c.SendString("reuse")
   948  	})
   949  
   950  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   951  
   952  	a := Get("http://example.com").
   953  		Reuse()
   954  
   955  	a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
   956  
   957  	code, body, errs := a.String()
   958  
   959  	utils.AssertEqual(t, StatusOK, code)
   960  	utils.AssertEqual(t, "reuse", body)
   961  	utils.AssertEqual(t, 0, len(errs))
   962  
   963  	code, body, errs = a.String()
   964  
   965  	utils.AssertEqual(t, StatusOK, code)
   966  	utils.AssertEqual(t, "reuse", body)
   967  	utils.AssertEqual(t, 0, len(errs))
   968  }
   969  
   970  func Test_Client_Agent_InsecureSkipVerify(t *testing.T) {
   971  	t.Parallel()
   972  
   973  	cer, err := tls.LoadX509KeyPair("./.github/testdata/ssl.pem", "./.github/testdata/ssl.key")
   974  	utils.AssertEqual(t, nil, err)
   975  
   976  	//nolint:gosec // We're in a test so using old ciphers is fine
   977  	serverTLSConf := &tls.Config{
   978  		Certificates: []tls.Certificate{cer},
   979  	}
   980  
   981  	ln, err := net.Listen(NetworkTCP4, "127.0.0.1:0")
   982  	utils.AssertEqual(t, nil, err)
   983  
   984  	ln = tls.NewListener(ln, serverTLSConf)
   985  
   986  	app := New(Config{DisableStartupMessage: true})
   987  
   988  	app.Get("/", func(c *Ctx) error {
   989  		return c.SendString("ignore tls")
   990  	})
   991  
   992  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   993  
   994  	code, body, errs := Get("https://" + ln.Addr().String()).
   995  		InsecureSkipVerify().
   996  		InsecureSkipVerify().
   997  		String()
   998  
   999  	utils.AssertEqual(t, 0, len(errs))
  1000  	utils.AssertEqual(t, StatusOK, code)
  1001  	utils.AssertEqual(t, "ignore tls", body)
  1002  }
  1003  
  1004  func Test_Client_Agent_TLS(t *testing.T) {
  1005  	t.Parallel()
  1006  
  1007  	serverTLSConf, clientTLSConf, err := tlstest.GetTLSConfigs()
  1008  	utils.AssertEqual(t, nil, err)
  1009  
  1010  	ln, err := net.Listen(NetworkTCP4, "127.0.0.1:0")
  1011  	utils.AssertEqual(t, nil, err)
  1012  
  1013  	ln = tls.NewListener(ln, serverTLSConf)
  1014  
  1015  	app := New(Config{DisableStartupMessage: true})
  1016  
  1017  	app.Get("/", func(c *Ctx) error {
  1018  		return c.SendString("tls")
  1019  	})
  1020  
  1021  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
  1022  
  1023  	code, body, errs := Get("https://" + ln.Addr().String()).
  1024  		TLSConfig(clientTLSConf).
  1025  		String()
  1026  
  1027  	utils.AssertEqual(t, 0, len(errs))
  1028  	utils.AssertEqual(t, StatusOK, code)
  1029  	utils.AssertEqual(t, "tls", body)
  1030  }
  1031  
  1032  func Test_Client_Agent_MaxRedirectsCount(t *testing.T) {
  1033  	t.Parallel()
  1034  
  1035  	ln := fasthttputil.NewInmemoryListener()
  1036  
  1037  	app := New(Config{DisableStartupMessage: true})
  1038  
  1039  	app.Get("/", func(c *Ctx) error {
  1040  		if c.Request().URI().QueryArgs().Has("foo") {
  1041  			return c.Redirect("/foo")
  1042  		}
  1043  		return c.Redirect("/")
  1044  	})
  1045  	app.Get("/foo", func(c *Ctx) error {
  1046  		return c.SendString("redirect")
  1047  	})
  1048  
  1049  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
  1050  
  1051  	t.Run("success", func(t *testing.T) {
  1052  		t.Parallel()
  1053  		a := Get("http://example.com?foo").
  1054  			MaxRedirectsCount(1)
  1055  
  1056  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
  1057  
  1058  		code, body, errs := a.String()
  1059  
  1060  		utils.AssertEqual(t, 200, code)
  1061  		utils.AssertEqual(t, "redirect", body)
  1062  		utils.AssertEqual(t, 0, len(errs))
  1063  	})
  1064  
  1065  	t.Run("error", func(t *testing.T) {
  1066  		t.Parallel()
  1067  		a := Get("http://example.com").
  1068  			MaxRedirectsCount(1)
  1069  
  1070  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
  1071  
  1072  		_, body, errs := a.String()
  1073  
  1074  		utils.AssertEqual(t, "", body)
  1075  		utils.AssertEqual(t, 1, len(errs))
  1076  		utils.AssertEqual(t, "too many redirects detected when doing the request", errs[0].Error())
  1077  	})
  1078  }
  1079  
  1080  func Test_Client_Agent_Struct(t *testing.T) {
  1081  	t.Parallel()
  1082  
  1083  	ln := fasthttputil.NewInmemoryListener()
  1084  
  1085  	app := New(Config{DisableStartupMessage: true})
  1086  
  1087  	app.Get("/", func(c *Ctx) error {
  1088  		return c.JSON(data{true})
  1089  	})
  1090  
  1091  	app.Get("/error", func(c *Ctx) error {
  1092  		return c.SendString(`{"success"`)
  1093  	})
  1094  
  1095  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
  1096  
  1097  	t.Run("success", func(t *testing.T) {
  1098  		t.Parallel()
  1099  
  1100  		a := Get("http://example.com")
  1101  
  1102  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
  1103  
  1104  		var d data
  1105  
  1106  		code, body, errs := a.Struct(&d)
  1107  
  1108  		utils.AssertEqual(t, StatusOK, code)
  1109  		utils.AssertEqual(t, `{"success":true}`, string(body))
  1110  		utils.AssertEqual(t, 0, len(errs))
  1111  		utils.AssertEqual(t, true, d.Success)
  1112  	})
  1113  
  1114  	t.Run("pre error", func(t *testing.T) {
  1115  		t.Parallel()
  1116  		a := Get("http://example.com")
  1117  
  1118  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
  1119  		a.errs = append(a.errs, errors.New("pre errors"))
  1120  
  1121  		var d data
  1122  		_, body, errs := a.Struct(&d)
  1123  
  1124  		utils.AssertEqual(t, "", string(body))
  1125  		utils.AssertEqual(t, 1, len(errs))
  1126  		utils.AssertEqual(t, "pre errors", errs[0].Error())
  1127  		utils.AssertEqual(t, false, d.Success)
  1128  	})
  1129  
  1130  	t.Run("error", func(t *testing.T) {
  1131  		t.Parallel()
  1132  		a := Get("http://example.com/error")
  1133  
  1134  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
  1135  
  1136  		var d data
  1137  
  1138  		code, body, errs := a.JSONDecoder(json.Unmarshal).Struct(&d)
  1139  
  1140  		utils.AssertEqual(t, StatusOK, code)
  1141  		utils.AssertEqual(t, `{"success"`, string(body))
  1142  		utils.AssertEqual(t, 1, len(errs))
  1143  		utils.AssertEqual(t, "unexpected end of JSON input", errs[0].Error())
  1144  	})
  1145  
  1146  	t.Run("nil jsonDecoder", func(t *testing.T) {
  1147  		t.Parallel()
  1148  		a := AcquireAgent()
  1149  		defer ReleaseAgent(a)
  1150  		defer a.ConnectionClose()
  1151  		request := a.Request()
  1152  		request.Header.SetMethod(MethodGet)
  1153  		request.SetRequestURI("http://example.com")
  1154  		err := a.Parse()
  1155  		utils.AssertEqual(t, nil, err)
  1156  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
  1157  		var d data
  1158  		code, body, errs := a.Struct(&d)
  1159  		utils.AssertEqual(t, StatusOK, code)
  1160  		utils.AssertEqual(t, `{"success":true}`, string(body))
  1161  		utils.AssertEqual(t, 0, len(errs))
  1162  		utils.AssertEqual(t, true, d.Success)
  1163  	})
  1164  }
  1165  
  1166  func Test_Client_Agent_Parse(t *testing.T) {
  1167  	t.Parallel()
  1168  
  1169  	a := Get("https://example.com:10443")
  1170  
  1171  	utils.AssertEqual(t, nil, a.Parse())
  1172  }
  1173  
  1174  func testAgent(t *testing.T, handler Handler, wrapAgent func(agent *Agent), excepted string, count ...int) {
  1175  	t.Helper()
  1176  
  1177  	ln := fasthttputil.NewInmemoryListener()
  1178  
  1179  	app := New(Config{DisableStartupMessage: true})
  1180  
  1181  	app.Get("/", handler)
  1182  
  1183  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
  1184  
  1185  	c := 1
  1186  	if len(count) > 0 {
  1187  		c = count[0]
  1188  	}
  1189  
  1190  	for i := 0; i < c; i++ {
  1191  		a := Get("http://example.com")
  1192  
  1193  		wrapAgent(a)
  1194  
  1195  		a.HostClient.Dial = func(addr string) (net.Conn, error) { return ln.Dial() }
  1196  
  1197  		code, body, errs := a.String()
  1198  
  1199  		utils.AssertEqual(t, StatusOK, code)
  1200  		utils.AssertEqual(t, excepted, body)
  1201  		utils.AssertEqual(t, 0, len(errs))
  1202  	}
  1203  }
  1204  
  1205  type data struct {
  1206  	Success bool `json:"success" xml:"success"`
  1207  }
  1208  
  1209  type errorMultipartWriter struct {
  1210  	count int
  1211  }
  1212  
  1213  func (*errorMultipartWriter) Boundary() string           { return "myBoundary" }
  1214  func (*errorMultipartWriter) SetBoundary(_ string) error { return nil }
  1215  func (e *errorMultipartWriter) CreateFormFile(_, _ string) (io.Writer, error) {
  1216  	if e.count == 0 {
  1217  		e.count++
  1218  		return nil, errors.New("CreateFormFile error")
  1219  	}
  1220  	return errorWriter{}, nil
  1221  }
  1222  func (*errorMultipartWriter) WriteField(_, _ string) error { return errors.New("WriteField error") }
  1223  func (*errorMultipartWriter) Close() error                 { return errors.New("Close error") }
  1224  
  1225  type errorWriter struct{}
  1226  
  1227  func (errorWriter) Write(_ []byte) (int, error) { return 0, errors.New("Write error") }