]> granicus.if.org Git - curl/commitdiff
Patrick Monnerat and I modified libcurl so that now it *copies* all strings
authorDaniel Stenberg <daniel@haxx.se>
Wed, 1 Aug 2007 21:20:01 +0000 (21:20 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 1 Aug 2007 21:20:01 +0000 (21:20 +0000)
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.

21 files changed:
CHANGES
RELEASE-NOTES
docs/libcurl/curl_easy_getinfo.3
docs/libcurl/curl_easy_setopt.3
include/curl/curlver.h
lib/connect.c
lib/easy.c
lib/ftp.c
lib/getinfo.c
lib/gtls.c
lib/gtls.h
lib/http.c
lib/nss.c
lib/nssg.h
lib/ssh.c
lib/sslgen.c
lib/ssluse.c
lib/transfer.c
lib/url.c
lib/url.h
lib/urldata.h

diff --git a/CHANGES b/CHANGES
index a245e7d0996aa2df0b1f5cbaf8594abca9fae484..ef30dc1e690fdfbe783d43f98d036030859f02d7 100644 (file)
--- 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
index 5e64b764c14e9f0ca6c99a11cf1bc9023603ad82..0377adb9360be0d4d7f5b15d3c95db513eb7e301 100644 (file)
@@ -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:
 
index fe13f07c9b001c2e35b4028ef5624076df37e528..95455e3a1607a8b3f9b1becd80adb32952db4d0b 100644 (file)
@@ -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
index 63b53f7c403c9da0c1eadecfd4397d2673ab9f1e..016bb918120c11ed54693eab7a07c36a256dbd1b 100644 (file)
@@ -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)
index 11b34dcafd714b639a8735302121f4e4fac2cb9f..4657398bc79689c88c791a44fa269bdb25e24a24 100644 (file)
 
 /* 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
index d608e1e2eb0ab1ab428f9029c56c1519acc7bb2d..634595766948e73c9fec6306d9fccc77ab3a8e53 100644 (file)
@@ -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 */
       }
index b1080a22d00c1a8e655f85bac68d554669585629..54915fb8848f67936e9f6ec5ef1594896bd2af1c 100644 (file)
@@ -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
index 4df17decbac4949a9795f1e614e3aab209cffc18..6958eb7f2ca6cecc263dae7c903a0b303061fd96 100644 (file)
--- 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");
index c94ca2cb9fb572d44dbb7e3741834a035fc1a589..2ec0242a6052822b8cc17ef08a61160915715829 100644 (file)
@@ -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;
index 03572d88ebd76aff2fb416ade7244bb161d72bd5..a40ea096b024b87038998fa8d07b08e326e70d49 100644 (file)
@@ -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;
     }
index bff3f8693970f903e6795f9e4b39750c4e14f255..feb02fd6461ade4da622e962eb1a7a09fe115251 100644 (file)
@@ -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,
index 19e7483dff993f55614d3d47b0c5f8154763c695..61511b57abb05d8cad1d818ce50c2cfd4f076afa 100644 (file)
@@ -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: <data> */,
-                (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: <data> */,
+                  (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;
 
index c9925896931e9c167d0cf754749d5129281c186a..e90156e154c47d315b28f6bb2be55c3606afcd17 100644 (file)
--- 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;
     }
index 3774c0fb3bdceccd85d31e72d095c039e76e358f..c8582d389bc97b5106a3beb23d77d8f042e3adeb 100644 (file)
@@ -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);
index 58d7c6963e94a62149e3b2f4aa06e668f9c9791a..7a0da7475adf0e1cd380ac217405ce15e11a379b 100644 (file)
--- 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 = "";
 
index 7410a00de428ced7602363bc7e38816eab05c38b..90af86053f0c176a45cbd61f2a411a8b8e1b2494 100644 (file)
@@ -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);
 }
 
 /**
index b5fc08d185ee22b81dd1c95987fbffe7c34d2bb1..f10002ecad51948d583d1ab56c716e9741ffa8b3 100644 (file)
@@ -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
index 8cf10f20e1837bff290280529950df601937e19f..efa8cdd026ee6f19de22eebf9cd08e6fe08279e5 100644 (file)
@@ -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
index 7a8effb1ef9fbdf480c2d7f4b45ebb97263e8163..0de87a824096ae2bab0eb6baf7637ee7be123bef 100644 (file)
--- 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;
   }
index 9f92e693b27764ed5b4593530acec0096112d4b8..0431cb06529d4e24d5f456359132fba01554af5e 100644 (file)
--- 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);
index d1da3331ccef11762bdddea74690a0102ead1945..41d85283255b441df6af5a815e39985f95666c10 100644 (file)
@@ -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 <user:password>, 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,         /* <user:password>, 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 <user:password>, 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;     /* <user:password>, 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 {