David Byron made CURLOPT_FAILONERROR work with authentications such as NTLM

or Digest.
This commit is contained in:
Daniel Stenberg 2004-03-30 06:40:01 +00:00
parent 5e75c310ba
commit 8e92600ddd
3 changed files with 129 additions and 30 deletions

View File

@ -188,23 +188,23 @@ void Curl_http_auth_act(struct connectdata *conn)
}
}
/*
/**
* Setup the authentication headers for the host/proxy and the correct
* authentication method.
* authentication method. @p conn->data->state.authdone set to TRUE
* when authentication is done.
*
* @param conn all information about the current connection
*/
static CURLcode http_auth_headers(struct connectdata *conn,
char *request,
char *path,
bool *ready) /* set TRUE when the auth phase
is done and ready to do the *actual*
request */
char *path)
{
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
char *auth=NULL;
*ready = FALSE; /* default is no */
curlassert(data);
data->state.authdone = FALSE; /* default is no */
if(!data->state.authstage) {
if(conn->bits.httpproxy && conn->bits.proxy_user_passwd)
@ -212,7 +212,7 @@ static CURLcode http_auth_headers(struct connectdata *conn,
else if(conn->bits.user_passwd)
Curl_http_auth_stage(data, 401);
else {
*ready = TRUE;
data->state.authdone = TRUE;
return CURLE_OK; /* no authentication with no user or password */
}
}
@ -229,7 +229,7 @@ static CURLcode http_auth_headers(struct connectdata *conn,
#ifdef USE_SSLEAY
if(data->state.authwant == CURLAUTH_NTLM) {
auth=(char *)"NTLM";
result = Curl_output_ntlm(conn, TRUE, ready);
result = Curl_output_ntlm(conn, TRUE);
if(result)
return result;
}
@ -244,7 +244,7 @@ static CURLcode http_auth_headers(struct connectdata *conn,
if(result)
return result;
}
*ready = TRUE;
data->state.authdone = TRUE;
/* Switch to web authentication after proxy authentication is done */
Curl_http_auth_stage(data, 401);
}
@ -262,14 +262,14 @@ static CURLcode http_auth_headers(struct connectdata *conn,
result = Curl_output_negotiate(conn);
if (result)
return result;
*ready = TRUE;
data->state.authdone = TRUE;
}
else
#endif
#ifdef USE_SSLEAY
if(data->state.authwant == CURLAUTH_NTLM) {
auth=(char *)"NTLM";
result = Curl_output_ntlm(conn, FALSE, ready);
result = Curl_output_ntlm(conn, FALSE);
if(result)
return result;
}
@ -284,7 +284,7 @@ static CURLcode http_auth_headers(struct connectdata *conn,
(unsigned char *)path);
if(result)
return result;
*ready = TRUE;
data->state.authdone = TRUE;
}
else if(data->state.authwant == CURLAUTH_BASIC) {/* Basic */
if(conn->bits.user_passwd &&
@ -295,7 +295,7 @@ static CURLcode http_auth_headers(struct connectdata *conn,
return result;
}
/* basic is always ready */
*ready = TRUE;
data->state.authdone = TRUE;
}
}
if(auth)
@ -304,7 +304,7 @@ static CURLcode http_auth_headers(struct connectdata *conn,
}
}
else
*ready = TRUE;
data->state.authdone = TRUE;
return result;
}
@ -438,6 +438,83 @@ CURLcode Curl_http_auth(struct connectdata *conn,
return CURLE_OK;
}
/**
* determine whether an http response has gotten us into an
* error state or not.
*
* @param conn all information about the current connection
*
* @retval 0 communications should continue
*
* @retval 1 communications should not continue
*/
int Curl_http_should_fail(struct connectdata *conn)
{
struct SessionHandle *data;
struct Curl_transfer_keeper *k;
curlassert(conn);
data = conn->data;
curlassert(data);
/*
** For readability
*/
k = &conn->keep;
/*
** If we haven't been asked to fail on error,
** don't fail.
*/
if (!data->set.http_fail_on_error)
return 0;
/*
** Any code < 400 is never terminal.
*/
if (k->httpcode < 400)
return 0;
/*
** Any code >= 400 that's not 401 or 407 is always
** a terminal error
*/
if ((k->httpcode != 401) &&
(k->httpcode != 407))
return 1;
/*
** All we have left to deal with is 401 and 407
*/
curlassert((k->httpcode == 401) || (k->httpcode == 407));
/*
** Examine the current authentication state to see if this
** is an error. The idea is for this function to get
** called after processing all the headers in a response
** message. So, if we've been to asked to authenticate a
** particular stage, and we've done it, we're OK. But, if
** we're already completely authenticated, it's not OK to
** get another 401 or 407.
**
** It is possible for authentication to go stale such that
** the client needs to reauthenticate. Once that info is
** available, use it here.
*/
infof(data,"%s: authstage = %d\n",__FUNCTION__,data->state.authstage);
infof(data,"%s: httpcode = %d\n",__FUNCTION__,k->httpcode);
infof(data,"%s: authdone = %d\n",__FUNCTION__,data->state.authdone);
if (data->state.authstage &&
(data->state.authstage == k->httpcode))
return data->state.authdone;
/*
** Either we're not authenticating, or we're supposed to
** be authenticating something else. This is an error.
*/
return 1;
}
/* fread() emulation to provide POST and/or request data */
static size_t readmoredata(char *buffer,
@ -760,9 +837,6 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
do {
bool auth; /* we don't really have to know when the auth phase is done,
but this variable will be set to true then */
if(conn->newurl) {
/* This only happens if we've looped here due to authentication reasons,
and we don't really use the newly cloned URL here then. Just free()
@ -776,7 +850,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
return CURLE_OUT_OF_MEMORY;
/* Setup the proxy-authorization header, if any */
result = http_auth_headers(conn, (char *)"CONNECT", host_port, &auth);
result = http_auth_headers(conn, (char *)"CONNECT", host_port);
if(CURLE_OK == result) {
/* OK, now send the connect request to the proxy */
@ -1066,7 +1140,6 @@ CURLcode Curl_http(struct connectdata *conn)
const char *te = ""; /* tranfer-encoding */
char *ptr;
char *request;
bool authdone=TRUE; /* if the authentication phase is done */
if(!conn->proto.http) {
/* Only allocate this struct if we don't already have it! */
@ -1105,7 +1178,7 @@ CURLcode Curl_http(struct connectdata *conn)
}
/* setup the authentication headers */
result = http_auth_headers(conn, request, ppath, &authdone);
result = http_auth_headers(conn, request, ppath);
if(result)
return result;
@ -1535,8 +1608,8 @@ CURLcode Curl_http(struct connectdata *conn)
/* setup variables for the upcoming transfer */
result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount,
authdone?FIRSTSOCKET:-1,
authdone?&http->writebytecount:NULL);
data->state.authdone?FIRSTSOCKET:-1,
data->state.authdone?&http->writebytecount:NULL);
if(result) {
Curl_formclean(http->sendit); /* free that whole lot */
return result;
@ -1574,8 +1647,8 @@ CURLcode Curl_http(struct connectdata *conn)
/* prepare for transfer */
result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount,
authdone?FIRSTSOCKET:-1,
authdone?&http->writebytecount:NULL);
data->state.authdone?FIRSTSOCKET:-1,
data->state.authdone?&http->writebytecount:NULL);
if(result)
return result;
break;
@ -1606,7 +1679,7 @@ CURLcode Curl_http(struct connectdata *conn)
if(data->set.postfields) {
if(authdone && (postsize < (100*1024))) {
if(data->state.authdone && (postsize < (100*1024))) {
/* If we're not done with the authentication phase, we don't expect
to actually send off any data yet. Hence, we delay the sending of
the body until we receive that friendly 100-continue response */
@ -1642,7 +1715,7 @@ CURLcode Curl_http(struct connectdata *conn)
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
if(!authdone && !checkheaders(data, "Expect:")) {
if(!data->state.authdone && !checkheaders(data, "Expect:")) {
/* if not disabled explicitly we add a Expect: 100-continue to the
headers which actually speeds up post operations (as there is
one packet coming back from the web server) */

View File

@ -42,9 +42,13 @@ CURLcode Curl_http_connect(struct connectdata *conn);
void Curl_httpchunk_init(struct connectdata *conn);
CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
ssize_t length, ssize_t *wrote);
/* These functions are in http.c */
void Curl_http_auth_stage(struct SessionHandle *data, int stage);
CURLcode Curl_http_auth(struct connectdata *conn,
int httpcode, char *header);
void Curl_http_auth_act(struct connectdata *conn);
int Curl_http_should_fail(struct connectdata *conn);
#endif
#endif

View File

@ -441,6 +441,16 @@ CURLcode Curl_readwrite(struct connectdata *conn,
FD_ZERO(&k->wkeepfd);
}
/*
** Now that all of the headers have been parsed, see
** if we should give up and return an error.
*/
if (Curl_http_should_fail(conn)) {
failf (data, "The requested URL returned error: %d",
k->httpcode);
return CURLE_HTTP_RETURNED_ERROR;
}
/* now, only output this if the header AND body are requested:
*/
writetype = CLIENTWRITE_HEADER;
@ -576,9 +586,21 @@ CURLcode Curl_readwrite(struct connectdata *conn,
data->info.httpcode = k->httpcode;
data->info.httpversion = k->httpversion;
/* 404 -> URL not found! */
/*
** This code executes as part of processing
** the header. As a result, it's not
** totally clear how to interpret the
** response code yet as that depends on what
** other headers may be present. 401 and
** 407 may be errors, but may be OK
** depending on how authentication is
** working. Other codes are definitely
** errors, so give up here.
*/
if (data->set.http_fail_on_error &&
(k->httpcode >= 400)) {
(k->httpcode >= 400) &&
(k->httpcode != 401) &&
(k->httpcode != 407)) {
/* If we have been told to fail hard on HTTP-errors,
here is the check for that: */
/* serious error, go home! */