1
0
mirror of https://github.com/moparisthebest/curl synced 2024-08-13 17:03:50 -04:00

url: use the URL API internally as well

... to make it a truly unified URL parser.

Closes #3017
This commit is contained in:
Daniel Stenberg 2018-09-14 23:33:28 +02:00
parent f078361c0e
commit 46e164069d
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
22 changed files with 386 additions and 928 deletions

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -39,7 +39,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
char *working_path; char *working_path;
size_t working_path_len; size_t working_path_len;
CURLcode result = CURLcode result =
Curl_urldecode(data, data->state.path, 0, &working_path, Curl_urldecode(data, data->state.up.path, 0, &working_path,
&working_path_len, FALSE); &working_path_len, FALSE);
if(result) if(result)
return result; return result;

View File

@ -136,7 +136,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
struct Curl_easy *data = conn->data; struct Curl_easy *data = conn->data;
curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
char *path = data->state.path; char *path = data->state.up.path;
curl_off_t *bytecount = &data->req.bytecount; curl_off_t *bytecount = &data->req.bytecount;
*done = TRUE; /* unconditionally */ *done = TRUE; /* unconditionally */

View File

@ -1002,10 +1002,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
*/ */
void curl_easy_reset(struct Curl_easy *data) void curl_easy_reset(struct Curl_easy *data)
{ {
Curl_safefree(data->state.pathbuffer);
data->state.path = NULL;
Curl_free_request_state(data); Curl_free_request_state(data);
/* zero out UserDefined data: */ /* zero out UserDefined data: */

View File

@ -143,7 +143,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
#endif #endif
size_t real_path_len; size_t real_path_len;
CURLcode result = Curl_urldecode(data, data->state.path, 0, &real_path, CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &real_path,
&real_path_len, FALSE); &real_path_len, FALSE);
if(result) if(result)
return result; return result;
@ -197,7 +197,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
file->fd = fd; file->fd = fd;
if(!data->set.upload && (fd == -1)) { if(!data->set.upload && (fd == -1)) {
failf(data, "Couldn't open file %s", data->state.path); failf(data, "Couldn't open file %s", data->state.up.path);
file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE); file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
return CURLE_FILE_COULDNT_READ_FILE; return CURLE_FILE_COULDNT_READ_FILE;
} }

View File

