advhttp

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Jun 19, 2015 License: MIT Imports: 14 Imported by: 2

README

advhttp

Advhttp is a go utility library to help out with some common http needs that aren't in the standard library. The library can be broken up into the following functionality categories.

  • Handlers
  • Logging
  • OAuth2
  • Cross Origin Resource Sharing
  • Reverse Proxy

Handlers

The included handlers try to build a handler stack to alleviate boilerplate code in go server applications. A common setup might look like:

ch := advhttp.NewDefaultCorsHandler(http.DefaultServeMux)
ph := advhttp.NewPanicRecoveryHandler(ch)
lh := advhttp.NewLoggingHandler(ph, os.Stdout)

http.ListenAndServe(":http", lh)

This creates a request pipeline that will eventually end up using the default serve mux provided in the http library. But you'll have Common Log Format logs printed to std out, panic recovery, and cors headers to allow cross origin resouce sharing.

Logging

You can also bypass the handlers and get a little bit more out of the library on your own. I provide a custom ResponseWriter that tracks bytes written and status code so that you can have those after you write. These are typically included in logs.

trw := advhttp.NewResponseWriter(w)
fmt.Fprintf(os.Stderr, "Status: %v\n", trw.Status())
fmt.Fprintf(os.Stderr, "Bytes Written: %v\n", trw.Length())
fmt.Fprint(os.Stdout, trw.LogCommonExtended(r))

OAuth2

The OAuth2 portion of the library is primarily for applications which may need to communicate with other apis via oauth2. The library will cache a token so that it may be re-used accross multiple calls and reduce latency.

tracker, err := advhttp.NewClientCredentialsTokenTracker(tokenEndpoint, tokenInfoEndpoint, client_id, client_secret, scope)
token, err := tracker.GetToken() //Get a new token or a cached token
token, err := tracker.GetNewToken() //Force getting a new token
ti, err := tracker.GetTokenInfo() //Return an object with the result from the tokenInfoEndpoint

//You can also just use the apis yourself
token, tokenExpires, refreshToken, err := advhttp.GetPasswordToken(tokenEndpoint, client_id, client_secret, username, password, scope)
token, tokenExpires, err := advhttp.GetRefreshToken(tokenEndpoint, client_id, client_secret, refresh_token, scope)
token, tokenExpires, err := advhttp.GetClientCredentialsToken(tokenEndpoint, client_id, client_secret string, scope []string)
ti, err := advhttp.GetTokenInformation(tokenInfoEndpoint, token string)

Cross Origin Resource Sharing

The cors library allows you to set up cors how you'd like, and then serve based on that. advhttp comes with a DefaultCors object that contains the default cors settings. advhttp.DefaultCors. A cors object includes:

  • AllowOrigin (string) Default "" meaning to mirror the Origin header
  • AllowHeaders ([]string) Default advhttp.CorsDefaultAllowHeaders
  • AllowMethods ([]string) Default advhttp.CorsDefaultAllowMethods
  • ExposeHeaders ([]string) Default advhttp.CorsDefaultExposeHeaders
  • MaxAge (int64) Default advhttp.CorsDefaultMaxAge
  • AllowCredentials (bool) Default advhttp.CorsDefaultAllowCredentials

You can use the default cors handler:

advhttp.ProcessCors(w,r)

Or you can create your own:

cors := new(Cors)
cors.AllowOrigin = "*"
cors.AllowHeaders = []string{"Location", "Content-Type", "ETag", "Accept-Patch"}
cors.AllowMethods = []string{"OPTIONS", "HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"}
cors.ExposeHeaders = []string{"Location", "Content-Type", "ETag", "Accept-Patch"}
cors.MaxAge = int64(1728000)
cors.AllowCredentials = true
cors.ProcessCors(w,r)

Or you can use the included handler:

ch := advhttp.NewDefaultCorsHandler(http.DefaultServeMux)
ch.ServeHTTP(w,r)

Reverse Proxy

The reverse proxy adds to the httputils and allows you to reverse proxy to different hosts, mutate the path on it's way there, (and also in the Location header in responses). It is helpful in gateway projects.

googleURL, _ := url.Parse("http://www.google.com/")
downloads := advhttp.NewGatewayReverseProxy(googleURL, true, "/google/")
http.Handle("/google/", someHandlerFunc)

In the above example, calls to the /google/ endpoint on your server http://yourserver.com/google/ will result in your server then calling google http://www.google.com/ but stripping off the /google/ path from the original url. If the response from google is a redirect or includes the Location header, then advhttp will rewrite the header to include the original /google/ path. This results in browser being able to (almost) transparently use the other server through your server.

Documentation

Index

Constants

