acceptable

package module
v0.3.0 Latest Latest
Warning

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

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

README

Acceptable

GoDoc Build Status Issues

This is a library that handles Accept headers, which form the basis of content negotiation in HTTP server applications written in Go. It provides an implementation of the content negotiation algorithm specified in RFC-7231.

Accept parsing

The Accept header is parsed using ParseMediaRanges(hdr), which returns the slice of media ranges, e.g.

    // handle Accept-Language
    mediaRanges := acceptable.ParseMediaRanges("application/json;q=0.8, application/xml, application/*;q=0.1")

The resulting slice is sorted according to precedence and quality rules, so in this example the order is {"application/xml", "application/json", "application/*"} because the middle item has an implied quality of 1, whereas the first item has a lower quality.

Accept-Language and Accept-Charset parsing

The other important content-negotiation headers, Accept-Language and Accept-Charset, are handled by the header.Parse method, e.g.

    // handle Accept-Language
    acceptLanguages := acceptable.Parse("en-GB,fr;q=0.5,en;q=0.8")

This will contain {"en-GB", "en", "fr"} in a header.PrecedenceValues slice, sorted according to precedence rules with the most preferred first.

The acceptable.Parse function can be used for Accept-Encoding as well as Accept-Language and Accept-Charset. However, the Go standard library deals with Accept-Encoding, so you won't need to.

Putting it together - simple content negotiation

Finding the best match depends on you listing your available response representations. For example

    offer1 := acceptable.OfferOf("application/json")
    offer2 := acceptable.OfferOf("application/xml")
    best := acceptable.BestRequestMatch(request, offer1, offer2)

The best result will be the one that best matches the request headers. If none match, it will be nil and the response should be 406-Not Acceptable. If you need to have a catch-all case, include acceptable.OfferOf("*/*") last in the list.

The offers can also be restricted by language matching using their Language field. This matches Accept-Language using the basic prefix algorithm, which means for example that if you specify "en" it will match "en", "en-GB" and everything else beginning with "en-".

The offers can hold a suitable rendering function in their Processor field if required. If the best offer matched is not nil, you can easily call its Processor function in order to render the response.

Documentation

Overview

