httplimit

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 25, 2024 License: Apache-2.0 Imports: 6 Imported by: 37

Documentation

Overview

Package httplimit provides middleware for rate limiting HTTP handlers.

The implementation is designed to work with Go's built-in http.Handler and http.HandlerFunc interfaces, so it will also work with any popular web frameworks that support middleware with these properties.

Index

Examples

Constants

View Source
const (
	// HeaderRateLimitLimit, HeaderRateLimitRemaining, and HeaderRateLimitReset
	// are the recommended return header values from IETF on rate limiting. Reset
	// is in UTC time.
	HeaderRateLimitLimit     = "X-RateLimit-Limit"
	HeaderRateLimitRemaining = "X-RateLimit-Remaining"
	HeaderRateLimitReset     = "X-RateLimit-Reset"

	// HeaderRetryAfter is the header used to indicate when a client should retry
	// requests (when the rate limit expires), in UTC time.
	HeaderRetryAfter = "Retry-After"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type KeyFunc

type KeyFunc func(r *http.Request) (string, error)

KeyFunc is a function that accepts an http request and returns a string key that uniquely identifies this request for the purpose of rate limiting.

KeyFuncs are called on each request, so be mindful of performance and implement caching where possible. If a KeyFunc returns an error, the HTTP handler will return Internal Server Error and will NOT take from the limiter store.

Example (Custom)
package main

import (
	"crypto/sha512"
	"encoding/base64"
	"net/http"

	"github.com/sethvargo/go-limiter/httplimit"
)

var keyFunc httplimit.KeyFunc

func main() {
	// This is an example KeyFunc that rate limits using the value from the
	// X-API-Key header. Since this value is likely a secret, it is hashed before
	// passing along to the store.
	keyFunc = httplimit.KeyFunc(func(r *http.Request) (string, error) {
		dig := sha512.Sum512([]byte(r.Header.Get("X-Token")))
		return base64.StdEncoding.EncodeToString(dig[:]), nil
	})
	// middleware, err := httplimit.NewMiddleware(store, keyFunc)
}
Output:

func IPKeyFunc

func IPKeyFunc(headers ...string) KeyFunc

IPKeyFunc returns a function that keys data based on the incoming requests IP address. By default this uses the RemoteAddr, but you can also specify a list of headers which will be checked for an IP address first (e.g. "X-Forwarded-For"). Headers are retrieved using Header.Get(), which means they are case insensitive.

Example (Headers)
package main

import (
	"github.com/sethvargo/go-limiter/httplimit"
)

var keyFunc httplimit.KeyFunc

func main() {
	keyFunc = httplimit.IPKeyFunc("X-Forwarded-For")
	// middleware, err := httplimit.NewMiddleware(store, keyFunc)
}
Output:

type Middleware

type Middleware struct {
	// contains filtered or unexported fields
}

Middleware is a handler/mux that can wrap other middlware to implement HTTP rate limiting. It can rate limit based on an arbitrary KeyFunc, and supports anything that implements limiter.StoreWithContext.

func NewMiddleware

func NewMiddleware(s limiter.Store, f KeyFunc) (*Middleware, error)

NewMiddleware creates a new middleware suitable for use as an HTTP handler. This function returns an error if either the Store or KeyFunc are nil.

Example
package main

import (
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/sethvargo/go-limiter/httplimit"
	"github.com/sethvargo/go-limiter/memorystore"
)

func main() {
	// Create a store that allows 30 requests per minute.
	store, err := memorystore.New(&memorystore.Config{
		Tokens:   30,
		Interval: time.Minute,
	})
	if err != nil {
		log.Fatal(err)
	}

	// Create the HTTP middleware from the store, keying by IP address.
	middleware, err := httplimit.NewMiddleware(store, httplimit.IPKeyFunc())
	if err != nil {
		log.Fatal(err)
	}

	doWork := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
		fmt.Fprintf(w, "hello world")
	})

	// Wrap an individual handler (only rate limits this endpoint).
	mux1 := http.NewServeMux()
	mux1.Handle("/foo", middleware.Handle(doWork)) // rate limited
	mux1.Handle("/bar", doWork)                    // not rate limited
	_ = mux1

	// Or wrap the entire mux (rate limits all endpoints).
	mux2 := http.NewServeMux()
	mux2.Handle("/foo", doWork)
	mux2.Handle("/bar", doWork)
	router := middleware.Handle(mux2) // all endpoints are rate limited
	_ = router
}
Output:

func (*Middleware) Handle

func (m *Middleware) Handle(next http.Handler) http.Handler

Handle returns the HTTP handler as a middleware. This handler calls Take() on the store and sets the common rate limiting headers. If the take is successful, the remaining middleware is called. If take is unsuccessful, the middleware chain is halted and the function renders a 429 to the caller with metadata about when it's safe to retry.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL