1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05:00

known bug #46: chunked-encoded CONNECT responses from a http proxy now works.

Added test case 1008 to verify. Note that #47 is still there.
This commit is contained in:
Daniel Stenberg 2007-10-02 10:21:36 +00:00
parent 8d1239c091
commit 119364741e
9 changed files with 277 additions and 89 deletions

View File

@ -6,6 +6,9 @@
Changelog Changelog
Daniel S (2 October 2007)
- libcurl now handles chunked-encoded CONNECT responses
Daniel S (1 October 2007) Daniel S (1 October 2007)
- Alex Fishman reported a curl_easy_escape() problem that was made the - Alex Fishman reported a curl_easy_escape() problem that was made the
function do wrong on all input bytes that are >= 0x80 (decimal 128) due to a function do wrong on all input bytes that are >= 0x80 (decimal 128) due to a

View File

@ -29,6 +29,7 @@ This release includes the following bugfixes:
before SIZE before SIZE
o re-used handle transfers with SFTP o re-used handle transfers with SFTP
o curl_easy_escape() problem with byte values >= 128 o curl_easy_escape() problem with byte values >= 128
o handles chunked-encoded CONNECT responses
This release includes the following known bugs: This release includes the following known bugs:

View File

@ -7,9 +7,6 @@ may have been fixed since this was written!
to be kept alive, the function will return prematurely and will confuse the to be kept alive, the function will return prematurely and will confuse the
rest of the HTTP protocol code. rest of the HTTP protocol code.
46. If a CONNECT response is chunked-encoded, the function may return
prematurely and will confuse the rest of the HTTP protocol code.
45. libcurl built to support ipv6 uses getaddrinfo() to resolve host names. 45. libcurl built to support ipv6 uses getaddrinfo() to resolve host names.
getaddrinfo() sorts the response list which effectively kills how libcurl getaddrinfo() sorts the response list which effectively kills how libcurl
deals with round-robin DNS entries. All details: deals with round-robin DNS entries. All details:

View File

