-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
🚀 Feature: Add earlydata middleware #2270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ReneWerner87
merged 4 commits into
gofiber:v3-beta
from
leonklingele:add-earlydata-middleware
Jan 27, 2023
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| # Early Data Middleware | ||
|
|
||
| The Early Data middleware for [Fiber](https://github.com/gofiber/fiber) adds support for TLS 1.3's early data ("0-RTT") feature. | ||
| Citing [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446#section-2-3), when a client and server share a PSK, TLS 1.3 allows clients to send data on the first flight ("early data") to speed up the request, effectively reducing the regular 1-RTT request to a 0-RTT request. | ||
|
|
||
| Make sure to enable fiber's `EnableTrustedProxyCheck` config option before using this middleware in order to not trust bogus HTTP request headers of the client. | ||
|
|
||
| Also be aware that enabling support for early data in your reverse proxy (e.g. nginx, as done with a simple `ssl_early_data on;`) makes requests replayable. Refer to the following documents before continuing: | ||
|
|
||
| - https://datatracker.ietf.org/doc/html/rfc8446#section-8 | ||
| - https://blog.trailofbits.com/2019/03/25/what-application-developers-need-to-know-about-tls-early-data-0rtt/ | ||
|
|
||
| By default, this middleware allows early data requests on safe HTTP request methods only and rejects the request otherwise, i.e. aborts the request before executing your handler. This behavior can be controlled by the `AllowEarlyData` config option. | ||
| Safe HTTP methods — `GET`, `HEAD`, `OPTIONS` and `TRACE` — should not modify a state on the server. | ||
|
|
||
| ## Table of Contents | ||
|
|
||
| - [Early Data Middleware](#early-data-middleware) | ||
| - [Table of Contents](#table-of-contents) | ||
| - [Signatures](#signatures) | ||
| - [Examples](#examples) | ||
| - [Default Config](#default-config) | ||
| - [Custom Config](#custom-config) | ||
| - [Config](#config) | ||
| - [Default Config](#default-config-1) | ||
|
|
||
| ## Signatures | ||
|
|
||
| ```go | ||
| func New(config ...Config) fiber.Handler | ||
| ``` | ||
|
|
||
| ## Examples | ||
|
|
||
| First import the middleware from Fiber, | ||
|
|
||
| ```go | ||
| import ( | ||
| "github.com/gofiber/fiber/v3" | ||
| "github.com/gofiber/fiber/v3/middleware/earlydata" | ||
| ) | ||
| ``` | ||
|
|
||
| Then create a Fiber app with `app := fiber.New()`. | ||
|
|
||
| ### Default Config | ||
|
|
||
| ```go | ||
| app.Use(earlydata.New()) | ||
| ``` | ||
|
|
||
| ### Custom Config | ||
|
|
||
| ```go | ||
| app.Use(earlydata.New(earlydata.Config{ | ||
| Error: fiber.ErrTooEarly, | ||
| // ... | ||
| })) | ||
| ``` | ||
|
|
||
| ### Config | ||
|
|
||
| ```go | ||
| 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 | ||
| } | ||
| ``` | ||
|
|
||
| ### Default Config | ||
|
|
||
| ```go | ||
| var ConfigDefault = Config{ | ||
| IsEarlyData: func(c fiber.Ctx) bool { | ||
| return c.Get("Early-Data") == "1" | ||
| }, | ||
|
|
||
| AllowEarlyData: func(c fiber.Ctx) bool { | ||
| return fiber.IsMethodSafe(c.Method()) | ||
| }, | ||
|
|
||
| Error: fiber.ErrTooEarly, | ||
| } | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| package earlydata | ||
|
|
||
| import ( | ||
| "github.com/gofiber/fiber/v3" | ||
| ) | ||
|
|
||
| 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 | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package earlydata | ||
|
|
||
| import ( | ||
| "github.com/gofiber/fiber/v3" | ||
| ) | ||
|
|
||
| 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 | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.