cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: NTLM proxy nightmare - POST problem?

From: Jonathan Arnold <jarnold_at_insors.com>
Date: Fri, 09 Mar 2007 17:58:51 -0500

Jonathan Arnold wrote:
> Jonathan Arnold wrote:
>> Daniel Stenberg wrote:
>>> On Thu, 8 Mar 2007, Jonathan Arnold wrote:
>>>
>>>> I've attached the '--trace-ascii' log for the hang. It doesn't show
>>>> much. A POST by curl, followed by a receive of the proxy auth error.
>>>> Then nothing. It's not surprising there's no auth info in the first
>>>> POST, as the key is that I'm doing an 'anyauth', so it first starts
>>>> with nothing and tries to figure it out from there. If it does a
>>>> GET, it works correctly, as you can see from the second log.
>>>
>>> Any chance you can run this with a debugger and see what libcurl is
>>> waiting for at that moment?
>>>
>>> It seems like it doesn't consider itself done with either recving or
>>> sending so it doesn't "act" on the auth stuff and thus just waits for
>>> the recv/send to complete...
>>
>> It is looping in the Transfer routine, waiting for done to be true. The
>> 'keepon' member variable is set to KEEP_WRITE, but it never gets cleared.
>> But for some reason, conn->writesockfd is -1, which doesn't look right at
>> all.
>>
>> I'll keep digging.
>
> More info:
>
> In the Curl_http_auth_act routine, 'perhapsrewind' is called if the request
> isn't either a POST or a HEAD and if pickhost or pickproxy is true (in
> this case,
> pickproxy is true). 'perhapsrewind' sets the conn's rewindaftersend to
> be true,
> even though there is nothing to be sent and thus curl just loops,
> sending nothing
> and receiving nothing.
>
> rewindwaftersend gets set to true because of this peculiar if:
>
> http.c(258):
> if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
> (data->state.authhost.picked == CURLAUTH_NTLM)) {
> if(((expectsend - bytessent) < 2000) ||
> (conn->ntlm.state != NTLMSTATE_NONE)) {
> /* The NTLM-negotiation has started *OR* there is just a little
> (<2K)
> data left to send, keep on sending. */
>
> /* rewind data when completely done sending! */
> if(!conn->bits.authneg)
> conn->bits.rewindaftersend = TRUE;
>
> return CURLE_OK;
> }
>
> And yes, authproxy.picked == CURLAUTH_NTLM. And expectsend == -1,
> because it never
> gets changed from its initial setting (not sure if the HTTPREQ_POST
> should be picking
> up a postfieldsize or not).
>
> I changed the if inside the CURLAUTH_NTLM if to check for a -1
> expectsend, and it gets
> a little further. But now it is looping because after it resends with
> the correct NTLM
> proxy info, it gets a 401, but still thinks it is still negotiating the
> proxy, and not
> now negotiating the http, so it keeps re-authing the proxy. I changed
> the if to be:
>
> if(((expectsend != -1) && (expectsend - bytessent) < 2000) ||
> (conn->ntlm.state != NTLMSTATE_NONE)) {
>

To continue:

It loops because a few lines later, the connection gets closed:

     /* This is not NTLM or NTLM with many bytes left to send: close
      */
     conn->bits.close = TRUE;

And thus begins the NTLM proxy auth, followed by the 401 for the HTTP auth.

As a test, I just took out the '(expectsend == -1) ||' test found in http.c, line
256. This seems to work okay in all cases (NTLM proxy, Basic Proxy and no proxy).
I have no idea why that test is in there, as a -1 expectsend seems to imply there's
nothing to send, yet the if is trying to do sending. I don't really know what it
is trying to do, exactly, but it seems to work.

-- 
Jonathan Arnold           Software Engineer
inSORS Integrated Communications, Inc
jarnold_at_insors.com Office/fax: 781.391.2818
Received on 2007-03-10