Subject: 1xx response semantics

From: Mark Nottingham <[email-masked]>
Date: Tue, 5 Jul 2011 09:41:59 +1000

One (of many) of the issues with 1xx responses is that people don't know how to surface two responses to one request in APIs and tools. 

I think we could make things a bit easier for folks if we stated that the headers in a 1xx response are semantically not significant; i.e., it's OK for APIs, etc. to drop them on the floor, because the only information is in the status code.

This would mean that people shouldn't put headers on a 1xx response and expect applications to see them -- which I think is already the case today.

Thoughts? 

--
Mark Nottingham   http://www.mnot.net/

---

From: Bjoern Hoehrmann <[email-masked]>
Date: Tue, 05 Jul 2011 01:50:57 +0200

* Mark Nottingham wrote:
>One (of many) of the issues with 1xx responses is that people don't know
>how to surface two responses to one request in APIs and tools. 
>
>I think we could make things a bit easier for folks if we stated that
>the headers in a 1xx response are semantically not significant; i.e.,
>it's OK for APIs, etc. to drop them on the floor, because the only
>information is in the status code.
>
>This would mean that people shouldn't put headers on a 1xx response and
>expect applications to see them -- which I think is already the case
>today.

The WebSocket protocol as currently proposed makes use of headers in the
101 Switching Protocols response and I suspect "Sec-WebSocket-Protocol"
will end up with the application somehow, but I haven't looked lately. I
also note that with protocol switches, you don't get two responses, just
the one and after that it's no longer HTTP, so maybe they can be special
under such a rule.
-- 
Björn Höhrmann · mailto:[email-masked] · http://bjoern.hoehrmann.de
Am Badedeich 7 · Telefon: +49(0)160/4415681 · http://www.bjoernsworld.de
25899 Dagebüll · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 5 Jul 2011 07:14:01 +0200

Hi Mark,

> This would mean that people shouldn't put headers on a 1xx response and expect applications to see them -- which I think is already the case today.

It's not exact because of 101 which should contain at least Upgrade and
Connection: Upgrade. In fact, 101 is a final status while 100 is an
intermediate one.

Maybe we should indicate that "headers are not significant on intermediate
responses such as 1xx, and are only meaningful on final responses such as
all other ones, including 101" ?

Willy

---

From: Amos Jeffries <[email-masked]>
Date: Tue, 05 Jul 2011 17:51:37 +1200

>> This would mean that people shouldn't put headers on a 1xx response and expect applications to see them -- which I think is already the case today.

Yes. HTTP/1.0 middleware will completely drop 1xx responses in certain 
situations. HTTP/1.1 obeying the rules of passing on things it does not 
understand should usually relay, but since it is not spec'd as required 
behaviour may also drop.

FWIW: Squid will treat headers attached to a 100 the same as any 2xx 
when relaying.

> all other ones, including 101" ?

Its always puzzled me why Upgrade got 101 while CONNECT gets 200. They 
are not that dissimilar.

AYJ

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Tue, 05 Jul 2011 06:13:03 +0000

In message <[email-masked]>, Willy Tarreau writes:

>In fact, 101 is a final status while 100 is an intermediate one.

That has always bugged, me: I think 101 should have been a 2xx or 3xx
response.

Maybe simply acknowleding rather than generalizing from this mistake
is the best idea ?

-- 
Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
[email-masked]         | TCP/IP since RFC 956
FreeBSD committer       | BSD since 4.3-tahoe    
Never attribute to malice what can adequately be explained by incompetence.

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 5 Jul 2011 08:51:11 +0200

> Its always puzzled me why Upgrade got 101 while CONNECT gets 200. They 

I perfectly agree with you on this, the issue is that it's been spec'd
like this and we have to live with it (as with a lot of special cases
for many other things).

Regards,
Willy

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 5 Jul 2011 08:53:39 +0200

> Maybe simply acknowleding rather than generalizing from this mistake

