New authentication code added, particularly noticable when doing POST or PUT

with Digest or NTLM. libcurl will now use HEAD to negotiate the authentication
and when done perform the requested POST.
This commit is contained in:
Daniel Stenberg 2004-04-06 15:14:10 +00:00
parent f617c1131a
commit 8ed44e8dfb
13 changed files with 459 additions and 47 deletions

39
CHANGES
View File

@ -7,6 +7,45 @@
Changelog
Daniel (6 April 2004)
- Gisle Vanem's fixed bug #927979 reported by Nathan O'Sullivan. The problem
made libcurl on Windows leak a small amount of memory in each name resolve
when not used as a DLL.
- New authentication code added, particularly noticable when doing POST or PUT
with Digest or NTLM. libcurl will now use HEAD to negotiate the
authentication and when done perform the requested POST. Previously libcurl
sent POST immediately and expected the server to reply a final status code
with an error and then libcurl would not send the request-body but instead
send then next request in the sequence.
The reason for this change is due to IIS6 barfing on libcurl when we attempt
to POST with NTLM authentication. The reason for the problems is found in
RFC2616 section 8.2.3 regarding how servers should deal with the 100
continue request-header:
If it responds with a final status code, it MAY close the transport
connection or it MAY continue to read and discard the rest of the
request.
Previous versions of IIS clearly did close the connection in this case,
while this newer version decided it should "read and discard". That would've
forced us to send the whole POST (or PUT) data only to have it discarded and
then be forced to send it again. To avoid that huge penality, we switch to
using HEAD until we are authenticated and then send the POST.
The only actual drawback I can think of (except for the odd sites that might
treat HEAD differently than they would treat POST/PUT when given the same
URL) is that if you do POST with CURLAUTH_ANY set and the site requires NO
authentication, libcurl will still use a HEAD in a first round and then do a
POST.
If you do a HEAD or a GET on a site using CURLAUTH_ANY, libcurl will send
an un-authenticated request at once, which then is the only request if the
site requires no auth.
Alan Pinstein helped me work out the protocol details by figuring out why
libcurl failed and what IIS6 expects.
- The --limit-rate logic was corrected and now it works a lot better for
higher speeds, such as '10m' or similar. Reported in bug report #930249.

View File

@ -13,6 +13,9 @@ This release includes the following changes:
This release includes the following bugfixes:
o fixed minor memory leak in libcurl for Windows when staticly linked
o POST/PUT using Digest/NTLM/Negotiate (including anyauth) now work better
o --limit-rate with high speed rates is a lot more accurate now
o curl_strnqual.3 "refer-to" man page fix
o fixed a minor very old progress meter final update bug
o added checks for a working NI_WITHSCOPEID before that is used
@ -40,8 +43,8 @@ Other curl-related news since the previous public release:
This release would not have looked like this without help, code, reports and
advice from friends like these:
Thomas Schwinge, Marty Kuhrt, Günter Knauf, Kevin Roth, Glen Nakamura,
Gisle Vanem, Greg Hewgill, Joe Halpin, Tor Arntsen, Dirk Manske, Roy Shan,
Mitz Wark, Andrés García, Robin Kay
Thomas Schwinge, Marty Kuhrt, Günter Knauf, Kevin Roth, Glen Nakamura, Gisle
Vanem, Greg Hewgill, Joe Halpin, Tor Arntsen, Dirk Manske, Roy Shan, Mitz
Wark, Andrés García, Robin Kay, Alan Pinstein, David Byron, Nathan O'Sullivan
Thanks! (and sorry if I forgot to mention someone)

View File

