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:
parent
5e75c310ba
commit
8e92600ddd
129
lib/http.c
129
lib/http.c
@ -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) */
|
||||||
|
@ -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
|
||||||
|
@ -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! */
|
||||||
|
Loading…
Reference in New Issue
Block a user