Maybe, how would you proceed then ? I think that describing what can
be an intermediate response and what can be a final one removes any
complicated case. After all, saying that 101 is an exception to 1xx
is not much different from saying that 204 is an exception to 2xx in
that it does not hold any body.

Willy

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Tue, 05 Jul 2011 07:17:22 +0000

>After all, saying that 101 is an exception to 1xx

Explaining that it is in the wrong group would make the overall scheme
clearer and hopefully deter similar additions in the future.

---

From: Julian Reschke <[email-masked]>
Date: Tue, 05 Jul 2011 09:41:33 +0200

On 2011-07-05 01:41, Mark Nottingham wrote:
> ...

This is news to me. Where does the spec say that right now?

Note that the status code 102 defined in RFC 2518 used the "status-uri" 
header code, and I believe something similar was proposed for the 
"progress" status code discussed over here not so long ago.

Best regards, Julian

---

From: Adrien de Croy <[email-masked]>
Date: Tue, 05 Jul 2011 19:54:10 +1200

yes, the status proposal used a header and multiple 1xx responses (last 
iteration was 103 I think - it's been a while).

On 5/07/2011 7:41 p.m., Julian Reschke wrote:
>> One (of many) of the issues with 1xx responses is that people don't 
>> know how to surface two responses to one request in APIs and tools.
>>
>> This would mean that people shouldn't put headers on a 1xx response 
>> and expect applications to see them -- which I think is already the 
>> case today.
>>
>> Thoughts?
>> ...
>
> Note that the status code 102 defined in RFC 2518 used the 
> "status-uri" header code, and I believe something similar was proposed 
> for the "progress" status code discussed over here not so long ago.
>
> Best regards, Julian
>
>
>

-- 
Adrien de Croy - WinGate Proxy Server - http://www.wingate.com

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 5 Jul 2011 10:25:21 +0200

> This is news to me. Where does the spec say that right now?

Strange, I too was sure it was the case but I failed to find that now.
RFC2616 only said "There are no required headers for this class of
status code."

I wonder whether we would have discussed this in the past concerning the
meaning of headers sent with an interim 1xx response, for the final response.

Maybe we should refine the indications so that it's more clear that any
header may only have a meaning for the progress status and that it must
not affect the final response ?

Willy

---

From: Willy Tarreau <[email-masked]>
Date: Tue, 5 Jul 2011 10:26:40 +0200

> clearer and hopefully deter similar additions in the future.

It could be an idea. Maybe we could express it slightly differently though,
in order not to confuse too much the rare people who read specs. Something
saying that 101 is always the last HTTP response.

Willy

---

From: Joe Orton <[email-masked]>
Date: Tue, 5 Jul 2011 17:41:48 +0100

> Connection: Upgrade. In fact, 101 is a final status while 100 is an

That is not true, the client must wait for the final response on the 
upgraded connection.

Regards, Joe

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Tue, 05 Jul 2011 16:50:35 +0000

>That is not true, the client must wait for the final response on the 

As far as HTTP is concerned it is final, we have no idea what the
upgraded protocol is or what semantics it might have.

---

From: "Roy T. Fielding" <[email-masked]>
Date: Tue, 5 Jul 2011 11:37:08 -0700

> Maybe simply acknowleding rather than generalizing from this mistake

Oh, for crying out loud.

101 is an interim response.  The first response in the new protocol
after an Upgrade is the response to the first request.  If I send an
Upgrade to waka on an HTTP GET request, the waka server will respond
with 101 in HTTP and then the equivalent of a 200 response in waka.
There is no second request.  That's the whole point in including a
zero-latency bootstrap upgrade within HTTP.

....Roy

---

From: Brian Pane <[email-masked]>
Date: Tue, 5 Jul 2011 12:25:43 -0700

> zero-latency bootstrap upgrade within HTTP.

Speaking of the 101/Upgrade mechanism... it seems fundamentally
incompatible with request pipelining. If the first request in a
pipeline indicates a willingness to upgrade to some non-HTTP protocol,
and the server decides to switch to that other protocol upon receipt
of the first request, the subsequent requests already in the pipeline
may very well be syntactically invalid in the newly chosen protocol.

Should the HTTP/1.1 spec thus prohibit the use of the Upgrade header
in pipelined requests, or is the issue too obvious to document
explicitly?

-Brian

---

From: Bjoern Hoehrmann <[email-masked]>
Date: Tue, 05 Jul 2011 21:35:35 +0200

>in pipelined requests, or is the issue too obvious to document

In http://lists.w3.org/Archives/Public/ietf-http-wg/2010JulSep/0293.html
I mentioned this, I'm not sure if we track this under some issue number.
-- 
Björn Höhrmann · mailto:[email-masked] · http://bjoern.hoehrmann.de
Am Badedeich 7 · Telefon: +49(0)160/4415681 · http://www.bjoernsworld.de
25899 Dagebüll · PGP Pub. KeyID: 0xA4357E78 · http://www.websitedev.de/

---

From: "Roy T. Fielding" <[email-masked]>
Date: Tue, 5 Jul 2011 12:39:12 -0700

> how to surface two responses to one request in APIs and tools. 

For the most part, there is no reason to surface them.  The only tools
that would are the command-line tools, which typically have a --verbose mode.

> information is in the status code.

They are significant.  I don't understand why anyone would think they
are not significant -- the fields are the only way to carry information
in the interim response other than the status code.

> expect applications to see them -- which I think is already the case

No, it is not the case today.  There just isn't a large scale need for
the 1xx response handling to be implemented *today* in mainstream apps.
They can be ignored by any client that isn't deliberately choosing to
use them for upgrade or continue.   I have not seen much use for the
1xx progress indicator, partly because of the chicken-and-egg problem
with browsers.  Those applications do not ignore the header fields.
And we have no idea what 1xx codes will be introduced in the future.

....Roy

---

From: "Roy T. Fielding" <[email-masked]>
Date: Tue, 5 Jul 2011 12:43:50 -0700

On Jul 5, 2011, at 12:25 PM, Brian Pane wrote:
> incompatible with request pipelining.

Generally speaking, it is unwise to pipeline the very first request
series with a new server (at least until you get the first response
code and headers back indicating that the connection is persistent).

....Roy

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Tue, 05 Jul 2011 20:40:19 +0000

>in pipelined requests, or is the issue too obvious to document

I have always read the text such that after a 101 response you
no longer run HTTP, and it follows pretty obviously there from,
that you cannot pipeline anything near an upgrade, which by
definition must be a synchronous and synchronizing operation.

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Jul 2011 00:52:28 +0200

> upgraded protocol is or what semantics it might have.

Agreed, and I'd also add that seeing nothing else might very well be a
valid final response for the upgraded protocol.

Willy

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Jul 2011 01:01:05 +0200

> definition must be a synchronous and synchronizing operation.

In fact we should be more precise on this in order to allow future
websocket implementations to save one round trip. We should state
that whatever is sent after the request will be handled by the
next protocol, whether it's the upgraded protocol (in case of success)
or HTTP (in case of upgrade failure).

Right now a client has to wait for a 101 before daring send anything
and I don't think that's an unsolvable situation.

Willy

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Jul 2011 01:03:51 +0200

> zero-latency bootstrap upgrade within HTTP.

OK for seeing it like this, but from an HTTP point of view it's final,
as there is no HTTP after the Upgrade. The server's response might
very well be that it's waiting for the client to send its request
(eg: TLS upgrade).

You way of describing it is very interesting in my opinion, because it
could be the solution to explain in the spec why it's in the 1xx codes
and why it's still final for HTTP.

Willy

---

From: Mark Nottingham <[email-masked]>
Date: Wed, 6 Jul 2011 10:19:40 +1000

> This is news to me. Where does the spec say that right now?

It doesn't. However, I've seen several implementations that don't expose the headers of a 1xx response, and there's also been a discussion of how to integrate 1xx into SPDY as something other than another full response with headers.

> Note that the status code 102 defined in RFC 2518 used the "status-uri" header code, and I believe something similar was proposed for the "progress" status code discussed over here not so long ago.

Ah. The 101 Switching Protocols approach isn't too much of a concern (if someone has the ability to get another protocol supported by a client, they can get access to as much of the response as they need), but I'd forgotten about Status-URI.

> in the interim response other than the status code.

They're significant to the specific semantics of the status code, but what I was trying to say was that someone shouldn't define a new header and expect to be able to grab it off of, for example, a 100 response.

What do people think about adding text to the "Considerations for New Headers" section stating that headers may not be available on 1xx responses in some implementations?

Regards,

---

From: Brian Pane <[email-masked]>
Date: Tue, 5 Jul 2011 17:30:18 -0700

> code and headers back indicating that the connection is persistent).