@ -1444,6 +1444,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
{ {
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data; struct Curl_easy *data = conn->data;
struct FTP *ftp = data->req.protop;
/* If this output is to be machine-parsed, the NLST command might be better /* If this output is to be machine-parsed, the NLST command might be better
to use, since the LIST command output is not specified or standard in any to use, since the LIST command output is not specified or standard in any
@ -1460,7 +1461,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
then just do LIST (in that case: nothing to do here) then just do LIST (in that case: nothing to do here)
*/ */
char *cmd, *lstArg, *slashPos; char *cmd, *lstArg, *slashPos;
const char *inpath = data->state.path; const char *inpath = ftp->path;
lstArg = NULL; lstArg = NULL;
if((data->set.ftp_filemethod == FTPFILE_NOCWD) && if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
@ -3141,7 +3142,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
int ftpcode; int ftpcode;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
char *path = NULL; char *path = NULL;
const char *path_to_use = data->state.path; const char *path_to_use = ftp->path;
if(!ftp) if(!ftp)
return CURLE_OK; return CURLE_OK;
@ -3346,7 +3347,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
/* Send any post-transfer QUOTE strings? */ /* Send any post-transfer QUOTE strings? */
if(!status && !result && !premature && data->set.postquote) if(!status && !result && !premature && data->set.postquote)
result = ftp_sendquote(conn, data->set.postquote); result = ftp_sendquote(conn, data->set.postquote);
Curl_safefree(ftp->pathalloc);
return result; return result;
} }
@ -3695,12 +3696,13 @@ static void wc_data_dtor(void *ptr)
static CURLcode init_wc_data(struct connectdata *conn) static CURLcode init_wc_data(struct connectdata *conn)
{ {
char *last_slash; char *last_slash;
char *path = conn->data->state.path; struct FTP *ftp = conn->data->req.protop;
char *path = ftp->path;
struct WildcardData *wildcard = &(conn->data->wildcard); struct WildcardData *wildcard = &(conn->data->wildcard);
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct ftp_wc *ftpwc = NULL; struct ftp_wc *ftpwc = NULL;
last_slash = strrchr(conn->data->state.path, '/'); last_slash = strrchr(ftp->path, '/');
if(last_slash) { if(last_slash) {
last_slash++; last_slash++;
if(last_slash[0] == '\0') { if(last_slash[0] == '\0') {
@ -3757,7 +3759,7 @@ static CURLcode init_wc_data(struct connectdata *conn)
goto fail; goto fail;
} }
wildcard->path = strdup(conn->data->state.path); wildcard->path = strdup(ftp->path);
if(!wildcard->path) { if(!wildcard->path) {
result = CURLE_OUT_OF_MEMORY; result = CURLE_OUT_OF_MEMORY;
goto fail; goto fail;
@ -3828,16 +3830,15 @@ static CURLcode wc_statemach(struct connectdata *conn)
/* filelist has at least one file, lets get first one */ /* filelist has at least one file, lets get first one */
struct ftp_conn *ftpc = &conn->proto.ftpc; struct ftp_conn *ftpc = &conn->proto.ftpc;
struct curl_fileinfo *finfo = wildcard->filelist.head->ptr; struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
struct FTP *ftp = conn->data->req.protop;
char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename); char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
if(!tmp_path) if(!tmp_path)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
/* switch default "state.pathbuffer" and tmp_path, good to see /* switch default ftp->path and tmp_path */
ftp_parse_url_path function to understand this trick */ free(ftp->pathalloc);
Curl_safefree(conn->data->state.pathbuffer); ftp->pathalloc = ftp->path = tmp_path;
conn->data->state.pathbuffer = tmp_path;
conn->data->state.path = tmp_path;
infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename); infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
if(conn->data->set.chunk_bgn) { if(conn->data->set.chunk_bgn) {
@ -4105,7 +4106,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
struct FTP *ftp = data->req.protop; struct FTP *ftp = data->req.protop;
struct ftp_conn *ftpc = &conn->proto.ftpc; struct ftp_conn *ftpc = &conn->proto.ftpc;
const char *slash_pos; /* position of the first '/' char in curpos */ const char *slash_pos; /* position of the first '/' char in curpos */
const char *path_to_use = data->state.path; const char *path_to_use = ftp->path;
const char *cur_pos; const char *cur_pos;
const char *filename = NULL; const char *filename = NULL;
@ -4191,7 +4192,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
/* parse the URL path into separate path components */ /* parse the URL path into separate path components */
while((slash_pos = strchr(cur_pos, '/')) != NULL) { while((slash_pos = strchr(cur_pos, '/')) != NULL) {
/* 1 or 0 pointer offset to indicate absolute directory */ /* 1 or 0 pointer offset to indicate absolute directory */
ssize_t absolute_dir = ((cur_pos - data->state.path > 0) && ssize_t absolute_dir = ((cur_pos - ftp->path > 0) &&
(ftpc->dirdepth == 0))?1:0; (ftpc->dirdepth == 0))?1:0;
/* seek out the next path component */ /* seek out the next path component */
@ -4268,7 +4269,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
size_t dlen; size_t dlen;
char *path; char *path;
CURLcode result = CURLcode result =
Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, TRUE); Curl_urldecode(conn->data, ftp->path, 0, &path, &dlen, TRUE);
if(result) { if(result) {
freedirs(ftpc); freedirs(ftpc);
return result; return result;
@ -4388,16 +4389,16 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
char *type; char *type;
struct FTP *ftp; struct FTP *ftp;
conn->data->req.protop = ftp = malloc(sizeof(struct FTP)); conn->data->req.protop = ftp = calloc(sizeof(struct FTP), 1);
if(NULL == ftp) if(NULL == ftp)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
data->state.path++; /* don't include the initial slash */ ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
data->state.slash_removed = TRUE; /* we've skipped the slash */ data->state.slash_removed = TRUE; /* we've skipped the slash */
/* FTP URLs support an extension like ";type=<typecode>" that /* FTP URLs support an extension like ";type=<typecode>" that
* we'll try to get now! */ * we'll try to get now! */
type = strstr(data->state.path, ";type="); type = strstr(ftp->path, ";type=");
if(!type) if(!type)
type = strstr(conn->host.rawalloc, ";type="); type = strstr(conn->host.rawalloc, ";type=");

View File

@ -105,6 +105,8 @@ struct FTP {
curl_off_t *bytecountp; curl_off_t *bytecountp;
char *user; /* user name string */ char *user; /* user name string */
char *passwd; /* password string */ char *passwd; /* password string */
char *path; /* points to the urlpieces struct field */
char *pathalloc; /* if non-NULL a pointer to an allocated path */
/* transfer a file/body or not, done as a typedefed enum just to make /* transfer a file/body or not, done as a typedefed enum just to make
debuggers display the full symbol and not just the numerical value */ debuggers display the full symbol and not just the numerical value */

View File

@ -78,7 +78,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
curl_off_t *bytecount = &data->req.bytecount; curl_off_t *bytecount = &data->req.bytecount;
char *path = data->state.path; char *path = data->state.up.path;
char *sel = NULL; char *sel = NULL;
char *sel_org = NULL; char *sel_org = NULL;
ssize_t amount, k; ssize_t amount, k;

View File

@ -1877,7 +1877,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
struct Curl_easy *data = conn->data; struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct HTTP *http; struct HTTP *http;
const char *ppath = data->state.path; const char *path = data->state.up.path;
const char *query = data->state.up.query;
bool paste_ftp_userpwd = FALSE; bool paste_ftp_userpwd = FALSE;
char ftp_typecode[sizeof("/;type=?")] = ""; char ftp_typecode[sizeof("/;type=?")] = "";
const char *host = conn->host.name; const char *host = conn->host.name;
@ -1995,7 +1996,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
} }
/* setup the authentication headers */ /* setup the authentication headers */
result = Curl_http_output_auth(conn, request, ppath, FALSE); result = Curl_http_output_auth(conn, request, path, FALSE);
if(result) if(result)
return result; return result;
@ -2223,47 +2224,59 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* The path sent to the proxy is in fact the entire URL. But if the remote /* The path sent to the proxy is in fact the entire URL. But if the remote
host is a IDN-name, we must make sure that the request we produce only host is a IDN-name, we must make sure that the request we produce only
uses the encoded host name! */ uses the encoded host name! */
/* and no fragment part */
CURLUcode uc;
char *url;
CURLU *h = curl_url_dup(data->state.uh);
if(!h)
return CURLE_OUT_OF_MEMORY;
if(conn->host.dispname != conn->host.name) { if(conn->host.dispname != conn->host.name) {
char *url = data->change.url; uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0);
ptr = strstr(url, conn->host.dispname); if(uc) {
if(ptr) { curl_url_cleanup(h);
/* This is where the display name starts in the URL, now replace this return CURLE_OUT_OF_MEMORY;
part with the encoded name. TODO: This method of replacing the host
name is rather crude as I believe there's a slight risk that the
user has entered a user name or password that contain the host name
string. */
size_t currlen = strlen(conn->host.dispname);
size_t newlen = strlen(conn->host.name);
size_t urllen = strlen(url);
char *newurl;
newurl = malloc(urllen + newlen - currlen + 1);
if(newurl) {
/* copy the part before the host name */
memcpy(newurl, url, ptr - url);
/* append the new host name instead of the old */
memcpy(newurl + (ptr - url), conn->host.name, newlen);
/* append the piece after the host name */
memcpy(newurl + newlen + (ptr - url),
ptr + currlen, /* copy the trailing zero byte too */
urllen - (ptr-url) - currlen + 1);
if(data->change.url_alloc) {
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
data->change.url = newurl;
data->change.url_alloc = TRUE;
}
else
return CURLE_OUT_OF_MEMORY;
} }
} }
ppath = data->change.url; uc = curl_url_set(h, CURLUPART_FRAGMENT, NULL, 0);
if(checkprefix("ftp://", ppath)) { if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
}
if(strcasecompare("http", data->state.up.scheme)) {
/* when getting HTTP, we don't want the userinfo the URL */
uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
}
uc = curl_url_set(h, CURLUPART_PASSWORD, NULL, 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
}
}
/* now extract the new version of the URL */
uc = curl_url_get(h, CURLUPART_URL, &url, 0);
if(uc) {
curl_url_cleanup(h);
return CURLE_OUT_OF_MEMORY;
}
if(data->change.url_alloc)
free(data->change.url);
data->change.url = url;
data->change.url_alloc = TRUE;
curl_url_cleanup(h);
if(strcasecompare("ftp", data->state.up.scheme)) {
if(data->set.proxy_transfer_mode) { if(data->set.proxy_transfer_mode) {
/* when doing ftp, append ;type=<a|i> if not present */ /* when doing ftp, append ;type=<a|i> if not present */
char *type = strstr(ppath, ";type="); char *type = strstr(path, ";type=");
if(type && type[6] && type[7] == 0) { if(type && type[6] && type[7] == 0) {
switch(Curl_raw_toupper(type[6])) { switch(Curl_raw_toupper(type[6])) {
case 'A': case 'A':
@ -2278,7 +2291,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
char *p = ftp_typecode; char *p = ftp_typecode;
/* avoid sending invalid URLs like ftp://example.com;type=i if the /* avoid sending invalid URLs like ftp://example.com;type=i if the
* user specified ftp://example.com without the slash */ * user specified ftp://example.com without the slash */
if(!*data->state.path && ppath[strlen(ppath) - 1] != '/') { if(!*data->state.up.path && path[strlen(path) - 1] != '/') {
*p++ = '/'; *p++ = '/';
} }
snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c", snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c",
@ -2431,18 +2444,32 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(result) if(result)
return result; return result;
if(data->set.str[STRING_TARGET]) if(data->set.str[STRING_TARGET]) {
ppath = data->set.str[STRING_TARGET]; path = data->set.str[STRING_TARGET];
query = NULL;
}
/* url */ /* url */
if(paste_ftp_userpwd) if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
char *url = data->change.url;
result = Curl_add_buffer(&req_buffer, url, strlen(url));
if(result)
return result;
}
else if(paste_ftp_userpwd)
result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s", result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s",
conn->user, conn->passwd, conn->user, conn->passwd,
ppath + sizeof("ftp://") - 1); path + sizeof("ftp://") - 1);
else else {
result = Curl_add_buffer(&req_buffer, ppath, strlen(ppath)); result = Curl_add_buffer(&req_buffer, path, strlen(path));
if(result) if(result)
return result; return result;
if(query) {
result = Curl_add_bufferf(&req_buffer, "?%s", query);
if(result)
return result;
}
}
result = result =
Curl_add_bufferf(&req_buffer, Curl_add_bufferf(&req_buffer,
@ -2515,7 +2542,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
co = Curl_cookie_getlist(data->cookies, co = Curl_cookie_getlist(data->cookies,
conn->allocptr.cookiehost? conn->allocptr.cookiehost?
conn->allocptr.cookiehost:host, conn->allocptr.cookiehost:host,
data->state.path, data->state.up.path,
(conn->handler->protocol&CURLPROTO_HTTPS)? (conn->handler->protocol&CURLPROTO_HTTPS)?
TRUE:FALSE); TRUE:FALSE);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
@ -3836,7 +3863,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
here, or else use real peer host name. */ here, or else use real peer host name. */
conn->allocptr.cookiehost? conn->allocptr.cookiehost?
conn->allocptr.cookiehost:conn->host.name, conn->allocptr.cookiehost:conn->host.name,
data->state.path); data->state.up.path);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
} }
#endif #endif

View File

@ -1717,8 +1717,6 @@ static CURLcode imap_regular_transfer(struct connectdata *conn,
static CURLcode imap_setup_connection(struct connectdata *conn) static CURLcode imap_setup_connection(struct connectdata *conn)
{ {
struct Curl_easy *data = conn->data;
/* Initialise the IMAP layer */ /* Initialise the IMAP layer */
CURLcode result = imap_init(conn); CURLcode result = imap_init(conn);
if(result) if(result)
@ -1726,7 +1724,6 @@ static CURLcode imap_setup_connection(struct connectdata *conn)
/* Clear the TLS upgraded flag */ /* Clear the TLS upgraded flag */
conn->tls_upgraded = FALSE; conn->tls_upgraded = FALSE;
data->state.path++; /* don't include the initial slash */
return CURLE_OK; return CURLE_OK;
} }
@ -1959,7 +1956,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
CURLcode result = CURLE_OK; CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data; struct Curl_easy *data = conn->data;
struct IMAP *imap = data->req.protop; struct IMAP *imap = data->req.protop;
const char *begin = data->state.path; const char *begin = &data->state.up.path[1]; /* skip leading slash */
const char *ptr = begin; const char *ptr = begin;
/* See how much of the URL is a valid path and decode it */ /* See how much of the URL is a valid path and decode it */
@ -2065,17 +2062,10 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
/* Does the URL contain a query parameter? Only valid when we have a mailbox /* Does the URL contain a query parameter? Only valid when we have a mailbox
and no UID as per RFC-5092 */ and no UID as per RFC-5092 */
if(imap->mailbox && !imap->uid && !imap->mindex && *ptr == '?') { if(imap->mailbox && !imap->uid && !imap->mindex) {
/* Find the length of the query parameter */ /* Get the query parameter, URL decoded */
begin = ++ptr; (void)curl_url_get(data->state.uh, CURLUPART_QUERY, &imap->query,
while(imap_is_bchar(*ptr)) CURLU_URLDECODE);
ptr++;
/* Decode the query parameter */
result = Curl_urldecode(data, begin, ptr - begin, &imap->query, NULL,
TRUE);
if(result)
return result;
} }
/* Any extra stuff at the end of the URL is an error */ /* Any extra stuff at the end of the URL is an error */

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -838,9 +838,9 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
size_t i; size_t i;
if(!conn->data || if(!conn->data ||
!conn->data->state.path || !conn->data->state.up.path ||
conn->data->state.path[0] != '/' || conn->data->state.up.path[0] != '/' ||
!checkprefix("LDAP", conn->data->change.url)) !strcasecompare("LDAP", conn->data->state.up.scheme))
return LDAP_INVALID_SYNTAX; return LDAP_INVALID_SYNTAX;
ludp->lud_scope = LDAP_SCOPE_BASE; ludp->lud_scope = LDAP_SCOPE_BASE;
@ -848,7 +848,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
ludp->lud_host = conn->host.name; ludp->lud_host = conn->host.name;
/* Duplicate the path */ /* Duplicate the path */
p = path = strdup(conn->data->state.path + 1); p = path = strdup(conn->data->state.up.path + 1);
if(!path) if(!path)
return LDAP_NO_MEMORY; return LDAP_NO_MEMORY;

View File

@ -542,10 +542,8 @@ static CURLcode multi_done(struct connectdata **connp,
Curl_getoff_all_pipelines(data, conn); Curl_getoff_all_pipelines(data, conn);
/* Cleanup possible redirect junk */ /* Cleanup possible redirect junk */
free(data->req.newurl); Curl_safefree(data->req.newurl);
data->req.newurl = NULL; Curl_safefree(data->req.location);
free(data->req.location);
data->req.location = NULL;
switch(status) { switch(status) {
case CURLE_ABORTED_BY_CALLBACK: case CURLE_ABORTED_BY_CALLBACK:
@ -657,7 +655,6 @@ static CURLcode multi_done(struct connectdata **connp,
cache here, and therefore cannot be used from this point on cache here, and therefore cannot be used from this point on
*/ */
Curl_free_request_state(data); Curl_free_request_state(data);
return result; return result;
} }
@ -2015,8 +2012,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
} }
else if(comeback) else if(comeback)
rc = CURLM_CALL_MULTI_PERFORM; rc = CURLM_CALL_MULTI_PERFORM;
free(newurl);
break; break;
} }

View File

@ -1303,8 +1303,6 @@ static CURLcode pop3_regular_transfer(struct connectdata *conn,
static CURLcode pop3_setup_connection(struct connectdata *conn) static CURLcode pop3_setup_connection(struct connectdata *conn)
{ {
struct Curl_easy *data = conn->data;
/* Initialise the POP3 layer */ /* Initialise the POP3 layer */
CURLcode result = pop3_init(conn); CURLcode result = pop3_init(conn);
if(result) if(result)
@ -1312,7 +1310,6 @@ static CURLcode pop3_setup_connection(struct connectdata *conn)
/* Clear the TLS upgraded flag */ /* Clear the TLS upgraded flag */
conn->tls_upgraded = FALSE; conn->tls_upgraded = FALSE;
data->state.path++; /* don't include the initial slash */
return CURLE_OK; return CURLE_OK;
} }
@ -1387,7 +1384,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn)
/* The POP3 struct is already initialised in pop3_connect() */ /* The POP3 struct is already initialised in pop3_connect() */
struct Curl_easy *data = conn->data; struct Curl_easy *data = conn->data;
struct POP3 *pop3 = data->req.protop; struct POP3 *pop3 = data->req.protop;
const char *path = data->state.path; const char *path = &data->state.up.path[1]; /* skip leading path */
/* URL decode the path for the message ID */ /* URL decode the path for the message ID */
return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE); return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);

View File

@ -969,7 +969,7 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
char *slash; char *slash;
/* URL decode the path */ /* URL decode the path */
result = Curl_urldecode(data, data->state.path, 0, &path, NULL, TRUE); result = Curl_urldecode(data, data->state.up.path, 0, &path, NULL, TRUE);
if(result) if(result)
return result; return result;

View File

@ -1441,7 +1441,6 @@ static CURLcode smtp_regular_transfer(struct connectdata *conn,
static CURLcode smtp_setup_connection(struct connectdata *conn) static CURLcode smtp_setup_connection(struct connectdata *conn)
{ {
struct Curl_easy *data = conn->data;
CURLcode result; CURLcode result;
/* Clear the TLS upgraded flag */ /* Clear the TLS upgraded flag */
@ -1452,8 +1451,6 @@ static CURLcode smtp_setup_connection(struct connectdata *conn)
if(result) if(result)
return result; return result;
data->state.path++; /* don't include the initial slash */
return CURLE_OK; return CURLE_OK;
} }
@ -1507,7 +1504,7 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn)
/* The SMTP struct is already initialised in smtp_connect() */ /* The SMTP struct is already initialised in smtp_connect() */
struct Curl_easy *data = conn->data; struct Curl_easy *data = conn->data;
struct smtp_conn *smtpc = &conn->proto.smtpc; struct smtp_conn *smtpc = &conn->proto.smtpc;
const char *path = data->state.path; const char *path = &data->state.up.path[1]; /* skip leading path */
char localhost[HOSTNAME_MAX + 1]; char localhost[HOSTNAME_MAX + 1];
/* Calculate the path if necessary */ /* Calculate the path if necessary */

View File

@ -485,7 +485,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
/* As RFC3617 describes the separator slash is not actually part of the /* As RFC3617 describes the separator slash is not actually part of the
file name so we skip the always-present first letter of the path file name so we skip the always-present first letter of the path
string. */ string. */
result = Curl_urldecode(data, &state->conn->data->state.path[1], 0, result = Curl_urldecode(data, &state->conn->data->state.up.path[1], 0,
&filename, NULL, FALSE); &filename, NULL, FALSE);
if(result) if(result)
return result; return result;
@ -1374,7 +1374,7 @@ static CURLcode tftp_setup_connection(struct connectdata * conn)
/* TFTP URLs support an extension like ";mode=<typecode>" that /* TFTP URLs support an extension like ";mode=<typecode>" that
* we'll try to get now! */ * we'll try to get now! */
type = strstr(data->state.path, ";mode="); type = strstr(data->state.up.path, ";mode=");
if(!type) if(!type)
type = strstr(conn->host.rawalloc, ";mode="); type = strstr(conn->host.rawalloc, ";mode=");

View File

@ -567,7 +567,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
infof(data, infof(data,
"Rewinding stream by : %zd" "Rewinding stream by : %zd"
" bytes on url %s (zero-length body)\n", " bytes on url %s (zero-length body)\n",
nread, data->state.path); nread, data->state.up.path);
read_rewind(conn, (size_t)nread); read_rewind(conn, (size_t)nread);
} }
else { else {
@ -575,7 +575,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
"Excess found in a non pipelined read:" "Excess found in a non pipelined read:"
" excess = %zd" " excess = %zd"
" url = %s (zero-length body)\n", " url = %s (zero-length body)\n",
nread, data->state.path); nread, data->state.up.path);
} }
} }
@ -744,7 +744,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
" bytes on url %s (size = %" CURL_FORMAT_CURL_OFF_T " bytes on url %s (size = %" CURL_FORMAT_CURL_OFF_T
", maxdownload = %" CURL_FORMAT_CURL_OFF_T ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
", bytecount = %" CURL_FORMAT_CURL_OFF_T ", nread = %zd)\n", ", bytecount = %" CURL_FORMAT_CURL_OFF_T ", nread = %zd)\n",
excess, data->state.path, excess, data->state.up.path,
k->size, k->maxdownload, k->bytecount, nread); k->size, k->maxdownload, k->bytecount, nread);
read_rewind(conn, excess); read_rewind(conn, excess);
} }
@ -1474,6 +1474,7 @@ CURLcode Curl_follow(struct Curl_easy *data,
/* Location: redirect */ /* Location: redirect */
bool disallowport = FALSE; bool disallowport = FALSE;
bool reachedmax = FALSE; bool reachedmax = FALSE;
CURLUcode uc;
if(type == FOLLOW_REDIR) { if(type == FOLLOW_REDIR) {
if((data->set.maxredirs != -1) && if((data->set.maxredirs != -1) &&
@ -1506,33 +1507,21 @@ CURLcode Curl_follow(struct Curl_easy *data,
} }
} }
if(!Curl_is_absolute_url(newurl, NULL, 8)) { if(Curl_is_absolute_url(newurl, NULL, MAX_SCHEME_LEN))
/***
*DANG* this is an RFC 2068 violation. The URL is supposed
to be absolute and this doesn't seem to be that!
*/
char *absolute = Curl_concat_url(data->change.url, newurl);
if(!absolute)
return CURLE_OUT_OF_MEMORY;
newurl = absolute;
}
else {
/* The new URL MAY contain space or high byte values, that means a mighty
stupid redirect URL but we still make an effort to do "right". */
char *newest;
size_t newlen = Curl_strlen_url(newurl, FALSE);
/* This is an absolute URL, don't allow the custom port number */ /* This is an absolute URL, don't allow the custom port number */
disallowport = TRUE; disallowport = TRUE;
newest = malloc(newlen + 1); /* get memory for this */ DEBUGASSERT(data->state.uh);
if(!newest) uc = curl_url_set(data->state.uh, CURLUPART_URL, newurl, 0);
return CURLE_OUT_OF_MEMORY; free(newurl);
if(uc)
/* TODO: consider an error code remap here */
return CURLE_URL_MALFORMAT;
Curl_strcpy_url(newest, newurl, FALSE); /* create a space-free URL */ uc = curl_url_get(data->state.uh, CURLUPART_URL, &newurl, 0);
newurl = newest; /* use this instead now */ if(uc)
/* TODO: consider an error code remap here */
} return CURLE_OUT_OF_MEMORY;
if(type == FOLLOW_FAKE) { if(type == FOLLOW_FAKE) {
/* we're only figuring out the new url if we would've followed locations /* we're only figuring out the new url if we would've followed locations
@ -1549,10 +1538,8 @@ CURLcode Curl_follow(struct Curl_easy *data,
if(disallowport) if(disallowport)
data->state.allow_port = FALSE; data->state.allow_port = FALSE;
if(data->change.url_alloc) { if(data->change.url_alloc)
Curl_safefree(data->change.url); Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
}
data->change.url = newurl; data->change.url = newurl;
data->change.url_alloc = TRUE; data->change.url_alloc = TRUE;

1007
lib/url.c

File diff suppressed because it is too large Load Diff

View File

@ -48,6 +48,8 @@ CURLcode Curl_open(struct Curl_easy **curl);
CURLcode Curl_init_userdefined(struct Curl_easy *data); CURLcode Curl_init_userdefined(struct Curl_easy *data);
void Curl_freeset(struct Curl_easy * data); void Curl_freeset(struct Curl_easy * data);
/* free the URL pieces */
void Curl_up_free(struct Curl_easy *data);
CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */ CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */
CURLcode Curl_connect(struct Curl_easy *, struct connectdata **, CURLcode Curl_connect(struct Curl_easy *, struct connectdata **,
bool *async, bool *protocol_connect); bool *async, bool *protocol_connect);

View File

@ -1224,6 +1224,18 @@ struct time_node {
expire_id eid; expire_id eid;
}; };
/* individual pieces of the URL */
struct urlpieces {
char *scheme;
char *hostname;
char *port;
char *user;
char *password;
char *options;
char *path;
char *query;
};
struct UrlState { struct UrlState {
/* Points to the connection cache */ /* Points to the connection cache */
@ -1314,9 +1326,6 @@ struct UrlState {
/* for FTP downloads: how many CRLFs did we converted to LFs? */ /* for FTP downloads: how many CRLFs did we converted to LFs? */
curl_off_t crlf_conversions; curl_off_t crlf_conversions;
#endif #endif
char *pathbuffer;/* allocated buffer to store the URL's path part in */
char *path; /* path to use, points to somewhere within the pathbuffer
area */
bool slash_removed; /* set TRUE if the 'path' points to a path where the bool slash_removed; /* set TRUE if the 'path' points to a path where the
initial URL slash separator has been taken off */ initial URL slash separator has been taken off */
bool use_range; bool use_range;
@ -1350,6 +1359,8 @@ struct UrlState {
#ifdef CURLDEBUG #ifdef CURLDEBUG
bool conncache_lock; bool conncache_lock;
#endif #endif
CURLU *uh; /* URL handle for the current parsed URL */
struct urlpieces up;
}; };

View File

@ -15,7 +15,7 @@ HTTP/1.1 301 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake Server: test-server/fake
Content-Length: 7 Content-Length: 7
Location: http://%HOSTIP:%HTTPPORT/325 Location: http://somewhere/325
MooMoo MooMoo
</data> </data>
@ -24,7 +24,7 @@ HTTP/1.1 301 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake Server: test-server/fake
Content-Length: 7 Content-Length: 7
Location: http://%HOSTIP:%HTTPPORT/325 Location: http://somewhere/325
</datacheck> </datacheck>
</reply> </reply>

View File

@ -39,7 +39,7 @@ HTTP GET with proxy and CURLOPT_PORT
</name> </name>
# first URL then proxy # first URL then proxy
<command> <command>
http://www.example.com:999/523 http://%HOSTIP:%HTTPPORT http://www.example.com:999/523 http://%HOSTIP:%HTTPPORT
</command> </command>
</client> </client>
@ -50,7 +50,7 @@ http://www.example.com:999/523 http://%HOSTIP:%HTTPPORT
^User-Agent:.* ^User-Agent:.*
</strip> </strip>
<protocol> <protocol>
GET HTTP://www.example.com:19999/523 HTTP/1.1 GET http://www.example.com:19999/523 HTTP/1.1
Host: www.example.com:19999 Host: www.example.com:19999
Authorization: Basic eHh4Onl5eQ== Authorization: Basic eHh4Onl5eQ==
Accept: */* Accept: */*

View File

@ -47,7 +47,7 @@ ftp_proxy=http://%HOSTIP:%HTTPPORT/
# Verify data after the test has been "shot" # Verify data after the test has been "shot"
<verify> <verify>
<protocol> <protocol>
GET FTP://%HOSTIP:%FTPPORT/563;type=A HTTP/1.1 GET ftp://%HOSTIP:%FTPPORT/563;type=A HTTP/1.1
Host: %HOSTIP:%FTPPORT Host: %HOSTIP:%FTPPORT
Accept: */* Accept: */*
Proxy-Connection: Keep-Alive Proxy-Connection: Keep-Alive