httpaux

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 15, 2020 License: Apache-2.0 Imports: 11 Imported by: 9

README

httpaux

The missing functionality from net/http

Build Status codecov.io Code Climate Issue Count Go Report Card Apache V2 License Quality Gate Status GitHub release GoDoc

Summary

httpaux augments golang's net/http package with a few extra goodies:

  • RoundTripperFunc that implements http.RoundTripper. This is an analog to http.HandlerFunc for clients.
  • Busy server middleware that constrains the number of concurrent requests by consulting a Limiter strategy
  • ObservableWriter which decorates the typical http.ResponseWriter, providing visibility into what handlers have written to the response. This type is intended to enable other middleware such as logging and metrics.
  • Gate middleware for both servers and clients which can explicity shut off code. One typical use case for this is putting an application into maintenance mode.
  • Header immutable data structure that is much more efficient in situations where the same set of headers are iterated over repeatedly. Useful when static headers need to be placed unconditionally on every request or response.
  • ConstantHandler which returns a statically specified set of information in every response
  • Error which can be used to wrap service and middleware errors in a form that makes rendering responses easier. This type is compatible with frameworks like go-kit.

Table of Contents

Code of Conduct

This project and everyone participating in it are governed by the XMiDT Code Of Conduct. By participating, you agree to this Code.

Install

go get github.com/xmidt-org/httpaux

Contributing

Refer to CONTRIBUTING.md.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NopRequestDone

func NopRequestDone()

NopRequestDone is a RequestDone implementation that does nothing. Useful to use instead of nil.

Types

type Busy

type Busy struct {
	// Limiter is the concurrent request limiting strategy.  If this field is unset,
	// then no limiting is done.
	Limiter Limiter

	// OnBusy is the optional http.Handler to invoke when the maximum number
	// concurrent requests has been exceeded.  ConstantHandler is a useful choice
	// for this field, as it allows one to tailor not only the status code but also
	// the headers and body.
	//
	// If this field is nil, this middleware simply returns http.StatusServiceUnavailable.
	OnBusy http.Handler
}

Busy defines a server middleware that enforces request limiting

func (Busy) Then

func (b Busy) Then(next http.Handler) http.Handler

Then is a server middleware that enforces this Busy configuration. If Limiter is nil, no decoration is done and next is returned as is. If OnBusy is nil, then the returned handler will simply set http.StatusServiceUnavailable when requests fail the limit check.

type ConstantHandler

type ConstantHandler struct {
	// StatusCode is the response code to pass to http.ResponseWriter.WriteHeader.
	// If this value is less than 100 (which also includes being unset), then no
	// response code is written which will trigger the default of http.StatusOK.
	StatusCode int

	// Header is the set of headers added to every response
	Header Header

	// ContentType is the MIME type of the Body.  This will override anything written by
	// the Headers closure.  This field has no effect if Body is not also set.  If Body is
	// set and this field is unset, then no Content-Type header is written by this handler.
	// A Content-Type may still be written by other infrastructure or by the Headers closure, however.
	ContentType string

	// Body is the optional HTTP entity body.  If unset, nothing is written for the response body.
	// A Content-Length header will be explicitly set if this field is set.
	Body []byte
}

ConstantHandler is an http.Handler that writes a statically defined HTTP response. Very useful for testing and for default behavior.

func ConstantJSON

func ConstantJSON(v interface{}) (ch ConstantHandler, err error)

ConstantJSON is a convenience for constructing a ConstantHandler that returns a static JSON message. The encoding/json package is used to marshal v.

func (ConstantHandler) ServeHTTP

func (ch ConstantHandler) ServeHTTP(response http.ResponseWriter, _ *http.Request)

ServeHTTP returns the constant information in the response.

type Error

type Error struct {
	// Err is the cause of this error.  This field is required.
	//
	// Typically, this field is set to the service-layer error or other error
	// that occurred below the presentation layer.
	Err error

	// Message is the optional message to associate with this error
	Message string

	// Code is the response code to use for this error.  If unset, http.StatusInternalServerError
	// is used instead.
	Code int

	// Header is the optional set of HTTP headers to associate with this error
	Header http.Header
}

Error is a convenient carrier of error information that exposes HTTP response information. This type implements several interfaces in popular packages like go-kit.

The primary use case for this type is wrapping errors so they can be easily rendered as HTTP responses.

func (*Error) Error

func (e *Error) Error() string

Error fulfills the error interface. Message is included in this text if it is supplied.

func (*Error) Headers

func (e *Error) Headers() http.Header

Headers returns the optional headers to associate with this error's response

func (*Error) MarshalJSON

