connegmatcher

package module
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: May 19, 2022 License: Apache-2.0 Imports: 11 Imported by: 0

README

Caddy Content Negotiation Plugin

Content negotiation is a mechanism of HTTP that allows client and server to agree on the best version of a resource to be delivered for the client's needs given the server's capabilities (see RFC). In short, when sending the request, the client can specify what content type, language, character set or encoding it prefers and the server responds with the best available version to fit the request.

This plugin to the Caddy 2 webserver allows you to configure named matchers for content negotiation parameters and/or store content negotiation results in variables.

The plugin can be configured via Caddyfile:

Syntax

@name {
    conneg {
        match_types <content-types...>
        force_type_query_string <name>
        var_type <name>

        match_languages <language codes...>
        force_language_query_string <name>
        var_language <name>

        match_charsets <character sets...>
        force_charset_query_string <name>
        var_charset <name>

        match_encoding <language codes...>
        force_encoding_query_string <name>
        var_encoding <name>
    }
}
  • match_types takes one or more (space-separated) content types (a.k.a. mime types) that are available in this matcher. If the client requests a type (via HTTP's Accept: request header) compatible with one of those, the matcher returns true, if the request specifies types that cannot be satisfied by this list of offered types, the matcher returns false.
  • force_type_query_string allows the client to specify a URL query parameter to override the HTTP Accept: header. (Say you want to download an application/rdf+xml file in the browser. Then the browser's default Accept: header will negotiate for a text/html version of the resource, but by specifying ?format=rdf, you can "manually" request your desired content type.) It works in both ways, i.e. it can cause and prevent a match. In order not to require typing full content types on the URL, there is a list of aliases hardcoded that allows URLs like ...com/test?format=rdf to be treated as equivalent to requesting application/rdf+xml. Suggestions for extending the list are welcome, please open an issue for that.
  • var_type allows you to define a string that, prefixed with conneg_, specifies a variable name that will store the result of the content type negotiation, i.e. the best content type according to the types and weights specified by the client and what is on offer by the server. You can access this variable with {vars.conneg_<name>} in other places of your configuration.
  • All of the above are repeated for languages (requested with the Accept-Language: header), character sets (requested with the Accept-Charset: header), and encodings (which in reality are rather compression methods like zip, deflate, compress etc., requested with the Accept-Encoding: header).
  • Requirements in the same named matcher are AND'ed together. If you want to OR, i.e. match alternatively, just configure multiple named matchers.
  • You must specify at least one of match_types, match_languages, match_charsets, and match_encodings. And when you specify one of the var_* parameters, the corresponding match_ parameter must be defined as well.
  • Wildcards like * and */* should work. If they don't behave as you expect, please open an issue.

A Caddyfile with some combinations for testing is provided with this repository. You can test it with commands like these:

$ curl -H "Accept: application/tei+xml" -H "Accept-Language: fr-FR" https://localhost/test?format=rdf\&lang=de\&enc=br
RDF auf deutsch oder englisch, de preferred!
$ curl -H "Accept: application/tei+xml" -H "Accept-Language: fr-FR" https://localhost/test?format=rdf
RDF en français!
$ curl -H "Accept: application/rdf+xml" -H "Accept-Language: en" https://localhost/test?lang=de
RDF auf deutsch oder englisch, de preferred!
$ curl -H "Accept: application/rdf+xml" -H "Accept-Language: en" https://localhost/test
RDF auf deutsch oder englisch, English / English preferred!
$ curl -H "Accept: application/rdf+xml" -H "Accept-Language: en, de;q=0.8" https://localhost/test
RDF auf deutsch oder englisch, English / English preferred!
$ curl -H "Accept: application/rdf+xml" -H "Accept-Language: de-DE" https://localhost/test
RDF auf deutsch oder englisch, German / Deutsch preferred!
$ curl -H "Accept: application/rdf+xml" https://localhost/test
RDF!
$ curl -H "Accept: text/html" -H "Accept-Language: fr-FR" -H "Accept-Encoding: br" https://localhost/test?format=html\&lang=de
HTML, but brotli-compressed!

Libraries

The plugin relies heavily on elnormous/contenttype and go's own x/text/language libraries. (For the intricacies of language negotiation, you may want to have a glance at the blog post that accompanied the release of go's language library.) The charset and encoding negotiation mechanisms that I have developed for this plugin are somewhat simplistic, by contrast.

Some other content negotiation libraries that I have consulted are mentioned (but not used) in the connegmatcher.go file. I've come across most of them in this go issue.

License

This software is licensed under the Apache License, Version 2.0.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type CharsetOrEncoding

type CharsetOrEncoding struct {
	Value      string
	Parameters Parameters
}

CharsetOrEncoding is s structure to represent charset or encoding with their parameters.

type MatchConneg

type MatchConneg struct {
	// List of content/mime types to match against ([IETF RFC 7231, section 5.3.2](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.2)). Default: Empty list
	MatchTypes []string `json:"match_types,omitempty"`
	// List of language codes to match against ([IETF RFC 7231, section 5.3.5](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.5)). Default: Empty list
	MatchLanguages []string `json:"match_languages,omitempty"`
	// List of character sets to match against ([IETF RFC 7231, section 5.3.3](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.3)). Default: Empty list
	MatchCharsets []string `json:"match_charsets,omitempty"`
	// List of encodings to match against ([IETF RFC 7231, section 5.3.4](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.4)). Default: Empty list
	MatchEncodings []string `json:"match_encodings,omitempty"`
	// Query string parameter key to override content negotiation. Default: ""
	ForceTypeQueryString string `json:"force_type_query_string,omitempty"`
	// Query string parameter key to override language negotiation. Default: ""
	ForceLanguageQueryString string `json:"force_language_query_string,omitempty"`
	// Query string parameter key to override charset negotiation. Default: ""
	ForceCharsetQueryString string `json:"force_charset_query_string,omitempty"`
	// Query string parameter key to override encoding negotiation. Default: ""
	ForceEncodingQueryString string `json:"force_encoding_query_string,omitempty"`
	// Variable name (will be prefixed with `conneg_`) to hold result of content negotiation. Default: ""
	VarType string `json:"var_type,omitempty"`
	// Variable name (will be prefixed with `conneg_`) to hold result of language negotiation. Default: ""
	VarLanguage string `json:"var_language,omitempty"`
	// Variable name (will be prefixed with `conneg_`) to hold result of charset negotiation. Default: ""
	VarCharset string `json:"var_charset,omitempty"`
	// Variable name (will be prefixed with `conneg_`) to hold result of encoding negotiation. Default: ""
	VarEncoding string `json:"var_encoding,omitempty"`

	// the following fields are populated internally/computationally
	MatchTTypes     []contenttype.MediaType `json:"omitempty"`
	MatchTLanguages []language.Tag          `json:"omitempty"`
	MatchTCharsets  []CharsetOrEncoding     `json:"omitempty"`
	MatchTEncodings []CharsetOrEncoding     `json:"omitempty"`
	LanguageMatcher language.Matcher        `json:"omitempty"`
	// contains filtered or unexported fields
}

MatchConneg matches requests by comparing results of a content negotiation process to a (list of) value(s).

Lists of media types, languages, charsets, and encodings to match the request against can be given - and at least one of them MUST be specified.

OPTIONAL parameters are strings for identifying URL query string parameter keys that allow requests to override/skip the connection negotiation process and force a media type, a language, a charset or an encoding.

Some shorthand values for query string parameters translating to full media types (languages, encodings, etc.) are hardcoded in a variable called `aliases`: They presently cover `htm` and `html` for `text/html`, `text` or `txt` for `text/plain`, `rdf` for `application/rdf+xml`, `tei` and `xml` for `application/tei+xml`, and `pdf` for `application/pdf`. For instance, if `force_type_query_string` is set to `format`, a request uri ending in `foo.com?format=tei` will result in content type `application/tei+xml` and then succeed or not, based on whether that content type is listed in `match_types`.

COMPATIBILITY NOTE: This module is still experimental and is not subject to Caddy's compatibility guarantee.

func (MatchConneg) CaddyModule

func (MatchConneg) CaddyModule() caddy.ModuleInfo

CaddyModule returns the Caddy module information.

func (MatchConneg) Match

func (m MatchConneg) Match(r *http.Request) bool

Match returns true if the request matches all requirements.

func (*MatchConneg) Provision

func (m *MatchConneg) Provision(ctx caddy.Context) error

Provision sets up the module.

func (*MatchConneg) UnmarshalCaddyfile

func (m *MatchConneg) UnmarshalCaddyfile(d *caddyfile.Dispenser) error

UnmarshalCaddyfile implements caddyfile.Unmarshaler.

func (MatchConneg) Validate

func (m MatchConneg) Validate() error

Validate validates that the module has a usable config.

type Parameters

type Parameters = map[string]string

Parameters is a map to represent charset or encoding parameters.

Jump to

Keyboard shortcuts

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