Like camel_url_encode, but works directly on an existing GString.
authorDan Winship <danw@src.gnome.org>
Thu, 27 Mar 2003 15:37:47 +0000 (15:37 +0000)
committerDan Winship <danw@src.gnome.org>
Thu, 27 Mar 2003 15:37:47 +0000 (15:37 +0000)
* camel-url.c (append_url_encoded): Like camel_url_encode, but
works directly on an existing GString.
(camel_url_to_string, output_param): Use it.
(camel_url_encode): Likewise. Remove "escape_unsafe" arg since the
"unsafe" chars are the ones that should *always* be escaped, and
the places we were passing FALSE were wrong.
(camel_url_decode): replace with a new version

* camel-file-utils.c (camel_file_util_safe_filename): Remove extra
arg to camel_url_encode.

* tests/misc/url.c (main): Add tests of basic URL parsing and
unparsing

camel/ChangeLog
camel/camel-file-utils.c
camel/camel-url.c
camel/camel-url.h
camel/tests/misc/.cvsignore
camel/tests/misc/url.c

index 8a01527..94dad5c 100644 (file)
@@ -1,3 +1,19 @@
+2003-03-27  Dan Winship  <danw@ximian.com>
+
+       * camel-url.c (append_url_encoded): Like camel_url_encode, but
+       works directly on an existing GString.
+       (camel_url_to_string, output_param): Use it.
+       (camel_url_encode): Likewise. Remove "escape_unsafe" arg since the
+       "unsafe" chars are the ones that should *always* be escaped, and
+       the places we were passing FALSE were wrong.
+       (camel_url_decode): replace with a new version
+
+       * camel-file-utils.c (camel_file_util_safe_filename): Remove extra
+       arg to camel_url_encode.
+
+       * tests/misc/url.c (main): Add tests of basic URL parsing and
+       unparsing
+
 2003-03-28  Not Zed  <NotZed@Ximian.com>
 
        *
index 33f599d..f0e400e 100644 (file)
@@ -328,5 +328,5 @@ camel_file_util_safe_filename(const char *name)
        if (name == NULL)
                return NULL;
        
-       return camel_url_encode(name, TRUE, "/?()'*");
+       return camel_url_encode(name, "/?()'*");
 }