That's orthogonal to the pipelining-vs-Upgrade incompatibility,
though.  It doesn't matter whether the request in which the client
sends an Upgrade header is the first request on a connection or the
Nth; it's the presence of HTTP requests in the pipeline after that
particular request that's the problem.

As a tangential issue, I'm curious: what's the rationale for
recommending against pipelining the first series of requests on a new
connection in the general case?  When I look at it from a performance
perspective, optimistically pipelining seems like a quite reasonable
tradeoff.  Consider the common case of a client that has just
determined it needs to GET several small resources from a site to
which it doesn't already have any connection:

In an aggressive implementation, the client opens the connection and
immediately sends all the requests in a pipeline.  In the best-case
scenario, where the server allows the persistent connection, the total
elapsed time is 2xRTT.  In the worst-case scenario, where the server
doesn't allow the persistent connection, the client must resubmit each
of the lost requests on a separate connection; if it establishes those
connections in parallel, the total elapsed time is 4xRTT.

In a conservative implementation, the client opens the connection,
sends the first request, and waits for the response before deciding
whether to pipeline the rest.  In the best-case scenario, the total
elapsed time is 3xRTT.  In the worst-case scenario, where the server
doesn't allow the persistent connection, the total elapsed time is
4xRTT.

Thus the aggressive implementation performs 1xRTT faster in the best
case.  Yes, it wastes upstream bandwidth in the worst case, because it
ends up sending all but one of the requests twice.  But for a typical
web browser issuing a series of GETs, upstream bandwidth is an
abundant resource and network round trips are expensive, so I'd rather
spend bandwidth less efficiently in the worst case to save on round
trips in the best case.