func (e *Error) MarshalJSON() ([]byte, error)

MarshalJSON produces a JSON representation of this error. The Err field is marshaled as "cause". If the Message field is set, it is marshaled as "message".

func (*Error) StatusCode

func (e *Error) StatusCode() int

StatusCode returns the Code field, or http.StatusInternalServerError if that field is less than 100.

func (*Error) Unwrap

func (e *Error) Unwrap() error

Unwrap produces the cause of this error

type Gate

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

Gate is an atomic boolean that controls access to http.Handlers and http.RoundTrippers. All methods of this type are safe for concurrent access.

A Gate can be observed via the Append method and supplying callbacks for state. These callbacks are useful for integrating logging, metrics, health checks, etc.

func NewGate

func NewGate(o GateOptions) *Gate

NewGate produces a Gate from a set of options. The returned Gate will be in the state indicated by GateOptions.InitiallyClosed.

func (*Gate) Close

func (g *Gate) Close() (closed bool)

Close atomically closes this gate and invokes any registered OnClose callbacks. If the gate was already closed, no callbacks are invoked since there was no state change.

func (*Gate) IsOpen

func (g *Gate) IsOpen() bool

IsOpen returns the current state of the gate: true for open and false for closed.

func (*Gate) Name

func (g *Gate) Name() string

Name returns the name for this gate, which can be empty. Typically, a name is useful when multiple gates are used within a single application.

func (*Gate) Open

func (g *Gate) Open() (opened bool)

Open atomically opens this gate and invokes any registered OnOpen callbacks. If the gate was already open, no callbacks are invoked since there was no state change.

func (*Gate) RoundTrip

func (g *Gate) RoundTrip(next http.RoundTripper) http.RoundTripper

RoundTrip is a client middleware that guards its next http.RoundTripper according to the gate's state. If next is nil, http.DefaultTransport is decorated instead.

The onClosed http.Handler associated with this gate is not used for this middleware. If the gate disallows the client request, a nil *http.Response together with a *GateClosedError are returned.

func (*Gate) String

func (g *Gate) String() string

String returns a human-readable representation of this Gate.

func (*Gate) Then

func (g *Gate) Then(next http.Handler) http.Handler

Then is a server middleware that guards its next http.Handler according to the gate's state.

type GateClosedError

type GateClosedError struct {
	// Gate is the gate instance that was closed at the time the attempt
	// to make a request was made.  Note that after this error returns, the
	// gate may be open.
	Gate *Gate
}

GateClosedError is returned by decorated http.RoundTripper instances to indicate that the gate disallowed the client request.

func (*GateClosedError) Error

func (gce *GateClosedError) Error() string

Error satisfies the error interface

type GateOptions

type GateOptions struct {
	// Name is an optional identifier for this gate.  The Gate itself does not make
	// use of this value.  It's purely for distinguishing gates when an application
	// uses more than one (1) gate.
	Name string

	// ClosedHandler is the optional http.Handler that handles requests when
	// the gate is closed.  If this field is unset, then the only response information
	// written is a status code of http.StatusServiceUnavailable.
	ClosedHandler http.Handler

	// InitiallyClosed indicates the state of a Gate when it is created.  The default
	// is to create a Gate that is open.  If this field is true, the Gate is created
	// in the closed state.
	InitiallyClosed bool

	// OnOpen is the set of callbacks to invoke when a gate's state changes to open.
	// These callbacks will also be invoked when a Gate is created if the Gate is
	// initially open.
	OnOpen []func(*Gate)

	// OnClosed is the set of callbacks to invoke when a gate's state changes to closed.
	// These callbacks will also be invoked when a Gate is created if the Gate is
	// initially closed.
	OnClosed []func(*Gate)
}

GateOptions describes all the various configurable settings for creating a Gate

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

Header is a more efficient version of http.Header for situations where a number of HTTP headers are stored in memory and reused. Rather than a map, a simple list of headers is maintained in canonicalized form. This is much faster to iterate over than a map, which becomes important when the same Header is used to add headers to many requests.

A Header instance is immutable once created.

func NewHeader

func NewHeader(v http.Header) Header

NewHeader creates an immutable, preprocessed Header given an http.Header

func NewHeaderFromMap

func NewHeaderFromMap(v map[string]string) Header

NewHeaderFromMap allows a Header to be built directly from a map[string]string rather than an http.Header.

func NewHeaders

func NewHeaders(v ...string) Header

NewHeaders takes a variadic list of values and interprets them as alternating name/value pairs, with each pair specifying an HTTP header. Duplicate header names are supported, which results in multivalued headers. If v contains an odd number of strings, the last string is interpreted as a header with a blank value.

