I was less hesitating in playing around with files, which is why I managed to 
get git to produce the patch.  There is one slight change, in tests/uri_test.c, 
compared to my original message.  However this time it is by git format-patch.

  One thing I forgot to write earlier is that this work includes, and enhances, 
the staging/ftpuser branch.  If it is accepted then staging/ftpuser should be 
removed.

From 2d51978fb15264f316df84f0d5932e3a2e1d55d3 Mon Sep 17 00:00:00 2001
From: gL2n30Y06arv2 <[email protected]>
Date: Sat, 19 Dec 2009 02:15:09 +0200
Subject: [PATCH] Decodes struct uri.{user,password} members.

This patch replaces the encoded user info (user:password), that was
kept in struct uri, with its decoded counterpart.  The decoded version
is expected to be much more useful.
It also attempts to amend the other parts of the project appropriately.
The reference is section 3.2 of RFC 3986.

Signed-off-by: gL2n30Y06arv2 <[email protected]>
---
 src/core/uri.c         |   45 ++++++++++++++++++++++++++++-----------------
 src/include/gpxe/uri.h |    4 ++--
 src/net/tcp/ftp.c      |   28 ++++++++++++++++++++++++++--
 src/net/tcp/http.c     |   17 ++---------------
 src/tests/uri_test.c   |   15 +++++++++------
 5 files changed, 67 insertions(+), 42 deletions(-)