-Brian

---

From: Julian Reschke <[email-masked]>
Date: Wed, 06 Jul 2011 02:43:23 +0200

> What do people think about adding text to the "Considerations for New Headers" section stating that headers may not be available on 1xx responses in some implementations?

Do you have an example of an implementation that *does* expose 1xx 
responses, but not the headers on them?

Best regards, Julian

---

From: Amos Jeffries <[email-masked]>
Date: Wed, 06 Jul 2011 13:36:09 +1200

On Tue, 5 Jul 2011 17:30:18 -0700, Brian Pane wrote:
 <snip>
> spend bandwidth less efficiently in the worst case to save on round

 Please have some consideration for those of us who still live with ADSL 
 and satellite connections (or heaven forbid, 56K). Where upstream 
 bandwidth is the overall limiting bottlneck.

 AYJ

---

From: "Roy T. Fielding" <[email-masked]>
Date: Tue, 5 Jul 2011 18:39:22 -0700

> particular request that's the problem.

True, but the only case I cared to design for was the one where
a new (incompatible) version of HTTP is being introduced using
existing http identifiers.  For that case, we always send Upgrade
on the first request and we always want the server to respond
in one round trip.  Keep in mind that this was designed in 1995,
when httpNG was still a goal.

> which it doesn't already have any connection:

The problem is that if the server does not want to support persistent
connections, then sending a lot more data than the server is willing
to consume is likely to result in a TCP RST which may cancel the buffer
before the client has finished reading the first response.  Apache's
lingering close is only going to help with that some of the time.

> connections in parallel, the total elapsed time is 4xRTT.

The worst case is that both ends get confused and the entire sequence
has to be started over after a fairly long timeout.

