middleware

package module
v0.0.0-...-c48df86 Latest Latest
Warning

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

Go to latest
Published: Sep 4, 2020 License: MIT Imports: 15 Imported by: 0

README

middleware

Package middleware makes it easy to chain net/http middleware in Go

Documentation

Overview

Package middleware makes it easy to chain net/http middleware in Go

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllHeadersPresent

func AllHeadersPresent(requiredHeaders http.Header, requestHeaders http.Header) bool

func DefaultValidation

func DefaultValidation(params HmacParams) func(r *http.Request, message []byte) (bool, error)

func FilterHeaders

func FilterHeaders(headers http.Header) func(http.Handler) http.Handler

func GithubValidation

func GithubValidation(params HmacParams) func(r *http.Request, message []byte) (bool, error)

func HmacFilter

func HmacFilter(params HmacParams) func(http.Handler) http.Handler
Example
package main

import (
	"bytes"
	"fmt"
	"github.com/seb-ehm/middleware"
	"log"
	"net/http"
)

func main() {
	mux := http.NewServeMux()
	//Some handler that prints both to stdout and the http response
	handler := func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hi!")
	}

	githubSignature := middleware.HmacFilter(middleware.HmacParams{Provider: "github", Secret: "ThisIsMySecret"})
	authenticated := middleware.New().Append(githubSignature)

	mux.Handle("/authenticated", authenticated.ApplyToFunc(handler))

	go func() { log.Fatal(http.ListenAndServe("localhost:9194", mux)) }()
	client := &http.Client{}
	validRequest, _ := http.NewRequest("POST", "http://localhost:9194/authenticated", bytes.NewBuffer([]byte("ThisIsARequest")))
	validRequest.Header.Add("X-Hub-Signature", "sha1=8c08e9b7e2bdb4d87982f40d6bf6d36c0d0caab4")
	resp, _ := client.Do(validRequest)
	fmt.Println(resp.Status)

	invalidRequest, _ := http.NewRequest("POST", "http://localhost:9194/authenticated", bytes.NewBuffer([]byte("ThisIsARequest")))
	invalidRequest.Header.Add("X-Hub-Signature", "sha1=1234")
	resp, _ = client.Do(invalidRequest)
	fmt.Println(resp.Status)

}
Output:

200 OK
403 Forbidden

func IPFilter

func IPFilter(ipRanges []string, header string) func(http.Handler) http.Handler
Example
mux := http.NewServeMux()
//Some handler that prints both to stdout and the http response
handler := func(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Hi!")
}

allowSomeIP := middleware.IPFilter([]string{"123.240.189.1/32"}, "")
noLocalhost := middleware.New().Append(allowSomeIP)

allowLocalhost := middleware.IPFilter([]string{"localhost"}, "")
localhost := middleware.New().Append(allowLocalhost)

allowLocalhostInHeader := middleware.IPFilter([]string{"localhost"}, "X-FORWARDED-FOR")
localhostInHeader := middleware.New().Append(allowLocalhostInHeader)

mux.Handle("/nolocalhost", noLocalhost.ApplyToFunc(handler))
mux.Handle("/localhost", localhost.ApplyToFunc(handler))
mux.Handle("/localhostinheader", localhostInHeader.ApplyToFunc(handler))

go func() { log.Fatal(http.ListenAndServe("localhost:9192", mux)) }()

_, status := GetWebsite("http://localhost:9192/nolocalhost")
fmt.Println(status)
content, _ := GetWebsite("http://localhost:9192/localhost")
fmt.Println(content)
content, _ = GetWebsiteWithHeader("http://localhost:9192/localhostinheader", "X-FORWARDED-FOR", "127.0.0.1")
fmt.Println(content)
Output:

403 Forbidden
Hi!

Hi!

Types

type HmacParams

type HmacParams struct {
	Provider    string
	Secret      string
	HmacSource  string
	NonceSource string
	TimeSource  string
	Encoding    string
	IncludeURL  bool
}

type Middleware

type Middleware func(http.Handler) http.Handler

Middleware is a type alias for the typical signature of a Go net/http middleware

Example
package main

import (
	"fmt"
	"io/ioutil"
	"log"
	"net/http"

	"github.com/seb-ehm/middleware"
)

// MiddlewareA is an example of a direct definition of a middleware.
// It uses a cast to http.HandlerFunc to enable its own ServeHTTP function
func MiddlewareA(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		fmt.Println("Calling A")
		next.ServeHTTP(w, r)
	})
}

// Greeting is an example of a middleware that uses a struct to keep state
// and an explicit definition of a ServeHTTP function to be useable as http.Handler
type Greeting struct {
	next    http.Handler
	message string
}

