aboutsummaryrefslogtreecommitdiff
path: root/lib/url.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2007-08-01 21:20:01 +0000
committerDaniel Stenberg <daniel@haxx.se>2007-08-01 21:20:01 +0000
commit50c10aa5bf545eedfdbe561116656b6ec12654cd (patch)
treeae3de37fd3877d42ffd4c0cdcd03c4530e68a326 /lib/url.c
parent006878686cfd3faa9eca92fc8fe60cb8f8073a59 (diff)
Patrick Monnerat and I modified libcurl so that now it *copies* all strings
passed to it with curl_easy_setopt()! Previously it has always just refered to the data, forcing the user to keep the data around until libcurl is done with it. That is now history and libcurl will instead clone the given strings and keep private copies.
Diffstat (limited to 'lib/url.c')
-rw-r--r--lib/url.c220
1 files changed, 159 insertions, 61 deletions
diff --git a/lib/url.c b/lib/url.c
index 7a8effb1e..0de87a824 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -217,6 +217,59 @@ static void close_connections(struct SessionHandle *data)
; /* empty loop */
}
+void Curl_freeset(struct SessionHandle * data)
+{
+ /* Free all dynamic strings stored in the data->set substructure. */
+ enum dupstring i;
+ for(i=0; i < STRING_LAST; i++)
+ Curl_safefree(data->set.str[i]);
+}
+
+static CURLcode Curl_setstropt(char **charp, char * s)
+{
+ /* Release the previous storage at `charp' and replace by a dynamic storage
+ copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
+
+ if (*charp) {
+ free(*charp);
+ *charp = (char *) NULL;
+ }
+
+ if (s) {
+ s = strdup(s);
+
+ if (!s)
+ return CURLE_OUT_OF_MEMORY;
+
+ *charp = s;
+ }
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src)
+{
+ CURLcode r;
+ enum dupstring i;
+
+ /* Copy src->set into dst->set first, then deal with the strings
+ afterwards */
+ dst->set = src->set;
+
+ /* clear all string pointers first */
+ memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
+
+ /* duplicate all strings */
+ for(i=0; i< STRING_LAST; i++) {
+ r = Curl_setstropt(&dst->set.str[i], src->set.str[i]);
+ if (r != CURLE_OK)
+ break;
+ }
+
+ /* If a failure occurred, freeing has to be performed externally. */
+ return r;
+}
+
/*
* This is the internal function curl_easy_cleanup() calls. This should
* cleanup and free all resources associated with this sessionhandle.
@@ -329,7 +382,7 @@ CURLcode Curl_close(struct SessionHandle *data)
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
- if(data->set.cookiejar) {
+ if(data->set.str[STRING_COOKIEJAR]) {
if(data->change.cookielist) {
/* If there is a list of cookie files to read, do it first so that
we have all the told files read before we write the new jar */
@@ -337,9 +390,9 @@ CURLcode Curl_close(struct SessionHandle *data)
}
/* we have a "destination" for all the cookies to get dumped to */
- if(Curl_cookie_output(data->cookies, data->set.cookiejar))
+ if(Curl_cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
infof(data, "WARNING: failed to save cookies in %s\n",
- data->set.cookiejar);
+ data->set.str[STRING_COOKIEJAR]);
}
else {
if(data->change.cookielist)
@@ -381,6 +434,7 @@ CURLcode Curl_close(struct SessionHandle *data)
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
}
+ Curl_freeset(data);
free(data);
return CURLE_OK;
}
@@ -609,7 +663,8 @@ CURLcode Curl_open(struct SessionHandle **curl)
data->set.ssl.sessionid = TRUE; /* session ID caching enabled by default */
#ifdef CURL_CA_BUNDLE
/* This is our preferred CA cert bundle since install time */
- data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
+ res = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
+ (char *) CURL_CA_BUNDLE);
#endif
}
@@ -617,6 +672,7 @@ CURLcode Curl_open(struct SessionHandle **curl)
ares_destroy(data->state.areschannel);
if(data->state.headerbuff)
free(data->state.headerbuff);
+ Curl_freeset(data);
free(data);
data = NULL;
}
@@ -648,7 +704,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
break;
case CURLOPT_SSL_CIPHER_LIST:
/* set a list of cipher we want to use in the SSL connection */
- data->set.ssl.cipher_list = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],
+ va_arg(param, char *));
break;
case CURLOPT_RANDOM_FILE:
@@ -656,13 +713,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* This is the path name to a file that contains random data to seed
* the random SSL stuff with. The file is only used for reading.
*/
- data->set.ssl.random_file = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_SSL_RANDOM_FILE],
+ va_arg(param, char *));
break;
case CURLOPT_EGDSOCKET:
/*
* The Entropy Gathering Daemon socket pathname
*/
- data->set.ssl.egdsocket = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_SSL_EGDSOCKET],
+ va_arg(param, char *));
break;
case CURLOPT_MAXCONNECTS:
/*
@@ -785,7 +844,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Use this file instead of the $HOME/.netrc file
*/
- data->set.netrc_file = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_NETRC_FILE],
+ va_arg(param, char *));
break;
case CURLOPT_TRANSFERTEXT:
/*
@@ -836,9 +896,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* and ignore an received Content-Encoding header.
*
*/
- data->set.encoding = va_arg(param, char *);
- if(data->set.encoding && !*data->set.encoding)
- data->set.encoding = (char*)ALL_CONTENT_ENCODINGS;
+ argptr = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_ENCODING],
+ (argptr && !*argptr)?
+ (char *) ALL_CONTENT_ENCODINGS: argptr);
break;
case CURLOPT_FOLLOWLOCATION:
@@ -881,7 +942,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* A string with POST data. Makes curl HTTP POST. Even if it is NULL.
*/
- data->set.postfields = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_POSTFIELDS],
+ va_arg(param, char *));
data->set.httpreq = HTTPREQ_POST;
break;
@@ -918,15 +980,17 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
free(data->change.referer);
data->change.referer_alloc = FALSE;
}
- data->set.set_referer = va_arg(param, char *);
- data->change.referer = data->set.set_referer;
+ result = Curl_setstropt(&data->set.str[STRING_SET_REFERER],
+ va_arg(param, char *));
+ data->change.referer = data->set.str[STRING_SET_REFERER];
break;
case CURLOPT_USERAGENT:
/*
* String to use in the HTTP User-Agent field
*/
- data->set.useragent = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_USERAGENT],
+ va_arg(param, char *));
break;
case CURLOPT_HTTPHEADER:
@@ -948,7 +1012,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Cookie string to send to the remote server in the request.
*/
- data->set.cookie = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_COOKIE],
+ va_arg(param, char *));
break;
case CURLOPT_COOKIEFILE:
@@ -973,7 +1038,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Set cookie file name to dump all cookies to when we're done.
*/
- data->set.cookiejar = (char *)va_arg(param, void *);
+ result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR],
+ va_arg(param, char *));
/*
* Activate the cookie parser. This may or may not already
@@ -1071,7 +1137,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Set a custom string to use as request
*/
- data->set.customrequest = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST],
+ va_arg(param, char *));
/* we don't set
data->set.httpreq = HTTPREQ_CUSTOM;
@@ -1137,7 +1204,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* Setting it to NULL, means no proxy but allows the environment variables
* to decide for us.
*/
- data->set.proxy = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_PROXY],
+ va_arg(param, char *));
break;
case CURLOPT_WRITEHEADER:
@@ -1163,8 +1231,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Use FTP PORT, this also specifies which IP address to use
*/
- data->set.ftpport = va_arg(param, char *);
- data->set.ftp_use_port = (bool)(NULL != data->set.ftpport);
+ result = Curl_setstropt(&data->set.str[STRING_FTPPORT],
+ va_arg(param, char *));
+ data->set.ftp_use_port = (bool)(NULL != data->set.str[STRING_FTPPORT]);
break;
case CURLOPT_FTP_USE_EPRT:
@@ -1247,8 +1316,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
free(data->change.url);
data->change.url_alloc=FALSE;
}
- data->set.set_url = va_arg(param, char *);
- data->change.url = data->set.set_url;
+ result = Curl_setstropt(&data->set.str[STRING_SET_URL],
+ va_arg(param, char *));
+ data->change.url = data->set.str[STRING_SET_URL];
data->change.url_changed = TRUE;
break;
case CURLOPT_PORT:
@@ -1284,7 +1354,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* user:password to use in the operation
*/
- data->set.userpwd = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_USERPWD],
+ va_arg(param, char *));
break;
case CURLOPT_POSTQUOTE:
/*
@@ -1325,13 +1396,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* user:password needed to use the proxy
*/
- data->set.proxyuserpwd = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_PROXYUSERPWD],
+ va_arg(param, char *));
break;
case CURLOPT_RANGE:
/*
* What range of the file you want to transfer
*/
- data->set.set_range = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_SET_RANGE],
+ va_arg(param, char *));
break;
case CURLOPT_RESUME_FROM:
/*
@@ -1428,31 +1501,36 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* String that holds file name of the SSL certificate to use
*/
- data->set.cert = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_CERT],
+ va_arg(param, char *));
break;
case CURLOPT_SSLCERTTYPE:
/*
* String that holds file type of the SSL certificate to use
*/
- data->set.cert_type = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE],
+ va_arg(param, char *));
break;
case CURLOPT_SSLKEY:
/*
* String that holds file name of the SSL certificate to use
*/
- data->set.key = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_KEY],
+ va_arg(param, char *));
break;
case CURLOPT_SSLKEYTYPE:
/*
* String that holds file type of the SSL certificate to use
*/
- data->set.key_type = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE],
+ va_arg(param, char *));
break;
case CURLOPT_SSLKEYPASSWD:
/*
* String that holds the SSL private key password.
*/
- data->set.key_passwd = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD],
+ va_arg(param, char *));
break;
case CURLOPT_SSLENGINE:
/*
@@ -1481,7 +1559,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* Set what interface or address/hostname to bind the socket to when
* performing an operation and thus what from-IP your connection will use.
*/
- data->set.device = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_DEVICE],
+ va_arg(param, char *));
break;
case CURLOPT_LOCALPORT:
/*
@@ -1499,8 +1578,9 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* A string that defines the kerberos security level.
*/
- data->set.krb_level = va_arg(param, char *);
- data->set.krb = (bool)(NULL != data->set.krb_level);
+ result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL],
+ va_arg(param, char *));
+ data->set.krb = (bool)(NULL != data->set.str[STRING_KRB_LEVEL]);
break;
case CURLOPT_SSL_VERIFYPEER:
/*
@@ -1530,7 +1610,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Set CA info for SSL connection. Specify file name of the CA certificate
*/
- data->set.ssl.CAfile = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
+ va_arg(param, char *));
break;
case CURLOPT_CAPATH:
/*
@@ -1538,7 +1619,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* certificates which have been prepared using openssl c_rehash utility.
*/
/* This does not work on windows. */
- data->set.ssl.CApath = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH],
+ va_arg(param, char *));
break;
case CURLOPT_TELNETOPTIONS:
/*
@@ -1639,7 +1721,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Set private data pointer.
*/
- data->set.private_data = va_arg(param, char *);
+ data->set.private_data = va_arg(param, void *);
break;
case CURLOPT_MAXFILESIZE:
@@ -1691,7 +1773,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
These former 3rd party transfer options are deprecated */
case CURLOPT_FTP_ACCOUNT:
- data->set.ftp_account = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT],
+ va_arg(param, char *));
break;
case CURLOPT_IGNORE_CONTENT_LENGTH:
@@ -1706,7 +1789,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
break;
case CURLOPT_FTP_ALTERNATIVE_TO_USER:
- data->set.ftp_alternative_to_user = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
+ va_arg(param, char *));
break;
case CURLOPT_SOCKOPTFUNCTION:
@@ -1735,14 +1819,16 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Use this file instead of the $HOME/.ssh/id_dsa.pub file
*/
- data->set.ssh_public_key = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
+ va_arg(param, char *));
break;
case CURLOPT_SSH_PRIVATE_KEYFILE:
/*
* Use this file instead of the $HOME/.ssh/id_dsa file
*/
- data->set.ssh_private_key = va_arg(param, char *);
+ result = Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
+ va_arg(param, char *));
break;
case CURLOPT_HTTP_TRANSFER_DECODING:
@@ -2780,14 +2866,14 @@ static CURLcode setup_range(struct SessionHandle *data)
struct HandleData *req = &data->reqdata;
req->resume_from = data->set.set_resume_from;
- if (req->resume_from || data->set.set_range) {
+ if (req->resume_from || data->set.str[STRING_SET_RANGE]) {
if (req->rangestringalloc == TRUE)
free(req->range);
if(req->resume_from)
req->range = aprintf("%" FORMAT_OFF_T "-", req->resume_from);
else
- req->range = strdup(data->set.set_range);
+ req->range = strdup(data->set.str[STRING_SET_RANGE]);
req->rangestringalloc = req->range?TRUE:FALSE;
@@ -2892,7 +2978,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
conn->connectindex = -1; /* no index */
conn->proxytype = data->set.proxytype; /* type */
- conn->bits.proxy = (bool)(data->set.proxy && *data->set.proxy);
+ conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] &&
+ *data->set.str[STRING_PROXY]);
conn->bits.httpproxy = (bool)(conn->bits.proxy
&& (conn->proxytype == CURLPROXY_HTTP));
@@ -2911,8 +2998,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* Store creation time to help future close decision making */
conn->created = Curl_tvnow();
- conn->bits.user_passwd = (bool)(NULL != data->set.userpwd);
- conn->bits.proxy_user_passwd = (bool)(NULL != data->set.proxyuserpwd);
+ conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERPWD]);
+ conn->bits.proxy_user_passwd = (bool)(NULL != data->set.str[STRING_PROXYUSERPWD]);
conn->bits.no_body = data->set.opt_no_body;
conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
@@ -2945,11 +3032,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
if(urllen < LEAST_PATH_ALLOC)
urllen=LEAST_PATH_ALLOC;
- if (!data->set.source_url /* 3rd party FTP */
- && data->reqdata.pathbuffer) {
- /* Free the old buffer */
- free(data->reqdata.pathbuffer);
- }
+ /* Free the old buffer */
+ Curl_safefree(data->reqdata.pathbuffer);
/*
* We malloc() the buffers below urllen+2 to make room for to possibilities:
@@ -2981,7 +3065,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
char proxyuser[MAX_CURL_USER_LENGTH]="";
char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
- sscanf(data->set.proxyuserpwd,
+ sscanf(data->set.str[STRING_PROXYUSERPWD],
"%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
"%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
proxyuser, proxypasswd);
@@ -2995,8 +3079,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
return CURLE_OUT_OF_MEMORY;
}
- if (data->set.proxy) {
- proxy = strdup(data->set.proxy); /* if global proxy is set, this is it */
+ if (data->set.str[STRING_PROXY]) {
+ proxy = strdup(data->set.str[STRING_PROXY]);
+ /* if global proxy is set, this is it */
if(NULL == proxy) {
failf(data, "memory shortage");
return CURLE_OUT_OF_MEMORY;
@@ -3711,9 +3796,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* user_password is set in "inherit initial knowledge' above,
* so it doesn't have to be set in this block
*/
- if (data->set.userpwd != NULL) {
+ if (data->set.str[STRING_USERPWD] != NULL) {
/* the name is given, get user+password */
- sscanf(data->set.userpwd,
+ sscanf(data->set.str[STRING_USERPWD],
"%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
"%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
user, passwd);
@@ -3723,7 +3808,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
if (data->set.use_netrc != CURL_NETRC_IGNORED) {
if(Curl_parsenetrc(conn->host.name,
user, passwd,
- data->set.netrc_file)) {
+ data->set.str[STRING_NETRC_FILE])) {
infof(data, "Couldn't find host %s in the " DOT_CHAR
"netrc file, using defaults\n",
conn->host.name);
@@ -3760,8 +3845,21 @@ static CURLcode CreateConnection(struct SessionHandle *data,
* new one.
*************************************************************/
- /* get a cloned copy of the SSL config situation stored in the
- connection struct */
+ /* Get a cloned copy of the SSL config situation stored in the
+ connection struct. But to get this going nicely, we must first make
+ sure that the strings in the master copy are pointing to the correct
+ strings in the session handle strings array!
+
+ Keep in mind that the pointers in the master copy are pointing to strings
+ that will be freed as part of the SessionHandle struct, but all cloned
+ copies will be separately allocated.
+ */
+ data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH];
+ data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE];
+ data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
+ data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
+ data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
+
if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config))
return CURLE_OUT_OF_MEMORY;
@@ -4081,10 +4179,10 @@ static CURLcode SetupConnection(struct connectdata *conn,
/*************************************************************
* Set user-agent for HTTP
*************************************************************/
- if((conn->protocol&PROT_HTTP) && data->set.useragent) {
+ if((conn->protocol&PROT_HTTP) && data->set.str[STRING_USERAGENT]) {
Curl_safefree(conn->allocptr.uagent);
conn->allocptr.uagent =
- aprintf("User-Agent: %s\r\n", data->set.useragent);
+ aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
if(!conn->allocptr.uagent)
return CURLE_OUT_OF_MEMORY;
}