url: Moved parsing of login details out of parse_url_login()
authorSteve Holme <steve_holme@hotmail.com>
Thu, 18 Apr 2013 16:52:05 +0000 (17:52 +0100)
committerSteve Holme <steve_holme@hotmail.com>
Thu, 18 Apr 2013 17:09:53 +0000 (18:09 +0100)
Separated the parsing of login details from the processing of them in
parse_url_login() ready for use by setstropt_userpwd().

lib/url.c

index d0f664d..afd8f1e 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -144,6 +144,9 @@ static CURLcode do_init(struct connectdata *conn);
 static CURLcode parse_url_login(struct SessionHandle *data,
                                 struct connectdata *conn,
                                 char *user, char *passwd, char *options);
+static CURLcode parse_login_details(const char *login, const size_t len,
+                                    char **userptr, char **passwdptr,
+                                    char **optionsptr);
 /*
  * Protocol table.
  */
@@ -4326,6 +4329,7 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
 #endif /* CURL_DISABLE_PROXY */
 
 /*
+ * parse_url_login()
  *
  * Parse the login details (user name, password and options) from the URL and
  * strip them out of the host name
@@ -4344,6 +4348,11 @@ static CURLcode parse_url_login(struct SessionHandle *data,
                                 struct connectdata *conn,
                                 char *user, char *passwd, char *options)
 {
+  CURLcode result = CURLE_OK;
+  char *userp = NULL;
+  char *passwdp = NULL;
+  char *optionsp = NULL;
+
   /* At this point, we're hoping all the other special cases have
    * been taken care of, so conn->host.name is at most
    *    [user[:password][;options]]@]hostname
@@ -4352,7 +4361,7 @@ static CURLcode parse_url_login(struct SessionHandle *data,
    */
 
   char *ptr = strchr(conn->host.name, '@');
-  char *userpass = conn->host.name;
+  char *login = conn->host.name;
 
   user[0] = 0;   /* to make everything well-defined */
   passwd[0] = 0;
@@ -4361,7 +4370,7 @@ static CURLcode parse_url_login(struct SessionHandle *data,
   /* We will now try to extract the
    * possible login information in a string like:
    * ftp://user:password@ftp.my.site:8021/README */
-  if(ptr != NULL) {
+  if(ptr) {
     /* There's login information to the left of the @ */
 
     conn->host.name = ++ptr;
@@ -4373,80 +4382,169 @@ static CURLcode parse_url_login(struct SessionHandle *data,
      */
 
     if(data->set.use_netrc != CURL_NETRC_REQUIRED) {
-      /* We could use the information in the URL so extract it */
-      if(*userpass != ':') {
-        if(*userpass != ';') {
-          /* The user is given so extract the user, password and options */
-          int result = sscanf(userpass,
-                              "%" MAX_CURL_USER_LENGTH_TXT "[^:;@]:"
-                              "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^;@];"
-                              "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]",
-                              user, passwd, options);
-
-          /* The extract failed so extract the user and options instead */
-          if(result == 1)
-            sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:;@];"
-                             "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]",
-                              user, options);
-        }
-        else {
-          /* No name or password are given so extract the options only */
-        sscanf(userpass, ";%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]", options);
+      /* We could use the login information in the URL so extract it */
+      result = parse_login_details(login, ptr - login - 1,
+                                   &userp, &passwdp, &optionsp);
+      if(!result) {
+        if(userp) {
+          char *newname;
+
+          /* We have a user in the URL */
+          conn->bits.userpwd_in_url = TRUE;
+          conn->bits.user_passwd = TRUE; /* enable user+password */
+
+          /* Decode the user */
+          newname = curl_easy_unescape(data, userp, 0, NULL);
+          if(!newname)
+            return CURLE_OUT_OF_MEMORY;
+
+          if(strlen(newname) < MAX_CURL_USER_LENGTH)
+            strcpy(user, newname);
+
+          free(newname);
         }
-      }
-      else
-        /* No name is given so extract the password and options */
-        sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^;@];"
-               "%" MAX_CURL_OPTIONS_LENGTH_TXT "[^@]",
-               passwd, options);
 
-      if(user[0]) {
-        char *newname;
+        if(passwdp) {
+          /* We have a password in the URL so decode it */
+          char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL);
+          if(!newpasswd)
+            return CURLE_OUT_OF_MEMORY;
+
+          if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
+            strcpy(passwd, newpasswd);
 
-        /* We have a user in the URL */
-        conn->bits.userpwd_in_url = TRUE;
-        conn->bits.user_passwd = TRUE; /* enable user+password */
+          free(newpasswd);
+        }
 
-        /* Decode the user */
-        newname = curl_easy_unescape(data, user, 0, NULL);
-        if(!newname)
-          return CURLE_OUT_OF_MEMORY;
+        if(optionsp) {
+          /* We have an options list in the URL so decode it */
+          char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL);
+          if(!newoptions)
+            return CURLE_OUT_OF_MEMORY;
 
-        if(strlen(newname) < MAX_CURL_USER_LENGTH)
-          strcpy(user, newname);
+          if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
+            strcpy(options, newoptions);
 
-        /* if the new name is longer than accepted, then just use
-           the unconverted name, it'll be wrong but what the heck */
-        free(newname);
+          free(newoptions);
+        }
       }
 
-      if(passwd[0]) {
-        /* We have a password in the URL so decode it */
-        char *newpasswd = curl_easy_unescape(data, passwd, 0, NULL);
-        if(!newpasswd)
-          return CURLE_OUT_OF_MEMORY;
+      Curl_safefree(userp);
+      Curl_safefree(passwdp);
+      Curl_safefree(optionsp);
+    }
+  }
 
