cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: HTTP Post with digest

From: Raf Nulens <raf.nulens_at_androme.com>
Date: Thu, 13 Mar 2008 12:36:13 +0100

Daniel Stenberg wrote:
> On Thu, 13 Mar 2008, Raf Nulens wrote:
>
>>> #2 - This site ignores this header and even when I experimented and
>>> had the
>>> code wait for 30 seconds it never sent anything back, but
>>> libcurl had to
>>> continue sending its request-body only to get a 401 back after
>>> it had
>>> completed it.
>>>
>>
>> How do you mean the server never sent anything back? With the fake
>> login/password it is never meant to send a 100 continue... It should
>> respond with a 401 Authorization Required twice...
>
> "should" being the operative word here. It's quite easy to see that this
> is not the case here. This site sends back a 100 Continue immediately,
> even if the user+password is completely made up (as it is in my case of
> course since I have no legitiate user on this site). In fact, this is a
> very common broken way of dealing with 100-continue. It effectively
> takes away the whole point of having it.
>
> This is a silly server/site that does this, it isn't libcurl's fault. It
> can but adapt to the circumstances.

But in my traces i've never seen that server return a 100-continue...

The first header we send (using CURLOPT_POSTFIELDS) looks like this:

POST /ws/1/track/ HTTP/1.1
Host: musicbrainz.org
Accept: */*
Content-Length: 0
Content-Type: application/x-www-form-urlencoded

Server responds with 401

Second header:

POST /ws/1/track/ HTTP/1.1
Authorization: Digest username="doesntmatter_at_example.com",
realm="musicbrainz.org",
nonce="fa87522a9a8ca783ebd634ec209375e41205399036", uri="/ws/1/track/",
response="ecf90cae4325454acf213a7cf9d10c28"
Host: musicbrainz.org
Accept: */*
Content-Length: 11
Content-Type: application/x-www-form-urlencoded

Server responds with 401

this is the way it should work.

>
>> So the 100-continue header is not the issue here, that header should
>> be sent after the authentication succeeded which is never the case
>> with our example (curl_easy_setopt(curl, CURLOPT_URL,
>> "http://musicbrainz.org/ws/1/track/");).
>
> No, the 100-continue header is sent in all posts where we want to let
> the server tell us we're wrong before we proceed with sending the data
> so we include it already in the first POST requests. And it's quite easy
> to see that libcurl does it on this host too, as my example shows.
>
>> Normally libcurl adds the 100-continue automatically when using
>> POSTFIELDS, but disabling this header explicitly ("Expect:") does not
>> alter the libcurl behavior.
>
> Disabling 100-continue will only take away the only means the server
> would have to deny the data to get posted when it hasn't been authorized
> properly. So no, we don't expect removing the header to improve this
> situation.
>

But its not an obligation to use the 100-continue header when using
digest. Libcurl should just wait with sending binary data until the 401
response is received from the server.

And this _does_ work this way when we're using CURLOPT_POSTFIELDS.

>>> So, I don't see how libcurl could do this any differently. Since you
>>> claim a different behavior when you used CURLOPT_POSTFIELDS, did you
>>> actually use the exact same target URL when you did that? Because I
>>> can't see how libcurl can do much different given how the server
>>> responds.
>>
>> We're using the same target URL with the two scenarios.
>
> And you're not seeing the 100-continue with the CURLOPT_POSTFIELDS
> approach?

No 100-continue header sent, no 100-continue received...

>
> Isn't it working fine with POSTFIELDS simply because rewinding the data
> and doing a second post is done internally in this situation and you
> just haven't provided any such callback for the read-callback way of
> posting?
>

It is not a data rewind issue, the data should just not be sent before
the headers are resent after the 401 reponse.

When we enter the Curl_readwrite function (before the 401 response is
received)the value of k->keepon seems to differ. With read_callback is
has value 3: KEEP_READ & KEEP_WRITE.
Therefore it enters: if((k->keepon & KEEP_WRITE) && (select_res &
CSELECT_OUT) ) { (at line 1403)
Then we perform the read-callback (result = Curl_fillreadbuffer(conn,
BUFSIZE, &fillcount);), and with that data we perform Curl_write.

When the POSTFIELDS option has been set k->keepon has value 1: KEEP_READ.
It doesnt enter the if((k->keepon & KEEP_WRITE) && (select_res &
CSELECT_OUT) ) { test and doesnt write data to the socket.
Received on 2008-03-13