Adding upstream version 2.52.6.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
a960158181
commit
6d002e9543
441 changed files with 95392 additions and 0 deletions
73
middleware/earlydata/config.go
Normal file
73
middleware/earlydata/config.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
package earlydata
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultHeaderName = "Early-Data"
|
||||
DefaultHeaderTrueValue = "1"
|
||||
)
|
||||
|
||||
// Config defines the config for middleware.
|
||||
type Config struct {
|
||||
// Next defines a function to skip this middleware when returned true.
|
||||
//
|
||||
// Optional. Default: nil
|
||||
Next func(c *fiber.Ctx) bool
|
||||
|
||||
// IsEarlyData returns whether the request is an early-data request.
|
||||
//
|
||||
// Optional. Default: a function which checks if the "Early-Data" request header equals "1".
|
||||
IsEarlyData func(c *fiber.Ctx) bool
|
||||
|
||||
// AllowEarlyData returns whether the early-data request should be allowed or rejected.
|
||||
//
|
||||
// Optional. Default: a function which rejects the request on unsafe and allows the request on safe HTTP request methods.
|
||||
AllowEarlyData func(c *fiber.Ctx) bool
|
||||
|
||||
// Error is returned in case an early-data request is rejected.
|
||||
//
|
||||
// Optional. Default: fiber.ErrTooEarly.
|
||||
Error error
|
||||
}
|
||||
|
||||
// ConfigDefault is the default config
|
||||
var ConfigDefault = Config{
|
||||
IsEarlyData: func(c *fiber.Ctx) bool {
|
||||
return c.Get(DefaultHeaderName) == DefaultHeaderTrueValue
|
||||
},
|
||||
|
||||
AllowEarlyData: func(c *fiber.Ctx) bool {
|
||||
return fiber.IsMethodSafe(c.Method())
|
||||
},
|
||||
|
||||
Error: fiber.ErrTooEarly,
|
||||
}
|
||||
|
||||
// Helper function to set default values
|
||||
func configDefault(config ...Config) Config {
|
||||
// Return default config if nothing provided
|
||||
if len(config) < 1 {
|
||||
return ConfigDefault
|
||||
}
|
||||
|
||||
// Override default config
|
||||
cfg := config[0]
|
||||
|
||||
// Set default values
|
||||
|
||||
if cfg.IsEarlyData == nil {
|
||||
cfg.IsEarlyData = ConfigDefault.IsEarlyData
|
||||
}
|
||||
|
||||
if cfg.AllowEarlyData == nil {
|
||||
cfg.AllowEarlyData = ConfigDefault.AllowEarlyData
|
||||
}
|
||||
|
||||
if cfg.Error == nil {
|
||||
cfg.Error = ConfigDefault.Error
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
47
middleware/earlydata/earlydata.go
Normal file
47
middleware/earlydata/earlydata.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package earlydata
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
localsKeyAllowed = "earlydata_allowed"
|
||||
)
|
||||
|
||||
func IsEarly(c *fiber.Ctx) bool {
|
||||
return c.Locals(localsKeyAllowed) != nil
|
||||
}
|
||||
|
||||
// New creates a new middleware handler
|
||||
// https://datatracker.ietf.org/doc/html/rfc8470#section-5.1
|
||||
func New(config ...Config) fiber.Handler {
|
||||
// Set default config
|
||||
cfg := configDefault(config...)
|
||||
|
||||
// Return new handler
|
||||
return func(c *fiber.Ctx) error {
|
||||
// Don't execute middleware if Next returns true
|
||||
if cfg.Next != nil && cfg.Next(c) {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Abort if we can't trust the early-data header
|
||||
if !c.IsProxyTrusted() {
|
||||
return cfg.Error
|
||||
}
|
||||
|
||||
// Continue stack if request is not an early-data request
|
||||
if !cfg.IsEarlyData(c) {
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Continue stack if we allow early-data for this request
|
||||
if cfg.AllowEarlyData(c) {
|
||||
_ = c.Locals(localsKeyAllowed, true)
|
||||
return c.Next()
|
||||
}
|
||||
|
||||
// Else return our error
|
||||
return cfg.Error
|
||||
}
|
||||
}
|
193
middleware/earlydata/earlydata_test.go
Normal file
193
middleware/earlydata/earlydata_test.go
Normal file
|
@ -0,0 +1,193 @@
|
|||
//nolint:bodyclose // Much easier to just ignore memory leaks in tests
|
||||
package earlydata_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/gofiber/fiber/v2/middleware/earlydata"
|
||||
"github.com/gofiber/fiber/v2/utils"
|
||||
)
|
||||
|
||||
const (
|
||||
headerName = "Early-Data"
|
||||
headerValOn = "1"
|
||||
headerValOff = "0"
|
||||
)
|
||||
|
||||
func appWithConfig(t *testing.T, c *fiber.Config) *fiber.App {
|
||||
t.Helper()
|
||||
t.Parallel()
|
||||
|
||||
var app *fiber.App
|
||||
if c == nil {
|
||||
app = fiber.New()
|
||||
} else {
|
||||
app = fiber.New(*c)
|
||||
}
|
||||
|
||||
app.Use(earlydata.New())
|
||||
|
||||
// Middleware to test IsEarly func
|
||||
const localsKeyTestValid = "earlydata_testvalid"
|
||||
app.Use(func(c *fiber.Ctx) error {
|
||||
isEarly := earlydata.IsEarly(c)
|
||||
|
||||
switch h := c.Get(headerName); h {
|
||||
case "", headerValOff:
|
||||
if isEarly {
|
||||
return errors.New("is early-data even though it's not")
|
||||
}
|
||||
|
||||
case headerValOn:
|
||||
switch {
|
||||
case fiber.IsMethodSafe(c.Method()):
|
||||
if !isEarly {
|
||||
return errors.New("should be early-data on safe HTTP methods")
|
||||
}
|
||||
default:
|
||||
if isEarly {
|
||||
return errors.New("early-data unsuported on unsafe HTTP methods")
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("header has unsupported value: %s", h)
|
||||
}
|
||||
|
||||
_ = c.Locals(localsKeyTestValid, true)
|
||||
|
||||
return c.Next()
|
||||
})
|
||||
|
||||
{
|
||||
{
|
||||
handler := func(c *fiber.Ctx) error {
|
||||
if !c.Locals(localsKeyTestValid).(bool) { //nolint:forcetypeassert // We store nothing else in the pool
|
||||
return errors.New("handler called even though validation failed")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
app.Get("/", handler)
|
||||
app.Post("/", handler)
|
||||
}
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// go test -run Test_EarlyData
|
||||
func Test_EarlyData(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
trustedRun := func(t *testing.T, app *fiber.App) {
|
||||
t.Helper()
|
||||
|
||||
{
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
|
||||
|
||||
resp, err := app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
|
||||
req.Header.Set(headerName, headerValOff)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
|
||||
req.Header.Set(headerName, headerValOn)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
}
|
||||
|
||||
{
|
||||
req := httptest.NewRequest(fiber.MethodPost, "/", http.NoBody)
|
||||
|
||||
resp, err := app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
|
||||
req.Header.Set(headerName, headerValOff)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusOK, resp.StatusCode)
|
||||
|
||||
req.Header.Set(headerName, headerValOn)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusTooEarly, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
untrustedRun := func(t *testing.T, app *fiber.App) {
|
||||
t.Helper()
|
||||
|
||||
{
|
||||
req := httptest.NewRequest(fiber.MethodGet, "/", http.NoBody)
|
||||
|
||||
resp, err := app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusTooEarly, resp.StatusCode)
|
||||
|
||||
req.Header.Set(headerName, headerValOff)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusTooEarly, resp.StatusCode)
|
||||
|
||||
req.Header.Set(headerName, headerValOn)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusTooEarly, resp.StatusCode)
|
||||
}
|
||||
|
||||
{
|
||||
req := httptest.NewRequest(fiber.MethodPost, "/", http.NoBody)
|
||||
|
||||
resp, err := app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusTooEarly, resp.StatusCode)
|
||||
|
||||
req.Header.Set(headerName, headerValOff)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusTooEarly, resp.StatusCode)
|
||||
|
||||
req.Header.Set(headerName, headerValOn)
|
||||
resp, err = app.Test(req)
|
||||
utils.AssertEqual(t, nil, err)
|
||||
utils.AssertEqual(t, fiber.StatusTooEarly, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
t.Run("empty config", func(t *testing.T) {
|
||||
app := appWithConfig(t, nil)
|
||||
trustedRun(t, app)
|
||||
})
|
||||
t.Run("default config", func(t *testing.T) {
|
||||
app := appWithConfig(t, &fiber.Config{})
|
||||
trustedRun(t, app)
|
||||
})
|
||||
|
||||
t.Run("config with EnableTrustedProxyCheck", func(t *testing.T) {
|
||||
app := appWithConfig(t, &fiber.Config{
|
||||
EnableTrustedProxyCheck: true,
|
||||
})
|
||||
untrustedRun(t, app)
|
||||
})
|
||||
t.Run("config with EnableTrustedProxyCheck and trusted TrustedProxies", func(t *testing.T) {
|
||||
app := appWithConfig(t, &fiber.Config{
|
||||
EnableTrustedProxyCheck: true,
|
||||
TrustedProxies: []string{
|
||||
"0.0.0.0",
|
||||
},
|
||||
})
|
||||
trustedRun(t, app)
|
||||
})
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue