I have been reading up on the HTTP/1.1 headers and in some of the sample headers in section 14.1 (Accept) they use accept-extensions (I believe that is what they are) called level=1, level=2, etc.
The problem I am having is that they use these level=X things as if it should be obvious what they do. Is the document just poor at explaining it or am I missing something?
Thanks.
...A Couple Years Later
The user TomWardrop points out that (from comments to this answer):
It use to be part of the text/html media type specification to indicate what version of HTML you wanted, but is wasn't used much (if at all), so it was dropped. Refer to ietf.org/rfc/rfc2854.txt.
Excerpt from the RFC:
Note that [HTML20] included an optional "level" parameter; in
practice, this parameter was never used and has been removed from
this specification. [HTML30] also suggested a "version"
parameter; in practice, this parameter also was never used and has
been removed from this specification.
This appears to be the best answer so far.
I am leaving the original answer below for posterity.
Summary
It appears from looking through RFC-2616 (Request For Comments) over at IETF and W3C, as well as websites elsewhere on the internet, that the level extension is not very well documented or explained. It also does not appear to be in use in headers by anyone, suggesting that it can probably be ignored.
The RFCs
In the RFCs the level parameter is seen in a few examples, but it is never mentioned or clearly expressed exactly what role it plays.
level is used in an example about precedence:
Media ranges can be overridden by more specific media ranges or
specific media types. If more than one media range applies to a given
type, the most specific reference has precedence. For example,
Accept: text/*, text/html, text/html;level=1, */*
have the following precedence:
1) text/html;level=1
2) text/html
3) text/*
4) */*
Source: IEFT RFC-2616 p.100 and W3C RFC2616 section "14.1 Accept"
Seeing the difference between how the types are ordered in the two examples, it looks like text/html;level=1 has greater precedence than text/html, meaning that the level extension must give it that precedence. The last two are obviously ordered further, according to declining specificity.
Now this brings up the quality factor, q. It is explained quite well in the RFCs. It can be anything between 0 and 1. The bigger the value the more precedence the type has. The RFC has an example using both q and level:
The media type quality factor associated with a given type is
determined by finding the media range with the highest precedence
which matches that type. For example,
Accept: text/*;q=0.3, text/html;q=0.7, text/html;level=1,
text/html;level=2;q=0.4, */*;q=0.5
would cause the following values to be associated:
text/html;level=1 = 1
text/html = 0.7
text/plain = 0.3
image/jpeg = 0.5
text/html;level=2 = 0.4
text/html;level=3 = 0.7
Source: IEFT RFC-2616 p.100 and W3C RFC2616 section "14.1 Accept"
From this it appears that level's value is used in decreasing precedence (1 has highest precedence, 2 second highest, etc.). That makes sense, but when taken together with the Accept: header it makes no sense at all:
First, the q parameters have magically disappeared from the types, in the associations (below). It is like the author assumed that it is obvious why they have been omitted, but forgot to tell us why it is obvious.
Second, the types in the Accept: header, and the types shown in the associations (below), are not the same types. E.g the image/jpeg type is never mentioned in the header, and the text/* type is missing from the associations.
I am at a loss to explain what it all means.
Zend Framework Discussion
On an answer to a question asking about the level parameter there is some interesting stuff.
q and level compliment each other
[...] The q-factor is the one most looked at. However, you can also specify a "level", and these CAN also act like priorities, but operate in the order of decreasing precedence (i.e., level 1 is higher priority than level 2). The examples they have in the spec are contrived, and, tbh, confusing at best [...]
The q parameter is what you should use, and the level parameter can be used. Okay, but it still does not clear up exactly what it does, and how it is supposed to affect the priorities of types.
Used for supported type/spec version
Another documented use case for the "level" is to indicate the _version_ of the type. As an example, a "level 1" might indicate the first version of that spec available. In such cases, it wouldn't be a priority, but instead a _descriptor_ [...]
So, a way of indicating what version of the type is supported. Now, this actually makes more sense:
text/html;level=5;q=1
text/html;level=4.01;q=0.9
; Etc.
Somehow I doubt level was supposed to be used for this, however. If it was then it would probably have been called something more descriptive, such as version, or simply v (like q).
Conflicting meanings
Unfortunately, the "level" selector has conflicting meanings, so I'm not 100% sure we should support it by default; "q", on the other hand, is well documented.
Yeah. Conflicting meanings and not very well documented. The level property has very little going for it.
Other stuff I found
Looking for questions/answers elsewhere on the Internet I found:
A seriously old-school document that does not mention level at all. It actually mentions two other ones, mxs and mxb.
A Moz Dev page listing common Accept headers from various browsers. Nowhere is level used. In fact, I have never seen it used outside the RFCs.
Conclusion
In conclusion I think it is safe to say that level is a waste of time. It is poorly documented, not used much in practice (if used at all), and it is more confusing than it is worth.
"level" is just an example for a media type parameter. It's not involved in computing the preference.
(The relevant spec nowadays is http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p2-semantics-26.html#header.accept)
Expanding on Julian Reschke's correct answer a little. The answer mentions "media type parameter" which comes directly from the specification:
Accept = #( media-range [ accept-params ] )
media-range = ( "*/*" / ( type "/" "*" ) / ( type "/" subtype )) *( OWS ";" OWS parameter )
accept-params = weight *( accept-ext )
accept-ext = OWS ";" OWS token [ "=" ( token / quoted-string ) ]
Where parameter is defined as:
parameter = token "=" ( token / quoted-string )
That is, a name/value pair (see token). So, in the examples, "level=1" is just an example of a legal "parameter". In that sense, there's nothing really special about it. If you take the time to parse the Backus-Naur of the definition, you'll see that, in all of the examples, the "level=x" must be a media-type parameter.
With regard to why the example specifically uses "level", I think the "level" in the HTTP spec examples refers to HTML levels. In all of the examples, level modifies the text/html media type. The best definition I've found for HTML levels is:
"There are four official levels [0-4], or versions of HTML conformance. Each encompasses a set of tags and higher levels include tags from all those below it."
http://scholar.lib.vt.edu/reports/soasis-slides/slide4.html
I.e., a request could use Accept to ask for a lower level of HTML if it wanted a subset of HTML elements/attributes. As an example, HTML level 0 defines the DOCTYPE element, but does not define the "Version" attribute until level 3; so that HTML levels 0-2 would/should not contain a Version attribute in a <!DOCTYPE> declaration.
http://www.december.com/html/spec/level0.html
http://www.december.com/html/spec/level3.html
"level" seems like an old aspect/feature of HTML. I can find very few references to it, none of them are clear (e.g., is there a difference between HTML level and major version?), and most of those I can find are old. However, the latest Apache httpd server docs still say they support "level" in content negotiation, and suggest that it may be synonymous with version, at least in that implementation:
"4. Select the variants with the highest 'level' media parameter (used to give the version of text/html media types)."
Note that the IANA registry doesn't mention anything about "level" as a text/html parameter. If nothing else, that says to me: "don't use it."
Interestingly, the DOM specification still uses the word "level".
http://www.w3.org/TR/DOM-Level-2-HTML/
http://www.w3.org/TR/DOM-Level-3-Core/
etc..
Related
Recently I read something about HTTP header format, I think I found some rule about it, but I cannot confirm it.
for example:
Some-Header:Foo;x=foo_attr,Bar;y=bar_attr\r\n
Foo and Bar are the list items of Some-Header, x is the attribute of Foo, y is the attribute of Bar, right?
If it is right, "," should be the delimiter of header items, and ";" should be the delimiter of the attributes of header item.
Unfortunately, how a HTTP header should be parsed depends on the header. You can't really look at a header and make assumptions about the structural format, because the format differs on a per-header basis.
What can be said is that for almost all HTTP headers, the comma represents multiple values your example is identical to:
Some-Header:Foo;x=foo_attr
Some-Header:Bar;y=bar_attr
However, there are exceptions to this rule. You can't for example do the same thing with the Set-Cookie header. Set-Cookie is the only exception I can recall from the top of my head though. (there might be more).
But aside from that, it's basically up to you. If you're defining Some-Headers then you need to tell implementors how to parse it.
There currently an effort to come up a standard way to describe structures in headers. You can read the current draft here:
draft-ietf-httpbis-header-structure
For example, if for whatever stupid reason I configured my server to parse the URL by splitting the queries by the "^" symbol (escaped if necessary) and the "-" symbol instead of the "?" and "&", would I run into any trouble at all apart from a confused user?
Will the browser/HTTP request sent treat it differently in a way that may be detrimental to my up and coming "power minus" business?
? is not arbitrary but defined in the URI RFC section 3.4 Query, I dont' think you can change that.
The Query component internal syntax (how name=value couples are encoded) is not defined by the URI RFC, separators can be defined by other specifications:
& is defined as separator of the application/x-www-form-urlencoded content type by HTML Spec. You may change this aspect supporting for example ; as separator, but you would have in any case to support & for when processing the request produced by an HTML FORM.
Should the following URLs be considered functionally equivalent?
http://example.com/foo?a=&b=
http://example.com/foo?a&b
This came about when a user of a Drupal module I wrote which parses apart and then rewrites URIs noticed that the code sometimes causes the query string parts to change in unexpected ways due to how some of the underlying PHP functions behave. For example:
parse_str("a&b", $values); print http_build_query($values);
a=&b=
Is this something I should bother worrying about?
Edit so SO stops complaining that this question is similar to another one: The question is whether it's safe to assume that "no value for X" and "empty value for X" are equivalent, not whether the "no value" style is syntactically correct (which it is).
RFC 3986 Uniform Resource Identifier (URI): Generic Syntax doesn't have anything to say about the structure of the query string aside from how characters like ? should be dealt with. So strictly speaking, your two example URLs are different. Of course, the application which receives those query strings may treat them as functionally equivalent, but this isn't something you can determine from the URL alone.
As per RFC6570 empty query parameters are allowed. Please refer to section 3.2.9
Example Template Expansion
{&x,y,empty} &x=1024&y=768&empty=
Is this a valid http url
http://www.example.com?x&y
or
we must always have = sign for parameters.
http://www.example.com?x1=x&x2=y
Well, it works, and the W3C recommendations are extremely general -- only the use of ? and + are defined. So I think from the perspective of HTTP/HTML the = is optional. It's use is obviously a common convention and many client & server libraries use it, but there doesn't seem to be any reason you couldn't define a service to work on some other scheme.
Anecdotally, I like to leave out the =blah part when I'm using the query string as a flag as in http://www.example.com?logout
Reference: http://www.w3.org/Addressing/URL/4_URI_Recommentations.html
According to the ABNF in Appendix A of RFC 3986, both examples above are valid URL.
Note that if you read only the Wikipedia article on Query string, you might get the false impression that the second ne is the only valid one.
I am having trouble on finding authoritative information about the behavior with HTTP GET query string duplicate fields, like
http://example.com/page?field=foo&field=bar
and in particular if the order is kept or not. Most web-oriented languages produce an array containing both foo and bar associated to a key "field", but I would like to know if authoritative statement exist (e.g. on a RFC) about this point. RFC 3986 has a section 3.4. Query, which refers to key=value pairs, but nothing is said on how to interpret order and duplicate fields and so on. This makes sense, since it's backend dependent, and not in the scope of that RFC...
Although a de-facto standard exists, I'd like to see an authoritative source for it, just out of curiosity.
There is no spec on this. You may do what you like.
Typical approaches include: first-given, last-given, array-of-all, string-join-with-comma-of-all.
Suppose the raw request is:
GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com
Then there are various options for what request.query['tag'] should yield, depending on the language or the framework:
request.query['tag'] => 'ruby'
request.query['tag'] => 'rails'
request.query['tag'] => ['ruby', 'rails']
request.query['tag'] => 'ruby,rails'
The situation seems to have changed since this question was asked and the accepted answer was written 12 years ago. I believe we now have an authoritative source: The WHATWG URL Standard describes the process of extracting and parsing a query string in detail in section 6.2 (https://url.spec.whatwg.org/#interface-urlsearchparams) and section 5.1 on x-www-form-urlencoded parsing (https://url.spec.whatwg.org/#urlencoded-parsing). The parsing output is "an initially empty list of name-value tuples where both name and value hold a string", where a list is defined as a finite ordered sequence, and the key-value pairs are added to this list in the order they appear in the URL. At first there is no mention of repeated keys, but some methods on the URLSearchParams class in section 6.2 (https://url.spec.whatwg.org/#interface-urlsearchparams) set clear expectations on ordering: "The getAll(name) method steps are to return the values of all name-value pairs whose name is name... in list order"; The sort() method specifies that "The relative order between name-value pairs with equal names must be preserved." (Emphasis mine). Examining the Github issue referenced in the commit where the sort method was added, we see that the original proposal was to sort on values where keys were identical, but this was changed: "The reason for the default sort not affecting the value order is that ordering of the values can be significant. We should not assume that it's ok to move the order of the values around." (https://github.com/whatwg/url/issues/26#issuecomment-271600764)
I can confirm that for PHP (at least in version 4.4.4 and newer) it works like this:
GET /blog/posts?tag=ruby&tag=rails HTTP/1.1
Host: example.com
results in:
request.query['tag'] => 'rails'
But
GET /blog/posts?tag[]=ruby&tag[]=rails HTTP/1.1
Host: example.com
results in:
request.query['tag'] => ['ruby', 'rails']
This behavior is the same for GET and POST data.
yfeldblum's answer is perfect.
Just a note about a fifth behavior I noticed recently: on Windows Phone, opening an application with an uri with a duplicate query key will result in NavigationFailed with:
System.ArgumentException: An item with the same key had already been added.
The culprit is System.Windows.Navigation.UriParsingHelper.InternalUriParseQueryStringToDictionary(Uri uri, Boolean decodeResults).
So the system won't even let you handle it the way you want, it will forbid it. You are left with the only solution to choose your own format (CSV, JSON, XML, ...) and uri-escape-it.
Most (all?) of the frameworks offer no guarantees, so assume they will be returned in random order.
Always take the safest approach.
For example, java HttpServlet interface:
ServletRequest.html#getParameterValues
Even the getParameterMap method leaves out any mention about parameter order (the order of a java.util.Map iterator cannot be relied on either.)
Typically, duplicate parameter values like
http://example.com/page?field=foo&field=bar
result in a single queryString parameter that is an array:
field[0]=='foo'
field[1]=='bar'
I've seen this behavior in ASP, ASP.NET and PHP4.
The ?array[]=value1&array[]=value2 approach is certainly a very popular one.
supported by most Javascript frameworks
supported by Java Spring
supported by PHP