cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: PUT/POST with Auth Done Right(?)

From: Jamie Lokier <jamie_at_shareable.org>
Date: Tue, 9 Nov 2004 00:25:38 +0000

Daniel Stenberg wrote:
> I am really not happy with the way RFC2616 forces us to behave.

Understandable, but I don't see any alternative that could have been
written into RFC2616 and still be compatible with old HTTP.

> o If a 100 response is received or the wait for one times out, start sending
> the request-body.
>
> o If a 401 (or 407 when talking through a proxy) is received, then:
>
> if we provided credentials in our request (alas, this is the first pass in
> the auth phase) and this is NTLM, we continue sending the whole
> request-body

This case does not occur with IIS 5.0, so is there any point coding it?

Did you see David's packet trace from IIS 5.0? It doesn't send 100
Continue _and_ it doesn't send 401 _until_ it has received the whole
large request body.

Therefore this case did not occur in the IIS 5.0 tests.

If they've improved the server, this might occur with IIS 6.0. That's
why I asked for a packet trace with that.

You might like to code this condition just because it's a sensible
thing to do, but it is not clear you will ever see it in reality.

Finally, if the server sends Connection: close (see David's traces)
then that should override this NTLM test. You should fall through to the
next case if the server sends Connection: close.

> if not, we close the connection at once (if we have more data to send that
> is, otherwise we keep it open)

Agreed: this is a good strategy.

A better strategy is to close the connection at once _except_ when we
know the request body is quite small. Small requests are very common,
and it's a net loss to break a connection for the sake of a few
hundred bytes.

> o When sending a PUT/POST request (that hasn't a negotiated auth) after a
> 401/407 response, we know that it will be rejected and thus we claim
> Content-Length zero. (This seems to be what IE does.)

Bad. (Unless you meant "after a 401/407 with NTLM auth type").

You should only do this if the negotiation is NTLM (or any other MS
type that depends on connections in the same way).

It is very wrong to do it with real RFC2616 HTTP servers that use
other auth types. You could send an incorrect POST or PUT request
with an unwanted side effect, such as creating a zero-length file or
submitting the wrong values to a form).

Well implemented HTTP servers implementing other auth types will send
401 without waiting, so the send-twice problem doesn't occur with
them. So there is no need for a special hack with them.

> o The last step in the auth phase (the second request in Digest and
> Negotiate, and the third in NTLM) then sends a full and proper
> PUT/POST request (again) with the proper Content-Length and a
> following request-body.

Agreed.

A minor thing: isn't it the third in Negotiate too?

> It would probably make sense to somehow make this instruction
> using the read callback. It will be troublesome for some apps to
> deal with a rewind like this. I'm thinking for example when using
> 'curl' to upload data from stdin...

You'll also have to warn authors that the input may not be all read
the first time (due to the early close).

By the way, what will you do if the server returns 401/407 to _this_
request? Couldn't that happen if a proxy demands authentication and
then the server does as well? Couldn't it even happen more times, if
several proxies demand authentication?

> o The approach used until now, that issues a HEAD on the given URL to
> trigger
> the auth negotiation could still be supported and encouraged, but it would
> be up to the app to first fetch a URL with GET/HEAD to negotiate on, since
> then a following PUT/POST wouldn't need to negotiate authentication and
> thus avoid double-sending data.
>
> Optionally, we keep the current approach if some option is set, since it
> seems to work fairly well for POST on most servers.

I know real servers where that will fail with PUT. My own is one of them.

A fairly standard Apache configuration requires basic or digest
authentication for PUT but none for GET/HEAD on the same URL. It's a
classic way of making public websites that an author can update with
standard web editing tools like "Netscape" and "Dreamweaver" :)

I expect it's fine with POST in most cases, but not fine by design.

It would be great if IIS 6 does the right thing and sends 401/407
immediately: then you can just tell people who don't like the
send-twice bandwidth wastage to upgrade IIS.

> o If told explicitly to use i.e NTLM when doing a POST/PUT, libcurl could
> immediately go the Content-Length: 0 bytes route to avoid the first send
> all data phase. (Unless it already passed the authentication phase.)
>
> Good? Bad? Flaws?

Your plan is good except for the flaws :)

I don't see any fundamental problems, just minor things to get right,
and I think I have described them all.

-- Jamie
Received on 2004-11-09