Skip to content

Commit

Permalink
πŸš€ Configure proxy.Balancer with custom timeout #1362 (#1364)
Browse files Browse the repository at this point in the history
* πŸš€ new possibility to escape special routing parameters, which gives the possibility to follow the google api design guide https://cloud.google.com/apis/design/custom_methods

* πŸš€ new possibility to escape special routing parameters, which gives the possibility to follow the google api design guide https://cloud.google.com/apis/design/custom_methods

* πŸš€ Configure proxy.Balancer with custom timeout or client #1362

* πŸš€ Configure proxy.Balancer with custom timeout or client #1362
  • Loading branch information
ReneWerner87 authored Jun 4, 2021
1 parent 2d6323c commit 8e89949
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 67 deletions.
14 changes: 14 additions & 0 deletions middleware/proxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ type Config struct {
//
// Optional. Default: nil
ModifyResponse fiber.Handler

// Timeout is the request timeout used when calling the proxy client
//
// Optional. Default: 1 second
Timeout time.Duration

// Per-connection buffer size for requests' reading.
// This also limits the maximum header size.
// Increase this buffer if your clients send multi-KB RequestURIs
// and/or multi-KB headers (for example, BIG cookies).
ReadBufferSize int

// Per-connection buffer size for responses' writing.
WriteBufferSize int
}
```

Expand Down
14 changes: 14 additions & 0 deletions middleware/proxy/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package proxy

import (
"time"

"github.com/gofiber/fiber/v2"
"github.com/valyala/fasthttp"
)

// Config defines the config for middleware.
Expand Down Expand Up @@ -29,6 +32,11 @@ type Config struct {
// Optional. Default: nil
ModifyResponse fiber.Handler

// Timeout is the request timeout used when calling the proxy client
//
// Optional. Default: 1 second
Timeout time.Duration

// Per-connection buffer size for requests' reading.
// This also limits the maximum header size.
// Increase this buffer if your clients send multi-KB RequestURIs
Expand All @@ -44,6 +52,7 @@ var ConfigDefault = Config{
Next: nil,
ModifyRequest: nil,
ModifyResponse: nil,
Timeout: fasthttp.DefaultLBClientTimeout,
}

// configDefault function to set default values
Expand All @@ -56,6 +65,11 @@ func configDefault(config ...Config) Config {
// Override default config
cfg := config[0]

// Set default values
if cfg.Timeout <= 0 {
cfg.Timeout = ConfigDefault.Timeout
}

// Set default values
if len(cfg.Servers) == 0 {
panic("Servers cannot be empty")
Expand Down
2 changes: 2 additions & 0 deletions middleware/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ func Balancer(config Config) fiber.Handler {

// Load balanced client
var lbc fasthttp.LBClient
// Set timeout
lbc.Timeout = cfg.Timeout

// Scheme must be provided, falls back to http
// TODO add https support
Expand Down
148 changes: 81 additions & 67 deletions middleware/proxy/proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,23 @@ import (
"github.com/gofiber/fiber/v2/utils"
)

func createProxyTestServer(handler fiber.Handler, t *testing.T) (*fiber.App, string) {
target := fiber.New(fiber.Config{DisableStartupMessage: true})
target.Get("/", handler)

ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
utils.AssertEqual(t, nil, err)

go func() {
utils.AssertEqual(t, nil, target.Listener(ln))
}()

time.Sleep(2 * time.Second)
addr := ln.Addr().String()

return target, addr
}

// go test -run Test_Proxy_Empty_Host
func Test_Proxy_Empty_Upstream_Servers(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -46,20 +63,9 @@ func Test_Proxy_Next(t *testing.T) {
func Test_Proxy(t *testing.T) {
t.Parallel()

target := fiber.New(fiber.Config{DisableStartupMessage: true})
target.Get("/", func(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusTeapot)
})

ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
utils.AssertEqual(t, nil, err)

go func() {
utils.AssertEqual(t, nil, target.Listener(ln))
}()

time.Sleep(2 * time.Second)
addr := ln.Addr().String()
target, addr := createProxyTestServer(
func(c *fiber.Ctx) error { return c.SendStatus(fiber.StatusTeapot) }, t,
)

resp, err := target.Test(httptest.NewRequest("GET", "/", nil), 2000)
utils.AssertEqual(t, nil, err)
Expand All @@ -76,25 +82,15 @@ func Test_Proxy(t *testing.T) {
utils.AssertEqual(t, fiber.StatusTeapot, resp.StatusCode)
}

// go test -run Test_Proxy_Forward
func Test_Proxy_Forward(t *testing.T) {
t.Parallel()

app := fiber.New()

target := fiber.New(fiber.Config{DisableStartupMessage: true})
target.Get("/", func(c *fiber.Ctx) error {
return c.SendString("forwarded")
})

ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
utils.AssertEqual(t, nil, err)

go func() {
utils.AssertEqual(t, nil, target.Listener(ln))
}()

time.Sleep(2 * time.Second)
addr := ln.Addr().String()
_, addr := createProxyTestServer(
func(c *fiber.Ctx) error { return c.SendString("forwarded") }, t,
)

app.Use(Forward("http://" + addr))

Expand All @@ -107,23 +103,13 @@ func Test_Proxy_Forward(t *testing.T) {
utils.AssertEqual(t, "forwarded", string(b))
}

// go test -run Test_Proxy_Modify_Response
func Test_Proxy_Modify_Response(t *testing.T) {
t.Parallel()

target := fiber.New(fiber.Config{DisableStartupMessage: true})
target.Get("/", func(c *fiber.Ctx) error {
_, addr := createProxyTestServer(func(c *fiber.Ctx) error {
return c.Status(500).SendString("not modified")
})

ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
utils.AssertEqual(t, nil, err)

go func() {
utils.AssertEqual(t, nil, target.Listener(ln))
}()

time.Sleep(2 * time.Second)
addr := ln.Addr().String()
}, t)

app := fiber.New()
app.Use(Balancer(Config{
Expand All @@ -143,24 +129,14 @@ func Test_Proxy_Modify_Response(t *testing.T) {
utils.AssertEqual(t, "modified response", string(b))
}

// go test -run Test_Proxy_Modify_Request
func Test_Proxy_Modify_Request(t *testing.T) {
t.Parallel()

target := fiber.New(fiber.Config{DisableStartupMessage: true})
target.Get("/", func(c *fiber.Ctx) error {
_, addr := createProxyTestServer(func(c *fiber.Ctx) error {
b := c.Request().Body()
return c.SendString(string(b))
})

ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
utils.AssertEqual(t, nil, err)

go func() {
utils.AssertEqual(t, nil, target.Listener(ln))
}()

time.Sleep(2 * time.Second)
addr := ln.Addr().String()
}, t)

app := fiber.New()
app.Use(Balancer(Config{
Expand All @@ -180,25 +156,63 @@ func Test_Proxy_Modify_Request(t *testing.T) {
utils.AssertEqual(t, "modified request", string(b))
}

func Test_Proxy_Buffer_Size_Response(t *testing.T) {
// go test -run Test_Proxy_Timeout_Slow_Server
func Test_Proxy_Timeout_Slow_Server(t *testing.T) {
t.Parallel()

target := fiber.New(fiber.Config{DisableStartupMessage: true})
target.Get("/", func(c *fiber.Ctx) error {
long := strings.Join(make([]string, 5000), "-")
c.Response().Header.Set("Very-Long-Header", long)
return c.SendString("ok")
})
_, addr := createProxyTestServer(func(c *fiber.Ctx) error {
time.Sleep(2 * time.Second)
return c.SendString("fiber is awesome")
}, t)

ln, err := net.Listen(fiber.NetworkTCP4, "127.0.0.1:0")
app := fiber.New()
app.Use(Balancer(Config{
Servers: []string{addr},
Timeout: 3 * time.Second,
}))

resp, err := app.Test(httptest.NewRequest("GET", "/", nil), 5000)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)

go func() {
utils.AssertEqual(t, nil, target.Listener(ln))
}()
b, err := ioutil.ReadAll(resp.Body)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "fiber is awesome", string(b))
}

time.Sleep(2 * time.Second)
addr := ln.Addr().String()
// go test -run Test_Proxy_With_Timeout
func Test_Proxy_With_Timeout(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(func(c *fiber.Ctx) error {
time.Sleep(1 * time.Second)
return c.SendString("fiber is awesome")
}, t)

app := fiber.New()
app.Use(Balancer(Config{
Servers: []string{addr},
Timeout: 100 * time.Millisecond,
}))

resp, err := app.Test(httptest.NewRequest("GET", "/", nil), 2000)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, fiber.StatusInternalServerError, resp.StatusCode)

b, err := ioutil.ReadAll(resp.Body)
utils.AssertEqual(t, nil, err)
utils.AssertEqual(t, "timeout", string(b))
}

// go test -run Test_Proxy_Buffer_Size_Response
func Test_Proxy_Buffer_Size_Response(t *testing.T) {
t.Parallel()

_, addr := createProxyTestServer(func(c *fiber.Ctx) error {
long := strings.Join(make([]string, 5000), "-")
c.Set("Very-Long-Header", long)
return c.SendString("ok")
}, t)

app := fiber.New()
app.Use(Balancer(Config{Servers: []string{addr}}))
Expand Down

0 comments on commit 8e89949

Please sign in to comment.