]> granicus.if.org Git - curl/commitdiff
url: Added support for parsing login options from the URL
authorSteve Holme <steve_holme@hotmail.com>
Sat, 13 Apr 2013 09:49:42 +0000 (10:49 +0100)
committerSteve Holme <steve_holme@hotmail.com>
Sat, 13 Apr 2013 09:49:42 +0000 (10:49 +0100)
As well as parsing the username and password from the URL, added support
for parsing the optional options part from the login details, to allow
the following supported URL format:

schema://username:password;options@example.com/path?q=foobar

This will only be used by IMAP, POP3 and SMTP at present but any
protocol that may be given login options in the URL will be able to
add support for them.

lib/url.c
lib/urldata.h

index 4399162a9daa64b5e4d157692ce1aab60f089c26..20823d078fa65e6b0f3ce06d8641aaadc54d2998 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -2452,6 +2452,7 @@ static void conn_free(struct connectdata *conn)
 
   Curl_safefree(conn->user);
   Curl_safefree(conn->passwd);
+  Curl_safefree(conn->options);
   Curl_safefree(conn->proxyuser);
   Curl_safefree(conn->proxypasswd);
   Curl_safefree(conn->allocptr.proxyuserpwd);
@@ -4342,24 +4343,27 @@ static CURLcode parse_url_userpass(struct SessionHandle *data,
                                    struct connectdata *conn,
                                    char *user, char *passwd)
 {
+  char options[MAX_CURL_OPTIONS_LENGTH];
+
   /* 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]]@]hostname
+   *    [user[:password][;options]]@]hostname
    *
    * We need somewhere to put the embedded details, so do that first.
    */
 
-  char *ptr=strchr(conn->host.name, '@');
+  char *ptr = strchr(conn->host.name, '@');
   char *userpass = conn->host.name;
 
-  user[0] =0;   /* to make everything well-defined */
-  passwd[0]=0;
+  user[0] = 0;   /* to make everything well-defined */
+  passwd[0] = 0;
+  options[0] = 0;
 
   /* We will now try to extract the
-   * possible user+password pair in a string like:
+   * possible login information in a string like:
    * ftp://user:password@ftp.my.site:8021/README */
   if(ptr != NULL) {
-    /* there's a user+password given here, to the left of the @ */
+    /* There's login information to the left of the @ */
 
     conn->host.name = ++ptr;
 
@@ -4369,26 +4373,46 @@ static CURLcode parse_url_userpass(struct SessionHandle *data,
      * set user/passwd, but doing that first adds more cases here :-(
      */
 
-    conn->bits.userpwd_in_url = TRUE;
     if(data->set.use_netrc != CURL_NETRC_REQUIRED) {
-      /* We could use the one in the URL */
-
-      conn->bits.user_passwd = TRUE; /* enable user+password */
-
+      /* We could use the information in the URL so extract it */
       if(*userpass != ':') {
-        /* the name is given, get user+password */
-        sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:"
-               "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
-               user, passwd);
+        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);
+        }
       }
       else
-        /* no name given, get the password only */
-        sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd);
+        /* 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=curl_easy_unescape(data, user, 0, NULL);
+        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, user, 0, NULL);
         if(!newname)
           return CURLE_OUT_OF_MEMORY;
+
         if(strlen(newname) < MAX_CURL_USER_LENGTH)
           strcpy(user, newname);
 
@@ -4396,18 +4420,33 @@ static CURLcode parse_url_userpass(struct SessionHandle *data,
            the unconverted name, it'll be wrong but what the heck */
         free(newname);
       }
+
       if(passwd[0]) {
-        /* we have a password found in the URL, decode it! */
-        char *newpasswd=curl_easy_unescape(data, passwd, 0, NULL);
+        /* 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;
+
         if(strlen(newpasswd) < MAX_CURL_PASSWORD_LENGTH)
           strcpy(passwd, newpasswd);
 
         free(newpasswd);
       }
+
+      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(strlen(newoptions) < MAX_CURL_OPTIONS_LENGTH)
+          conn->options = newoptions;
+        else
+          free(newoptions);
+      }
     }
   }
+
   return CURLE_OK;
 }
 
index 1113020eef5b246715bf9d7b51f431a7c62770f9..13a01d4b3c095dfb703e4c836d03f85607c997ff 100644 (file)
@@ -859,6 +859,7 @@ struct connectdata {
 
   char *user;    /* user name string, allocated */
   char *passwd;  /* password string, allocated */
+  char *options; /* options string, allocated */
 
   char *proxyuser;    /* proxy user name string, allocated */
   char *proxypasswd;  /* proxy password string, allocated */
@@ -1136,8 +1137,10 @@ typedef enum {
  * Session-data MUST be put in the connectdata struct and here.  */
 #define MAX_CURL_USER_LENGTH 256
 #define MAX_CURL_PASSWORD_LENGTH 256
+#define MAX_CURL_OPTIONS_LENGTH 256
 #define MAX_CURL_USER_LENGTH_TXT "255"
 #define MAX_CURL_PASSWORD_LENGTH_TXT "255"
+#define MAX_CURL_OPTIONS_LENGTH_TXT "255"
 
 struct auth {
   unsigned long want;  /* Bitmask set to the authentication methods wanted by