1
0
Fork 0

Adding upstream version 2.52.6.

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-05-17 06:50:16 +02:00
parent a960158181
commit 6d002e9543
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
441 changed files with 95392 additions and 0 deletions

View 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
}

View 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
}
}

View 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)
})
}