> doesn't allow the persistent connection, the total elapsed time is

Yes, but the normal request profile is to request one page and then
parse it for a bunch of embedded requests (images, stylesheets, etc.).
In other words, when accessing a server for the first time, the client
is usually going to wait for the first response anyway.  After that
first time, the client can remember how the server responded and
make a reasonable estimate of what it can do with pipelining for
later pages.  Even if the resources are partitioned across multiple
servers, there is very little gained by pushing multiple requests
down the pipe right away because the connection is going to be stuck
on slow start anyway.

> spend bandwidth less efficiently in the worst case to save on round

Reasonable people will disagree.  Try convincing Jim Gettys that it
won't have an effect on network buffers. ;-)

....Roy

---

From: Brian Pane <[email-masked]>
Date: Tue, 5 Jul 2011 22:01:53 -0700

On Tuesday, July 5, 2011, Roy T. Fielding <[email-masked]> wrote:

> later pages.

Ah, it looks like I'm working from a different base assumption than
you are.  In my normal request profile, all of the images,
stylesheets, etc. are fetched from a different server than the initial
page request (well, different scheme:host:port, anyway, and it usually
resolves to a different IP address).  With the widespread adoption of
CDNs and cookie-free domains, it's rare these days that I'll encounter
a nontrivial website that uses the same base URL for static content as
for the initial page.  Thus any insight that the client gains from the
first server's handling of the initial page request can't be applied
to the separate connection(s) needed for the subsequent requests.

> Even if the resources are partitioned across multiple

At present, with implementations commonly defaulting to an initial
congestion window of 1 MSS, it's still possible to send multiple
requests as long as their total size fits in a single packet.  And on
the server side, the conventional wisdom seems to point toward the use
of a much larger initial congestion window nowadays.

Thus I think it would be beneficial for a client to begin pipelining
requests immediately upon opening a connection.  The big challenge is
that, as you rightly noted,

-Brian

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Jul 2011 07:14:40 +0200

On Wed, Jul 06, 2011 at 02:43:23AM +0200, Julian Reschke wrote:
> >What do people think about adding text to the "Considerations for New 
> >Headers" section stating that headers may not be available on 1xx 
> >responses in some implementations?
> >...
> 

Julian, I think I understand what Mark means. It's not much a matter
of exposing either the header or the status, but to see how the header
will be used. For instance, if you send a "connection: close" on a 100
response, it will be ignored by most implementations. If you send
"Transfer-encoding: chunked", it should (hopefully) be ignored. If some
implementations were to consider such headers, they could adopt a wrong
behaviour.

I remember in early versions of haproxy when I didn't even know about
1xx responses. Haproxy is able to add a set-cookie header in responses
to perform cookie-based persistence. A customer reported that it failed
on one of their service, where I noticed a lot of 100 responses. The
browsers didn't learn the cookie on the 100 so my set-cookie was ignored.
Fortunately, two weeks ago I had discovered the 100 status and already
had a fix for that. But this is an example of how headers on 1xx might
be ignored or at least not be considered as one would think they should
be.

Regards,
Willy

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Jul 2011 07:30:58 +0200

> lingering close is only going to help with that some of the time.

Indeed that's still an issue with most TCP stacks, but even if the server
supports persistent connections, nothing prevents it from closing after
any response. Some servers close after any error for instance, so in the
end, the same risk exists all the time with pipelining.

(...)
> down the pipe right away because the connection is going to be stuck

At a customer's (3G provider) we wanted to "fill the pipe" as much as
we could in both directions. We always observed significant holes that
were not caused by the slow start because we already had a sufficient
initial CWND. I tried hard to force them to test with pipelining, they
accepted to test. We never gained anything precisely because of this
first non-pipelined request. The most efficient solution always was to
use many hosts for the servers. In practice, browsers establish many
connections to the servers and fetch requests from these connections.
when you have between 2 and 5 objects to fetch over a given connection,
the browser will still fetch the first one alone then up to 4 others.
This long pause between the first one and the subsequent ones really
was hurting performance.