@ -196,7 +196,7 @@ CURLcode Curl_file(struct connectdata *conn)
/* If we have selected NOBODY and HEADER, it means that we only want file
information. Which for FILE can't be much more than the file size and
date. */
if(data->set.no_body && data->set.include_header && fstated) {
if(conn->bits.no_body && data->set.include_header && fstated) {
CURLcode result;
sprintf(buf, "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size);
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);

View File

@ -1838,7 +1838,7 @@ CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
return result;
}
else if(!data->set.no_body) {
else if(!conn->bits.no_body) {
/* Retrieve file or directory */
bool dirlist=FALSE;
curl_off_t downloadsize=-1;
@ -2209,7 +2209,7 @@ CURLcode ftp_perform(struct connectdata *conn,
/* If we have selected NOBODY and HEADER, it means that we only want file
information. Which in FTP can't be much more than the file size and
date. */
if(data->set.no_body && data->set.include_header && ftp->file) {
if(conn->bits.no_body && data->set.include_header && ftp->file) {
/* The SIZE command is _not_ RFC 959 specified, and therefor many servers
may not support it! It is however the only way we have to get a file's
size! */
@ -2272,7 +2272,7 @@ CURLcode ftp_perform(struct connectdata *conn,
return CURLE_OK;
}
if(data->set.no_body)
if(conn->bits.no_body)
/* doesn't really transfer any data */
ftp->no_transfer = TRUE;
/* Get us a second connection up and connected */

View File

@ -186,6 +186,17 @@ void Curl_http_auth_act(struct connectdata *conn)
conn->newurl = strdup(data->change.url); /* clone URL */
data->state.authavail = CURLAUTH_NONE; /* clear it here */
}
else if(!data->state.authdone && (data->info.httpcode < 400)) {
/* no (known) authentication available,
authentication is not "done" yet and
no authentication seems to be required and
we didn't try HEAD or GET */
if((data->set.httpreq != HTTPREQ_GET) &&
(data->set.httpreq != HTTPREQ_HEAD)) {
conn->newurl = strdup(data->change.url); /* clone URL */
data->state.authdone = TRUE;
}
}
}
/**
@ -204,13 +215,16 @@ static CURLcode http_auth_headers(struct connectdata *conn,
char *auth=NULL;
curlassert(data);
data->state.authdone = FALSE; /* default is no */
if(!data->state.authstage) {
if(conn->bits.httpproxy && conn->bits.proxy_user_passwd)
if(conn->bits.httpproxy && conn->bits.proxy_user_passwd) {
data->state.authdone = FALSE;
Curl_http_auth_stage(data, 407);
else if(conn->bits.user_passwd)
}
else if(conn->bits.user_passwd) {
data->state.authdone = FALSE;
Curl_http_auth_stage(data, 401);
}
else {
data->state.authdone = TRUE;
return CURLE_OK; /* no authentication with no user or password */
@ -1139,6 +1153,7 @@ CURLcode Curl_http(struct connectdata *conn)
const char *te = ""; /* tranfer-encoding */
char *ptr;
char *request;
Curl_HttpReq httpreq = data->set.httpreq;
if(!conn->proto.http) {
/* Only allocate this struct if we don't already have it! */
@ -1157,19 +1172,40 @@ CURLcode Curl_http(struct connectdata *conn)
if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
data->set.upload) {
data->set.httpreq = HTTPREQ_PUT;
httpreq = HTTPREQ_PUT;
}
request = data->set.customrequest?
data->set.customrequest:
(data->set.no_body?(char *)"HEAD":
((HTTPREQ_POST == data->set.httpreq) ||
(HTTPREQ_POST_FORM == data->set.httpreq))?(char *)"POST":
(HTTPREQ_PUT == data->set.httpreq)?(char *)"PUT":(char *)"GET");
/* Now set the 'request' pointer to the proper request string */
if(data->set.customrequest)
request = data->set.customrequest;
else {
if(conn->bits.no_body)
request = (char *)"HEAD";
else {
curlassert((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
switch(httpreq) {
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
request = (char *)"POST";
break;
case HTTPREQ_PUT:
request = (char *)"PUT";
break;
case HTTPREQ_GET:
request = (char *)"GET";
break;
case HTTPREQ_HEAD:
request = (char *)"HEAD";
break;
default: /* this should never happen */
break;
}
}
}
/* The User-Agent string has been built in url.c already, because it might
have been used in the proxy connect, but if we have got a header with
the user-agent string specified, we erase the previously made string
/* The User-Agent string might have been allocated in url.c already, because
it might have been used in the proxy connect, but if we have got a header
with the user-agent string specified, we erase the previously made string
here. */
if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
free(conn->allocptr.uagent);
@ -1181,6 +1217,16 @@ CURLcode Curl_http(struct connectdata *conn)
if(result)
return result;
if(!data->state.authdone && (httpreq != HTTPREQ_GET)) {
/* Until we are authenticated, we switch over to HEAD. Unless its a GET
we want to do. The explanation for this is rather long and boring, but
the point is that it can't be done otherwise without risking having to
send the POST or PUT data multiple times. */
httpreq = HTTPREQ_HEAD;
request = (char *)"HEAD";
conn->bits.no_body = TRUE;
}
Curl_safefree(conn->allocptr.ref);
if(data->change.referer && !checkheaders(data, "Referer:"))
conn->allocptr.ref = aprintf("Referer: %s\015\012", data->change.referer);
@ -1193,7 +1239,7 @@ CURLcode Curl_http(struct connectdata *conn)
else
conn->allocptr.cookie = NULL;
if(!conn->bits.upload_chunky && (data->set.httpreq != HTTPREQ_GET)) {
if(!conn->bits.upload_chunky && (httpreq != HTTPREQ_GET)) {
/* not a chunky transfer yet, but data is to be sent */
ptr = checkheaders(data, "Transfer-Encoding:");
if(ptr) {
@ -1284,7 +1330,7 @@ CURLcode Curl_http(struct connectdata *conn)
/* The path sent to the proxy is in fact the entire URL */
ppath = data->change.url;
}
if(HTTPREQ_POST_FORM == data->set.httpreq) {
if(HTTPREQ_POST_FORM == httpreq) {
/* we must build the whole darned post sequence first, so that we have
a size of the whole shebang before we start to send it */
result = Curl_getFormData(&http->sendit, data->set.httppost,
@ -1303,9 +1349,9 @@ CURLcode Curl_http(struct connectdata *conn)
if(!checkheaders(data, "Accept:"))
http->p_accept = "Accept: */*\r\n";
if(( (HTTPREQ_POST == data->set.httpreq) ||
(HTTPREQ_POST_FORM == data->set.httpreq) ||
(HTTPREQ_PUT == data->set.httpreq) ) &&
if(( (HTTPREQ_POST == httpreq) ||
(HTTPREQ_POST_FORM == httpreq) ||
(HTTPREQ_PUT == httpreq) ) &&
conn->resume_from) {
/**********************************************************************
* Resuming upload in HTTP means that we PUT or POST and that we have
@ -1368,14 +1414,14 @@ CURLcode Curl_http(struct connectdata *conn)
* or uploading and we always let customized headers override our internal
* ones if any such are specified.
*/
if((data->set.httpreq == HTTPREQ_GET) &&
if((httpreq == HTTPREQ_GET) &&
!checkheaders(data, "Range:")) {
/* if a line like this was already allocated, free the previous one */
if(conn->allocptr.rangeline)
free(conn->allocptr.rangeline);
conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", conn->range);
}
else if((data->set.httpreq != HTTPREQ_GET) &&
else if((httpreq != HTTPREQ_GET) &&
!checkheaders(data, "Content-Range:")) {
if(conn->resume_from) {
@ -1538,11 +1584,11 @@ CURLcode Curl_http(struct connectdata *conn)
http->postdata = NULL; /* nothing to post at this point */
Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
/* If 'authdone' is still FALSE, we must not set the write socket index to
the Curl_transfer() call below, as we're not ready to actually upload
any data yet. */
/* If 'authdone' is FALSE, we must not set the write socket index to the
Curl_transfer() call below, as we're not ready to actually upload any
data yet. */
switch(data->set.httpreq) {
switch(httpreq) {
case HTTPREQ_POST_FORM:
if(Curl_FormInit(&http->form, http->sendit)) {

View File

@ -498,7 +498,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
* If we requested a "no body", this is a good time to get
* out and return home.
*/
if(data->set.no_body)
if(conn->bits.no_body)
stop_reading = TRUE;
else {
/* If we know the expected size of this document, we set the
@ -555,10 +555,10 @@ CURLcode Curl_readwrite(struct connectdata *conn,
/* This is the first header, it MUST be the error code line
or else we consiser this to be the body right away! */
int httpversion_major;
int nc=sscanf (k->p, " HTTP/%d.%d %3d",
&httpversion_major,
&k->httpversion,
&k->httpcode);
int nc=sscanf(k->p, " HTTP/%d.%d %3d",
&httpversion_major,
&k->httpversion,
&k->httpcode);
if (nc==3) {
k->httpversion += 10 * httpversion_major;
}
@ -566,7 +566,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
/* this is the real world, not a Nirvana
NCSA 1.5.x returns this crap when asked for HTTP/1.1
*/
nc=sscanf (k->p, " HTTP %3d", &k->httpcode);
nc=sscanf(k->p, " HTTP %3d", &k->httpcode);
k->httpversion = 10;
/* If user has set option HTTP200ALIASES,
@ -1274,7 +1274,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
* returning.
*/
if(!(data->set.no_body) && (conn->size != -1) &&
if(!(conn->bits.no_body) && (conn->size != -1) &&
(k->bytecount != conn->size) &&
!conn->newurl) {
failf(data, "transfer closed with %" FORMAT_OFF_T
@ -1331,7 +1331,7 @@ CURLcode Curl_readwrite_init(struct connectdata *conn)
Curl_pgrsSetDownloadSize(data, conn->size);
}
/* we want header and/or body, if neither then don't do this! */
if(conn->bits.getheader || !data->set.no_body) {
if(conn->bits.getheader || !conn->bits.no_body) {
FD_ZERO (&k->readfd); /* clear it */
if(conn->sockfd != CURL_SOCKET_BAD) {
@ -1420,7 +1420,6 @@ void Curl_single_fdset(struct connectdata *conn,
static CURLcode
Transfer(struct connectdata *conn)
{
struct SessionHandle *data = conn->data;
CURLcode result;
struct Curl_transfer_keeper *k = &conn->keep;
bool done=FALSE;
@ -1435,7 +1434,7 @@ Transfer(struct connectdata *conn)
return CURLE_OK;
/* we want header and/or body, if neither then don't do this! */
if(!conn->bits.getheader && data->set.no_body)
if(!conn->bits.getheader && conn->bits.no_body)
return CURLE_OK;
k->writefdp = &k->writefd; /* store the address of the set */
@ -1859,7 +1858,7 @@ CURLcode Curl_follow(struct SessionHandle *data,
if(data->set.httpreq != HTTPREQ_GET) {
data->set.httpreq = HTTPREQ_GET; /* enforce GET request */
infof(data, "Disables POST, goes with %s\n",
data->set.no_body?"HEAD":"GET");
data->set.opt_no_body?"HEAD":"GET");
}
break;
case 304: /* Not Modified */

View File

@ -463,7 +463,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
/*
* Do not include the body part in the output data stream.
*/
data->set.no_body = va_arg(param, long)?TRUE:FALSE;
data->set.opt_no_body = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FAILONERROR:
/*
@ -2066,6 +2066,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
conn->bits.user_passwd = data->set.userpwd?1:0;
conn->bits.proxy_user_passwd = data->set.proxyuserpwd?1:0;
conn->bits.no_body = data->set.opt_no_body;
/* This initing continues below, see the comment "Continue connectdata
* initialization here" */
@ -2924,6 +2925,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
conn->bits.user_passwd = old_conn->bits.user_passwd;
conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
/* get the newly set value, not the old one */
conn->bits.no_body = old_conn->bits.no_body;
/* If we speak over a proxy, we need to copy the host name too, as it
might be another remote host even when re-using a connection */
strcpy(conn->gname, old_conn->gname); /* safe strcpy() */

View File

@ -302,6 +302,7 @@ struct ConnectBits {
call */
bool retry; /* this connection is about to get closed and then
re-attempted at another connection. */
bool no_body; /* CURLOPT_NO_BODY (or similar) was set */
};
/*
@ -644,6 +645,7 @@ typedef enum {
HTTPREQ_POST,
HTTPREQ_POST_FORM, /* we make a difference internally */
HTTPREQ_PUT,
HTTPREQ_HEAD,
HTTPREQ_CUSTOM,
HTTPREQ_LAST /* last in list */
} Curl_HttpReq;
@ -866,7 +868,7 @@ struct UserDefined {
bool http_set_referer;
bool http_auto_referer; /* set "correct" referer when following location: */
bool no_body;
bool opt_no_body; /* as set with CURLOPT_NO_BODY */
bool set_port;
bool upload;
enum CURL_NETRC_OPTION

90
tests/data/test154 Normal file
View File

@ -0,0 +1,90 @@
# Server-side
<reply>
<servercmd>
auth_required
</servercmd>
<data>
HTTP/1.1 401 Authorization Required swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
WWW-Authenticate: Blackmagic realm="gimme all yer s3cr3ts"
WWW-Authenticate: Basic realm="gimme all yer s3cr3ts"
WWW-Authenticate: Digest realm="gimme all yer s3cr3ts", nonce="11223344"
Content-Type: text/html; charset=iso-8859-1
This is not the real page
</data>
# This is supposed to be returned when the server gets a
# Authorization: Digest line passed-in from the client
<data1000>
HTTP/1.1 200 OK swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
Content-Type: text/html; charset=iso-8859-1
Content-Length: 23
This IS the real page!
</data1000>
<datacheck>
HTTP/1.1 401 Authorization Required swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
WWW-Authenticate: Blackmagic realm="gimme all yer s3cr3ts"
WWW-Authenticate: Basic realm="gimme all yer s3cr3ts"
WWW-Authenticate: Digest realm="gimme all yer s3cr3ts", nonce="11223344"
Content-Type: text/html; charset=iso-8859-1
HTTP/1.1 200 OK swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
Content-Type: text/html; charset=iso-8859-1
Content-Length: 23
This IS the real page!
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
<name>
HTTP PUT with --anyauth authorization (picking Digest)
</name>
<command>
http://%HOSTIP:%HOSTPORT/154 -T log/put154 -u testuser:testpass --anyauth
</command>
<file name="log/put154">
This is data we upload with PUT
a second line
line three
four is the number of lines
</file>
</client>
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent:.*
</strip>
<protocol>
HEAD /154 HTTP/1.1
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: */*
PUT /154 HTTP/1.1
Authorization: Digest username="testuser", realm="gimme all yer s3cr3ts", nonce="11223344", uri="/154", response="b71551e12d1c456e47d8388ecb2edeca"
User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: */*
Content-Length: 85
Expect: 100-continue
This is data we upload with PUT
a second line
line three
four is the number of lines
</protocol>
</verify>

114
tests/data/test155 Normal file
View File

@ -0,0 +1,114 @@
# Server-side
<reply>
<servercmd>
auth_required
</servercmd>
<data>
HTTP/1.1 401 NTLM Authorization Required swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
WWW-Authenticate: Blackmagic realm="gimme all yer s3cr3ts"
WWW-Authenticate: Basic realm="gimme all yer s3cr3ts"
WWW-Authenticate: NTLM
Content-Type: text/html; charset=iso-8859-1
Connection: close
moo
</data>
# This is supposed to be returned when the server gets a first
# Authorization: NTLM line passed-in from the client
<data1001>
HTTP/1.1 401 Type-1 received, send back type-2
Server: Microsoft-IIS/5.0
Content-Length: 34
Content-Type: text/html; charset=iso-8859-1
WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA==
This is not the real page either!
</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 Type-3 Recevied and all Things are fine swsclose
Server: Microsoft-IIS/5.0
Content-Type: text/html; charset=iso-8859-1
Finally, this is the real page!
</data1002>
<datacheck>
HTTP/1.1 401 NTLM Authorization Required swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
WWW-Authenticate: Blackmagic realm="gimme all yer s3cr3ts"
WWW-Authenticate: Basic realm="gimme all yer s3cr3ts"
WWW-Authenticate: NTLM
Content-Type: text/html; charset=iso-8859-1
Connection: close
HTTP/1.1 401 Type-1 received, send back type-2
Server: Microsoft-IIS/5.0
Content-Length: 34
Content-Type: text/html; charset=iso-8859-1
WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA==
HTTP/1.1 200 Type-3 Recevied and all Things are fine swsclose
Server: Microsoft-IIS/5.0
Content-Type: text/html; charset=iso-8859-1
Finally, this is the real page!
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
<name>
HTTP PUT with --anyauth authorization (picking NTLM)
</name>
<command>
http://%HOSTIP:%HOSTPORT/155 -T log/put155 -u testuser:testpass --anyauth
</command>
<file name="log/put155">
This is data we upload with PUT
a second line
line three
four is the number of lines
</file>
</client>
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent:.*
</strip>
<protocol>
HEAD /155 HTTP/1.1
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: */*
HEAD /155 HTTP/1.1
Authorization: NTLM TlRMTVNTUAABAAAAAgIAAAAAAAAgAAAAAAAAACAAAAA=
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: */*
PUT /155 HTTP/1.1
Authorization: NTLM TlRMTVNTUAADAAAAGAAYAEgAAAAYABgAYAAAAAAAAABAAAAACAAIAEAAAAAAAAAASAAAAAAAAAB4AAAAAYIAAHRlc3R1c2VyWmRDApEJkUyGOPS3DjvASModEeW/N/FBqYVyF4y6/y/7F6qmEQ7lXjXFF3tH1145
User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: */*
Content-Length: 85
Expect: 100-continue
This is data we upload with PUT
a second line
line three
four is the number of lines
</protocol>
</verify>

79
tests/data/test156 Normal file
View File

@ -0,0 +1,79 @@
# Server-side
<reply>
<data>
HTTP/1.1 200 No Authorization Required swsclose swsbounce
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
Content-Type: text/html; charset=iso-8859-1
Connection: close
</data>
<data1>
HTTP/1.1 200 No Authorization Required swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
Content-Type: text/html; charset=iso-8859-1
Connection: close
PUT received fine. Thank you very much
</data1>
<datacheck>
HTTP/1.1 200 No Authorization Required swsclose swsbounce
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
Content-Type: text/html; charset=iso-8859-1
Connection: close
HTTP/1.1 200 No Authorization Required swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
Content-Type: text/html; charset=iso-8859-1
Connection: close
PUT received fine. Thank you very much
</datacheck>
</reply>
# Client-side
<client>
<server>
http
</server>
<name>
HTTP PUT with --anyauth (when the server requires none)
</name>
<command>
http://%HOSTIP:%HOSTPORT/156 -T log/put156 -u testuser:testpass --anyauth
</command>
<file name="log/put156">
This is data we upload with PUT
a second line
line three
four is the number of lines
</file>
</client>
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent:.*
</strip>
<protocol>
HEAD /156 HTTP/1.1
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: */*
PUT /156 HTTP/1.1
User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: */*
Content-Length: 85
Expect: 100-continue
This is data we upload with PUT
a second line
line three
four is the number of lines
</protocol>
</verify>

38
tests/data/test157 Normal file
View File

@ -0,0 +1,38 @@
# Server-side
<reply>
<data>
HTTP/1.1 200 No Authorization Required swsclose
Server: Apache/1.3.27 (Darwin) PHP/4.1.2
Content-Type: text/html; charset=iso-8859-1
Connection: close
GET received and served just fine. Thank you very much
</data>
</reply>
# Client-side
<client>
<server>
http
</server>
<name>
HTTP GET with --anyauth (when the server requires none)
</name>
<command>
http://%HOSTIP:%HOSTPORT/157 -u testuser:testpass --anyauth
</command>
</client>
# Verify data after the test has been "shot"
<verify>
<strip>
^User-Agent:.*
</strip>
<protocol>
GET /157 HTTP/1.1
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: */*
</protocol>
</verify>

View File

@ -62,12 +62,10 @@ four is the number of lines
^User-Agent:.*
</strip>
<protocol>
PUT /88 HTTP/1.1
HEAD /88 HTTP/1.1
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: */*
Content-Length: 85
Expect: 100-continue
PUT /88 HTTP/1.1
Authorization: Digest username="testuser", realm="testrealm", nonce="1053604145", uri="/88", response="78a49fa53d0c228778297687d4168e71"