index a78ba44..7b1c31d 100644 (file)
@@ -4,7 +4,6 @@
 /* 
  * Authors:
  *  Dan Winship <danw@ximian.com>
- *  Tiago Antào <tiagoantao@bigfoot.com>
  *  Jeffrey Stedfast <fejj@ximian.com>
  *
  * Copyright 1999-2001 Ximian, Inc. (www.ximian.com)
@@ -42,6 +41,8 @@
 static void copy_param (GQuark key_id, gpointer data, gpointer user_data);
 static void output_param (GQuark key_id, gpointer data, gpointer user_data);
 
+static void append_url_encoded (GString *str, const char *in, const char *extra_enc_chars);
+
 /**
  * camel_url_new_with_base:
  * @base: a base URL
@@ -304,7 +305,7 @@ char *
 camel_url_to_string (CamelURL *url, guint32 flags)
 {
        GString *str;
-       char *enc, *return_result;
+       char *return_result;
        
        /* IF YOU CHANGE ANYTHING IN THIS FUNCTION, RUN
         * tests/misc/url AFTERWARD.
@@ -318,47 +319,35 @@ camel_url_to_string (CamelURL *url, guint32 flags)
        if (url->host) {
                g_string_append (str, "//");
                if (url->user) {
-                       enc = camel_url_encode (url->user, TRUE, ":;@/");
-                       g_string_append (str, enc);
-                       g_free (enc);
-               }
-               if (url->authmech && *url->authmech) {
-                       enc = camel_url_encode (url->authmech, TRUE, ":@/");
-                       g_string_append_printf (str, ";auth=%s", enc);
-                       g_free (enc);
-               }
-               if (url->passwd && !(flags & CAMEL_URL_HIDE_PASSWORD)) {
-                       enc = camel_url_encode (url->passwd, TRUE, "@/");
-                       g_string_append_printf (str, ":%s", enc);
-                       g_free (enc);
-               }
-               if (url->host) {
-                       enc = camel_url_encode (url->host, TRUE, ":/");
-                       g_string_append_printf (str, "%s%s", url->user ? "@" : "", enc);
-                       g_free (enc);
+                       append_url_encoded (str, url->user, ":;@/");
+                       if (url->authmech && *url->authmech) {
+                               g_string_append (str, ";auth=");
+                               append_url_encoded (str, url->authmech, ":@/");
+                       }
+                       if (url->passwd && !(flags & CAMEL_URL_HIDE_PASSWORD)) {
+                               g_string_append_c (str, ':');
+                               append_url_encoded (str, url->passwd, "@/");
+                       }
+                       g_string_append_c (str, '@');
                }
+               append_url_encoded (str, url->host, ":/");
                if (url->port)
                        g_string_append_printf (str, ":%d", url->port);
                if (!url->path && (url->params || url->query || url->fragment))
                        g_string_append_c (str, '/');
        }
        
-       if (url->path) {
-               enc = camel_url_encode (url->path, FALSE, ";?#");
-               g_string_append_printf (str, "%s", enc);
-               g_free (enc);
-       }
+       if (url->path)
+               append_url_encoded (str, url->path, ";?");
        if (url->params && !(flags & CAMEL_URL_HIDE_PARAMS))
                g_datalist_foreach (&url->params, output_param, str);
        if (url->query) {
-               enc = camel_url_encode (url->query, FALSE, "#");
-               g_string_append_printf (str, "?%s", enc);
-               g_free (enc);
+               g_string_append_c (str, '?');
+               append_url_encoded (str, url->query, NULL);
        }
        if (url->fragment) {
-               enc = camel_url_encode (url->fragment, FALSE, NULL);
-               g_string_append_printf (str, "#%s", enc);
-               g_free (enc);
+               g_string_append_c (str, '#');
+               append_url_encoded (str, url->fragment, NULL);
        }
        
        return_result = str->str;
@@ -371,15 +360,12 @@ static void
 output_param (GQuark key_id, gpointer data, gpointer user_data)
 {
        GString *str = user_data;
-       char *enc;
-       
-       enc = camel_url_encode (g_quark_to_string (key_id), FALSE, "?#");
-       g_string_append_printf (str, ";%s", enc);
-       g_free (enc);
+
+       g_string_append_c (str, ';');
+       append_url_encoded (str, g_quark_to_string (key_id), "?=");
        if (*(char *)data) {
-               enc = camel_url_encode (data, FALSE, "?#");
-               g_string_append_printf (str, "=%s", enc);
-               g_free (enc);
+               g_string_append_c (str, '=');
+               append_url_encoded (str, data, "?");
        }
 }
 
@@ -443,42 +429,63 @@ camel_url_get_param (CamelURL *url, const char *name)
        return g_datalist_get_data (&url->params, name);
 }
 
+/* From RFC 2396 2.4.3, the characters that should always be encoded */
+static const char url_encoded_char[] = {
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x00 - 0x0f */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  /* 0x10 - 0x1f */
+       1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  ' ' - '/'  */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0,  /*  '0' - '?'  */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  '@' - 'O'  */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,  /*  'P' - '_'  */
+       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  /*  '`' - 'o'  */
+       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1,  /*  'p' - 0x7f */
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+};
+
+static void
+append_url_encoded (GString *str, const char *in, const char *extra_enc_chars)
+{
+       const unsigned char *s = (const unsigned char *)in;
+
+       while (*s) {
+               if (url_encoded_char[*s] ||
+                   (extra_enc_chars && strchr (extra_enc_chars, *s)))
+                       g_string_append_printf (str, "%%%02x", (int)*s++);
+               else
+                       g_string_append_c (str, *s++);
+       }
+}
 
 /**
  * camel_url_encode:
  * @part: a URL part
- * @escape_unsafe: whether or not to %-escape "unsafe" characters.
- * ("%#<>{}|\^~[]`)
- * @escape_extra: additional characters to escape.
+ * @escape_extra: additional characters beyond " \"%#<>{}|\^[]`"
+ * to escape (or %NULL)
  *
  * This %-encodes the given URL part and returns the escaped version
  * in allocated memory, which the caller must free when it is done.
  **/
 char *
