curl-library
connection reuse, NTLM, multi-interface
Date: Thu, 04 Mar 2004 10:26:32 -0500
When using the multi-interface and trying to connect to a
server using NTLM using CURLAUTH_ANY (not CURLAUTH_NTLM),
there appears to be a race condition on a socket reuse.
There are three requests sent:
1. unauthenticated request, returns 401 with a "Connection: close".
2. NTLM request sent, server replies with a challenge
3. NTLM response sent, server sends the data
In between steps 1 and 2, I am encountering periodic failures where
the library tries to re-use the connection. I can fix the problem
by changing adding "check->bits.close" to the test on line 1461 of url.c
(7.11.0 or 1476 of the 20040226 snapshot),
making it:
if(match) {
bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
* if(check->bits.close || dead) {
(ie, the connection is dead if we know that the server will close the
connection or if the connection is already dead).
This is almost definitely not the right way to fix the problem. Has
it been fixed in someway for the normal (non-multi) interface? Running
the same thing with the curl executable always seems to handle the
situation correctly (as does my example code if I use curl_easy_perform
instead of the multi interface).
I have a windows machine that uses NTLM authentication. I've obviously
blanked out my username and password. Otherwise, the following code
when compiled with either 7.11.0 or 20040226 snapshot fails periodically
on the second request.
The trace of a verbose output for a failing request is:
* About to connect() to 192.168.0.3 port 80
* Connected to (192.168.0.3) port 80
> GET /localstart.asp HTTP/1.1
Host: 192.168.0.3
Pragma: no-cache
Accept: */*
Accept-Encoding: deflate, gzip
< HTTP/1.1 401 Access Denied
< Server: Microsoft-IIS/5.1
< Date: Thu, 26 Feb 2004 21:10:44 GMT
< WWW-Authenticate: Negotiate
< WWW-Authenticate: NTLM
< WWW-Authenticate: Basic realm="VIVISIMO"
< Connection: close
< Content-Length: 4431
< Content-Type: text/html
* Issue another request to this URL: 'http://192.168.0.3/localstart.asp'
* Re-using existing connection! (#0)
* Connected to (192.168.0.3) port 80
* Server auth using NTLM with user 'crpalmer'
> GET /localstart.asp HTTP/1.1
Authorization: NTLM TlRMTVNTUAABAAAAAgIAAAAAAAAgAAAAAAAAACAAAAA=
Host: 192.168.0.3
Pragma: no-cache
Accept: */*
Accept-Encoding: deflate, gzip
* Connection #0 left intact
and the source code that I'm using to test this is:
#include <stdio.h>
#include <stdlib.h>
#include "curl/curl.h"
int use_easy = 0;
int
main(int argc, char **argv)
{
CURL *c;
if (argc > 1) use_easy = 1;
curl_global_init(CURL_GLOBAL_ALL);
c = curl_easy_init();
curl_easy_setopt(c, CURLOPT_ENCODING, "");
curl_easy_setopt(c, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_easy_setopt(c, CURLOPT_USERPWD, "****:****");
curl_easy_setopt(c, CURLOPT_URL, "http://192.168.0.3/localstart.asp");
curl_easy_setopt(c, CURLOPT_VERBOSE, 1);
if (use_easy) {
curl_easy_perform(c);
} else {
CURLM *m = curl_multi_init();
fd_set rd, wr, exc;
CURLMcode res;
int running;
int max_fd;
res = curl_multi_add_handle(m, c);
for (;;) {
while (res == CURLM_CALL_MULTI_PERFORM) {
res = curl_multi_perform(m, &running);
if (running <= 0) {
fprintf(stderr, "nothing left running.\n");
exit(1);
}
}
if (res != CURLM_OK) {
fprintf(stderr, "not okay???\n");
exit(2);
}
FD_ZERO(&rd);
FD_ZERO(&wr);
FD_ZERO(&exc);
max_fd = 0;
if (curl_multi_fdset(m, &rd, &wr, &exc, &max_fd) != CURLM_OK) {
fprintf(stderr, "unexpected failured of fdset.\n");
exit(3);
}
select(max_fd+1, &rd, &wr, &exc, NULL);
res = CURLM_CALL_MULTI_PERFORM;
}
}
}
Cheers,
Chris.
-- Christopher R. Palmer palmer_at_vivisimo.com Chief Technology Officer www.vivisimo.com Vivisimo, Inc. 412-422-2499Received on 2004-03-04