diff --git a/src/core/uri.c b/src/core/uri.c
index 50a96d3..63166e5 100644
--- a/src/core/uri.c
+++ b/src/core/uri.c
@@ -45,9 +45,9 @@ static void dump_uri ( struct uri *uri ) {
     if ( uri->opaque )
         DBG ( " opaque \"%s\"", uri->opaque );
     if ( uri->user )
-        DBG ( " user \"%s\"", uri->user );
+        DBG ( " decoded user \"%s\"", uri->user );
     if ( uri->password )
-        DBG ( " password \"%s\"", uri->password );
+        DBG ( " decoded password \"%s\"", uri->password );
     if ( uri->host )
         DBG ( " host \"%s\"", uri->host );
     if ( uri->port )
@@ -149,19 +149,25 @@ struct uri * parse_uri ( const char *uri_string ) {
         uri->path = path;
     }
 
-    /* Split authority into user[:password] and host[:port] portions */
+    /* Split authority into user[:password] and host[:port]
+       portions.  Decodes authority. */
     if ( ( tmp = strchr ( authority, '@' ) ) ) {
         /* Has user[:password] */
         *(tmp++) = '\0';
         uri->host = tmp;
+        uri_decode ( authority, authority /* in place */, 
+                strlen ( authority ) + 1 /* NULL */ );
+        /* assert ( uri->host>= ( authority + 
+                    strlen ( authority ) + 1 ) ); */
         uri->user = authority;
-        if ( ( tmp = strchr ( authority, ':' ) ) ) {
+        if ( ( tmp = strchr ( uri->user, ':' ) ) ) {
             /* Has password */
             *(tmp++) = '\0';
             uri->password = tmp;
         }
+
     } else {
-        /* No user:password */
+        /* No user[:password] */
         uri->host = authority;
     }
 
@@ -229,13 +235,14 @@ int unparse_uri ( char *buf, size_t size, struct uri *uri 
) {
     /* [user[:passwo...@]host[:port] */
     if ( uri->host ) {
         if ( uri->user ) {
+            used += uri_encode ( uri->user, ( buf + used ),
+                         ( size - used ) );
             used += ssnprintf ( ( buf + used ), ( size - used ),
-                        "%s", uri->user );
-            if ( uri->password ) {
-                used += ssnprintf ( ( buf + used ),
-                            ( size - used ),
-                            ":%s", uri->password );
-            }
+                        ":" );
+            if ( uri->password ) 
+                used += uri_encode ( uri->password,
+                            ( buf + used ),
+                            ( size - used ) );
             used += ssnprintf ( ( buf + used ), ( size - used ),
                         "@" );
         }
@@ -435,12 +442,14 @@ size_t uri_encode ( const char *raw_string, char *buf, 
size_t len ) {
 }
 
 /**
- * Decode URI-encoded string
+ * Decode URI-encoded string.
  *
  * @v encoded_string    URI-encoded string
  * @v buf        Buffer to contain decoded string
  * @v len        Length of buffer
  * @ret len        Length of decoded string (excluding NUL)
+ *
+ * Can be used when encoded_string and buf overlap and in place.
  */
 size_t uri_decode ( const char *encoded_string, char *buf, size_t len ) {
     ssize_t remaining = len;
@@ -448,10 +457,8 @@ size_t uri_decode ( const char *encoded_string, char *buf, 
size_t len ) {
     char *hexbuf_end;
     unsigned char c;
 
-    if ( len )
-        buf[0] = '\0';
-
-    while ( *encoded_string ) {
+    while ( *encoded_string  &&  
+            remaining> 1 /* a NULL is essential */ ) {
         if ( *encoded_string == '%' ) {
             encoded_string++;
             snprintf ( hexbuf, sizeof ( hexbuf ), "%s",
@@ -461,7 +468,11 @@ size_t uri_decode ( const char *encoded_string, char *buf, 
size_t len ) {
         } else {
             c = *(encoded_string++);
         }
-        ssnprintf ( buf++, remaining--, "%c", c );
+        *(remaining--, buf++) = c;
     }
+
+    if ( remaining )
+        *buf = '\0';
+
     return ( len - remaining );
 }
diff --git a/src/include/gpxe/uri.h b/src/include/gpxe/uri.h
index 03c88d2..de8d5a9 100644
--- a/src/include/gpxe/uri.h
+++ b/src/include/gpxe/uri.h
@@ -47,9 +47,9 @@ struct uri {
     const char *scheme;
     /** Opaque part */
     const char *opaque;
-    /** User name */
+    /** Decoded user name */
     const char *user;
-    /** Password */
+    /** Decoded password */
     const char *password;
     /** Host name */
     const char *host;
diff --git a/src/net/tcp/ftp.c b/src/net/tcp/ftp.c
index 0719bf7..26103f6 100644
--- a/src/net/tcp/ftp.c
+++ b/src/net/tcp/ftp.c
@@ -131,11 +131,35 @@ static const char * ftp_uri_path ( struct ftp_request 
*ftp ) {
     return ftp->uri->path;
 }
 
+/**
+ * Retrieve FTP user
+ *
+ * @v ftp        FTP request
+ * @ret user        FTP user
+ */
+static const char * ftp_user ( struct ftp_request *ftp ) {
+    static char *ftp_default_user = "anonymous";
+    return ftp->uri->user ? ftp->uri->user : ftp_default_user;
+}
+
+/**
+ * Retrieve FTP password
+ *
+ * @v ftp        FTP request
+ * @ret password    FTP password
+ */
+static const char * ftp_password ( struct ftp_request *ftp ) {
+    static char *ftp_default_password = 
+                    "[email protected]";
+    return ftp->uri->password ? 
+        ftp->uri->password : ftp_default_password;
+}
+
 /** FTP control channel strings */
 static struct ftp_control_string ftp_strings[] = {
     [FTP_CONNECT]    = { NULL, NULL },
-    [FTP_USER]    = { "USER anonymous", NULL },
-    [FTP_PASS]    = { "PASS [email protected]", NULL },
+    [FTP_USER]    = { "USER ", ftp_user },
+    [FTP_PASS]    = { "PASS ", ftp_password },
     [FTP_TYPE]    = { "TYPE I", NULL },
     [FTP_PASV]    = { "PASV", NULL },
     [FTP_RETR]    = { "RETR ", ftp_uri_path },
diff --git a/src/net/tcp/http.c b/src/net/tcp/http.c
index a02408a..eda9f8b 100644
--- a/src/net/tcp/http.c
+++ b/src/net/tcp/http.c
@@ -437,21 +437,8 @@ static void http_step ( struct process *process ) {
 
         /* Construct authorisation, if applicable */
         if ( user ) {
-            char *buf = user_pw;
-            ssize_t remaining = sizeof ( user_pw );
-            size_t len;
-
-            /* URI-decode the username and password */
-            len = uri_decode ( user, buf, remaining );
-            buf += len;
-            remaining -= len;
-            *(remaining--, buf++) = ':';
-            len = uri_decode ( password, buf, remaining );
-            buf += len;
-            remaining -= len;
-            assert ( remaining>= 0 );
-
-            /* Base64-encode the "user:password" string */
+            snprintf ( user_pw, user_pw_len + 1 /* NUL */,
+                   "%s:%s", user, password );
             base64_encode ( user_pw, user_pw_base64 );
         }
 
diff --git a/src/tests/uri_test.c b/src/tests/uri_test.c
index 2548760..8f5b3d1 100644
--- a/src/tests/uri_test.c
+++ b/src/tests/uri_test.c
@@ -14,12 +14,13 @@ struct uri_test {
 };
 
 static struct uri_test uri_tests[] = {
-    { "http://www.fensystems.co.uk";, "",
-      "http://www.fensystems.co.uk/"; },
-    { "http://etherboot.org/wiki/page1";, "page2",
-      "http://etherboot.org/wiki/page2"; },
-    { "http://etherboot.org/wiki/page1";, "../page3",
-      "http://etherboot.org/page3"; },
+    { "ftp://:user%[email protected]";, "",
+      "ftp://:user%[email protected]/"; },
+    { "https://user%40isp.fr:@etherboot.org/wiki/page1";, "page2",
+      "https://user%40isp.fr:@etherboot.org/wiki/page2"; },
+    { "http://user:gpxe%[email protected]/wiki/page1";,
+      "../page3",
+      "http://user:gpxe%[email protected]/page3"; },
     { "tftp://192.168.0.1/";, "/tftpboot/vmlinuz",
       "tftp://192.168.0.1/tftpboot/vmlinuz"; },
 #if 0
@@ -120,6 +121,7 @@ int uri_test ( void ) {
     int rc;
     int overall_rc = 0;
 
+    printf ( "Start uri_test () \n" );
     for ( i = 0 ; i < ( sizeof ( uri_tests ) /
                 sizeof ( uri_tests[0] ) ) ; i++ ) {
         uri_test = &uri_tests[i];
@@ -141,5 +143,6 @@ int uri_test ( void ) {
 
     if ( overall_rc )
         printf ( "URI tests failed: %s\n", strerror ( overall_rc ) );
+    printf ( "End uri_test () \n" );
     return overall_rc;
 }
-- 
1.6.5


                                          
_________________________________________________________________
Windows Live: Keep your friends up to date with what you do online.
http://www.microsoft.com/middleeast/windows/windowslive/see-it-in-action/social-network-basics.aspx?ocid=PID23461::T:WLMTAGL:ON:WL:en-xm:SI_SB_1:092010
_______________________________________________
gPXE mailing list
[email protected]
http://etherboot.org/mailman/listinfo/gpxe

Reply via email to