-        if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
-          strcpy(passwd, newpasswd);
+  return result;
+}
 
-        free(newpasswd);
-      }
+/*
+ * parse_login_details()
+ *
+ * This is used to parse a login string for user name, password and options in
+ * the following formats:
+ *
+ *   user
+ *   user:password
+ *   user:password;options
+ *   user;options
+ *   user;options:password
+ *   :password
+ *   :password;options
+ *   ;options
+ *   ;options:password
+ *
+ * Parameters:
+ *
+ * login    [in]     - The login string.
+ * len      [in]     - The length of the login string.
+ * userp    [in/out] - The address where a pointer to newly allocated memory
+ *                     holding the user will be stored upon completion.
+ * passdwp  [in/out] - The address where a pointer to newly allocated memory
+ *                     holding the password will be stored upon completion.
+ * optionsp [in/out] - The address where a pointer to newly allocated memory
+ *                     holding the options will be stored upon completion.
+ *
+ * Returns CURLE_OK on success.
+ */
+static CURLcode parse_login_details(const char *login, const size_t len,
+                                    char **userp, char **passwdp, char **optionsp)
+{
+  int result = CURLE_OK;
+  char *utemp = NULL;
+  char *ptemp = NULL;
+  char *otemp = NULL;
+  const char *psep = NULL;
+  const char *osep = NULL;
+  size_t ulen;
+  size_t plen;
+  size_t olen;
+
+  /* Attempt to find the password separator */
+  if(passwdp)
+    psep = strchr(login, ':');
+
+  /* Attempt to find the options separator */
+  if(optionsp)
+    osep = strchr(login, ';');
+
+  /* Calculate the portion lengths */
+  ulen = (psep ?
+          (osep && psep > osep ? osep - login : psep - login) :
+          (osep ? osep - login : len));
+  plen = (psep ?
+          (osep && osep > psep ? osep - psep : login + len - psep) - 1 : 0);
+  olen = (osep ?
+          (psep && psep > osep ? psep - osep : login + len - osep) - 1 : 0);
+
+  /* Allocate the user portion temporary buffer */
+  if(userp && ulen) {
+    utemp = malloc(ulen + 1);
+    if(!utemp)
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Allocate the password portion temporary buffer */
+  if(!result && passwdp && plen) {
+    ptemp = malloc(plen + 1);
+    if(!ptemp)
+      result = CURLE_OUT_OF_MEMORY;
+  }
+
+  /* Allocate the options  portion temporary buffer */
+  if(!result && optionsp && olen) {
+    otemp = malloc(olen + 1);
+    if(!otemp)
+      result = CURLE_OUT_OF_MEMORY;
+  }
 
-      if(options[0]) {
-        /* We have an options list in the URL so decode it */
-        char *newoptions = curl_easy_unescape(data, options, 0, NULL);
-        if(!newoptions)
-          return CURLE_OUT_OF_MEMORY;
+  if(!result) {
+    /* Copy the user portion if necessary */
+    if(utemp) {
+      memcpy(utemp, login, ulen);
+      utemp[ulen] = '\0';
+      Curl_safefree(*userp);
+      *userp = utemp;
+    }
 
-        if(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
-          strcpy(options, newoptions);
+    /* Copy the password portion if necessary */
+    if(ptemp) {
+      memcpy(ptemp, psep + 1, plen);
+      ptemp[plen] = '\0';
+      Curl_safefree(*passwdp);
+      *passwdp = ptemp;
+    }
 
-        free(newoptions);
-      }
+    /* Copy the password portion if necessary */
+    if(otemp) {
+      memcpy(otemp, osep + 1, olen);
+      otemp[olen] = '\0';
+      Curl_safefree(*optionsp);
+      *optionsp = otemp;
     }
   }
 
-  return CURLE_OK;
+  return result;
 }
 
 /*************************************************************