var sys = require('sys');
var http = require('http');
var server = http.createServer(
function(request, response) {
sys.puts(JSON.stringify(request.headers));
}
);
server.listen(8080);
Receives a request from:
var http = require('http');
var client = http.createClient(8080, "localhost");
var request = client.request("POST", "/test", {
"Host": "localhost",
'Content-Type': 'text/plain',
'Content-Length': '4'
});
request.sendBody('test');
request.finish(function() {});
Such that the http.ServerRequest.headers have been lowercased:
{
"host": "localhost",
"content-type": "text/plain",
"content-length": "4",
"connection": "close"
}
Is this behavior correct?
Yes, HTTP specifies header fields to be case-insensitive [1].
Node has taken the pragmatic approach of lowercasing all incoming
headers to ease accessing them.
--fg
[1]: http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
Why not case incoming headers according to the most common
convention,
namely Upper-Dash-Case, e.g.: 'Content-Type', 'Host', 'Content-
Length', etc.
(The Node docs use upper dashcase when referring to the headers
object).
Just a silly idea in the spirit of http://en.wikipedia.org/wiki/Principle_of_least_surprise
Why not case incoming headers according to the most common
convention,
namely Upper-Dash-Case, e.g.: 'Content-Type', 'Host', 'Content-
Length', etc.
Just use a lookup hash:
1. Lowercase incoming header key.
2. Use lookup table to find corresponding "most common" key.
3. If not found, resort to upper dash case.
Pretty sane to me.
Avoids a whole lot of code having to be re-written,
http://github.com/guille/node.websocket.js/ for starters.
One could also suggest that a low-level (and fantastic) Http client
that doesn't handle cookies, gzip, etc. (far more useful in my
opinion) should perhaps let the headers just "pass-through". Albeit in
the name of convenience, the second-order effects of lowercasing cause
more inconvenience.
On Feb 4, 4:26 pm, Dean Landolt <d...@deanlandolt.com> wrote:
And slow.
Sorry if it's causing inconvenience, but I think the current solution
is a good compromise between simplicity & speed. I also think that
explaining your surprise-elimination algorithm, and the exceptions to
the rules, will take longer than just telling people the headers are
lowercased.
--fg
On Feb 4, 3:41 pm, Joran Greef <jorangr...@gmail.com> wrote:
> Principle of least surprise: ETag -> ETag
>
> Just use a lookup hash:
>
> 1. Lowercase incoming header key.
> 2. Use lookup table to find corresponding "most common" key.
> 3. If not found, resort to upper dash case.
>
> Pretty sane to me.
>
> Avoids a whole lot of code having to be re-written,http://github.com/guille/node.websocket.js/for starters.
So if I sent 'content-type' and you were expecting 'Content-Type'? The
case conversion has to happen somewhere for reliable header checks.
The rule is pretty simple.
Almost every piece of literature ever written regarding headers writes
headers case-sensitively. And almost everyone, expects them thus. When
last did you receive a request with a 'conTENT-type' header? Those
that want to cater for that sort of request are already doing /Content-
Type/i. If case conversion has to happen somewhere then the answer is
that it already does. Where it happens is beyond the scope of Node.
Because otherwise, Node will be obliviously lowercasing incoming
headers, only to: 1. break existing code or 2. find that existing code
then does the same thing. The consequences of whether the case
conversion happens or not are beyond the responsibility of Node.
What existing code?
I can't figure out why you're arguing against reliable handling of
something the spec defines as case insensitive and going against best
practices by being strict about what you accept.
Besides that, it would become a major PITA to access headers:
var contentType;
for (var header in req.headers) {
if (header.match(/Content-Type/i) {
contentType = req.headers[header];
break;
}
}
puts(contentType);
instead of:
puts(req.headers['content-type']);
Not much fun.
We could also provide a convenience function that abstracts this logic
away from the user, so they could call:
puts(req.header('Content-Type'));
But that is really overkill for something that is not actually a
problem.
That being said, the function approach may be interesting for headers
with multiple occurrences of the same field, but that's another
problem / discussion.
--fg
On Feb 4, 5:24 pm, Karl Guertin <grayr...@gmail.com> wrote:
The spec is clear, headers are case insensitive. Any proxy along the
way may do with them as he pleases, there is not much point in keeping
the "original" casing.
Besides that, it would become a major PITA to access headers:
var contentType;
for (var header in req.headers) {
if (header.match(/Content-Type/i) {
contentType = req.headers[header];
break;
}
}
puts(contentType);
instead of:
puts(req.headers['content-type']);
Not much fun.
We could also provide a convenience function that abstracts this logic
away from the user, so they could call:
puts(req.header('Content-Type'));
But that is really overkill for something that is not actually a
problem.
That being said, the function approach may be interesting for headers
with multiple occurrences of the same field, but that's another
problem / discussion.
I was excited to see that Node had broken with the legacy of CGI-style
headers. I was disappointed that it had opted to be so helpful in this
regard however (and without mentioning it in the docs).
Almost every piece of literature ever written regarding headers writes
headers case-sensitively.
Then the user has to be aware of what the "most common" (according to who? you?) casing of a particular header name is. This is far worse than just lowercasing everything.
Yeah, talk about the principle of least surprise. As it works now
everything works in the same exact, easily predictable way. Where if
you go another route then you have no idea if a header is common
enough to have another name. Yuck.
Not all of them. The WebSocket draft protocol is strict on header
order, case, and newlines (requires \r\n, see 1.2 of
http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75).
It's fine for a server to be more lenient in what it receives though,
as long as it's strict in how it formats its response. E.g., Go's
WebSocket implementation uses a regular HTTP handler that listens on
the appropriate URL path, checks that the header fields are correct
(to the best of its ability, given the sanitization already applied by
the generic HTTP parts), and then hijacks the TCP socket and sends the
strict header back itself.
I suppose I should go ahead and include a link to the relevant source code:
Not the entire header, but section 1.2 states "[t]he first three lines
in each case are hard-coded (the exact case and order matters)."
I didn't claim WebSockets to be HTTP. :) Just pointing out an
application where header, case, and newlines matter in the HTTP
protocol. Thanks Matthew. As for a hole in the spec, I don't know if
I would call it that. I've worked on WireShark protocol analyzers and
the less slack in a spec the better. And I agree, just feels odd when
you're used to trying to cover everything under the sun.
On Thu, Feb 4, 2010 at 3:49 PM, Tom Robinson <tlrob...@gmail.com> wrote:[SNIP]
> On Feb 4, 2010, at 3:24 PM, Louis Santillan wrote:
>> On Thu, Feb 4, 2010 at 9:05 AM, Dean Landolt <de...@deanlandolt.com> wrote:
>>> Every piece of literature that describes HTTP message headers describes themI didn't claim WebSockets to be HTTP. :) Just pointing out an
>>> as case-insensitive -- to me the fact that the examples typically use
>>> Mixed-Case only reinforces this point, but I can see how
>>> the almost-kinda-usually-consistent casing convention looks more correct. If
>>> you feel that way, or you have code that (incorrectly) assumes a specific
>>> case, you can certainly rewrite the headers with a proxy. Perhaps it would
>>> be a worthwhile feature for node to offer a configurable map for those folks
>>> that really want their headers a specific case on the wire but it's not
>>> strictly necessary.
>>
>> Not all of them. The WebSocket draft protocol is strict on header
>> order, case, and newlines (requires \r\n, see 1.2 of
>> http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75).
>
> WebSocket != HTTP
>
> http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75#page-7
application where header, case, and newlines matter in the HTTP
protocol.
Thanks Matthew. As for a hole in the spec, I don't know if
I would call it that. I've worked on WireShark protocol analyzers and
the less slack in a spec the better.
It doesn't use HTTP as a transport. It just uses a handshake that
looks like HTTP.
> Sure but by using HTTP as a transport you have no control what happens to
> your message on the wire -- so long as its legal within the bounds of HTTP.
Are you talking about HTTP proxy servers? If so, then if they don't
know how to speak all of the WebSocket protocol anyway, then it's
kinda moot whether or not they mangle the HTTP-lookalike handshake,
and possibly even better if they do.
On Fri, Feb 5, 2010 at 7:59 AM, Dean Landolt <de...@deanlandolt.com> wrote:It doesn't use HTTP as a transport. It just uses a handshake that
> There -- that -- you just did it again (conflating WebSockets and HTTP)
> The WebSockets protocol uses HTTP as a transport, but it isn't HTTP.
looks like HTTP.
Are you talking about HTTP proxy servers? If so, then if they don't
> Sure but by using HTTP as a transport you have no control what happens to
> your message on the wire -- so long as its legal within the bounds of HTTP.
know how to speak all of the WebSocket protocol anyway, then it's
kinda moot whether or not they mangle the HTTP-lookalike handshake,
and possibly even better if they do.