View Source
const (
	CorsOrigin                        = "Origin"
	CorsAccessControlRequestMethod    = "Access-Control-Request-Method"
	CorsAccessControlRequestHeader    = "Access-Control-Request-Header"
	CorsAccessControlAllowOrigin      = "Access-Control-Allow-Origin"
	CorsAccessControlAllowMethods     = "Access-Control-Allow-Methods"
	CorsAccessControlAllowHeaders     = "Access-Control-Allow-Headers"
	CorsAccessControlAllowCredentials = "Access-Control-Allow-Credentials"
	CorsAccessControlExposeHeaders    = "Access-Control-Expose-Headers"
	CorsAccessControlMaxAge           = "Access-Control-Max-Age"
)

Variables

View Source
var (
	CorsDefaultAllowOrigin      = "*"
	CorsDefaultAllowHeaders     = []string{"Location", "Content-Type", "ETag", "Accept-Patch"}
	CorsDefaultAllowMethods     = []string{"OPTIONS", "HEAD", "GET", "POST", "PUT", "PATCH", "DELETE"}
	CorsDefaultExposeHeaders    = []string{"Location", "Content-Type", "ETag", "Accept-Patch"}
	CorsDefaultMaxAge           = int64(1728000)
	CorsDefaultAllowCredentials = true
)

Functions

func BearerAuth

func BearerAuth(r *http.Request) (bearerToken string, ok bool)

BearerAuth is a function that will pull an access token out of the Authorization header it will return the bearer token if found, and ok will tell you whether it was able to find the token or not. This function will look for the token in the query params, as well as the headers.

func GetClientCredentialsToken

func GetClientCredentialsToken(tokenEndpoint, client_id, client_secret string, scope []string) (token string, tokenExpires time.Time, err error)

This method uses the client_credentials grant_type of oauth2 to obtain a token from the token endpoint.

func GetPasswordToken

func GetPasswordToken(tokenEndpoint, client_id, client_secret, username, password string, scope []string) (token string, tokenExpires time.Time, refreshToken string, err error)

This method uses the password grant type of oauth2 to get a token from the token endpoint.

func GetRefreshToken

func GetRefreshToken(tokenEndpoint, client_id, client_secret, refresh_token string, scope []string) (token string, tokenExpires time.Time, err error)

This method uses the refresh_token grant type of oauth2 to obtain a token from the token endpoint

func GetTokenInformation

func GetTokenInformation(tokenInfoEndpoint, token string) (tokenInfo map[string]interface{}, err error)

This method calls the token information endpoint and returns the json response as a map of string to interface{} values.

func IsJSONAnAcceptableResponse

func IsJSONAnAcceptableResponse(acceptHeader string) bool

This function will take in the accept header string from a inbound request and determine if application/json is an acceptable response for the request. It ignores any priorities that the requester has, and if they don't include an accept header it will treat it as if they had just used Accept: */*

func LogApache

func LogApache(trw *ResponseWriter, r *http.Request) string

func LogCommonExtended

func LogCommonExtended(trw *ResponseWriter, r *http.Request) string

func LogCommonExtendedForwarded

func LogCommonExtendedForwarded(trw *ResponseWriter, r *http.Request) string

func NewCorsHandler

func NewCorsHandler(h http.Handler, cors *Cors) http.Handler

func NewDefaultCorsHandler

func NewDefaultCorsHandler(h http.Handler) http.Handler

func NewForwardedLoggingHandler

func NewForwardedLoggingHandler(h http.Handler, log io.Writer) http.Handler

func NewLoggingHandler

func NewLoggingHandler(h http.Handler, log io.Writer) http.Handler

func NewPanicRecoveryHandler

func NewPanicRecoveryHandler(h http.Handler) http.Handler

func NewReverseProxyHandler

func NewReverseProxyHandler(destinationURL *url.URL, stripListenPath bool, listenPath string) http.Handler

func ProcessCors

func ProcessCors(w http.ResponseWriter, r *http.Request)

Types

type Cors

type Cors struct {
	AllowOrigin      string
	AllowHeaders     []string
	AllowMethods     []string
	ExposeHeaders    []string
	MaxAge           int64
	AllowCredentials bool
}
var DefaultCors *Cors

func (*Cors) ProcessCors

func (cors *Cors) ProcessCors(w http.ResponseWriter, r *http.Request)

This function will write out cross origin headers so that javascript clients can call apis.

type GatewayReverseProxy

type GatewayReverseProxy struct {
	Name            string
	StripListenPath bool
	ListenPath      string
	// Director must be a function which modifies
	// the request into a new request to be sent
	// using Transport. Its response is then copied
	// back to the original client unmodified.
	Director func(*http.Request)

	// The transport used to perform proxy requests.
	// If nil, http.DefaultTransport is used.
	Transport http.RoundTripper

	// FlushInterval specifies the flush interval
	// to flush to the client while copying the
	// response body.
	// If zero, no periodic flushing is done.
	FlushInterval time.Duration

	// ErrorLog specifies an optional logger for errors
	// that occur when attempting to proxy the request.
	// If nil, logging goes to os.Stderr via the log package's
	// standard logger.
	ErrorLog *log.Logger
}