// ServeHTTP prints both to the response body and stdout and calls the next middleware afterwards
func (g Greeting) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, g.message)
	g.next.ServeHTTP(w, r)
}

// GetGreeting is a factory function to generate a handler that prints a certain message
func GetGreeting(message string) func(http.Handler) http.Handler {
	fn := func(next http.Handler) http.Handler {
		return Greeting{next, message}
	}
	return fn
}

func GetWebsite(url string) (string, string) {
	resp, err := http.Get(url)
	defer resp.Body.Close()
	html, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	return string(html), resp.Status
}

func GetWebsiteWithHeader(url string, headerName string, headerValue string) (string, string) {
	client := &http.Client{}

	request, _ := http.NewRequest("GET", url, nil)
	request.Header.Add(headerName, headerValue)
	resp, err := client.Do(request)
	defer resp.Body.Close()
	html, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}
	return string(html), resp.Status
}

func main() {

	mux := http.NewServeMux()
	//Some handler that prints to the http response
	handler := func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "Hi!")
	}
	//Create two middlewares that output different greetings
	hello := GetGreeting("Hello!")
	namaste := GetGreeting("Namaste!")

	//Use middleware.New() as start of a new middleware chain
	greetings := middleware.New().Append(hello)
	greetings = greetings.Append(namaste)

	//Instead of using middleware.New(), any existing handler can be explicitely cast to type Middleware
	//to start a chain
	direct := middleware.Middleware(namaste).Append(hello)

	//Several middlewares can be assembled at once
	assembly := middleware.Assemble(hello, namaste, hello, namaste)

	//A middleware can be prepended to the beginning of the middleware stack
	assembly = assembly.Prepend(hello)

	//Because of the no-op ServeHTTP implementation, any middleware can be used
	//in a mux without an explicit final handler
	mux.Handle("/greetings", greetings)
	mux.Handle("/direct", direct)
	//middleware can also be applied to a final handler
	mux.Handle("/assembly", assembly.ApplyToFunc(handler))

	go func() { log.Fatal(http.ListenAndServe("localhost:9191", mux)) }()

	content, _ := GetWebsite("http://localhost:9191/greetings")
	fmt.Println(content)
	content, _ = GetWebsite("http://localhost:9191/direct")
	fmt.Println(content)
	content, _ = GetWebsite("http://localhost:9191/assembly")
	fmt.Println(content)

}
Output:

Hello!
Namaste!

Namaste!
Hello!

Hello!
Hello!
Namaste!
Hello!
Namaste!
Hi!

func Assemble

func Assemble(middlewares ...Middleware) Middleware

Assemble can be used to chain an arbitrary number of middlewares

middlewares := middleware.Assemble(middlewareA, middlewareB, middlewareC)

func New

func New() Middleware

New creates a new middleware that does nothing by itself, but can be used as a starting point for a chain of middlewares:

middleware := middleware.New()
middleware.Append(someMiddleware)

func (Middleware) Append

func (m Middleware) Append(other Middleware) Middleware

Append adds another middleware to the end of the middleware stack. Given two middlewares that print greetings to stdout:

hello := getGreeting("Hello!")
namaste := getGreeting("Namaste!")

Using them as follows:

mux := http.NewServeMux()
greetings := middleware.New().Append(hello)
greetings = greetings.Append(namaste)
mux.Handle("/greetings", greetings(middleware.End())

Will result in the following output:

Hello!
Namaste!

func (Middleware) ApplyToFunc

func (m Middleware) ApplyToFunc(fun http.HandlerFunc) http.Handler

ApplyToFunc is a convenience function to apply middleware to a HandlerFunc:

 mux := http.NewServeMux()
 handler := func(w http.ResponseWriter, r *http.Request) {
 	fmt.Fprintf(w, "Hi!")
	}
 middlewares := := middleware.Assemble(middlewareA, middlewareB, middlewareC)
 mux.Handle("/endpoint", middlewares.ApplyToFunc(handler))

func (Middleware) Prepend

func (m Middleware) Prepend(other Middleware) Middleware

Prepend adds another middleware to the beginning of the middleware stack. Given two middlewares that print greetings to stdout:

hello := getGreeting("Hello!")
namaste := getGreeting("Namaste!")

Using them as follows:

mux := http.NewServeMux()
greetings := middleware.New().Append(hello)
greetings = greetings.Prepend(namaste)
mux.Handle("/greetings", greetings(middleware.End())

Will result in the following output:

Namaste!
Hello!

func (Middleware) ServeHTTP

func (m Middleware) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements the http.Handler interface with a no-op, thus any middleware can be used as a handler in a mux without an explicit final handler.

mux := http.NewServeMux()
mux.Handle("/endpoint", someMiddleware)

Jump to

Keyboard shortcuts

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