@ -1143,6 +1143,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
curl_socket_t tunnelsocket = conn->sock[sockindex]; curl_socket_t tunnelsocket = conn->sock[sockindex];
curl_off_t cl=0; curl_off_t cl=0;
bool closeConnection = FALSE; bool closeConnection = FALSE;
bool chunked_encoding = FALSE;
long check; long check;
#define SELECT_OK 0 #define SELECT_OK 0
@ -1203,37 +1204,37 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
data->set.str[STRING_USERAGENT]) data->set.str[STRING_USERAGENT])
useragent = conn->allocptr.uagent; useragent = conn->allocptr.uagent;
/* Send the connect request to the proxy */ /* Send the connect request to the proxy */
/* BLOCKING */ /* BLOCKING */
result = result =
add_bufferf(req_buffer, add_bufferf(req_buffer,
"CONNECT %s:%d HTTP/1.0\r\n" "CONNECT %s:%d HTTP/1.0\r\n"
"%s" /* Host: */ "%s" /* Host: */
"%s" /* Proxy-Authorization */ "%s" /* Proxy-Authorization */
"%s" /* User-Agent */ "%s" /* User-Agent */
"%s", /* Proxy-Connection */ "%s", /* Proxy-Connection */
hostname, remote_port, hostname, remote_port,
host, host,
conn->allocptr.proxyuserpwd? conn->allocptr.proxyuserpwd?
conn->allocptr.proxyuserpwd:"", conn->allocptr.proxyuserpwd:"",
useragent, useragent,
proxyconn); proxyconn);
if(host && *host) if(host && *host)
free(host); free(host);
if(CURLE_OK == result) if(CURLE_OK == result)
result = add_custom_headers(conn, req_buffer); result = add_custom_headers(conn, req_buffer);
if(CURLE_OK == result) if(CURLE_OK == result)
/* CRLF terminate the request */ /* CRLF terminate the request */
result = add_bufferf(req_buffer, "\r\n"); result = add_bufferf(req_buffer, "\r\n");
if(CURLE_OK == result) { if(CURLE_OK == result) {
/* Now send off the request */ /* Now send off the request */
result = add_buffer_send(req_buffer, conn, result = add_buffer_send(req_buffer, conn,
&data->info.request_size, 0, sockindex); &data->info.request_size, 0, sockindex);
} }
req_buffer = NULL; req_buffer = NULL;
if(result) if(result)
failf(data, "Failed sending CONNECT to proxy"); failf(data, "Failed sending CONNECT to proxy");
@ -1340,13 +1341,33 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
nread += gotbytes; nread += gotbytes;
if(keepon > TRUE) { if(keepon > TRUE) {
/* This means we are currently ignoring a response-body, so we /* This means we are currently ignoring a response-body */
simply count down our counter and make sure to break out of if(cl) {
the loop when we're done! */ /* A Content-Length based body: simply count down the counter
cl -= gotbytes; and make sure to break out of the loop when we're done! */
if(cl<=0) { cl -= gotbytes;
keepon = FALSE; if(cl<=0) {
break; keepon = FALSE;
break;
}
}
else {
/* chunked-encoded body, so we need to do the chunked dance
properly to know when the end of the body is reached */
CHUNKcode r;
ssize_t tookcareof=0;
/* now parse the chunked piece of data so that we can
properly tell when the stream ends */
r = Curl_httpchunk_read(conn, ptr, gotbytes, &tookcareof);
if(r == CHUNKE_STOP) {
/* we're done reading chunks! */
infof(data, "chunk reading DONE\n");
keepon = FALSE;
}
else
infof(data, "Read %d bytes of chunk, continue\n",
tookcareof);
} }
} }
else else
@ -1366,7 +1387,8 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
if(data->set.include_header) if(data->set.include_header)
writetype |= CLIENTWRITE_BODY; writetype |= CLIENTWRITE_BODY;
result = Curl_client_write(conn, writetype, line_start, perline); result = Curl_client_write(conn, writetype, line_start,
perline);
if(result) if(result)
return result; return result;
@ -1377,19 +1399,60 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
if(('\r' == line_start[0]) || if(('\r' == line_start[0]) ||
('\n' == line_start[0])) { ('\n' == line_start[0])) {
/* end of response-headers from the proxy */ /* end of response-headers from the proxy */
if(cl && (407 == k->httpcode) && if((407 == k->httpcode) && !data->state.authproblem) {
!data->state.authproblem) {
/* If we get a 407 response code with content length /* If we get a 407 response code with content length
* when we have no auth problem, we must ignore the when we have no auth problem, we must ignore the
* whole response-body */ whole response-body */
keepon = 2; keepon = 2;
infof(data, "Ignore %" FORMAT_OFF_T
" bytes of response-body\n", cl); if(cl) {
cl -= (gotbytes - i);/* remove the remaining chunk of
what we already read */ infof(data, "Ignore %" FORMAT_OFF_T
if(cl<=0) " bytes of response-body\n", cl);
/* if the whole thing was already read, we are done! */ /* remove the remaining chunk of what we already
read */
cl -= (gotbytes - i);
if(cl<=0)
/* if the whole thing was already read, we are done!
*/
keepon=FALSE;
}
else if(chunked_encoding) {
CHUNKcode r;
/* We set ignorebody true here since the chunked
decoder function will acknowledge that. Pay
attention so that this is cleared again when this
function returns! */
k->ignorebody = TRUE;
infof(data, "%d bytes of chunk left\n", gotbytes-i);
if(line_start[1] == '\n') {
/* this can only be a LF if the letter at index 0
was a CR */
line_start++;
i++;
}
/* now parse the chunked piece of data so that we can
properly tell when the stream ends */
r = Curl_httpchunk_read(conn, line_start+1,
gotbytes -i, &gotbytes);
if(r == CHUNKE_STOP) {
/* we're done reading chunks! */
infof(data, "chunk reading DONE\n");
keepon = FALSE;
}
else
infof(data, "Read %d bytes of chunk, continue\n",
gotbytes);
}
else {
/* without content-length or chunked encoding, we
can't keep the connection alive since the close is
the end signal so we bail out at once instead */
keepon=FALSE; keepon=FALSE;
}
} }
else else
keepon = FALSE; keepon = FALSE;
@ -1415,6 +1478,13 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
else if(Curl_compareheader(line_start, else if(Curl_compareheader(line_start,
"Connection:", "close")) "Connection:", "close"))
closeConnection = TRUE; closeConnection = TRUE;
else if(Curl_compareheader(line_start,
"Transfer-Encoding:", "chunked")) {
infof(data, "CONNECT responded chunked\n");
chunked_encoding = TRUE;
/* init our chunky engine */
Curl_httpchunk_init(conn);
}
else if(Curl_compareheader(line_start, else if(Curl_compareheader(line_start,
"Proxy-Connection:", "close")) "Proxy-Connection:", "close"))
closeConnection = TRUE; closeConnection = TRUE;
@ -1472,6 +1542,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
data->state.authproxy.done = TRUE; data->state.authproxy.done = TRUE;
infof (data, "Proxy replied OK to CONNECT request\n"); infof (data, "Proxy replied OK to CONNECT request\n");
k->ignorebody = FALSE; /* put it (back) to non-ignore state */
return CURLE_OK; return CURLE_OK;
} }