What's sad was that the next hop was a transparent proxy which did
support pipelining and persistent connections. But even when declared
as an explicit proxy, browsers wouldn't let us pipeline from the first
request. I think something is missing there, as there are scenarii
where there's little or no risk to pipeline and browsers should accept
to pipeline first if configured for such (typically with a proxy, or
when config says always to do so).

> won't have an effect on network buffers. ;-)

I agree with you Roy that I disagree with Brian :-)  Our upstream bandwidth
was limited too and in the end, by opening many connections to workaround
the lack of pipelining, we were saturating it with far too many SYN-SYN/ACK-ACK
and FIN-FIN-ACK sequences.

The result is that we could never find a satisfying setting. We always had
to trade-off between saturating upstream with TCP and leaving huge holes due
to pipelining. I was a bit frustrated, I admit.

Regards,
Willy

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Wed, 06 Jul 2011 06:55:00 +0000

>or HTTP (in case of upgrade failure).

1. That is not necessary to write, it follows directly from how
   TCP works underneath.

2. It unnecessarily constrains the design of the protocols we could
   upgrade to:  Relying on HTTP to choke on the wrong protocol is
   bad, but permissible behaviour.

---

From: Julian Reschke <[email-masked]>
Date: Wed, 06 Jul 2011 09:41:21 +0200

> implementations were to consider such headers, they could adopt a wrong

Still not convinced. Maybe it's worth noting that 100 is really a very 
special kind of 1xx, and coming to conclusions about what other 1xx 
codes can do based on what happens with 100 is not going to work?

Best regards, Julian

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Jul 2011 10:09:36 +0200

> codes can do based on what happens with 100 is not going to work?

That would be one solution, but the issue we have with 100 is that any
unknown 1xx should be processed as 100, so it's hard to define it as the
special case.

Willy

---

From: Julian Reschke <[email-masked]>
Date: Wed, 06 Jul 2011 10:23:13 +0200

> unknown 1xx should be processed as 100, so it's hard to define it as the

Actually, I meant to say 101, not 100.

Using 100 as fallback behavior is ok.

So can we agree on a statement like:

	"Many frameworks do not report header fields received with an 1xx 
status message back to the application, although they should. Thus it 
may be hard to introduce new 1xx status codes that depend on additional 
header fields to report information."

?

---

From: Willy Tarreau <[email-masked]>
Date: Wed, 6 Jul 2011 10:28:34 +0200

> header fields to report information."

I don't precisely see it that way. Roy gave an example of a header that
made sense for an interim response. Shouldn't we instead state that headers
sent with interim responses will not affect the final response and may be
ignored by a number of intermediaries or UAs ?

Willy

---

From: Julian Reschke <[email-masked]>
Date: Wed, 06 Jul 2011 10:30:55 +0200

> ignored by a number of intermediaries or UAs ?

That is true, and we could state that.

So Mark -- what made you start this thread? What's the problem you think 
we need to fix?

---

From: Joe Orton <[email-masked]>
Date: Wed, 6 Jul 2011 11:00:19 +0100

> very well be that it's waiting for the client to send its request

RFC2817 section 3.3, last para:

   Once the TLS handshake completes successfully, the server MUST
   continue with the response to the original request. Any TLS handshake
   failure MUST lead to disconnection, per the TLS error alert
   specification.

---

From: Mark Nottingham <[email-masked]>
Date: Thu, 7 Jul 2011 11:52:52 +1000

On 06/07/2011, at 6:30 PM, Julian Reschke wrote:

[...]

> So Mark -- what made you start this thread? What's the problem you think we need to fix?

I was hoping that we could simplify things for implementers, future API designers, extension authors, etc.

It's pretty clear that this isn't so simple. I'm concerned that any advice we could give would be so vague as to be useless. 

Part of me wonders whether it would be useful to say something specific about 100 Continue responses and the relationship of their headers to the final response's, but that also feels like a rathole.

If someone has a suggestion for specific text that concretely improves things, great, but otherwise, we should probably move on to more productive discussions.

Cheers,