mirror of https://github.com/moparisthebest/curl
Adjusted to work properly with the new authentication stuff
Added code to deal with white spaces in relocation headers.
This commit is contained in:
parent
ed908b7f89
commit
2d3734b8b5
254
lib/transfer.c
254
lib/transfer.c
|
@ -97,15 +97,13 @@
|
||||||
#include "ssluse.h"
|
#include "ssluse.h"
|
||||||
#include "http_digest.h"
|
#include "http_digest.h"
|
||||||
#include "http_ntlm.h"
|
#include "http_ntlm.h"
|
||||||
#ifdef GSSAPI
|
|
||||||
#include "http_negotiate.h"
|
#include "http_negotiate.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#define _MPRINTF_REPLACE /* use our functions only */
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
#include <curl/mprintf.h>
|
#include <curl/mprintf.h>
|
||||||
|
|
||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
#ifdef MALLOCDEBUG
|
#ifdef CURLDEBUG
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -368,6 +366,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
||||||
k->hbufp += full_length;
|
k->hbufp += full_length;
|
||||||
k->hbuflen += full_length;
|
k->hbuflen += full_length;
|
||||||
*k->hbufp = 0;
|
*k->hbufp = 0;
|
||||||
|
k->end_ptr = k->hbufp;
|
||||||
|
|
||||||
k->p = data->state.headerbuff;
|
k->p = data->state.headerbuff;
|
||||||
|
|
||||||
|
@ -724,53 +723,81 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
||||||
if(data->set.get_filetime)
|
if(data->set.get_filetime)
|
||||||
data->info.filetime = k->timeofdoc;
|
data->info.filetime = k->timeofdoc;
|
||||||
}
|
}
|
||||||
#ifdef GSSAPI
|
else if(checkprefix("WWW-Authenticate:", k->p) &&
|
||||||
else if (Curl_compareheader(k->p, "WWW-Authenticate:",
|
(401 == k->httpcode)) {
|
||||||
"GSS-Negotiate") &&
|
/*
|
||||||
(401 == k->httpcode) &&
|
* This page requires authentication
|
||||||
(data->set.httpauth == CURLAUTH_GSSNEGOTIATE)) {
|
*/
|
||||||
int neg;
|
char *start = k->p+strlen("WWW-Authenticate:");
|
||||||
|
|
||||||
neg = Curl_input_negotiate(conn,
|
/* pass all white spaces */
|
||||||
k->p+strlen("WWW-Authenticate:"));
|
while(*start && isspace((int)*start))
|
||||||
if (neg == 0)
|
start++;
|
||||||
/* simulate redirection to make curl send the request again */
|
|
||||||
conn->newurl = strdup(data->change.url);
|
#ifdef GSSAPI
|
||||||
}
|
if (checkprefix("GSS-Negotiate", start)) {
|
||||||
|
if(data->state.authwant == CURLAUTH_GSSNEGOTIATE) {
|
||||||
|
/* if exactly this is wanted, go */
|
||||||
|
int neg = Curl_input_negotiate(conn, start);
|
||||||
|
if (neg == 0)
|
||||||
|
conn->newurl = strdup(data->change.url);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(data->state.authwant & CURLAUTH_GSSNEGOTIATE)
|
||||||
|
data->state.authavail |= CURLAUTH_GSSNEGOTIATE;
|
||||||
|
}
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_SSLEAY
|
#ifdef USE_SSLEAY
|
||||||
/* NTLM support requires the SSL crypto libs */
|
/* NTLM support requires the SSL crypto libs */
|
||||||
else if(Curl_compareheader(k->p,
|
if(checkprefix("NTLM", start)) {
|
||||||
"WWW-Authenticate:", "NTLM") &&
|
if(data->state.authwant == CURLAUTH_NTLM) {
|
||||||
(401 == k->httpcode) &&
|
/* NTLM authentication is activated */
|
||||||
(data->set.httpauth == CURLAUTH_NTLM)
|
CURLntlm ntlm =
|
||||||
/* NTLM authentication is activated */) {
|
Curl_input_ntlm(conn, start);
|
||||||
CURLntlm ntlm =
|
|
||||||
Curl_input_ntlm(conn, k->p+strlen("WWW-Authenticate:"));
|
if(CURLNTLM_BAD != ntlm)
|
||||||
|
conn->newurl = strdup(data->change.url); /* clone string */
|
||||||
if(CURLNTLM_BAD != ntlm)
|
else
|
||||||
conn->newurl = strdup(data->change.url); /* clone string */
|
infof(data, "Authentication problem. Ignoring this.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(data->state.authwant & CURLAUTH_NTLM)
|
||||||
|
data->state.authavail |= CURLAUTH_NTLM;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
infof(data, "Authentication problem. Ignoring this.\n");
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
else if(Curl_compareheader(k->p,
|
if(checkprefix("Digest", start)) {
|
||||||
"WWW-Authenticate:", "Digest") &&
|
if(data->state.authwant == CURLAUTH_DIGEST) {
|
||||||
(401 == k->httpcode) &&
|
/* Digest authentication is activated */
|
||||||
(data->set.httpauth == CURLAUTH_DIGEST)
|
CURLdigest dig = CURLDIGEST_BAD;
|
||||||
/* Digest authentication is activated */) {
|
|
||||||
CURLdigest dig = CURLDIGEST_BAD;
|
|
||||||
|
|
||||||
if(data->state.digest.nonce)
|
if(data->state.digest.nonce)
|
||||||
infof(data, "Authentication problem. Ignoring this.\n");
|
infof(data, "Authentication problem. Ignoring this.\n");
|
||||||
else
|
else
|
||||||
dig = Curl_input_digest(conn,
|
dig = Curl_input_digest(conn, start);
|
||||||
k->p+strlen("WWW-Authenticate:"));
|
|
||||||
|
|
||||||
if(CURLDIGEST_FINE == dig)
|
if(CURLDIGEST_FINE == dig)
|
||||||
/* We act on it. Store our new url, which happens to be
|
/* We act on it. Store our new url, which happens to be
|
||||||
the same one we already use! */
|
the same one we already use! */
|
||||||
conn->newurl = strdup(data->change.url); /* clone string */
|
conn->newurl = strdup(data->change.url); /* clone string */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if(data->state.authwant & CURLAUTH_DIGEST) {
|
||||||
|
/* We don't know if Digest is what we're gonna use, but we
|
||||||
|
call this function anyway to store the digest data that
|
||||||
|
is provided on this line, to skip the extra round-trip
|
||||||
|
we need to do otherwise. We must sure to free this
|
||||||
|
data! */
|
||||||
|
Curl_input_digest(conn, start);
|
||||||
|
data->state.authavail |= CURLAUTH_DIGEST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(checkprefix("Basic", start)) {
|
||||||
|
if(data->state.authwant & CURLAUTH_BASIC) {
|
||||||
|
data->state.authavail |= CURLAUTH_BASIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ((k->httpcode >= 300 && k->httpcode < 400) &&
|
else if ((k->httpcode >= 300 && k->httpcode < 400) &&
|
||||||
checkprefix("Location:", k->p)) {
|
checkprefix("Location:", k->p)) {
|
||||||
|
@ -786,11 +813,17 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
||||||
white spaces after the "Location:" keyword. */
|
white spaces after the "Location:" keyword. */
|
||||||
while(*start && isspace((int)*start ))
|
while(*start && isspace((int)*start ))
|
||||||
start++;
|
start++;
|
||||||
ptr = start; /* start scanning here */
|
|
||||||
|
/* Scan through the string from the end to find the last
|
||||||
|
non-space. k->end_ptr points to the actual terminating zero
|
||||||
|
letter, move pointer one letter back and start from
|
||||||
|
there. This logic strips off trailing whitespace, but keeps
|
||||||
|
any embedded whitespace. */
|
||||||
|
ptr = k->end_ptr-1;
|
||||||
|
while((ptr>=start) && isspace((int)*ptr))
|
||||||
|
ptr--;
|
||||||
|
ptr++;
|
||||||
|
|
||||||
/* scan through the string to find the end */
|
|
||||||
while(*ptr && !isspace((int)*ptr))
|
|
||||||
ptr++;
|
|
||||||
backup = *ptr; /* store the ending letter */
|
backup = *ptr; /* store the ending letter */
|
||||||
if(ptr != start) {
|
if(ptr != start) {
|
||||||
*ptr = '\0'; /* zero terminate */
|
*ptr = '\0'; /* zero terminate */
|
||||||
|
@ -852,6 +885,25 @@ CURLcode Curl_readwrite(struct connectdata *conn,
|
||||||
write a piece of the body */
|
write a piece of the body */
|
||||||
if(conn->protocol&PROT_HTTP) {
|
if(conn->protocol&PROT_HTTP) {
|
||||||
/* HTTP-only checks */
|
/* HTTP-only checks */
|
||||||
|
|
||||||
|
if(data->state.authavail) {
|
||||||
|
if(data->state.authavail & CURLAUTH_GSSNEGOTIATE)
|
||||||
|
data->state.authwant = CURLAUTH_GSSNEGOTIATE;
|
||||||
|
else if(data->state.authavail & CURLAUTH_DIGEST)
|
||||||
|
data->state.authwant = CURLAUTH_DIGEST;
|
||||||
|
else if(data->state.authavail & CURLAUTH_NTLM)
|
||||||
|
data->state.authwant = CURLAUTH_NTLM;
|
||||||
|
else if(data->state.authavail & CURLAUTH_BASIC)
|
||||||
|
data->state.authwant = CURLAUTH_BASIC;
|
||||||
|
else
|
||||||
|
data->state.authwant = CURLAUTH_NONE; /* none */
|
||||||
|
|
||||||
|
if(data->state.authwant)
|
||||||
|
conn->newurl = strdup(data->change.url); /* clone string */
|
||||||
|
|
||||||
|
data->state.authavail = CURLAUTH_NONE; /* clear it here */
|
||||||
|
}
|
||||||
|
|
||||||
if (conn->newurl) {
|
if (conn->newurl) {
|
||||||
if(conn->bits.close) {
|
if(conn->bits.close) {
|
||||||
/* Abort after the headers if "follow Location" is set
|
/* Abort after the headers if "follow Location" is set
|
||||||
|
@ -1442,6 +1494,10 @@ CURLcode Curl_pretransfer(struct SessionHandle *data)
|
||||||
data->state.this_is_a_follow = FALSE; /* reset this */
|
data->state.this_is_a_follow = FALSE; /* reset this */
|
||||||
data->state.errorbuf = FALSE; /* no error has occurred */
|
data->state.errorbuf = FALSE; /* no error has occurred */
|
||||||
|
|
||||||
|
/* set preferred authentication, default to basic */
|
||||||
|
data->state.authwant = data->set.httpauth?data->set.httpauth:CURLAUTH_BASIC;
|
||||||
|
data->state.authavail = CURLAUTH_NONE; /* nothing so far */
|
||||||
|
|
||||||
/* If there was a list of cookie files to read and we haven't done it before,
|
/* If there was a list of cookie files to read and we haven't done it before,
|
||||||
do it now! */
|
do it now! */
|
||||||
if(data->change.cookielist) {
|
if(data->change.cookielist) {
|
||||||
|
@ -1488,6 +1544,60 @@ CURLcode Curl_posttransfer(struct SessionHandle *data)
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int strlen_url(char *url)
|
||||||
|
{
|
||||||
|
char *ptr;
|
||||||
|
int newlen=0;
|
||||||
|
bool left=TRUE; /* left side of the ? */
|
||||||
|
|
||||||
|
for(ptr=url; *ptr; ptr++) {
|
||||||
|
switch(*ptr) {
|
||||||
|
case '?':
|
||||||
|
left=FALSE;
|
||||||
|
default:
|
||||||
|
newlen++;
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
if(left)
|
||||||
|
newlen+=3;
|
||||||
|
else
|
||||||
|
newlen++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void strcpy_url(char *output, char *url)
|
||||||
|
{
|
||||||
|
/* we must add this with whitespace-replacing */
|
||||||
|
bool left=TRUE;
|
||||||
|
char *iptr;
|
||||||
|
char *optr = output;
|
||||||
|
for(iptr = url; /* read from here */
|
||||||
|
*iptr; /* until zero byte */
|
||||||
|
iptr++) {
|
||||||
|
switch(*iptr) {
|
||||||
|
case '?':
|
||||||
|
left=FALSE;
|
||||||
|
default:
|
||||||
|
*optr++=*iptr;
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
|
if(left) {
|
||||||
|
*optr++='%'; /* add a '%' */
|
||||||
|
*optr++='2'; /* add a '2' */
|
||||||
|
*optr++='0'; /* add a '0' */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*optr++='+'; /* add a '+' here */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*optr=0; /* zero terminate output buffer */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
CURLcode Curl_follow(struct SessionHandle *data,
|
CURLcode Curl_follow(struct SessionHandle *data,
|
||||||
char *newurl) /* this 'newurl' is the Location: string,
|
char *newurl) /* this 'newurl' is the Location: string,
|
||||||
and it must be malloc()ed before passed
|
and it must be malloc()ed before passed
|
||||||
|
@ -1496,6 +1606,8 @@ CURLcode Curl_follow(struct SessionHandle *data,
|
||||||
/* Location: redirect */
|
/* Location: redirect */
|
||||||
char prot[16]; /* URL protocol string storage */
|
char prot[16]; /* URL protocol string storage */
|
||||||
char letter; /* used for a silly sscanf */
|
char letter; /* used for a silly sscanf */
|
||||||
|
int newlen;
|
||||||
|
char *newest;
|
||||||
|
|
||||||
if (data->set.maxredirs &&
|
if (data->set.maxredirs &&
|
||||||
(data->set.followlocation >= data->set.maxredirs)) {
|
(data->set.followlocation >= data->set.maxredirs)) {
|
||||||
|
@ -1532,9 +1644,9 @@ CURLcode Curl_follow(struct SessionHandle *data,
|
||||||
*/
|
*/
|
||||||
char *protsep;
|
char *protsep;
|
||||||
char *pathsep;
|
char *pathsep;
|
||||||
char *newest;
|
|
||||||
|
|
||||||
char *useurl = newurl;
|
char *useurl = newurl;
|
||||||
|
int urllen;
|
||||||
|
|
||||||
/* we must make our own copy of the URL to play with, as it may
|
/* we must make our own copy of the URL to play with, as it may
|
||||||
point to read-only data */
|
point to read-only data */
|
||||||
|
@ -1607,30 +1719,62 @@ CURLcode Curl_follow(struct SessionHandle *data,
|
||||||
*pathsep=0;
|
*pathsep=0;
|
||||||
}
|
}
|
||||||
|
|
||||||
newest=(char *)malloc( strlen(url_clone) +
|
/* If the new part contains a space, this is a mighty stupid redirect
|
||||||
1 + /* possible slash */
|
but we still make an effort to do "right". To the left of a '?'
|
||||||
strlen(useurl) + 1/* zero byte */);
|
letter we replace each space with %20 while it is replaced with '+'
|
||||||
|
on the right side of the '?' letter.
|
||||||
|
*/
|
||||||
|
newlen = strlen_url(useurl);
|
||||||
|
|
||||||
|
urllen = strlen(url_clone);
|
||||||
|
|
||||||
|
newest=(char *)malloc( urllen + 1 + /* possible slash */
|
||||||
|
newlen + 1 /* zero byte */);
|
||||||
|
|
||||||
if(!newest)
|
if(!newest)
|
||||||
return CURLE_OUT_OF_MEMORY; /* go out from this */
|
return CURLE_OUT_OF_MEMORY; /* go out from this */
|
||||||
|
|
||||||
sprintf(newest, "%s%s%s", url_clone,
|
/* copy over the root url part */
|
||||||
(('/' == useurl[0]) || (protsep && !*protsep))?"":"/",
|
memcpy(newest, url_clone, urllen);
|
||||||
useurl);
|
|
||||||
|
/* check if we need to append a slash */
|
||||||
|
if(('/' == useurl[0]) || (protsep && !*protsep))
|
||||||
|
;
|
||||||
|
else
|
||||||
|
newest[urllen++]='/';
|
||||||
|
|
||||||
|
/* then append the new piece on the right side */
|
||||||
|
strcpy_url(&newest[urllen], useurl);
|
||||||
|
|
||||||
free(newurl); /* newurl is the allocated pointer */
|
free(newurl); /* newurl is the allocated pointer */
|
||||||
free(url_clone);
|
free(url_clone);
|
||||||
newurl = newest;
|
newurl = newest;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
/* This is an absolute URL, don't allow the custom port number */
|
/* This is an absolute URL, don't allow the custom port number */
|
||||||
data->state.allow_port = FALSE;
|
data->state.allow_port = FALSE;
|
||||||
|
|
||||||
|
if(strchr(newurl, ' ')) {
|
||||||
|
/* This new URL contains at least one space, this is a mighty stupid
|
||||||
|
redirect but we still make an effort to do "right". */
|
||||||
|
newlen = strlen_url(newurl);
|
||||||
|
|
||||||
|
newest = malloc(newlen+1); /* get memory for this */
|
||||||
|
if(newest) {
|
||||||
|
strcpy_url(newest, newurl); /* create a space-free URL */
|
||||||
|
|
||||||
|
free(newurl); /* that was no good */
|
||||||
|
newurl = newest; /* use this instead now */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
if(data->change.url_alloc)
|
if(data->change.url_alloc)
|
||||||
free(data->change.url);
|
free(data->change.url);
|
||||||
else
|
else
|
||||||
data->change.url_alloc = TRUE; /* the URL is allocated */
|
data->change.url_alloc = TRUE; /* the URL is allocated */
|
||||||
|
|
||||||
/* TBD: set the URL with curl_setopt() */
|
|
||||||
data->change.url = newurl;
|
data->change.url = newurl;
|
||||||
newurl = NULL; /* don't free! */
|
newurl = NULL; /* don't free! */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue