github.com/gofiber/fiber/v2@v2.47.0/middleware/proxy/proxy_test.go (about)

     1  package proxy
     2  
     3  import (
     4  	"crypto/tls"
     5  	"errors"
     6  	"io"
     7  	"net"
     8  	"net/http/httptest"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/gofiber/fiber/v2"
    14  	"github.com/gofiber/fiber/v2/internal/tlstest"
    15  	"github.com/gofiber/fiber/v2/utils"
    16  
    17  	"github.com/valyala/fasthttp"
    18  )
    19  
    20  func createProxyTestServer(t *testing.T, handler fiber.Handler) (*fiber.App, string) {
    21  	t.Helper()
    22  
    23  	target := fiber.New(fiber.Config{DisableStartupMessage: true})
    24  	target.Get("/", handler)
    25  
    26  	ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
    27  	utils.AssertEqual(t, nil, err)
    28  
    29  	go func() {
    30  		utils.AssertEqual(t, nil, target.Listener(ln))
    31  	}()
    32  
    33  	time.Sleep(2 * time.Second)
    34  	addr := ln.Addr().String()
    35  
    36  	return target, addr
    37  }
    38  
    39  // go test -run Test_Proxy_Empty_Host
    40  func Test_Proxy_Empty_Upstream_Servers(t *testing.T) {
    41  	t.Parallel()
    42  
    43  	defer func() {
    44  		if r := recover(); r != nil {
    45  			utils.AssertEqual(t, "Servers cannot be empty", r)
    46  		}
    47  	}()
    48  	app := fiber.New()
    49  	app.Use(Balancer(Config{Servers: []string{}}))
    50  }
    51  
    52  // go test -run Test_Proxy_Empty_Config
    53  func Test_Proxy_Empty_Config(t *testing.T) {
    54  	t.Parallel()
    55  
    56  	defer func() {
    57  		if r := recover(); r != nil {
    58  			utils.AssertEqual(t, "Servers cannot be empty", r)
    59  		}
    60  	}()
    61  	app := fiber.New()
    62  	app.Use(New(Config{}))
    63  }
    64  
    65  // go test -run Test_Proxy_Next
    66  func Test_Proxy_Next(t *testing.T) {
    67  	t.Parallel()
    68  
    69  	app := fiber.New()
    70  	app.Use(Balancer(Config{
    71  		Servers: []string{"127.0.0.1"},
    72  		Next: func(_ *fiber.Ctx) bool {
    73  			return true
    74  		},
    75  	}))
    76  
    77  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
    78  	utils.AssertEqual(t, nil, err)
    79  	utils.AssertEqual(t, fiber.StatusNotFound, resp.StatusCode)
    80  }
    81  
    82  // go test -run Test_Proxy
    83  func Test_Proxy(t *testing.T) {
    84  	t.Parallel()
    85  
    86  	target, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
    87  		return c.SendStatus(fiber.StatusTeapot)
    88  	})
    89  
    90  	resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2000)
    91  	utils.AssertEqual(t, nil, err)
    92  	utils.AssertEqual(t, fiber.StatusTeapot, resp.StatusCode)
    93  
    94  	app := fiber.New(fiber.Config{DisableStartupMessage: true})
    95  
    96  	app.Use(Balancer(Config{Servers: []string{addr}}))
    97  
    98  	req := httptest.NewRequest(fiber.MethodGet, "/", nil)
    99  	req.Host = addr
   100  	resp, err = app.Test(req)
   101  	utils.AssertEqual(t, nil, err)
   102  	utils.AssertEqual(t, fiber.StatusTeapot, resp.StatusCode)
   103  }
   104  
   105  // go test -run Test_Proxy_Balancer_WithTlsConfig
   106  func Test_Proxy_Balancer_WithTlsConfig(t *testing.T) {
   107  	t.Parallel()
   108  
   109  	serverTLSConf, _, err := tlstest.GetTLSConfigs()
   110  	utils.AssertEqual(t, nil, err)
   111  
   112  	ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
   113  	utils.AssertEqual(t, nil, err)
   114  
   115  	ln = tls.NewListener(ln, serverTLSConf)
   116  
   117  	app := fiber.New(fiber.Config{DisableStartupMessage: true})
   118  
   119  	app.Get("/tlsbalaner", func(c *fiber.Ctx) error {
   120  		return c.SendString("tls balancer")
   121  	})
   122  
   123  	addr := ln.Addr().String()
   124  	clientTLSConf := &tls.Config{InsecureSkipVerify: true} //nolint:gosec // We're in a test func, so this is fine
   125  
   126  	// disable certificate verification in Balancer
   127  	app.Use(Balancer(Config{
   128  		Servers:   []string{addr},
   129  		TlsConfig: clientTLSConf,
   130  	}))
   131  
   132  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   133  
   134  	code, body, errs := fiber.Get("https://" + addr + "/tlsbalaner").TLSConfig(clientTLSConf).String()
   135  
   136  	utils.AssertEqual(t, 0, len(errs))
   137  	utils.AssertEqual(t, fiber.StatusOK, code)
   138  	utils.AssertEqual(t, "tls balancer", body)
   139  }
   140  
   141  // go test -run Test_Proxy_Forward_WithTlsConfig_To_Http
   142  func Test_Proxy_Forward_WithTlsConfig_To_Http(t *testing.T) {
   143  	t.Parallel()
   144  
   145  	_, targetAddr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   146  		return c.SendString("hello from target")
   147  	})
   148  
   149  	proxyServerTLSConf, _, err := tlstest.GetTLSConfigs()
   150  	utils.AssertEqual(t, nil, err)
   151  
   152  	proxyServerLn, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
   153  	utils.AssertEqual(t, nil, err)
   154  
   155  	proxyServerLn = tls.NewListener(proxyServerLn, proxyServerTLSConf)
   156  
   157  	app := fiber.New(fiber.Config{DisableStartupMessage: true})
   158  
   159  	proxyAddr := proxyServerLn.Addr().String()
   160  
   161  	app.Use(Forward("http://" + targetAddr))
   162  
   163  	go func() { utils.AssertEqual(t, nil, app.Listener(proxyServerLn)) }()
   164  
   165  	code, body, errs := fiber.Get("https://" + proxyAddr).
   166  		InsecureSkipVerify().
   167  		Timeout(5 * time.Second).
   168  		String()
   169  
   170  	utils.AssertEqual(t, 0, len(errs))
   171  	utils.AssertEqual(t, fiber.StatusOK, code)
   172  	utils.AssertEqual(t, "hello from target", body)
   173  }
   174  
   175  // go test -run Test_Proxy_Forward
   176  func Test_Proxy_Forward(t *testing.T) {
   177  	t.Parallel()
   178  
   179  	app := fiber.New()
   180  
   181  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   182  		return c.SendString("forwarded")
   183  	})
   184  
   185  	app.Use(Forward("http://" + addr))
   186  
   187  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   188  	utils.AssertEqual(t, nil, err)
   189  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   190  
   191  	b, err := io.ReadAll(resp.Body)
   192  	utils.AssertEqual(t, nil, err)
   193  	utils.AssertEqual(t, "forwarded", string(b))
   194  }
   195  
   196  // go test -run Test_Proxy_Forward_WithTlsConfig
   197  func Test_Proxy_Forward_WithTlsConfig(t *testing.T) {
   198  	t.Parallel()
   199  
   200  	serverTLSConf, _, err := tlstest.GetTLSConfigs()
   201  	utils.AssertEqual(t, nil, err)
   202  
   203  	ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
   204  	utils.AssertEqual(t, nil, err)
   205  
   206  	ln = tls.NewListener(ln, serverTLSConf)
   207  
   208  	app := fiber.New(fiber.Config{DisableStartupMessage: true})
   209  
   210  	app.Get("/tlsfwd", func(c *fiber.Ctx) error {
   211  		return c.SendString("tls forward")
   212  	})
   213  
   214  	addr := ln.Addr().String()
   215  	clientTLSConf := &tls.Config{InsecureSkipVerify: true} //nolint:gosec // We're in a test func, so this is fine
   216  
   217  	// disable certificate verification
   218  	WithTlsConfig(clientTLSConf)
   219  	app.Use(Forward("https://" + addr + "/tlsfwd"))
   220  
   221  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   222  
   223  	code, body, errs := fiber.Get("https://" + addr).TLSConfig(clientTLSConf).String()
   224  
   225  	utils.AssertEqual(t, 0, len(errs))
   226  	utils.AssertEqual(t, fiber.StatusOK, code)
   227  	utils.AssertEqual(t, "tls forward", body)
   228  }
   229  
   230  // go test -run Test_Proxy_Modify_Response
   231  func Test_Proxy_Modify_Response(t *testing.T) {
   232  	t.Parallel()
   233  
   234  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   235  		return c.Status(500).SendString("not modified")
   236  	})
   237  
   238  	app := fiber.New()
   239  	app.Use(Balancer(Config{
   240  		Servers: []string{addr},
   241  		ModifyResponse: func(c *fiber.Ctx) error {
   242  			c.Response().SetStatusCode(fiber.StatusOK)
   243  			return c.SendString("modified response")
   244  		},
   245  	}))
   246  
   247  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   248  	utils.AssertEqual(t, nil, err)
   249  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   250  
   251  	b, err := io.ReadAll(resp.Body)
   252  	utils.AssertEqual(t, nil, err)
   253  	utils.AssertEqual(t, "modified response", string(b))
   254  }
   255  
   256  // go test -run Test_Proxy_Modify_Request
   257  func Test_Proxy_Modify_Request(t *testing.T) {
   258  	t.Parallel()
   259  
   260  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   261  		b := c.Request().Body()
   262  		return c.SendString(string(b))
   263  	})
   264  
   265  	app := fiber.New()
   266  	app.Use(Balancer(Config{
   267  		Servers: []string{addr},
   268  		ModifyRequest: func(c *fiber.Ctx) error {
   269  			c.Request().SetBody([]byte("modified request"))
   270  			return nil
   271  		},
   272  	}))
   273  
   274  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   275  	utils.AssertEqual(t, nil, err)
   276  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   277  
   278  	b, err := io.ReadAll(resp.Body)
   279  	utils.AssertEqual(t, nil, err)
   280  	utils.AssertEqual(t, "modified request", string(b))
   281  }
   282  
   283  // go test -run Test_Proxy_Timeout_Slow_Server
   284  func Test_Proxy_Timeout_Slow_Server(t *testing.T) {
   285  	t.Parallel()
   286  
   287  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   288  		time.Sleep(2 * time.Second)
   289  		return c.SendString("fiber is awesome")
   290  	})
   291  
   292  	app := fiber.New()
   293  	app.Use(Balancer(Config{
   294  		Servers: []string{addr},
   295  		Timeout: 3 * time.Second,
   296  	}))
   297  
   298  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 5000)
   299  	utils.AssertEqual(t, nil, err)
   300  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   301  
   302  	b, err := io.ReadAll(resp.Body)
   303  	utils.AssertEqual(t, nil, err)
   304  	utils.AssertEqual(t, "fiber is awesome", string(b))
   305  }
   306  
   307  // go test -run Test_Proxy_With_Timeout
   308  func Test_Proxy_With_Timeout(t *testing.T) {
   309  	t.Parallel()
   310  
   311  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   312  		time.Sleep(1 * time.Second)
   313  		return c.SendString("fiber is awesome")
   314  	})
   315  
   316  	app := fiber.New()
   317  	app.Use(Balancer(Config{
   318  		Servers: []string{addr},
   319  		Timeout: 100 * time.Millisecond,
   320  	}))
   321  
   322  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2000)
   323  	utils.AssertEqual(t, nil, err)
   324  	utils.AssertEqual(t, fiber.StatusInternalServerError, resp.StatusCode)
   325  
   326  	b, err := io.ReadAll(resp.Body)
   327  	utils.AssertEqual(t, nil, err)
   328  	utils.AssertEqual(t, "timeout", string(b))
   329  }
   330  
   331  // go test -run Test_Proxy_Buffer_Size_Response
   332  func Test_Proxy_Buffer_Size_Response(t *testing.T) {
   333  	t.Parallel()
   334  
   335  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   336  		long := strings.Join(make([]string, 5000), "-")
   337  		c.Set("Very-Long-Header", long)
   338  		return c.SendString("ok")
   339  	})
   340  
   341  	app := fiber.New()
   342  	app.Use(Balancer(Config{Servers: []string{addr}}))
   343  
   344  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   345  	utils.AssertEqual(t, nil, err)
   346  	utils.AssertEqual(t, fiber.StatusInternalServerError, resp.StatusCode)
   347  
   348  	app = fiber.New()
   349  	app.Use(Balancer(Config{
   350  		Servers:        []string{addr},
   351  		ReadBufferSize: 1024 * 8,
   352  	}))
   353  
   354  	resp, err = app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   355  	utils.AssertEqual(t, nil, err)
   356  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   357  }
   358  
   359  // go test -race -run Test_Proxy_Do_RestoreOriginalURL
   360  func Test_Proxy_Do_RestoreOriginalURL(t *testing.T) {
   361  	t.Parallel()
   362  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   363  		return c.SendString("proxied")
   364  	})
   365  
   366  	app := fiber.New()
   367  	app.Get("/test", func(c *fiber.Ctx) error {
   368  		return Do(c, "http://"+addr)
   369  	})
   370  	resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil))
   371  	utils.AssertEqual(t, nil, err1)
   372  	utils.AssertEqual(t, "/test", resp.Request.URL.String())
   373  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   374  	body, err := io.ReadAll(resp.Body)
   375  	utils.AssertEqual(t, nil, err)
   376  	utils.AssertEqual(t, "proxied", string(body))
   377  }
   378  
   379  // go test -race -run Test_Proxy_Do_WithRealURL
   380  func Test_Proxy_Do_WithRealURL(t *testing.T) {
   381  	t.Parallel()
   382  	app := fiber.New()
   383  	app.Get("/test", func(c *fiber.Ctx) error {
   384  		return Do(c, "https://www.google.com")
   385  	})
   386  
   387  	resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil))
   388  	utils.AssertEqual(t, nil, err1)
   389  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   390  	utils.AssertEqual(t, "/test", resp.Request.URL.String())
   391  	body, err := io.ReadAll(resp.Body)
   392  	utils.AssertEqual(t, nil, err)
   393  	utils.AssertEqual(t, true, strings.Contains(string(body), "https://www.google.com/"))
   394  }
   395  
   396  // go test -race -run Test_Proxy_Do_WithRedirect
   397  func Test_Proxy_Do_WithRedirect(t *testing.T) {
   398  	t.Parallel()
   399  	app := fiber.New()
   400  	app.Get("/test", func(c *fiber.Ctx) error {
   401  		return Do(c, "https://google.com")
   402  	})
   403  
   404  	resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil))
   405  	utils.AssertEqual(t, nil, err1)
   406  	body, err := io.ReadAll(resp.Body)
   407  	utils.AssertEqual(t, nil, err)
   408  	utils.AssertEqual(t, true, strings.Contains(string(body), "https://www.google.com/"))
   409  	utils.AssertEqual(t, 301, resp.StatusCode)
   410  }
   411  
   412  // go test -race -run Test_Proxy_DoRedirects_RestoreOriginalURL
   413  func Test_Proxy_DoRedirects_RestoreOriginalURL(t *testing.T) {
   414  	t.Parallel()
   415  	app := fiber.New()
   416  	app.Get("/test", func(c *fiber.Ctx) error {
   417  		return DoRedirects(c, "http://google.com", 1)
   418  	})
   419  
   420  	resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil))
   421  	utils.AssertEqual(t, nil, err1)
   422  	_, err := io.ReadAll(resp.Body)
   423  	utils.AssertEqual(t, nil, err)
   424  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   425  	utils.AssertEqual(t, "/test", resp.Request.URL.String())
   426  }
   427  
   428  // go test -race -run Test_Proxy_DoRedirects_TooManyRedirects
   429  func Test_Proxy_DoRedirects_TooManyRedirects(t *testing.T) {
   430  	t.Parallel()
   431  	app := fiber.New()
   432  	app.Get("/test", func(c *fiber.Ctx) error {
   433  		return DoRedirects(c, "http://google.com", 0)
   434  	})
   435  
   436  	resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil))
   437  	utils.AssertEqual(t, nil, err1)
   438  	body, err := io.ReadAll(resp.Body)
   439  	utils.AssertEqual(t, nil, err)
   440  	utils.AssertEqual(t, "too many redirects detected when doing the request", string(body))
   441  	utils.AssertEqual(t, fiber.StatusInternalServerError, resp.StatusCode)
   442  	utils.AssertEqual(t, "/test", resp.Request.URL.String())
   443  }
   444  
   445  // go test -race -run Test_Proxy_DoTimeout_RestoreOriginalURL
   446  func Test_Proxy_DoTimeout_RestoreOriginalURL(t *testing.T) {
   447  	t.Parallel()
   448  
   449  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   450  		return c.SendString("proxied")
   451  	})
   452  
   453  	app := fiber.New()
   454  	app.Get("/test", func(c *fiber.Ctx) error {
   455  		return DoTimeout(c, "http://"+addr, time.Second)
   456  	})
   457  
   458  	resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil))
   459  	utils.AssertEqual(t, nil, err1)
   460  	body, err := io.ReadAll(resp.Body)
   461  	utils.AssertEqual(t, nil, err)
   462  	utils.AssertEqual(t, "proxied", string(body))
   463  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   464  	utils.AssertEqual(t, "/test", resp.Request.URL.String())
   465  }
   466  
   467  // go test -race -run Test_Proxy_DoTimeout_Timeout
   468  func Test_Proxy_DoTimeout_Timeout(t *testing.T) {
   469  	t.Parallel()
   470  
   471  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   472  		time.Sleep(time.Second * 5)
   473  		return c.SendString("proxied")
   474  	})
   475  
   476  	app := fiber.New()
   477  	app.Get("/test", func(c *fiber.Ctx) error {
   478  		return DoTimeout(c, "http://"+addr, time.Second)
   479  	})
   480  
   481  	_, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil))
   482  	utils.AssertEqual(t, errors.New("test: timeout error 1000ms"), err1)
   483  }
   484  
   485  // go test -race -run Test_Proxy_DoDeadline_RestoreOriginalURL
   486  func Test_Proxy_DoDeadline_RestoreOriginalURL(t *testing.T) {
   487  	t.Parallel()
   488  
   489  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   490  		return c.SendString("proxied")
   491  	})
   492  
   493  	app := fiber.New()
   494  	app.Get("/test", func(c *fiber.Ctx) error {
   495  		return DoDeadline(c, "http://"+addr, time.Now().Add(time.Second))
   496  	})
   497  
   498  	resp, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil))
   499  	utils.AssertEqual(t, nil, err1)
   500  	body, err := io.ReadAll(resp.Body)
   501  	utils.AssertEqual(t, nil, err)
   502  	utils.AssertEqual(t, "proxied", string(body))
   503  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   504  	utils.AssertEqual(t, "/test", resp.Request.URL.String())
   505  }
   506  
   507  // go test -race -run Test_Proxy_DoDeadline_PastDeadline
   508  func Test_Proxy_DoDeadline_PastDeadline(t *testing.T) {
   509  	t.Parallel()
   510  
   511  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   512  		time.Sleep(time.Second * 5)
   513  		return c.SendString("proxied")
   514  	})
   515  
   516  	app := fiber.New()
   517  	app.Get("/test", func(c *fiber.Ctx) error {
   518  		return DoDeadline(c, "http://"+addr, time.Now().Add(time.Second))
   519  	})
   520  
   521  	_, err1 := app.Test(httptest.NewRequest(fiber.MethodGet, "/test", nil))
   522  	utils.AssertEqual(t, errors.New("test: timeout error 1000ms"), err1)
   523  }
   524  
   525  // go test -race -run Test_Proxy_Do_HTTP_Prefix_URL
   526  func Test_Proxy_Do_HTTP_Prefix_URL(t *testing.T) {
   527  	t.Parallel()
   528  
   529  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   530  		return c.SendString("hello world")
   531  	})
   532  
   533  	app := fiber.New(fiber.Config{DisableStartupMessage: true})
   534  	app.Get("/*", func(c *fiber.Ctx) error {
   535  		path := c.OriginalURL()
   536  		url := strings.TrimPrefix(path, "/")
   537  
   538  		utils.AssertEqual(t, "http://"+addr, url)
   539  		if err := Do(c, url); err != nil {
   540  			return err
   541  		}
   542  		c.Response().Header.Del(fiber.HeaderServer)
   543  		return nil
   544  	})
   545  
   546  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/http://"+addr, nil))
   547  	utils.AssertEqual(t, nil, err)
   548  	s, err := io.ReadAll(resp.Body)
   549  	utils.AssertEqual(t, nil, err)
   550  	utils.AssertEqual(t, "hello world", string(s))
   551  }
   552  
   553  // go test -race -run Test_Proxy_Forward_Global_Client
   554  func Test_Proxy_Forward_Global_Client(t *testing.T) {
   555  	t.Parallel()
   556  	ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
   557  	utils.AssertEqual(t, nil, err)
   558  	WithClient(&fasthttp.Client{
   559  		NoDefaultUserAgentHeader: true,
   560  		DisablePathNormalizing:   true,
   561  	})
   562  	app := fiber.New(fiber.Config{DisableStartupMessage: true})
   563  	app.Get("/test_global_client", func(c *fiber.Ctx) error {
   564  		return c.SendString("test_global_client")
   565  	})
   566  
   567  	addr := ln.Addr().String()
   568  	app.Use(Forward("http://" + addr + "/test_global_client"))
   569  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   570  
   571  	code, body, errs := fiber.Get("http://" + addr).String()
   572  	utils.AssertEqual(t, 0, len(errs))
   573  	utils.AssertEqual(t, fiber.StatusOK, code)
   574  	utils.AssertEqual(t, "test_global_client", body)
   575  }
   576  
   577  // go test -race -run Test_Proxy_Forward_Local_Client
   578  func Test_Proxy_Forward_Local_Client(t *testing.T) {
   579  	t.Parallel()
   580  	ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
   581  	utils.AssertEqual(t, nil, err)
   582  	app := fiber.New(fiber.Config{DisableStartupMessage: true})
   583  	app.Get("/test_local_client", func(c *fiber.Ctx) error {
   584  		return c.SendString("test_local_client")
   585  	})
   586  
   587  	addr := ln.Addr().String()
   588  	app.Use(Forward("http://"+addr+"/test_local_client", &fasthttp.Client{
   589  		NoDefaultUserAgentHeader: true,
   590  		DisablePathNormalizing:   true,
   591  
   592  		Dial: fasthttp.Dial,
   593  	}))
   594  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   595  
   596  	code, body, errs := fiber.Get("http://" + addr).String()
   597  	utils.AssertEqual(t, 0, len(errs))
   598  	utils.AssertEqual(t, fiber.StatusOK, code)
   599  	utils.AssertEqual(t, "test_local_client", body)
   600  }
   601  
   602  // go test -run Test_ProxyBalancer_Custom_Client
   603  func Test_ProxyBalancer_Custom_Client(t *testing.T) {
   604  	t.Parallel()
   605  
   606  	target, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   607  		return c.SendStatus(fiber.StatusTeapot)
   608  	})
   609  
   610  	resp, err := target.Test(httptest.NewRequest(fiber.MethodGet, "/", nil), 2000)
   611  	utils.AssertEqual(t, nil, err)
   612  	utils.AssertEqual(t, fiber.StatusTeapot, resp.StatusCode)
   613  
   614  	app := fiber.New(fiber.Config{DisableStartupMessage: true})
   615  
   616  	app.Use(Balancer(Config{Client: &fasthttp.LBClient{
   617  		Clients: []fasthttp.BalancingClient{
   618  			&fasthttp.HostClient{
   619  				NoDefaultUserAgentHeader: true,
   620  				DisablePathNormalizing:   true,
   621  				Addr:                     addr,
   622  			},
   623  		},
   624  		Timeout: time.Second,
   625  	}}))
   626  
   627  	req := httptest.NewRequest(fiber.MethodGet, "/", nil)
   628  	req.Host = addr
   629  	resp, err = app.Test(req)
   630  	utils.AssertEqual(t, nil, err)
   631  	utils.AssertEqual(t, fiber.StatusTeapot, resp.StatusCode)
   632  }
   633  
   634  // go test -run Test_Proxy_Domain_Forward_Local
   635  func Test_Proxy_Domain_Forward_Local(t *testing.T) {
   636  	t.Parallel()
   637  	ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
   638  	utils.AssertEqual(t, nil, err)
   639  	app := fiber.New(fiber.Config{DisableStartupMessage: true})
   640  
   641  	// target server
   642  	ln1, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
   643  	utils.AssertEqual(t, nil, err)
   644  	app1 := fiber.New(fiber.Config{DisableStartupMessage: true})
   645  
   646  	app1.Get("/test", func(c *fiber.Ctx) error {
   647  		return c.SendString("test_local_client:" + c.Query("query_test"))
   648  	})
   649  
   650  	proxyAddr := ln.Addr().String()
   651  	targetAddr := ln1.Addr().String()
   652  	localDomain := strings.Replace(proxyAddr, "127.0.0.1", "localhost", 1)
   653  	app.Use(DomainForward(localDomain, "http://"+targetAddr, &fasthttp.Client{
   654  		NoDefaultUserAgentHeader: true,
   655  		DisablePathNormalizing:   true,
   656  
   657  		Dial: fasthttp.Dial,
   658  	}))
   659  
   660  	go func() { utils.AssertEqual(t, nil, app.Listener(ln)) }()
   661  	go func() { utils.AssertEqual(t, nil, app1.Listener(ln1)) }()
   662  
   663  	code, body, errs := fiber.Get("http://" + localDomain + "/test?query_test=true").String()
   664  	utils.AssertEqual(t, 0, len(errs))
   665  	utils.AssertEqual(t, fiber.StatusOK, code)
   666  	utils.AssertEqual(t, "test_local_client:true", body)
   667  }
   668  
   669  // go test -run Test_Proxy_Balancer_Forward_Local
   670  func Test_Proxy_Balancer_Forward_Local(t *testing.T) {
   671  	t.Parallel()
   672  
   673  	app := fiber.New()
   674  
   675  	_, addr := createProxyTestServer(t, func(c *fiber.Ctx) error {
   676  		return c.SendString("forwarded")
   677  	})
   678  
   679  	app.Use(BalancerForward([]string{addr}))
   680  
   681  	resp, err := app.Test(httptest.NewRequest(fiber.MethodGet, "/", nil))
   682  	utils.AssertEqual(t, nil, err)
   683  	utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
   684  
   685  	b, err := io.ReadAll(resp.Body)
   686  	utils.AssertEqual(t, nil, err)
   687  
   688  	utils.AssertEqual(t, string(b), "forwarded")
   689  }