aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2004-03-30 06:40:01 +0000
committerDaniel Stenberg <daniel@haxx.se>2004-03-30 06:40:01 +0000
commit8e92600ddd6ed324fc1f8410e859cca3182018f7 (patch)
tree5795ba2eb237e16bcfb0513e8b46c7aee1492e2e
parent5e75c310ba0b74ad9dd075710d55bcb1fd58aadb (diff)
David Byron made CURLOPT_FAILONERROR work with authentications such as NTLM
or Digest.
-rw-r--r--lib/http.c129
-rw-r--r--lib/http.h4
-rw-r--r--lib/transfer.c26
3 files changed, 129 insertions, 30 deletions
diff --git a/lib/http.c b/lib/http.c
index ccbbf4962..7358f7aeb 100644
--- a/lib/http.c
+++ b/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
- * 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) */
diff --git a/lib/http.h b/lib/http.h
index ad7179ff9..5dff8cb71 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -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
diff --git a/lib/transfer.c b/lib/transfer.c
index 2a0df0f64..4e5d71137 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -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! */