Package acceptable is a library that handles headers for content negotiation in web applications written in Go. Content negotiation is specified by RFC (http://tools.ietf.org/html/rfc7231) and, less formally, by Ajax (https://en.wikipedia.org/wiki/XMLHttpRequest).

Accept

from https://tools.ietf.org/html/rfc7231#section-5.3.2:

The "Accept" header field can be used by user agents to specify response media types that are acceptable. Accept header fields can be used to indicate that the request is specifically limited to a small set of desired types, as in the case of a request for an in-line image.

A request without any Accept header field implies that the user agent will accept any media type in response.

If the header field is present in a request and none of the available representations for the response have a media type that is listed as acceptable, the origin server can either honor the header field by sending a 406 (Not Acceptable) response, or disregard the header field by treating the response as if it is not subject to content negotiation.

Accept-Language

from https://tools.ietf.org/html/rfc7231#section-5.3.5:

The "Accept-Language" header field can be used by user agents to indicate the set of natural languages that are preferred in the response.

A request without any Accept-Language header field implies that the user agent will accept any language in response.

If the header field is present in a request and none of the available representations for the response have a matching language tag, the origin server can either disregard the header field by treating the response as if it is not subject to content negotiation or honor the header field by sending a 406 (Not Acceptable) response. However, the latter is not encouraged, as doing so can prevent users from accessing content that they might be able to use (with translation software, for example).

package header provides parsing rules for content negotiation headers according to RFC-7231.

For "Accept-Language", "Accept-Encoding" or "Accept-Charset" use the Parse function.

For "Accept" use the ParseMediaRanges function. This has more complex attributes and rules.

Index

Constants

View Source
const (
	Accept         = "Accept"
	AcceptLanguage = "Accept-Language"
	AcceptCharset  = "Accept-Charset"

	// The header strings used for XHR.
	XRequestedWith = "X-Requested-With"
	XMLHttpRequest = "xmlhttprequest"
)
View Source
const (
	// DefaultQuality is the default quality of a media range without explicit "q"
	// https://tools.ietf.org/html/rfc7231#section-5.3.1
	DefaultQuality float64 = 1.0 //e.g text/html;q=1

	// NotAcceptable is the value indicating that its item is not acceptable
	// https://tools.ietf.org/html/rfc7231#section-5.3.1
	NotAcceptable float64 = 0.0 //e.g text/foo;q=0
)

Variables

View Source
var Debug = func(string, ...interface{}) {}

Debug can be used for observing decisions made by the negotiator. By default it is no-op.

Functions

func IsAjax

func IsAjax(req *http.Request) bool

IsAjax tests whether a request has the Ajax header sent by browsers for XHR requests.

Types

type ContentType

type ContentType struct {
	// Type and Subtype carry the media type, e.g. "text" and "html"
	Type, Subtype string
	// Params and Extensions hold optional parameter information
	Params     []KV
	Extensions []KV
}

ContentType is a media type as defined in RFC-2045, RFC-2046, RFC-2231 (https://tools.ietf.org/html/rfc2045, https://tools.ietf.org/html/rfc2046, https://tools.ietf.org/html/rfc2231) There may also be parameters (e.g. "charset=utf-8") and extension values.

func ContentTypeOf

func ContentTypeOf(typ, subtype string, paramKV ...string) ContentType

ContentTypeOf builds a content type value with optional parameters. The parameters are passed in as literal strings, e.g. "charset=utf-8".

func (ContentType) String

func (ct ContentType) String() string

type KV

type KV struct {
	Key, Value string
}

KV holds a parameter with a key and optional value.

type Match added in v0.3.0

type Match struct {
	Type      string
	Subtype   string
	Language  string
	Charset   string
	Processor Processor
}

func BestRequestMatch

func BestRequestMatch(req *http.Request, available ...Offer) *Match

BestRequestMatch finds the content type and language that best matches the accepted media ranges and languages contained in request headers. The result contains the best match, based on the rules of RFC-7231. On exit, the result will contain the preferred language and charset, if these are known.

Whenever the result is nil, the response should be 406-Not Acceptable.

For all Ajax requests, the available offers are filtered so that only those capable of providing an Ajax response are considered by the content negotiation algorithm. The other offers are discarded.

If no available offers are provided, the response will always be nil. Note too that Ajax requests will result in nil being returned if no offer is capable of handling them, even if other offers are provided.

func (*Match) ApplyHeaders added in v0.3.0

func (r *Match) ApplyHeaders(w http.ResponseWriter)

type MediaRange

type MediaRange struct {
	ContentType
	Quality float64
}

MediaRange is a content type and associated quality between 0.0 and 1.0.

func (MediaRange) String

func (mr MediaRange) String() string

func (MediaRange) StrongerThan

func (mr MediaRange) StrongerThan(other MediaRange) bool

StrongerThan compares a media range with another value using the precedence rules.

func (MediaRange) Value

func (mr MediaRange) Value() string

Value gets the conjoined type and subtype string, plus any parameters. It does not include the quality value nor any of the extensions.

type MediaRanges

type MediaRanges []MediaRange

MediaRanges holds a slice of media ranges.

func ParseMediaRanges

func ParseMediaRanges(acceptHeader string) MediaRanges

ParseMediaRanges splits a prioritised "Accept" header value and sorts the parts based on quality values and precedence rules. These are returned in order with the most preferred first.

A request without any Accept header field implies that the user agent will accept any media type in response. If the header field is present in a request and none of the available representations for the response have a media type that is listed as acceptable, the origin server can either honor the header field by sending a 406 (Not Acceptable) response or disregard the header field by treating the response as if it is not subject to content negotiation.

func (MediaRanges) String

func (mrs MediaRanges) String() string

func (MediaRanges) WithDefault

func (mrs MediaRanges) WithDefault() MediaRanges

WithDefault returns a list of media ranges that is always non-empty. If the input list is empty, the result holds a wildcard entry ("*/*").

type Offer

type Offer struct {
	// ContentType is the content type that is to be matched.
	// Wildcard values may be used.
	ContentType

	// Language defines which language will be provided if this offer is matched.
	// Can also be blank or "*" - both indicate that this is not used.
	Language string

	// Charset returns the preferred character set for the response, if any.
	// This is set on return from the BestRequestMatch function.
	Charset string

	// Processor is an optional function you can use to apply the offer if it is selected.
	// How this is used is entirely at the discretion of the call site.
	Processor Processor
}

Offer holds information about one particular resource representation that can potentially provide an acceptable response.

func OfferOf

func OfferOf(contentType string, language ...string) Offer

OfferOf constructs an Offer easily. If the language is absent, it is assumed to be the wildcard "*". If the content type is blank, it is assumed to be the full wildcard "*/*". If the content subtype is blank, it is assumed to be the partial wildcard "type/*".

func (Offer) String

func (o Offer) String() string

func (Offer) With

func (o Offer) With(processor Processor) Offer

With attaches a processor function to an offer and returns the modified offer. The original offer is unchanged.

type Offers

type Offers []Offer

Offers holds a slice of Offer.

func (Offers) Filter

func (offers Offers) Filter(typ, subtype string) Offers

Filter returns only the offers that match specified type and subtype.

type PrecedenceValue

type PrecedenceValue struct {
	Value   string
	Quality float64
}

PrecedenceValue is a value and associate quality between 0.0 and 1.0

func (PrecedenceValue) String

func (pv PrecedenceValue) String() string

type PrecedenceValues

type PrecedenceValues []PrecedenceValue

PrecedenceValues holds a slice of precedence values.

func Parse

func Parse(acceptXyzHeader string) PrecedenceValues

Parse splits a prioritised "Accept-Language", "Accept-Encoding" or "Accept-Charset" header value and sorts the parts. These are returned in order with the most preferred first.

func (PrecedenceValues) String

func (pvs PrecedenceValues) String() string

func (PrecedenceValues) WithDefault

func (pvs PrecedenceValues) WithDefault() PrecedenceValues

type Processor added in v0.3.0

type Processor func(w http.ResponseWriter, match Match, template string, dataModel interface{}) error

Processor is a function that renders content according to the matched result.

Directories

Path Synopsis
Package processor contains flexible implementations for rendering JSON, XML, CSV etc.
Package processor contains flexible implementations for rendering JSON, XML, CSV etc.

Jump to

Keyboard shortcuts

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