-camel_url_encode (const char *part, gboolean escape_unsafe,
-                 const char *escape_extra)
+camel_url_encode (const char *part, const char *escape_extra)
 {
-       char *work, *p;
-
-       /* worst case scenario = 3 times the initial */
-       p = work = g_malloc (3 * strlen (part) + 1);
+       GString *str;
+       char *encoded;
 
-       while (*part) {
-               if (((guchar) *part >= 127) || ((guchar) *part <= ' ') ||
-                   (escape_unsafe && strchr ("\"%#<>{}|\\^~[]`", *part)) ||
-                   (escape_extra && strchr (escape_extra, *part))) {
-                       sprintf (p, "%%%.02hX", (guchar) *part++);
-                       p += 3;
-               } else
-                       *p++ = *part++;
-       }
-       *p = '\0';
+       str = g_string_new (NULL);
+       append_url_encoded (str, part, escape_extra);
+       encoded = str->str;
+       g_string_free (str, FALSE);
 
-       return work;
+       return encoded;
 }
 
-#define HEXVAL(c) (isdigit (c) ? (c) - '0' : tolower (c) - 'a' + 10)
-
 /**
  * camel_url_decode:
  * @part: a URL part
@@ -490,22 +497,21 @@ camel_url_encode (const char *part, gboolean escape_unsafe,
 void
 camel_url_decode (char *part)
 {
-       guchar *s, *d;
+       unsigned char *s, *d;
 
-       s = d = (guchar *)part;
-       while (*s) {
-               if (*s == '%') {
-                       if (isxdigit (s[1]) && isxdigit (s[2])) {
-                               *d++ = HEXVAL (s[1]) * 16 + HEXVAL (s[2]);
-                               s += 3;
-                       } else
-                               *d++ = *s++;
+#define XDIGIT(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - 'A' + 10)
+
+       s = d = (unsigned char *)part;
+       do {
+               if (*s == '%' && s[1] && s[2]) {
+                       *d++ = (XDIGIT (s[1]) << 4) + XDIGIT (s[2]);
+                       s += 2;
                } else
-                       *d++ = *s++;
-       }
-       *d = '\0';
+                       *d++ = *s;
+       } while (*s++);
 }
 
+
 guint
 camel_url_hash (const void *v)
 {
index 6bce26c..562befa 100644 (file)
@@ -59,8 +59,7 @@ CamelURL *camel_url_new (const char *url_string, CamelException *ex);
 char *camel_url_to_string (CamelURL *url, guint32 flags);
 void camel_url_free (CamelURL *url);
 
-char *camel_url_encode (const char *part, gboolean escape_unsafe,
-                       const char *escape_extra);
+char *camel_url_encode (const char *part, const char *escape_extra);
 void camel_url_decode (char *part);
 
 /* for editing url's */
index 7ef94ab..fbb8316 100644 (file)
@@ -9,4 +9,6 @@ Makefile.in
 *.bbg
 *.da
 *.gcov
-url
\ No newline at end of file
+split
+url
+utf7
\ No newline at end of file
index adc6278..c2db806 100644 (file)
@@ -52,7 +52,22 @@ struct {
        { "g/./h", "http://a/b/c/g/h" },
        { "g/../h", "http://a/b/c/h" },
        { "http:g", "http:g" },
-       { "http:", "http:" }
+       { "http:", "http:" },
+
+       /* (not from rfc 1808) */
+       { "sendmail:", "sendmail:" },
+       { "mbox:/var/mail/user", "mbox:/var/mail/user" },
+       { "pop://user@host", "pop://user@host" },
+       { "pop://user@host:99", "pop://user@host:99" },
+       { "pop://user:password@host", "pop://user:password@host" },
+       { "pop://user:password@host:99", "pop://user:password@host:99" },
+       { "pop://user;auth=APOP@host", "pop://user;auth=APOP@host" },
+       { "pop://user@host/;keep_on_server", "pop://user@host/;keep_on_server" },
+       { "pop://user@host/;keep_on_server=1", "pop://user@host/;keep_on_server=1" },
+       { "pop://us%65r@host", "pop://user@host" },
+       { "pop://us%40r@host", "pop://us%40r@host" },
+       { "pop://us%3ar@host", "pop://us%3ar@host" },
+       { "pop://us%2fr@host", "pop://us%2fr@host" }
 };
 int num_tests = sizeof (tests) / sizeof (tests[0]);
 
@@ -66,7 +81,7 @@ main (int argc, char **argv)
 
        camel_test_init (argc, argv);
 
-       camel_test_start ("RFC1808 relative URL parsing");
+       camel_test_start ("URL parsing");
 
        camel_test_push ("base URL parsing");
        camel_exception_init (&ex);