ReverseProxy is an HTTP Handler that takes an incoming request and sends it to another server, proxying the response back to the client.

func NewGatewayReverseProxy

func NewGatewayReverseProxy(target *url.URL, stripListenPath bool, listenPath string) *GatewayReverseProxy

NewGatewayReverseProxy returns a new GatewayReverseProxy that rewrites URLs to the scheme, host, and base path provided in target. If the target's path is "/base" and the incoming request was for "/dir", the target request will be for /base/dir.

func (*GatewayReverseProxy) ServeHTTP

func (p *GatewayReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request)

type ResponseWriter

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

func NewResponseWriter

func NewResponseWriter(w http.ResponseWriter) *ResponseWriter

func (*ResponseWriter) CloseNotify

func (trw *ResponseWriter) CloseNotify() <-chan bool

func (*ResponseWriter) Flush

func (trw *ResponseWriter) Flush()

func (*ResponseWriter) GetCloseNotifier

func (trw *ResponseWriter) GetCloseNotifier() (closeNotifier http.CloseNotifier, ok bool)

func (*ResponseWriter) GetFlusher

func (trw *ResponseWriter) GetFlusher() (flusher http.Flusher, ok bool)

func (*ResponseWriter) GetHijacker

func (trw *ResponseWriter) GetHijacker() (hijacker http.Hijacker, ok bool)

func (*ResponseWriter) Header

func (trw *ResponseWriter) Header() http.Header

func (*ResponseWriter) Hijack

func (trw *ResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error)

func (*ResponseWriter) Length

func (trw *ResponseWriter) Length() int64

func (*ResponseWriter) LogCommonExtended

func (trw *ResponseWriter) LogCommonExtended(r *http.Request) string

func (*ResponseWriter) LogCommonExtendedForwarded

func (trw *ResponseWriter) LogCommonExtendedForwarded(r *http.Request) string

func (*ResponseWriter) Status

func (trw *ResponseWriter) Status() int

func (*ResponseWriter) Write

func (trw *ResponseWriter) Write(bytes []byte) (int, error)

func (*ResponseWriter) WriteHeader

func (trw *ResponseWriter) WriteHeader(status int)

type TokenTracker

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

A structure to cache oauth2 state. Has helper methods which will allow users to pull cached tokens from the structure when needed without utilizing the network to obtain new tokens constantly

func NewClientCredentialsTokenTracker

func NewClientCredentialsTokenTracker(tokenEndpoint, tokenInfoEndpoint, client_id, client_secret string, scope []string) (tokenTracker *TokenTracker, err error)

This method will return a new TokenTracker set up to cache and obtain new tokens in behalf of a oauth2 client. It will always use the client_credentials grant type to obtain the new tokens from the token endpoint.

func NewPasswordTokenTracker

func NewPasswordTokenTracker(tokenEndpoint, tokenInfoEndpoint, client_id, client_secret, username, password string, scope []string) (tokenTracker *TokenTracker, err error)

This method will return a new TokenTracker set up to cache and obtain tokens on behalf of a particular user. It will use the password grant type to obtain the first token, and a refresh token. Subsequent tokens will be obtained by using the refresh_token grant type. It will not cache the username and password for the user. So if for any reason the refresh_token is invalidated or revoked special logic will need to be done (outside of this lib) to reset the TokenTracker so it doesn't forever remain in a bad state.

func (*TokenTracker) GetNewToken

func (tt *TokenTracker) GetNewToken() (token string, err error)

This method will fetch a new token from the token endpoint. It will replace any cached tokens that the tracker has. It uses the client credentials to get a new token on behalf of a client, and uses the refresh token to get a token on behalf of a client and user combination.

func (*TokenTracker) GetSafeToken

func (tt *TokenTracker) GetSafeToken() (token string, err error)

This method of the token tracker will verify the veracity of the token against the token info endpoint before it returns it to the user. If the token info endpoint returns anything other than a 200 status, this endpoint will then attempt to get a fresh token.

func (*TokenTracker) GetToken

func (tt *TokenTracker) GetToken() (token string, err error)

The get token method will grab a cached token from it's store if it has not expired (using the expires_in value from the original token call. It is not guaranteed to be a valid token as it may have been invalidated or revoked before it expired. If you want to ensure the token is valid use the GetSafeToken() method.

func (*TokenTracker) GetTokenInformation

func (tt *TokenTracker) GetTokenInformation() (tokenInfo map[string]interface{}, err error)

This method will return the cached token information if it is available, or call the token information endpoint if it doesn't have any.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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