From 50c10aa5bf545eedfdbe561116656b6ec12654cd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 1 Aug 2007 21:20:01 +0000 Subject: 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. --- CHANGES | 12 +++ RELEASE-NOTES | 1 + docs/libcurl/curl_easy_getinfo.3 | 4 +- docs/libcurl/curl_easy_setopt.3 | 22 ++-- include/curl/curlver.h | 8 +- lib/connect.c | 20 ++-- lib/easy.c | 7 +- lib/ftp.c | 40 +++---- lib/getinfo.c | 2 +- lib/gtls.c | 10 +- lib/gtls.h | 4 +- lib/http.c | 46 ++++---- lib/nss.c | 9 +- lib/nssg.h | 4 +- lib/ssh.c | 10 +- lib/sslgen.c | 19 +--- lib/ssluse.c | 56 +++++----- lib/transfer.c | 4 +- lib/url.c | 220 ++++++++++++++++++++++++++++----------- lib/url.h | 2 + lib/urldata.h | 82 ++++++++------- 21 files changed, 364 insertions(+), 218 deletions(-) diff --git a/CHANGES b/CHANGES index a245e7d09..ef30dc1e6 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,18 @@ Changelog Daniel S (1 August 2007) +- 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. This is also part of Patrick Monnerat's + OS/400 port. + + Due to this being a somewhat interesting change API wise, I've decided to + bump the version of the upcoming release to 7.17.0. Older applications will + of course not notice this change nor do they have to care, but new + applications can be written to take advantage of this. + - Greg Morse reported a problem with POSTing using ANYAUTH to a server requiring NTLM, and he provided test code and a test server and we worked out a bug fix. We failed to count sent body data at times, which then caused diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 5e64b764c..0377adb93 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -12,6 +12,7 @@ Curl and libcurl 7.16.5 This release includes the following changes: o support for OS/400 Secure Sockets Layer library + o curl_easy_setopt() now allocates strings passed to it This release includes the following bugfixes: diff --git a/docs/libcurl/curl_easy_getinfo.3 b/docs/libcurl/curl_easy_getinfo.3 index fe13f07c9..95455e3a1 100644 --- a/docs/libcurl/curl_easy_getinfo.3 +++ b/docs/libcurl/curl_easy_getinfo.3 @@ -133,7 +133,9 @@ protocol used doesn't support this. .IP CURLINFO_PRIVATE Pass a pointer to a 'char *' to receive the pointer to the private data associated with the curl handle (set with the CURLOPT_PRIVATE option to -\fIcurl_easy_setopt(3)\fP). (Added in 7.10.3) +\fIcurl_easy_setopt(3)\fP). Please note that for internal reasons, the +value is returned as a 'char *', although effectively being a 'void *'. +(Added in 7.10.3) .IP CURLINFO_HTTPAUTH_AVAIL Pass a pointer to a long to receive a bitmask indicating the authentication method(s) available. The meaning of the bits is explained in the diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index 63b53f7c4..016bb9181 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -21,7 +21,7 @@ .\" * $Id$ .\" ************************************************************************** .\" -.TH curl_easy_setopt 3 "22 Feb 2007" "libcurl 7.16.2" "libcurl Manual" +.TH curl_easy_setopt 3 "1 Aug 2007" "libcurl 7.17.0" "libcurl Manual" .SH NAME curl_easy_setopt \- set options for a curl easy handle .SH SYNOPSIS @@ -44,11 +44,13 @@ between transfers, so if you want subsequent transfers with different options, you must change them between the transfers. You can optionally reset all options back to internal default with \fIcurl_easy_reset(3)\fP. -Strings passed to libcurl as 'char *' arguments, will not be copied by the -library. Instead you should keep them available until libcurl no longer needs -them. Failing to do so will cause very odd behavior or even crashes. libcurl -will need them until you call \fIcurl_easy_cleanup(3)\fP or you set the same -option again to use a different pointer. +Strings passed to libcurl as 'char *' arguments, are copied by the library; +thus the string storage associated to the pointer argument may be overwritten +after curl_easy_setopt() returns. Exceptions to this rule are described in +the option details below. + +NOTE: before 7.17.0 strings were not copied. Instead the user was forced keep +them available until libcurl no longer needed them. The \fIhandle\fP is the return code from a \fIcurl_easy_init(3)\fP or \fIcurl_easy_duphandle(3)\fP call. @@ -330,6 +332,12 @@ system. Pass a char * to a buffer that the libcurl may store human readable error messages in. This may be more helpful than just the return code from \fIcurl_easy_perform\fP. The buffer must be at least CURL_ERROR_SIZE big. +Although this argument is a 'char *', it does not describe an input string. +Therefore the (probably undefined) contents of the buffer is NOT copied +by the library. You should keep the associated storage available until +libcurl no longer needs it. Failing to do so will cause very odd behavior +or even crashes. libcurl will need it until you call \fIcurl_easy_cleanup(3)\fP +or you set the same option again to use a different pointer. Use \fICURLOPT_VERBOSE\fP and \fICURLOPT_DEBUGFUNCTION\fP to better debug/trace why errors happen. @@ -1397,7 +1405,7 @@ If the file is password-protected, set the password with \fICURLOPT_SSLKEYPASSWD (Added in 7.16.1) .SH OTHER OPTIONS .IP CURLOPT_PRIVATE -Pass a char * as parameter, pointing to data that should be associated with +Pass a void * as parameter, pointing to data that should be associated with this curl handle. The pointer can subsequently be retrieved using \fIcurl_easy_getinfo(3)\fP with the CURLINFO_PRIVATE option. libcurl itself does nothing with this data. (Added in 7.10.3) diff --git a/include/curl/curlver.h b/include/curl/curlver.h index 11b34dcaf..4657398bc 100644 --- a/include/curl/curlver.h +++ b/include/curl/curlver.h @@ -28,13 +28,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.16.5-CVS" +#define LIBCURL_VERSION "7.17.0-CVS" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 16 -#define LIBCURL_VERSION_PATCH 5 +#define LIBCURL_VERSION_MINOR 17 +#define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will @@ -51,7 +51,7 @@ and it is always a greater number in a more recent release. It makes comparisons with greater than and less than work. */ -#define LIBCURL_VERSION_NUM 0x071005 +#define LIBCURL_VERSION_NUM 0x071100 /* * This is the date and time when the full source package was created. The diff --git a/lib/connect.c b/lib/connect.c index d608e1e2e..634595766 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -228,11 +228,12 @@ static CURLcode bindlocal(struct connectdata *conn, "random" */ /* how many port numbers to try to bind to, increasing one at a time */ int portnum = data->set.localportrange; + const char *dev = data->set.str[STRING_DEVICE]; /************************************************************* * Select device to bind socket to *************************************************************/ - if (data->set.device && (strlen(data->set.device)<255) ) { + if (dev && (strlen(dev)<255) ) { struct Curl_dns_entry *h=NULL; char myhost[256] = ""; in_addr_t in; @@ -241,10 +242,10 @@ static CURLcode bindlocal(struct connectdata *conn, int in6 = -1; /* First check if the given name is an IP address */ - in=inet_addr(data->set.device); + in=inet_addr(dev); if((in == CURL_INADDR_NONE) && - Curl_if2ip(data->set.device, myhost, sizeof(myhost))) { + Curl_if2ip(dev, myhost, sizeof(myhost))) { /* * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer */ @@ -263,7 +264,7 @@ static CURLcode bindlocal(struct connectdata *conn, * This was not an interface, resolve the name as a host name * or IP number */ - rc = Curl_resolv(conn, data->set.device, 0, &h); + rc = Curl_resolv(conn, dev, 0, &h); if(rc == CURLRESOLV_PENDING) (void)Curl_wait_for_resolv(conn, &h); @@ -275,7 +276,7 @@ static CURLcode bindlocal(struct connectdata *conn, myhost, sizeof myhost); else /* we know data->set.device is shorter than the myhost array */ - strcpy(myhost, data->set.device); + strcpy(myhost, dev); Curl_resolv_unlock(data, h); } } @@ -287,7 +288,7 @@ static CURLcode bindlocal(struct connectdata *conn, hostent_buf, sizeof(hostent_buf)); */ - failf(data, "Couldn't bind to '%s'", data->set.device); + failf(data, "Couldn't bind to '%s'", dev); return CURLE_INTERFACE_FAILED; } @@ -307,11 +308,10 @@ static CURLcode bindlocal(struct connectdata *conn, * hostname or ip address. */ if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE, - data->set.device, strlen(data->set.device)+1) != 0) { + dev, strlen(dev)+1) != 0) { /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n", - sockfd, data->set.device, Curl_strerror(SOCKERRNO)); */ - infof(data, "SO_BINDTODEVICE %s failed\n", - data->set.device); + sockfd, dev, Curl_strerror(SOCKERRNO)); */ + infof(data, "SO_BINDTODEVICE %s failed\n", dev); /* This is typically "errno 1, error: Operation not permitted" if you're not running as root or another suitable privileged user */ } diff --git a/lib/easy.c b/lib/easy.c index b1080a22d..54915fb88 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -579,7 +579,8 @@ CURL *curl_easy_duphandle(CURL *incurl) outcurl->state.headersize=HEADERSIZE; /* copy all userdefined values */ - outcurl->set = data->set; + if (Curl_dupset(outcurl, data) != CURLE_OK) + break; if(data->state.used_interface == Curl_if_multi) outcurl->state.connc = data->state.connc; @@ -658,6 +659,7 @@ CURL *curl_easy_duphandle(CURL *incurl) free(outcurl->change.url); if(outcurl->change.referer) free(outcurl->change.referer); + Curl_freeset(outcurl); free(outcurl); /* free the memory again */ outcurl = NULL; } @@ -681,6 +683,7 @@ void curl_easy_reset(CURL *curl) data->reqdata.proto.generic=NULL; /* zero out UserDefined data: */ + Curl_freeset(data); memset(&data->set, 0, sizeof(struct UserDefined)); /* zero out Progress data: */ @@ -732,7 +735,7 @@ void curl_easy_reset(CURL *curl) data->set.ssl.verifyhost = 2; #ifdef CURL_CA_BUNDLE /* This is our prefered CA cert bundle since install time */ - data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE; + (void) curl_easy_setopt(curl, CURLOPT_CAINFO, (char *) CURL_CA_BUNDLE); #endif data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth diff --git a/lib/ftp.c b/lib/ftp.c index 4df17decb..6958eb7f2 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -871,11 +871,12 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, /* Step 1, figure out what address that is requested */ - if(data->set.ftpport && (strlen(data->set.ftpport) > 1)) { + if(data->set.str[STRING_FTPPORT] && + (strlen(data->set.str[STRING_FTPPORT]) > 1)) { /* attempt to get the address of the given interface name */ - if(!Curl_if2ip(data->set.ftpport, hbuf, sizeof(hbuf))) + if(!Curl_if2ip(data->set.str[STRING_FTPPORT], hbuf, sizeof(hbuf))) /* not an interface, use the given string as host name instead */ - host = data->set.ftpport; + host = data->set.str[STRING_FTPPORT]; else host = hbuf; /* use the hbuf for host name */ } /* data->set.ftpport */ @@ -1080,27 +1081,28 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, unsigned short ip[4]; bool freeaddr = TRUE; socklen_t sslen = sizeof(sa); + const char *ftpport = data->set.str[STRING_FTPPORT]; (void)fcmd; /* not used in the IPv4 code */ - if(data->set.ftpport) { + if(ftpport) { in_addr_t in; /* First check if the given name is an IP address */ - in=inet_addr(data->set.ftpport); + in=inet_addr(ftpport); if(in != CURL_INADDR_NONE) /* this is an IPv4 address */ - addr = Curl_ip2addr(in, data->set.ftpport, 0); + addr = Curl_ip2addr(in, ftpport, 0); else { - if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) { + if(Curl_if2ip(ftpport, myhost, sizeof(myhost))) { /* The interface to IP conversion provided a dotted address */ in=inet_addr(myhost); addr = Curl_ip2addr(in, myhost, 0); } - else if(strlen(data->set.ftpport)> 1) { + else if(strlen(ftpport)> 1) { /* might be a host name! */ struct Curl_dns_entry *h=NULL; - int rc = Curl_resolv(conn, data->set.ftpport, 0, &h); + int rc = Curl_resolv(conn, ftpport, 0, &h); if(rc == CURLRESOLV_PENDING) /* BLOCKING */ rc = Curl_wait_for_resolv(conn, &h); @@ -1114,11 +1116,11 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, since it points to a DNS cache entry! */ } /* (h) */ else { - infof(data, "Failed to resolve host name %s\n", data->set.ftpport); + infof(data, "Failed to resolve host name %s\n", ftpport); } } /* strlen */ } /* CURL_INADDR_NONE */ - } /* data->set.ftpport */ + } /* ftpport */ if(!addr) { /* pick a suitable default here */ @@ -1346,7 +1348,8 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn) servers either... */ NBFTPSENDF(conn, "%s", - data->set.customrequest?data->set.customrequest: + data->set.str[STRING_CUSTOMREQUEST]? + data->set.str[STRING_CUSTOMREQUEST]: (data->set.ftp_list_only?"NLST":"LIST")); state(conn, FTP_LIST); @@ -1720,7 +1723,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, return CURLE_FTP_WEIRD_PASV_REPLY; } - if(data->set.proxy && *data->set.proxy) { + if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) { /* * This is a tunnel through a http proxy and we need to connect to the * proxy again here. @@ -2384,8 +2387,8 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, result = ftp_state_loggedin(conn); } else if(ftpcode == 332) { - if(data->set.ftp_account) { - NBFTPSENDF(conn, "ACCT %s", data->set.ftp_account); + if(data->set.str[STRING_FTP_ACCOUNT]) { + NBFTPSENDF(conn, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]); state(conn, FTP_ACCT); } else { @@ -2399,10 +2402,11 @@ static CURLcode ftp_state_user_resp(struct connectdata *conn, 530 User ... access denied (the server denies to log the specified user) */ - if (conn->data->set.ftp_alternative_to_user && + if (conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] && !conn->data->state.ftp_trying_alternative) { /* Ok, USER failed. Let's try the supplied command. */ - NBFTPSENDF(conn, "%s", conn->data->set.ftp_alternative_to_user); + NBFTPSENDF(conn, "%s", + conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]); conn->data->state.ftp_trying_alternative = TRUE; state(conn, FTP_USER); result = CURLE_OK; @@ -2488,7 +2492,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) Curl_sec_request_prot(conn, "private"); /* We set private first as default, in case the line below fails to set a valid level */ - Curl_sec_request_prot(conn, data->set.krb_level); + Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); if(Curl_sec_login(conn) != 0) infof(data, "Logging in with password in cleartext!\n"); diff --git a/lib/getinfo.c b/lib/getinfo.c index c94ca2cb9..2ec0242a6 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -176,7 +176,7 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) *param_charp = data->info.contenttype; break; case CURLINFO_PRIVATE: - *param_charp = data->set.private_data; + *param_charp = (char *) data->set.private_data; break; case CURLINFO_HTTPAUTH_AVAIL: *param_longp = data->info.httpauthavail; diff --git a/lib/gtls.c b/lib/gtls.c index 03572d88e..a40ea096b 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -299,11 +299,13 @@ Curl_gtls_connect(struct connectdata *conn, if(rc < 0) return CURLE_SSL_CONNECT_ERROR; - if(data->set.cert) { + if(data->set.str[STRING_CERT]) { if( gnutls_certificate_set_x509_key_file( - conn->ssl[sockindex].cred, data->set.cert, - data->set.key != 0 ? data->set.key : data->set.cert, - do_file_type(data->set.cert_type) ) ) { + conn->ssl[sockindex].cred, + data->set.str[STRING_CERT], + data->set.str[STRING_KEY] ? + data->set.str[STRING_KEY] : data->set.str[STRING_CERT], + do_file_type(data->set.str[STRING_CERT_TYPE]) ) ) { failf(data, "error reading X.509 key or certificate file"); return CURLE_SSL_CONNECT_ERROR; } diff --git a/lib/gtls.h b/lib/gtls.h index bff3f8693..feb02fd64 100644 --- a/lib/gtls.h +++ b/lib/gtls.h @@ -29,7 +29,9 @@ CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex); /* tell GnuTLS to close down all open information regarding connections (and thus session ID caching etc) */ void Curl_gtls_close_all(struct SessionHandle *data); -void Curl_gtls_close(struct connectdata *conn); /* close a SSL connection */ + + /* close a SSL connection */ +void Curl_gtls_close(struct connectdata *conn, int index); /* return number of sent (non-SSL) bytes */ ssize_t Curl_gtls_send(struct connectdata *conn, int sockindex, diff --git a/lib/http.c b/lib/http.c index 19e7483df..61511b57a 100644 --- a/lib/http.c +++ b/lib/http.c @@ -1187,7 +1187,8 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(!checkheaders(data, "Proxy-Connection:")) proxyconn = "Proxy-Connection: Keep-Alive\r\n"; - if(!checkheaders(data, "User-Agent:") && data->set.useragent) + if(!checkheaders(data, "User-Agent:") && + data->set.str[STRING_USERAGENT]) useragent = conn->allocptr.uagent; /* Send the connect request to the proxy */ @@ -1770,8 +1771,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } /* Now set the 'request' pointer to the proper request string */ - if(data->set.customrequest) - request = data->set.customrequest; + if(data->set.str[STRING_CUSTOMREQUEST]) + request = data->set.str[STRING_CUSTOMREQUEST]; else { if(conn->bits.no_body) request = (char *)"HEAD"; @@ -1826,14 +1827,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else conn->allocptr.ref = NULL; - if(data->set.cookie && !checkheaders(data, "Cookie:")) - addcookies = data->set.cookie; + if(data->set.str[STRING_COOKIE] && !checkheaders(data, "Cookie:")) + addcookies = data->set.str[STRING_COOKIE]; if(!checkheaders(data, "Accept-Encoding:") && - data->set.encoding) { + data->set.str[STRING_ENCODING]) { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = - aprintf("Accept-Encoding: %s\r\n", data->set.encoding); + aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); if(!conn->allocptr.accept_encoding) return CURLE_OUT_OF_MEMORY; } @@ -2107,19 +2108,23 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.userpwd?conn->allocptr.userpwd:"", (data->reqdata.use_range && conn->allocptr.rangeline)? conn->allocptr.rangeline:"", - (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)? + (data->set.str[STRING_USERAGENT] && + *data->set.str[STRING_USERAGENT] && conn->allocptr.uagent)? conn->allocptr.uagent:"", (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */ http->p_pragma?http->p_pragma:"", http->p_accept?http->p_accept:"", - (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)? - conn->allocptr.accept_encoding:"", - (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !checkheaders(data, "Proxy-Connection:"))? + (data->set.str[STRING_ENCODING] && + *data->set.str[STRING_ENCODING] && + conn->allocptr.accept_encoding)? + conn->allocptr.accept_encoding:"", + (data->change.referer && conn->allocptr.ref)? + conn->allocptr.ref:"" /* Referer: */, + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !checkheaders(data, "Proxy-Connection:"))? "Proxy-Connection: Keep-Alive\r\n":"", - te + te ); if(result) @@ -2384,7 +2389,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* figure out the size of the postfields */ postsize = (data->set.postfieldsize != -1)? data->set.postfieldsize: - (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0); + (data->set.str[STRING_POSTFIELDS]? + (curl_off_t)strlen(data->set.str[STRING_POSTFIELDS]):0); if(!conn->bits.upload_chunky) { /* We only set Content-Length and allow a custom Content-Length if @@ -2409,7 +2415,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } - if(data->set.postfields) { + if(data->set.str[STRING_POSTFIELDS]) { /* for really small posts we don't use Expect: headers at all, and for the somewhat bigger ones we allow the app to disable it */ @@ -2437,7 +2443,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(!conn->bits.upload_chunky) { /* We're not sending it 'chunked', append it to the request already now to reduce the number if send() calls */ - result = add_buffer(req_buffer, data->set.postfields, + result = add_buffer(req_buffer, data->set.str[STRING_POSTFIELDS], (size_t)postsize); included_body = postsize; } @@ -2445,7 +2451,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* Append the POST data chunky-style */ result = add_bufferf(req_buffer, "%x\r\n", (int)postsize); if(CURLE_OK == result) - result = add_buffer(req_buffer, data->set.postfields, + result = add_buffer(req_buffer, data->set.str[STRING_POSTFIELDS], (size_t)postsize); if(CURLE_OK == result) result = add_buffer(req_buffer, @@ -2459,7 +2465,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else { /* A huge POST coming up, do data separate from the request */ http->postsize = postsize; - http->postdata = data->set.postfields; + http->postdata = data->set.str[STRING_POSTFIELDS]; http->sending = HTTPSEND_BODY; diff --git a/lib/nss.c b/lib/nss.c index c99258969..e90156e15 100644 --- a/lib/nss.c +++ b/lib/nss.c @@ -225,8 +225,8 @@ static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg) pphrase_arg_t *parg = (pphrase_arg_t *) arg; (void)slot; /* unused */ (void)retry; /* unused */ - if(parg->data->set.key_passwd) - return (char *)PORT_Strdup((char *)parg->data->set.key_passwd); + if(parg->data->set.str[STRING_KEY_PASSWD]) + return (char *)PORT_Strdup((char *)parg->data->set.str[STRING_KEY_PASSWD]); else return NULL; } @@ -488,10 +488,11 @@ CURLcode Curl_nss_connect(struct connectdata * conn, int sockindex) NULL) != SECSuccess) goto error; - if(data->set.cert) { + if(data->set.str[STRING_CERT]) { if(SSL_GetClientAuthDataHook(model, (SSLGetClientAuthData) SelectClientCert, - (void *)data->set.cert) != SECSuccess) { + (void *)data->set.str[STRING_CERT]) != + SECSuccess) { curlerr = CURLE_SSL_CERTPROBLEM; goto error; } diff --git a/lib/nssg.h b/lib/nssg.h index 3774c0fb3..c8582d389 100644 --- a/lib/nssg.h +++ b/lib/nssg.h @@ -32,7 +32,9 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex); CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, int sockindex, bool *done); -void Curl_nss_close(struct connectdata *conn); /* close a SSL connection */ +/* close a SSL connection */ +void Curl_nss_close(struct connectdata *conn, int index); + /* tell NSS to close down all open information regarding connections (and thus session ID caching etc) */ int Curl_nss_close_all(struct SessionHandle *data); diff --git a/lib/ssh.c b/lib/ssh.c index 58d7c6963..7a0da7475 100644 --- a/lib/ssh.c +++ b/lib/ssh.c @@ -422,8 +422,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn) HOME environment variable etc? */ home = curl_getenv("HOME"); - if (data->set.ssh_public_key) - sshc->rsa_pub = aprintf("%s", data->set.ssh_public_key); + if (data->set.str[STRING_SSH_PUBLIC_KEY]) + sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]); else if (home) sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home); @@ -435,8 +435,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn) break; } - if (data->set.ssh_private_key) - sshc->rsa = aprintf("%s", data->set.ssh_private_key); + if (data->set.str[STRING_SSH_PRIVATE_KEY]) + sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]); else if (home) sshc->rsa = aprintf("%s/.ssh/id_dsa", home); @@ -450,7 +450,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn) break; } - sshc->passphrase = data->set.key_passwd; + sshc->passphrase = data->set.str[STRING_KEY_PASSWD]; if (!sshc->passphrase) sshc->passphrase = ""; diff --git a/lib/sslgen.c b/lib/sslgen.c index 7410a00de..90af86053 100644 --- a/lib/sslgen.c +++ b/lib/sslgen.c @@ -135,20 +135,11 @@ Curl_clone_ssl_config(struct ssl_config_data *source, void Curl_free_ssl_config(struct ssl_config_data* sslc) { - if(sslc->CAfile) - free(sslc->CAfile); - - if(sslc->CApath) - free(sslc->CApath); - - if(sslc->cipher_list) - free(sslc->cipher_list); - - if(sslc->egdsocket) - free(sslc->egdsocket); - - if(sslc->random_file) - free(sslc->random_file); + Curl_safefree(sslc->CAfile); + Curl_safefree(sslc->CApath); + Curl_safefree(sslc->cipher_list); + Curl_safefree(sslc->egdsocket); + Curl_safefree(sslc->random_file); } /** diff --git a/lib/ssluse.c b/lib/ssluse.c index b5fc08d18..f10002eca 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -182,8 +182,9 @@ static int ossl_seed(struct SessionHandle *data) #endif { /* let the option override the define */ - nread += RAND_load_file((data->set.ssl.random_file? - data->set.ssl.random_file:RANDOM_FILE), + nread += RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]? + data->set.str[STRING_SSL_RANDOM_FILE]: + RANDOM_FILE), RAND_LOAD_LENGTH); if(seed_enough(nread)) return nread; @@ -195,14 +196,14 @@ static int ossl_seed(struct SessionHandle *data) #ifndef EGD_SOCKET /* If we don't have the define set, we only do this if the egd-option is set */ - if(data->set.ssl.egdsocket) + if(data->set.str[STRING_SSL_EGDSOCKET]) #define EGD_SOCKET "" /* doesn't matter won't be used */ #endif { /* If there's an option and a define, the option overrides the define */ - int ret = RAND_egd(data->set.ssl.egdsocket? - data->set.ssl.egdsocket:EGD_SOCKET); + int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]? + data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET); if(-1 != ret) { nread += ret; if(seed_enough(nread)) @@ -261,7 +262,8 @@ int Curl_ossl_seed(struct SessionHandle *data) time-consuming seedings in vain */ static bool ssl_seeded = FALSE; - if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) { + if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] || + data->set.str[STRING_SSL_EGDSOCKET]) { ossl_seed(data); ssl_seeded = TRUE; } @@ -306,7 +308,7 @@ int cert_stuff(struct connectdata *conn, X509 *x509; int cert_done = 0; - if(data->set.key_passwd) { + if(data->set.str[STRING_KEY_PASSWD]) { #ifndef HAVE_USERDATA_IN_PWD_CALLBACK /* * If password has been given, we store that in the global @@ -320,7 +322,7 @@ int cert_stuff(struct connectdata *conn, * We set the password in the callback userdata */ SSL_CTX_set_default_passwd_cb_userdata(ctx, - data->set.key_passwd); + data->set.str[STRING_KEY_PASSWD]); #endif /* Set passwd callback: */ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); @@ -373,7 +375,8 @@ int cert_stuff(struct connectdata *conn, PKCS12_PBE_add(); - if (!PKCS12_parse(p12, data->set.key_passwd, &pri, &x509, NULL)) { + if (!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509, + NULL)) { failf(data, "could not parse PKCS12 file, check password, OpenSSL error %s", ERR_error_string(ERR_get_error(), NULL) ); @@ -446,7 +449,7 @@ int cert_stuff(struct connectdata *conn, #ifdef HAVE_ENGINE_LOAD_FOUR_ARGS ui_method, #endif - data->set.key_passwd); + data->set.str[STRING_KEY_PASSWD]); if(!priv_key) { failf(data, "failed to load private key from crypto engine\n"); return 0; @@ -1340,37 +1343,40 @@ Curl_ossl_connect_step1(struct connectdata *conn, SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL); #endif - if(data->set.cert) { + if(data->set.str[STRING_CERT]) { if(!cert_stuff(conn, connssl->ctx, - data->set.cert, - data->set.cert_type, - data->set.key, - data->set.key_type)) { + data->set.str[STRING_CERT], + data->set.str[STRING_CERT_TYPE], + data->set.str[STRING_KEY], + data->set.str[STRING_KEY_TYPE])) { /* failf() is already done in cert_stuff() */ return CURLE_SSL_CERTPROBLEM; } } - if(data->set.ssl.cipher_list) { + if(data->set.str[STRING_SSL_CIPHER_LIST]) { if(!SSL_CTX_set_cipher_list(connssl->ctx, - data->set.ssl.cipher_list)) { + data->set.str[STRING_SSL_CIPHER_LIST])) { failf(data, "failed setting cipher list"); return CURLE_SSL_CIPHER; } } - if (data->set.ssl.CAfile || data->set.ssl.CApath) { + if (data->set.str[STRING_SSL_CAFILE] || data->set.str[STRING_SSL_CAPATH]) { /* tell SSL where to find CA certificates that are used to verify the servers certificate. */ - if (!SSL_CTX_load_verify_locations(connssl->ctx, data->set.ssl.CAfile, - data->set.ssl.CApath)) { + if (!SSL_CTX_load_verify_locations(connssl->ctx, + data->set.str[STRING_SSL_CAFILE], + data->set.str[STRING_SSL_CAPATH])) { if (data->set.ssl.verifypeer) { /* Fail if we insist on successfully verifying the server. */ failf(data,"error setting certificate verify locations:\n" " CAfile: %s\n CApath: %s\n", - data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", - data->set.ssl.CApath ? data->set.ssl.CApath : "none"); + data->set.str[STRING_SSL_CAFILE]? + data->set.str[STRING_SSL_CAFILE]: "none", + data->set.str[STRING_SSL_CAPATH]? + data->set.str[STRING_SSL_CAPATH] : "none"); return CURLE_SSL_CACERT_BADFILE; } else { @@ -1387,8 +1393,10 @@ Curl_ossl_connect_step1(struct connectdata *conn, infof(data, " CAfile: %s\n" " CApath: %s\n", - data->set.ssl.CAfile ? data->set.ssl.CAfile : "none", - data->set.ssl.CApath ? data->set.ssl.CApath : "none"); + data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]: + "none", + data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]: + "none"); } /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue diff --git a/lib/transfer.c b/lib/transfer.c index 8cf10f20e..efa8cdd02 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -233,7 +233,7 @@ CURLcode Curl_readrewind(struct connectdata *conn) /* We have sent away data. If not using CURLOPT_POSTFIELDS or CURLOPT_HTTPPOST, call app to rewind */ - if(data->set.postfields || + if(data->set.str[STRING_POSTFIELDS] || (data->set.httpreq == HTTPREQ_POST_FORM)) ; /* do nothing */ else { @@ -992,7 +992,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, } else if (checkprefix("Content-Encoding:", k->p) && - data->set.encoding) { + data->set.str[STRING_ENCODING]) { /* * Process Content-Encoding. Look for the values: identity, * gzip, deflate, compress, x-gzip and x-compress. x-gzip and 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; } diff --git a/lib/url.h b/lib/url.h index 9f92e693b..0431cb065 100644 --- a/lib/url.h +++ b/lib/url.h @@ -32,6 +32,8 @@ CURLcode Curl_open(struct SessionHandle **curl); CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, va_list arg); +CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src); +void Curl_freeset(struct SessionHandle * data); CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */ CURLcode Curl_connect(struct SessionHandle *, struct connectdata **, bool *async, bool *protocol_connect); diff --git a/lib/urldata.h b/lib/urldata.h index d1da3331c..41d852832 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -195,7 +195,7 @@ struct ssl_config_data { long verifyhost; /* 0: no verify 1: check that CN exists 2: CN must match hostname */ - char *CApath; /* DOES NOT WORK ON WINDOWS */ + char *CApath; /* certificate dir (doesn't work on windows) */ char *CAfile; /* cerficate to verify peer against */ char *random_file; /* path to file containing "random" data */ char *egdsocket; /* path to file containing the EGD daemon socket */ @@ -1237,43 +1237,69 @@ struct DynamicStatic { * calculated internally for the "session handle" MUST be defined within the * 'struct UrlState' instead. The only exceptions MUST note the changes in * the 'DynamicStatic' struct. + * Character pointer fields point to dynamic storage, unless otherwise stated. */ struct Curl_one_easy; /* declared and used only in multi.c */ struct Curl_multi; /* declared and used only in multi.c */ +enum dupstring { + STRING_CERT, /* client certificate file name */ + STRING_CERT_TYPE, /* format for certificate (default: PEM)*/ + STRING_COOKIE, /* HTTP cookie string to send */ + STRING_COOKIEJAR, /* dump all cookies to this file */ + STRING_CUSTOMREQUEST, /* HTTP/FTP request/method to use */ + STRING_DEVICE, /* local network interface/address to use */ + STRING_ENCODING, /* Accept-Encoding string */ + STRING_FTP_ACCOUNT, /* ftp account data */ + STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */ + STRING_FTPPORT, /* port to send with the FTP PORT command */ + STRING_KEY, /* private key file name */ + STRING_KEY_PASSWD, /* plain text private key password */ + STRING_KEY_TYPE, /* format for private key (default: PEM) */ + STRING_KRB_LEVEL, /* krb security level */ + STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find + $HOME/.netrc */ + STRING_POSTFIELDS, /* if POST, set the fields' values here */ + STRING_PROXY, /* proxy to use */ + STRING_PROXYUSERPWD, /* Proxy , if used */ + STRING_SET_RANGE, /* range, if used */ + STRING_SET_REFERER, /* custom string for the HTTP referer field */ + STRING_SET_URL, /* what original URL to work on */ + STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */ + STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */ + STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */ + STRING_SSL_CAFILE, /* certificate file to verify peer against */ + STRING_SSL_CIPHER_LIST, /* list of ciphers to use */ + STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */ + STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */ + STRING_USERAGENT, /* User-Agent string */ + STRING_USERPWD, /* , if used */ + + /* -- end of strings -- */ + STRING_LAST /* not used, just an end-of-list marker */ +}; + struct UserDefined { FILE *err; /* the stderr user data goes here */ void *debugdata; /* the data that will be passed to fdebug */ - char *errorbuffer; /* store failure messages in here */ - char *proxyuserpwd; /* Proxy , if used */ + char *errorbuffer; /* (Static) store failure messages in here */ long proxyport; /* If non-zero, use this port number by default. If the proxy string features a ":[port]" that one will override this. */ void *out; /* the fetched file goes here */ void *in; /* the uploaded file is read from here */ void *writeheader; /* write the header to this if non-NULL */ - char *set_url; /* what original URL to work on */ - char *proxy; /* proxy to use */ long use_port; /* which port to use (when not using default) */ - char *userpwd; /* , if used */ long httpauth; /* what kind of HTTP authentication to use (bitmask) */ long proxyauth; /* what kind of proxy authentication to use (bitmask) */ - char *set_range; /* range, if used. See README for detailed specification - on this syntax. */ long followlocation; /* as in HTTP Location: */ long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 for infinity */ - char *set_referer; /* custom string */ bool free_referer; /* set TRUE if 'referer' points to a string we allocated */ - char *useragent; /* User-Agent string */ - char *encoding; /* Accept-Encoding string */ - char *postfields; /* if POST, set the fields' values here */ curl_off_t postfieldsize; /* if POST, this might have a size to use instead of strlen(), and then the data *may* be binary (contain zero bytes) */ - char *ftpport; /* port to send with the FTP PORT command */ - char *device; /* local network interface/address to use */ unsigned short localport; /* local port number to bind to */ int localportrange; /* number of additional port numbers to test in case the 'localport' one can't be bind()ed */ @@ -1305,19 +1331,10 @@ struct UserDefined { curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */ curl_off_t max_recv_speed; /* high speed limit in bytes/second for download */ curl_off_t set_resume_from; /* continue [ftp] transfer from here */ - char *cookie; /* HTTP cookie string to send */ struct curl_slist *headers; /* linked list of extra headers */ struct curl_httppost *httppost; /* linked list of POST data */ - char *cert; /* certificate */ - char *cert_type; /* format for certificate (default: PEM) */ - char *key; /* private key */ - char *key_type; /* format for private key (default: PEM) */ - char *key_passwd; /* plain text private key password */ - char *cookiejar; /* dump all cookies to this file */ bool cookiesession; /* new cookie session? */ bool crlf; /* convert crlf on ftp upload(?) */ - char *ftp_account; /* ftp account data */ - char *ftp_alternative_to_user; /* command to send if USER/PASS fails */ struct curl_slist *quote; /* after connection is established */ struct curl_slist *postquote; /* after the transfer */ struct curl_slist *prequote; /* before the transfer, after type */ @@ -1330,14 +1347,8 @@ struct UserDefined { curl_TimeCond timecondition; /* kind of time/date comparison */ time_t timevalue; /* what time to compare with */ Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */ - char *customrequest; /* HTTP/FTP request to use */ long httpversion; /* when non-zero, a specific HTTP version requested to be used in the library's request(s) */ - char *auth_host; /* if set, this is the allocated string to the host name - * to which to send the authorization data to, and no other - * host (which location-following otherwise could lead to) - */ - char *krb_level; /* what security level */ struct ssl_config_data ssl; /* user defined SSL stuff */ curl_proxytype proxytype; /* what kind of proxy that is in use */ @@ -1345,7 +1356,7 @@ struct UserDefined { int dns_cache_timeout; /* DNS cache timeout */ long buffer_size; /* size of receive buffer to use */ - char *private_data; /* Private data */ + void *private_data; /* Private data */ struct Curl_one_easy *one_easy; /* When adding an easy handle to a multi handle, an internal 'Curl_one_easy' @@ -1359,9 +1370,6 @@ struct UserDefined { curl_off_t max_filesize; /* Maximum file size to download */ - char *source_url; /* for 3rd party transfer */ - char *source_userpwd; /* for 3rd party transfer */ - curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */ /* Here follows boolean settings that define how to behave during @@ -1388,8 +1396,6 @@ struct UserDefined { bool upload; enum CURL_NETRC_OPTION use_netrc; /* defined in include/curl.h */ - char *netrc_file; /* if not NULL, use this instead of trying to find - $HOME/.netrc */ bool verbose; bool krb; /* kerberos connection requested */ bool reuse_forbid; /* forbidden to be reused, close after use */ @@ -1408,16 +1414,14 @@ struct UserDefined { us */ bool connect_only; /* make connection, let application use the socket */ long ssh_auth_types; /* allowed SSH auth types */ - char *ssh_public_key; /* the path to the public key file for - authentication */ - char *ssh_private_key; /* the path to the private key file for - authentication */ bool http_te_skip; /* pass the raw body data to the user, even when transfer-encoded (chunked, compressed) */ bool http_ce_skip; /* pass the raw body data to the user, even when content-encoded (chunked, compressed) */ long new_file_perms; /* Permissions to use when creating remote files */ long new_directory_perms; /* Permissions to use when creating remote dirs */ + + char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */ }; struct Names { -- cgit v1.2.3