1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-22 08:08:50 -05:00

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 * 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, static CURLcode http_auth_headers(struct connectdata *conn,
char *request, char *request,
char *path, char *path)
bool *ready) /* set TRUE when the auth phase
is done and ready to do the *actual*
request */
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
char *auth=NULL; char *auth=NULL;
*ready = FALSE; /* default is no */ curlassert(data);
data->state.authdone = FALSE; /* default is no */
if(!data->state.authstage) { if(!data->state.authstage) {
if(conn->bits.httpproxy && conn->bits.proxy_user_passwd) 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) else if(conn->bits.user_passwd)
Curl_http_auth_stage(data, 401); Curl_http_auth_stage(data, 401);
else { else {
*ready = TRUE; data->state.authdone = TRUE;
return CURLE_OK; /* no authentication with no user or password */ 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 #ifdef USE_SSLEAY
if(data->state.authwant == CURLAUTH_NTLM) { if(data->state.authwant == CURLAUTH_NTLM) {
auth=(char *)"NTLM"; auth=(char *)"NTLM";
result = Curl_output_ntlm(conn, TRUE, ready); result = Curl_output_ntlm(conn, TRUE);
if(result) if(result)
return result; return result;
} }
@ -244,7 +244,7 @@ static CURLcode http_auth_headers(struct connectdata *conn,
if(result) if(result)
return result; return result;
} }
*ready = TRUE; data->state.authdone = TRUE;
/* Switch to web authentication after proxy authentication is done */ /* Switch to web authentication after proxy authentication is done */
Curl_http_auth_stage(data, 401); Curl_http_auth_stage(data, 401);
} }
@ -262,14 +262,14 @@ static CURLcode http_auth_headers(struct connectdata *conn,
result = Curl_output_negotiate(conn); result = Curl_output_negotiate(conn);
if (result) if (result)
return result; return result;
*ready = TRUE; data->state.authdone = TRUE;
} }
else else
#endif #endif
#ifdef USE_SSLEAY #ifdef USE_SSLEAY
if(data->state.authwant == CURLAUTH_NTLM) { if(data->state.authwant == CURLAUTH_NTLM) {
auth=(char *)"NTLM"; auth=(char *)"NTLM";
result = Curl_output_ntlm(conn, FALSE, ready); result = Curl_output_ntlm(conn, FALSE);
if(result) if(result)
return result; return result;
} }
@ -284,7 +284,7 @@ static CURLcode http_auth_headers(struct connectdata *conn,
(unsigned char *)path); (unsigned char *)path);
if(result) if(result)
return result; return result;
*ready = TRUE; data->state.authdone = TRUE;
} }
else if(data->state.authwant == CURLAUTH_BASIC) {/* Basic */ else if(data->state.authwant == CURLAUTH_BASIC) {/* Basic */
if(conn->bits.user_passwd && if(conn->bits.user_passwd &&
@ -295,7 +295,7 @@ static CURLcode http_auth_headers(struct connectdata *conn,
return result; return result;
} }
/* basic is always ready */ /* basic is always ready */
*ready = TRUE; data->state.authdone = TRUE;
} }
} }
if(auth) if(auth)
@ -304,7 +304,7 @@ static CURLcode http_auth_headers(struct connectdata *conn,
} }
} }
else else
*ready = TRUE; data->state.authdone = TRUE;
return result; return result;
} }
@ -438,6 +438,83 @@ CURLcode Curl_http_auth(struct connectdata *conn,
return CURLE_OK; 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 */ /* fread() emulation to provide POST and/or request data */
static size_t readmoredata(char *buffer, 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); infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
do { 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) { if(conn->newurl) {
/* This only happens if we've looped here due to authentication reasons, /* 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() 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; return CURLE_OUT_OF_MEMORY;
/* Setup the proxy-authorization header, if any */ /* 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) { if(CURLE_OK == result) {
/* OK, now send the connect request to the proxy */ /* OK, now send the connect request to the proxy */
@ -1066,7 +1140,6 @@ CURLcode Curl_http(struct connectdata *conn)
const char *te = ""; /* tranfer-encoding */ const char *te = ""; /* tranfer-encoding */
char *ptr; char *ptr;
char *request; char *request;
bool authdone=TRUE; /* if the authentication phase is done */
if(!conn->proto.http) { if(!conn->proto.http) {
/* Only allocate this struct if we don't already have it! */ /* 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 */ /* setup the authentication headers */
result = http_auth_headers(conn, request, ppath, &authdone); result = http_auth_headers(conn, request, ppath);
if(result) if(result)
return result; return result;
@ -1535,8 +1608,8 @@ CURLcode Curl_http(struct connectdata *conn)
/* setup variables for the upcoming transfer */ /* setup variables for the upcoming transfer */
result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount, &http->readbytecount,
authdone?FIRSTSOCKET:-1, data->state.authdone?FIRSTSOCKET:-1,
authdone?&http->writebytecount:NULL); data->state.authdone?&http->writebytecount:NULL);
if(result) { if(result) {
Curl_formclean(http->sendit); /* free that whole lot */ Curl_formclean(http->sendit); /* free that whole lot */
return result; return result;
@ -1574,8 +1647,8 @@ CURLcode Curl_http(struct connectdata *conn)
/* prepare for transfer */ /* prepare for transfer */
result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE, result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
&http->readbytecount, &http->readbytecount,
authdone?FIRSTSOCKET:-1, data->state.authdone?FIRSTSOCKET:-1,
authdone?&http->writebytecount:NULL); data->state.authdone?&http->writebytecount:NULL);
if(result) if(result)
return result; return result;
break; break;
@ -1606,7 +1679,7 @@ CURLcode Curl_http(struct connectdata *conn)
if(data->set.postfields) { 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 /* 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 to actually send off any data yet. Hence, we delay the sending of
the body until we receive that friendly 100-continue response */ 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 */ /* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize); 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 /* if not disabled explicitly we add a Expect: 100-continue to the
headers which actually speeds up post operations (as there is headers which actually speeds up post operations (as there is
one packet coming back from the web server) */ 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); void Curl_httpchunk_init(struct connectdata *conn);
CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap, CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
ssize_t length, ssize_t *wrote); ssize_t length, ssize_t *wrote);
/* These functions are in http.c */
void Curl_http_auth_stage(struct SessionHandle *data, int stage); void Curl_http_auth_stage(struct SessionHandle *data, int stage);
CURLcode Curl_http_auth(struct connectdata *conn, CURLcode Curl_http_auth(struct connectdata *conn,
int httpcode, char *header); int httpcode, char *header);
void Curl_http_auth_act(struct connectdata *conn); void Curl_http_auth_act(struct connectdata *conn);
int Curl_http_should_fail(struct connectdata *conn);
#endif #endif
#endif #endif

View File

@ -441,6 +441,16 @@ CURLcode Curl_readwrite(struct connectdata *conn,
FD_ZERO(&k->wkeepfd); 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: /* now, only output this if the header AND body are requested:
*/ */
writetype = CLIENTWRITE_HEADER; writetype = CLIENTWRITE_HEADER;
@ -576,9 +586,21 @@ CURLcode Curl_readwrite(struct connectdata *conn,
data->info.httpcode = k->httpcode; data->info.httpcode = k->httpcode;
data->info.httpversion = k->httpversion; 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 && 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, /* If we have been told to fail hard on HTTP-errors,
here is the check for that: */ here is the check for that: */
/* serious error, go home! */ /* serious error, go home! */