Re: p1 7.2.4: retrying requests

Hi Mark,

On Sat, Jun 04, 2011 at 09:06:07AM +1000, Mark Nottingham wrote:
> <http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.2.4>
> 
>    If an HTTP/1.1 client sends a request which includes a request body,
>    but which does not include an Expect header field with the "100-
>    continue" expectation, and if the client is not directly connected to
>    an HTTP/1.1 origin server, and if the client sees the connection
>    close before receiving a status line from the server, the client
>    SHOULD retry the request. 
> 
> So, this basically requires retrying POSTs and other unsafe request methods, under certain conditions (using a proxy OR connected to a 1.0 origin server, AND conn closed before response status).
> 
> However, 7.1.4 <http://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging-14#section-7.1.4> says:
> 
>    This means that clients, servers, and proxies MUST be able to recover
>    from asynchronous close events.  Client software SHOULD reopen the
>    transport connection and retransmit the aborted sequence of requests
>    without user interaction so long as the request sequence is
>    idempotent (see Section 7.1.2 of [Part2]).  Non-idempotent request
>    methods or sequences MUST NOT be automatically retried, although user
>    agents MAY offer a human operator the choice of retrying the
>    request(s).  Confirmation by user-agent software with semantic
>    understanding of the application MAY substitute for user
>    confirmation.  The automatic retry SHOULD NOT be repeated if the
>    second sequence of requests fails.
> 
> where non-idempotent request methods MUST NOT be automatically retried.
> 
> These seem to conflict.  A generous reading would be that 7.2 is a special case of 7.1.4, but if that's the case, it should be explicit (e.g., by placing them in the same section, or explicitly referring to each other in context).
> 
> Personally -- I'm uncomfortable with 7.2, because a) it's pretty complex with all of those conditions, and b) POST is non-idempotent, and the request may have already been processed on the server. 
> 
> I.e., AFAIK we don't have a requirement that the server MUST send a status code at the moment that the resource's state is affected, and the connection may have been closed by an intermediary.
> 
> In my experience, implementations do retry GETs, but not POSTs, and they often use a fresh connection for POSTs (et al) to avoid just this situation. 
> 
> So, I'm inclined to just drop 7.2.4, but maybe I don't know the whole story. Thoughts?

I agree with you. However, this point still leaves open a small hole where
a difficult case still exists : some gateways are using connection pools to
servers and aggregate incoming requests over those existing connections. In
theory those connections never die (in theory...). If a connection dies during
an idempotent request, it's easy to retry it. POSTs are also sent over those
connections, at the risk of loosing them and having to retry them. In my
opinion, adding an "Expect: 100-Continue" header to those requests is enough
to ensure they are sent over a valid connection. But the issue remains when
there is an empty body with the POST, because if we set the Expect header
with the empty body, we'll cause a deadlock (or the server might notice it
and proceed anyway).

So for empty POST requests, we still have no means of testing the connection
before reusing it. Or maybe by using chunked encoding and sending the 0<CRLF>
after 100 is received, provided the server accepts chunked encoded requests ?

In fact, connection pooling becomes so much common nowadays that I think we
should ensure any implementation gets all corner cases right than just saying
they can't replay a POST over a broken connection, because they'll do stupid
or dangerous things to get it working anyway (and if you knew the number of
people I encounter who are amazed that a POST must not be blindly replayed...).

Cheers,
Willy

Received on Saturday, 4 June 2011 05:32:41 UTC