func (Header) RoundTrip

func (h Header) RoundTrip(next http.RoundTripper) http.RoundTripper

RoundTrip is a client middleware that adds all these headers to the http.Request prior to invoking the next http.RoundTripper. As an optimization, if this Header is empty no decoration is done. Next is returned as is in that case.

If next is nil and this Header is non-empty, then http.DefaultTransport is decorated.

func (Header) SetTo

func (h Header) SetTo(dst http.Header)

SetTo overwrites headers in the destination with the ones defined by this Header.

func (Header) Then

func (h Header) Then(next http.Handler) http.Handler

Then is a server middleware that adds all the headers to the http.ResponseWriter prior to invoking the next handler. As an optimization, if this Header is empty no decoration is done.

type Limiter

type Limiter interface {
	// Check enforces a concurrent request limit, possibly using information
	// from the given HTTP request.  If this method returns true, it indicates
	// that the request is allowed.  In that case, the RequestDone must be non-nil
	// and must be invoked by calling code to update the Limiter's state.
	//
	// If this method returns false, the request should not proceed.  The
	// RequestDone should be ignored.
	//
	// The RequestDone returned by this method is not guaranteed to be idempotent.
	// Callers must take care to invoke it exactly once for any given request.
	Check(*http.Request) (RequestDone, bool)
}

Limiter is a request limiter. It constrains the number of concurrent requests either globally or based on some aspect of each request, such as a user account.

type MaxRequestLimiter

type MaxRequestLimiter struct {
	// MaxRequests is the maximum number of concurrent HTTP requests.  If this
	// is nonpositive, then all requests are allowed.
	MaxRequests int64
	// contains filtered or unexported fields
}

MaxRequestLimiter is a Limiter that imposes a global limit for maximum concurrent requests. No aspect of each HTTP request is taken into account.

func (*MaxRequestLimiter) Check

func (rcl *MaxRequestLimiter) Check(*http.Request) (RequestDone, bool)

Check verifies that no more than MaxRequests requests are currently inflight. If MaxRequests is nonpositive, this method returns NopRequestDone and true.

type ObservableWriter

type ObservableWriter interface {
	http.ResponseWriter
	StatusCoder
	ResponseBody

	// OnWriteHeader appends callbacks that are invoked when WriteHeader is called, whether
	// explicitly or implicitly due to calling methods like Flush.
	//
	// If the status code for the response has already been established, these callbacks
	// are invoked immediately.
	OnWriteHeader(...OnWriteHeader)
}

ObservableWriter is the decorator interface for instrumented http.ResponseWriter instances

func Observe

func Observe(delegate http.ResponseWriter) ObservableWriter

Observe decorates an http.ResponseWriter to produces an ObservableWriter If the delegate is already an ObservableWriter, it is returned as is.

type OnWriteHeader

type OnWriteHeader func(int)

OnWriteHeader is a callback that is invoked once a handler either invokes WriteHeader or calls Write for the first time. Note that if a handler never writes to the response body for any reason, including panicing, these callbacks will not be invoked.

Use of this callback enables logging and metrics around things like how long a handler took to write headers. Note that the status code passed to this callback is also available via the StatusCoder interface, so use of this callback is only in the niche cases where code needs to be aware of the point in time the header was written.

type RequestDone

type RequestDone func()

RequestDone is a callback that must be invoked when a request is finished so that its corresponding Limiter can update its state. Care must be taken by clients to invoke a RequestDone exactly once for any request.

type ResponseBody

type ResponseBody interface {
	// ContentLength returns the count of bytes actually written with Write.  It does
	// not consult the Content-Length header.
	//
	// The count of bytes returned by this method is simply the current count of bytes
	// written so far.  If Write is called after this method, this method will return
	// a different value.
	ContentLength() int64
}

ResponseBody is the interface implemented by an observable http.ResponseWriter

type RoundTripperFunc

type RoundTripperFunc func(*http.Request) (*http.Response, error)

RoundTripperFunc is a function that that implements http.RoundTripper

func (RoundTripperFunc) RoundTrip

func (rtf RoundTripperFunc) RoundTrip(request *http.Request) (*http.Response, error)

RoundTrip invokes this function and returns the results

type StatusCoder

type StatusCoder interface {
	// StatusCode returns the response code reported through WriteHeader.  Certain
	// methods cause WriteHeader to be called implicitly, with a status of http.StatusOK.
	//
	// If no status code has been written yet, this method returns zero (0).
	StatusCode() int
}

StatusCoder is the interface implemented by an observable http.ResponseWriter.

Jump to

Keyboard shortcuts

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