Balancing what's acceptable with what's possible
Content Negotiation
Preliminaries
This note describes how browsers and servers proclaim their ability to handle different file formats, allowing the browser to request and receive only files that it is able to understand.
Browser capabilities evolve over time, with the deprecation of old file formats and the introduction of new file formats. Servers learn about these changes through the accept-type
header which the browser sends with each request. If the server has a file in a format that is acceptable to the browser, it responds with a content-type
header. When an acceptable type is not available, the server responds with status code 406
.
By way of example, some versions of Internet Explorer used to send request headers that included the value image/x-windows-bmp
, Microsoft Paint's bitmap file format. On the other hand, some newer versions of Chrome have begun sending headers that include image/webp
, Google's new WebP file format.
In this exchange of information, file formats are identified using media-types, also known as MIME types or content-types. These are described in IETF RFC 6838 Media Type Specifications and Registration Procedures.
Browsers can properly read and render many different file types, depending on the context of the request. When an anchor tag is clicked, a request might include an accept-type like text/html,
indicating to the server that it can handle HTML, XHTML, XML or anything else. Alternatively, when an image tag is encountered, a request might include an accept-type like image/webp,
indicating that it can handle WebP, animated PNG, or any other image type. Or, when a link tag referencing an external stylesheet is encountered, a request might include an accept-type like text/css,
indicating preference for a CSS file, but fallback acceptance of any file type.
Configuration
The server side of this negotiation is configured using the accept-types
configuration section, which comprises a list of mime-type
entries, each entry specifying a single RFC 6838 media type.
Each MIME type is composed of a media type and a subtype. Media types include: text
, application
, image
, audio
, video
and multipart
. Subtypes include values like: html
, javascript
, jpeg
, mp3
, mp4
and so forth.
When configuring the server, an asterisk may be used for the subtype, to indicate that any file format defined under that media type can be served. For example, a value of text/*
could be configured to indicate that all requests having an accept-type
with a media type of text
will be honored; this would include the wide variety of file formats including: text/html
, text/plain
, text/css
, etc.
The special configuration value '*/*'
may also be used (as the last entry in the list) to indicate that any file type will be served.
When preparing a response, the server decides whether to respond with a status code of 200
or 406
using this pattern:
Request Header | Server Configuration | Status Code |
---|---|---|
image/webp |
image/webp |
200 |
image/* |
image/webp |
200 |
*/* |
image/webp |
200 |
image/webp |
image/* |
200 |
image/webp |
*/* |
200 |
image/webp |
--- |
406 |
Placement
The accept-types
configuration section may appear in either the server
section or a host
section. When values occur in both the server
and host
sections, they are merged according to the standard rules defined for the merge
attribute.
Information Headers
When a user-agent's request cannot be fulfilled because there is no acceptable type configured, the standard HTTP status code 406
is returned together with a rw-no-acceptable-type
header providing additional information.
EBNF
SP | ::= | U+20 |
CR | ::= | U+0D |
SOLIDUS | ::= | U+2F |
ASTERISK | ::= | U+2A |
LEFT-CURLY-BRACKET | ::= | U+7B |
RIGHT-CURLY-BRACKET | ::= | U+7D |
media-type | ::= | 'text' | 'application' | 'image' | 'audio' | 'video' | 'multipart' |
subtype | ::= | (ALPHA | DIGIT | †)* |
MIME-type | ::= | (media-type | ASTERISK) SOLIDUS (subtype | ASTERISK) |
mime-type-entry | ::= | 'mime-type' SP MIME-type CR |
accept-types-section | ::= | 'accept-types' SP LEFT-CURLY-BRACKET CR mime-type-entry* RIGHT-CURLY-BRACKET CR |
† See section 4.2 of RFC 6838 for exact rules
Cookbook
Example 1: All types are acceptable
server {
accept-types {
mime-type '*/*'
}
}
(Note that the special value '*/*'
must be enclosed in single or double quotes so that the parser does not misinterpret the sequence as a comment opening tag.)
Example 2: All text and image types are acceptable
server {
accept-types {
mime-type text/*
mime-type image/*
}
}
Example 3: Selected text and image types are acceptable
server {
accept-types {
mime-type text/html
mime-type text/plain
mime-type text/css
mime-type image/png
mime-type image/jpeg
mime-type image/gif
mime-type image/svg+xml
mime-type image/webp
}
}
Example 4: A comprehensive configuration
server {
accept-types {
mime-type text/html
mime-type text/plain
mime-type text/css
mime-type application/xhtml+xml
mime-type application/xml
mime-type application/json
mime-type application/javascript
mime-type application/pdf
mime-type image/png
mime-type image/jpeg
mime-type image/gif
mime-type image/svg+xml
mime-type image/webp
mime-type audio/webm
mime-type audio/ogg
mime-type audio/mpeg
mime-type audio/wav
mime-type audio/flac
mime-type video/webm
mime-type video/ogg
mime-type video/mp4
}
}
Review
Key points to remember:
- The server will respond with status code
200
for any request whoseaccept-type
matches a configured mime-type, either exactly or through wildcards. - The server will respond with status code
406
andrw-no-acceptable-type
information header for requests that do not match any configured mime-type.