httpctx

package module
v0.0.0-...-49ace10 Latest Latest
Warning

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

Go to latest
Published: Jan 6, 2017 License: MIT Imports: 5 Imported by: 0

README

Context-Aware HTTP Handlers

GoDoc Build Status (Linux) Build status (Windows) license GoReportCard

Deprecated

Go 1.7 includes the context package in the standard library, and the net/http package includes a Context in the http.Request structure. If you are targeting Go 1.7 and later, there is significantly less need for a package like httpctx.

Description

The httpctx package provides a convenient way to handle HTTP requests using "context-aware" handler functions. Context-aware handlers are different from the standard http.Handler in two important ways:

  1. They accept an additional parameter of the (almost) standard type context.Context (golang.org/x/net/context); and
  2. They return an error result.

The httpctx package also implements a simple middleware chaining mechanism. The idea for this comes from Justinas Stankevičius and his alice package. (https://github.com/justinas/alice).

For usage examples, refer to the GoDoc documentation.

Documentation

Overview

Package httpctx provides a convenient way to handle HTTP requests using "context-aware" handler functions. The "context-aware" handler functions are different from the standard http.Handler functions in two important ways:

1. They accept an additional parameter of the (almost) standard type context.Context (golang.org/x/net/context); and

2. They return an error result.

Passing a context.Context to the handler functions is a useful addition because the handler functions can make use of any values associated with the context; and also because the Done channel of the context will be closed if the HTTP client closes the connection prematurely; or a timeout period has elapsed.

Returning an error value simplifies error handling in the handler functions. Common error handling is provided, which can be enhanced by middleware.

A simple middleware mechanism is also provided by this package. A middleware function is one that accepts a httpctx.Handler as a parameter and returns a httpctx.Handler as a result. (Thanks to Justinas Stankevičius for the idea for this. See github.com/justinas/alice).

Example
package main

import (
	"context"
	"net/http"

	"github.com/spkg/httpctx"
)

func main() {
	public := httpctx.Use(ensureHttps)
	authenticate := public.Use(authenticate, ensureAdmin)

	http.Handle("/admin", authenticate.HandleFunc(admin))
	http.Handle("/", public.HandleFunc(index))
	http.ListenAndServe(":8080", nil)
}

func index(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	w.Write([]byte("index page"))
	return nil
}

func admin(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
	w.Write([]byte("admin page, userid=" + useridFrom(ctx)))
	return nil
}

// ensureHttps is an example of middleware that ensures that the request scheme is https.
func ensureHttps(h httpctx.Handler) httpctx.Handler {
	return httpctx.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		if r.URL.Scheme != "https" {
			u := *r.URL
			u.Scheme = "https"
			http.Redirect(w, r, u.String(), http.StatusMovedPermanently)
			return nil
		}
		return h.ServeHTTPContext(ctx, w, r)
	})
}

// authenticate is an example of middleware that authenticates using basic authentication
func authenticate(h httpctx.Handler) httpctx.Handler {
	return httpctx.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		credentials := r.Header.Get("WWW-Authenticate")
		ctx, err := checkCredentials(ctx, credentials)
		if err != nil {
			return err
		}
		return h.ServeHTTPContext(ctx, w, r)
	})
}

func ensureAdmin(h httpctx.Handler) httpctx.Handler {
	return httpctx.HandlerFunc(func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
		// ... get the userid from the context and ensure that the user has admin privilege ...
		return h.ServeHTTPContext(ctx, w, r)
	})
}

// checkCredentials is a placeholder for a function that checks
// credentials, and if successful returns a context with the
// identity of the user attached as a value.
func checkCredentials(ctx context.Context, credentials string) (context.Context, error) {
	// ... just an example ...
	// Note that you would not normally use a string as the key to context.WithValue
	return context.WithValue(ctx, "userid", "username"), nil
}

func useridFrom(ctx context.Context) string {
	userid, _ := ctx.Value("userid").(string)
	return userid
}
Output:

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Handle

func Handle(h Handler) http.Handler

Handle converts a httpctx.Handler into a http.Handler.

func HandleFunc

HandleFunc returns a http.Handler (compatible with the standard library http package), which calls the handler function f.

Types

type Handler

type Handler interface {
	ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) error
}

The Handler interface used for registering handlers that serve a particular path or subtree in the HTTP server. If the ServeHTTPContext function returns an error, it is returned to the client as a HTTP error code.

type HandlerFunc

type HandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request) error

The HandlerFunc type is an adapter to allow the use of ordinary functions as HTTP handlers. If f is a function with the appropriate signature, HandlerFunc(f) is a Handler object that calls f.

func (HandlerFunc) ServeHTTPContext

func (f HandlerFunc) ServeHTTPContext(ctx context.Context, w http.ResponseWriter, r *http.Request) error

ServeHTTPContext calls f(ctx, w, r)

type Stack

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

A Stack is a stack of middleware functions that are common to one or more HTTP handlers. A middleware function is any function that accepts a Handler as a parameter and returns a Handler.

func Context

func Context(ctx context.Context) *Stack

Context returns a middleware stack that applies the context to any handlers added to the stack. This is useful when the main program creates a context that should be used as the base context for all HTTP handlers.

Example
package main

import (
	"context"
	"net/http"

	"github.com/spkg/httpctx"
)

func main() {
	ctx := context.Background()

	// Create a new context based on the background context.
	// For example, cancel on SIGINT and/or SIGTERM.
	ctx = makeNewContext(ctx)

	// Any call using the public stack will be passed ctx
	// instead of the background context for the handlers
	// in the stack.
	public := httpctx.Context(ctx).Use(ensureHttps)

	// Because authenticate is based on public, any call
	// using this stack will also be passed ctx instead
	// of the background context for handlers in the stack.
	authenticate := public.Use(authenticate, ensureAdmin)

	http.Handle("/admin", authenticate.HandleFunc(admin))
	http.Handle("/", public.HandleFunc(index))
	http.ListenAndServe(":8080", nil)
}

func makeNewContext(ctx context.Context) context.Context {
	// Just an example of setting up a context, you should
	// avoid using strings for keys in context.WithValue
	ctx = context.WithValue(ctx, "some-key", "some-value")
	return ctx
}
Output:

func Use

func Use(f ...func(h Handler) Handler) *Stack

Use creates a Stack of middleware functions.

func (*Stack) Handle

func (s *Stack) Handle(h Handler) http.Handler

Handle creates a http.Handler from a stack of middleware functions and a httpctx.Handler.

func (*Stack) HandleFunc

func (s *Stack) HandleFunc(f func(context.Context, http.ResponseWriter, *http.Request) error) http.Handler

HandleFunc returns a http.Handler (compatible with the standard library http package), which calls the middleware handlers in the stack s, followed by the handler function f.

func (*Stack) Use

func (s *Stack) Use(f ...func(h Handler) Handler) *Stack

Use creates a new stack by appending the middleware functions to the existing stack.

Jump to

Keyboard shortcuts

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