View File

@ -84,7 +84,7 @@
void Curl_httpchunk_init(struct connectdata *conn) void Curl_httpchunk_init(struct connectdata *conn)
{ {
struct Curl_chunker *chunk = &conn->data->reqdata.proto.http->chunk; struct Curl_chunker *chunk = &conn->chunk;
chunk->hexindex=0; /* start at 0 */ chunk->hexindex=0; /* start at 0 */
chunk->dataleft=0; /* no data left yet! */ chunk->dataleft=0; /* no data left yet! */
chunk->state = CHUNK_HEX; /* we get hex first! */ chunk->state = CHUNK_HEX; /* we get hex first! */
@ -108,7 +108,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
{ {
CURLcode result=CURLE_OK; CURLcode result=CURLE_OK;
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
struct Curl_chunker *ch = &data->reqdata.proto.http->chunk; struct Curl_chunker *ch = &conn->chunk;
struct Curl_transfer_keeper *k = &data->reqdata.keep; struct Curl_transfer_keeper *k = &data->reqdata.keep;
size_t piece; size_t piece;
size_t length = (size_t)datalen; size_t length = (size_t)datalen;
@ -124,11 +124,11 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
while(length) { while(length) {
switch(ch->state) { switch(ch->state) {
case CHUNK_HEX: case CHUNK_HEX:
/* Check for an ASCII hex digit. /* Check for an ASCII hex digit.
We avoid the use of isxdigit to accommodate non-ASCII hosts. */ We avoid the use of isxdigit to accommodate non-ASCII hosts. */
if((*datap >= 0x30 && *datap <= 0x39) /* 0-9 */ if((*datap >= 0x30 && *datap <= 0x39) /* 0-9 */
|| (*datap >= 0x41 && *datap <= 0x46) /* A-F */ || (*datap >= 0x41 && *datap <= 0x46) /* A-F */
|| (*datap >= 0x61 && *datap <= 0x66)) { /* a-f */ || (*datap >= 0x61 && *datap <= 0x66)) { /* a-f */
if(ch->hexindex < MAXNUM_SIZE) { if(ch->hexindex < MAXNUM_SIZE) {
ch->hexbuffer[ch->hexindex] = *datap; ch->hexbuffer[ch->hexindex] = *datap;
datap++; datap++;
@ -218,39 +218,39 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
switch (conn->data->set.http_ce_skip? switch (conn->data->set.http_ce_skip?
IDENTITY : data->reqdata.keep.content_encoding) { IDENTITY : data->reqdata.keep.content_encoding) {
case IDENTITY: case IDENTITY:
#endif #endif
if(!k->ignorebody) { if(!k->ignorebody) {
if ( !data->set.http_te_skip ) if ( !data->set.http_te_skip )
result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
piece); piece);
else else
result = CURLE_OK; result = CURLE_OK;
} }
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
break; break;
case DEFLATE: case DEFLATE:
/* update data->reqdata.keep.str to point to the chunk data. */ /* update data->reqdata.keep.str to point to the chunk data. */
data->reqdata.keep.str = datap; data->reqdata.keep.str = datap;
result = Curl_unencode_deflate_write(conn, &data->reqdata.keep, result = Curl_unencode_deflate_write(conn, &data->reqdata.keep,
(ssize_t)piece); (ssize_t)piece);
break; break;
case GZIP: case GZIP:
/* update data->reqdata.keep.str to point to the chunk data. */ /* update data->reqdata.keep.str to point to the chunk data. */
data->reqdata.keep.str = datap; data->reqdata.keep.str = datap;
result = Curl_unencode_gzip_write(conn, &data->reqdata.keep, result = Curl_unencode_gzip_write(conn, &data->reqdata.keep,
(ssize_t)piece); (ssize_t)piece);
break; break;
case COMPRESS: case COMPRESS:
default: default:
failf (conn->data, failf (conn->data,
"Unrecognized content encoding type. " "Unrecognized content encoding type. "
"libcurl understands `identity', `deflate' and `gzip' " "libcurl understands `identity', `deflate' and `gzip' "
"content encodings."); "content encodings.");
return CHUNKE_BAD_ENCODING; return CHUNKE_BAD_ENCODING;
} }
#endif #endif
@ -319,7 +319,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
else { else {
datap++; datap++;
length--; length--;
} }
break; break;
case CHUNK_TRAILER_CR: case CHUNK_TRAILER_CR:
@ -403,7 +403,6 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
return CHUNKE_BAD_CHUNK; return CHUNKE_BAD_CHUNK;
} }
default: default:
return CHUNKE_STATE_ERROR; return CHUNKE_STATE_ERROR;
} }

View File

@ -1262,7 +1262,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
We DO care about this data if we are pipelining. We DO care about this data if we are pipelining.
Push it back to be read on the next pass. */ Push it back to be read on the next pass. */
dataleft = data->reqdata.proto.http->chunk.dataleft; dataleft = conn->chunk.dataleft;
if (dataleft != 0) { if (dataleft != 0) {
infof(conn->data, "Leftovers after chunking. " infof(conn->data, "Leftovers after chunking. "
" Rewinding %d bytes\n",dataleft); " Rewinding %d bytes\n",dataleft);
@ -1617,7 +1617,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
} }
else if(!(conn->bits.no_body) && else if(!(conn->bits.no_body) &&
conn->bits.chunk && conn->bits.chunk &&
(data->reqdata.proto.http->chunk.state != CHUNK_STOP)) { (conn->chunk.state != CHUNK_STOP)) {
/* /*
* In chunked mode, return an error if the connection is closed prior to * In chunked mode, return an error if the connection is closed prior to
* the empty (terminiating) chunk is read. * the empty (terminiating) chunk is read.

View File

@ -296,7 +296,6 @@ struct HTTP {
/* For FORM posting */ /* For FORM posting */
struct Form form; struct Form form;
struct Curl_chunker chunk;
struct back { struct back {
curl_read_callback fread_func; /* backup storage for fread pointer */ curl_read_callback fread_func; /* backup storage for fread pointer */
@ -818,6 +817,11 @@ struct connectdata {
connection is used! */ connection is used! */
struct SessionHandle *data; struct SessionHandle *data;
/* chunk is for HTTP chunked encoding, but is in the general connectdata
struct only because we can do just about any protocol through a HTTP proxy
and a HTTP proxy may in fact respond using chunked encoding */
struct Curl_chunker chunk;
bool inuse; /* This is a marker for the connection cache logic. If this is bool inuse; /* This is a marker for the connection cache logic. If this is
TRUE this handle is being used by an easy handle and cannot TRUE this handle is being used by an easy handle and cannot
be used by any other easy handle without careful be used by any other easy handle without careful

View File

@ -44,7 +44,8 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
test409 test613 test614 test700 test701 test702 test704 test705 test703 \ test409 test613 test614 test700 test701 test702 test704 test705 test703 \
test706 test707 test350 test351 test352 test353 test289 test540 test354 \ test706 test707 test350 test351 test352 test353 test289 test540 test354 \
test231 test1000 test1001 test1002 test1003 test1004 test1005 test1006 \ test231 test1000 test1001 test1002 test1003 test1004 test1005 test1006 \
test615 test1007 test541 test1010 test1011 test1012 test542 test543 test536 test615 test1007 test541 test1010 test1011 test1012 test542 test543 \
test536 test1008
filecheck: filecheck:
@mkdir test-place; \ @mkdir test-place; \

112
tests/data/test1008 Normal file
View File

@ -0,0 +1,112 @@
<testcase>
# Server-side
<reply>
# this is returned first since we get no proxy-auth
<data1001>
HTTP/1.1 407 Authorization Required to proxy me my dear
Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA==
Transfer-Encoding: chunked
20
And you should ignore this data.
FA0
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0
</data1001>
# This is supposed to be returned when the server gets the second
# Authorization: NTLM line passed-in from the client
<data1002>
HTTP/1.1 200 Things are fine in proxy land
Server: Microsoft-IIS/5.0
Content-Type: text/html; charset=iso-8859-1
</data1002>
# this is returned when we get a GET!
<data2>
HTTP/1.1 200 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT
Content-Length: 7
Connection: close
Content-Type: text/html
Funny-head: yesyes
daniel
</data2>
# then this is returned when we get proxy-auth
<data1000>
HTTP/1.1 200 OK swsbounce
Server: no
Nice proxy auth sir!
</data1000>
<datacheck>
HTTP/1.1 407 Authorization Required to proxy me my dear
Proxy-Authenticate: NTLM TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA==
Transfer-Encoding: chunked
HTTP/1.1 200 Things are fine in proxy land
Server: Microsoft-IIS/5.0
Content-Type: text/html; charset=iso-8859-1
HTTP/1.1 200 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT
Content-Length: 7
Connection: close
Content-Type: text/html
Funny-head: yesyes
daniel
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
<features>
NTLM
</features>
<name>
HTTP proxy CONNECT auth NTLM with chunked-encoded 407 response
</name>
<command>
http://test.remote.server.com:1008/path/10080002 --proxy http://%HOSTIP:%HTTPPORT --proxy-user silly:person --proxy-ntlm --proxytunnel
</command>
</client>
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent: curl/.*
</strip>
# We strip off a large chunk of the type-2 NTLM message since it depends on
# the local host name and thus differs on different machines!
<strippart>
s/^(Proxy-Authorization: NTLM TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAAAAAAAAABwAAAABQAFAHAAAAA).*/$1/
</strippart>
<protocol>
CONNECT test.remote.server.com:1008 HTTP/1.0
Host: test.remote.server.com:1008
Proxy-Authorization: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAAAAAAAAAA=
Proxy-Connection: Keep-Alive
CONNECT test.remote.server.com:1008 HTTP/1.0
Host: test.remote.server.com:1008
Proxy-Authorization: NTLM TlRMTVNTUAADAAAAGAAYAEAAAAAYABgAWAAAAAAAAABwAAAABQAFAHAAAAA
Proxy-Connection: Keep-Alive
GET /path/10080002 HTTP/1.1
User-Agent: curl/7.12.3-CVS (i686-pc-linux-gnu) libcurl/7.12.3-CVS OpenSSL/0.9.6b zlib/1.1.4
Host: test.remote.server.com:1008
Accept: */*
</protocol>
</verify>
</testcase>