Thomas Mullaly : urlmon: Implemented the canonicalization routine for the userinfo of a URI.

Alexandre Julliard julliard at winehq.org
Thu Jul 22 12:09:31 CDT 2010


Module: wine
Branch: master
Commit: eff59a51072d172f9d0c9c867a6f4d7c4ca772b7
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=eff59a51072d172f9d0c9c867a6f4d7c4ca772b7

Author: Thomas Mullaly <thomas.mullaly at gmail.com>
Date:   Thu Jun 17 15:58:17 2010 -0400

urlmon: Implemented the canonicalization routine for the userinfo of a URI.

---

 dlls/urlmon/uri.c |  191 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 190 insertions(+), 1 deletions(-)

diff --git a/dlls/urlmon/uri.c b/dlls/urlmon/uri.c
index 0942d8a..f8d99a8 100644
--- a/dlls/urlmon/uri.c
+++ b/dlls/urlmon/uri.c
@@ -38,6 +38,10 @@ typedef struct {
     INT         scheme_start;
     DWORD       scheme_len;
     URL_SCHEME  scheme_type;
+
+    INT         userinfo_start;
+    DWORD       userinfo_len;
+    INT         userinfo_split;
 } Uri;
 
 typedef struct {
@@ -61,6 +65,8 @@ typedef struct {
     INT             userinfo_split;
 } parse_data;
 
+static const CHAR hexDigits[] = "0123456789ABCDEF";
+
 /* List of scheme types/scheme names that are recognized by the IUri interface as of IE 7. */
 static const struct {
     URL_SCHEME  scheme;
@@ -161,12 +167,64 @@ static inline BOOL is_auth_delim(WCHAR val, BOOL acceptSlash) {
             val == '\0' || (acceptSlash && val == '\\'));
 }
 
+/* reserved = gen-delims / sub-delims */
+static inline BOOL is_reserved(WCHAR val) {
+    return (is_subdelim(val) || is_gendelim(val));
+}
+
 static inline BOOL is_hexdigit(WCHAR val) {
     return ((val >= 'a' && val <= 'f') ||
             (val >= 'A' && val <= 'F') ||
             (val >= '0' && val <= '9'));
 }
 
+/* Taken from dlls/jscript/lex.c */
+static int hex_to_int(WCHAR val) {
+    if(val >= '0' && val <= '9')
+        return val - '0';
+    else if(val >= 'a' && val <= 'f')
+        return val - 'a' + 10;
+    else if(val >= 'A' && val <= 'F')
+        return val - 'A' + 10;
+
+    return -1;
+}
+
+/* Helper function for converting a percent encoded string
+ * representation of a WCHAR value into its actual WCHAR value. If
+ * the two characters following the '%' aren't valid hex values then
+ * this function returns the NULL character.
+ *
+ * Eg.
+ *  "%2E" will result in '.' being returned by this function.
+ */
+static WCHAR decode_pct_val(const WCHAR *ptr) {
+    WCHAR ret = '\0';
+
+    if(*ptr == '%' && is_hexdigit(*(ptr + 1)) && is_hexdigit(*(ptr + 2))) {
+        INT a = hex_to_int(*(ptr + 1));
+        INT b = hex_to_int(*(ptr + 2));
+
+        ret = a << 4;
+        ret += b;
+    }
+
+    return ret;
+}
+
+/* Helper function for percent encoding a given character
+ * and storing the encoded value into a given buffer (dest).
+ *
+ * It's up to the calling function to ensure that there is
+ * at least enough space in 'dest' for the percent encoded
+ * value to be stored (so dest + 3 spaces available).
+ */
+static inline void pct_encode_val(WCHAR val, WCHAR *dest) {
+    dest[0] = '%';
+    dest[1] = hexDigits[(val >> 4) & 0xf];
+    dest[2] = hexDigits[val & 0xf];
+}
+
 /* Checks if the characters pointed to by 'ptr' are
  * a percent encoded data octet.
  *
@@ -488,6 +546,126 @@ static BOOL parse_uri(parse_data *data, DWORD flags) {
     return TRUE;
 }
 
+/* Canonicalizes the userinfo of the URI represented by the parse_data.
+ *
+ * Canonicalization of the userinfo is a simple process. If there are any percent
+ * encoded characters that fall in the "unreserved" character set, they are decoded
+ * to their actual value. If a character is not in the "unreserved" or "reserved" sets
+ * then it is percent encoded. Other than that the characters are copied over without
+ * change.
+ */
+static BOOL canonicalize_userinfo(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    DWORD i = 0;
+
+    uri->userinfo_start = uri->userinfo_split = -1;
+    uri->userinfo_len = 0;
+
+    if(!data->userinfo)
+        /* URI doesn't have userinfo, so nothing to do here. */
+        return TRUE;
+
+    uri->userinfo_start = uri->canon_len;
+
+    while(i < data->userinfo_len) {
+        if(data->userinfo[i] == ':' && uri->userinfo_split == -1)
+            /* Windows only considers the first ':' as the delimiter. */
+            uri->userinfo_split = uri->canon_len - uri->userinfo_start;
+        else if(data->userinfo[i] == '%') {
+            /* Only decode % encoded values for known scheme types. */
+            if(data->scheme_type != URL_SCHEME_UNKNOWN) {
+                /* See if the value really needs decoded. */
+                WCHAR val = decode_pct_val(data->userinfo + i);
+                if(is_unreserved(val)) {
+                    if(!computeOnly)
+                        uri->canon_uri[uri->canon_len] = val;
+
+                    ++uri->canon_len;
+
+                    /* Move pass the hex characters. */
+                    i += 3;
+                    continue;
+                }
+            }
+        } else if(!is_reserved(data->userinfo[i]) && !is_unreserved(data->userinfo[i]) &&
+                  data->userinfo[i] != '\\') {
+            /* Only percent encode forbidden characters if the NO_ENCODE_FORBIDDEN_CHARACTERS flag
+             * is NOT set.
+             */
+            if(!(flags & Uri_CREATE_NO_ENCODE_FORBIDDEN_CHARACTERS)) {
+                if(!computeOnly)
+                    pct_encode_val(data->userinfo[i], uri->canon_uri + uri->canon_len);
+
+                uri->canon_len += 3;
+                ++i;
+                continue;
+            }
+        }
+
+        if(!computeOnly)
+            /* Nothing special, so just copy the character over. */
+            uri->canon_uri[uri->canon_len] = data->userinfo[i];
+
+        ++uri->canon_len;
+        ++i;
+    }
+
+    uri->userinfo_len = uri->canon_len - uri->userinfo_start;
+    if(!computeOnly)
+        TRACE("(%p %p %x %d): Canonicalized userinfo, userinfo_start=%d, userinfo=%s, userinfo_split=%d userinfo_len=%d.\n",
+                data, uri, flags, computeOnly, uri->userinfo_start, debugstr_wn(uri->canon_uri + uri->userinfo_start, uri->userinfo_len),
+                uri->userinfo_split, uri->userinfo_len);
+
+    /* Now insert the '@' after the userinfo. */
+    if(!computeOnly)
+        uri->canon_uri[uri->canon_len] = '@';
+
+    ++uri->canon_len;
+    return TRUE;
+}
+
+/* Canonicalizes the authority of the URI represented by the parse_data. */
+static BOOL canonicalize_authority(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    if(!canonicalize_userinfo(data, uri, flags, computeOnly))
+        return FALSE;
+
+    /* TODO: canonicalize the host and port information. */
+
+    return TRUE;
+}
+
+/* Determines how the URI represented by the parse_data should be canonicalized.
+ *
+ * Essentially, if the parse_data represents an hierarchical URI then it calls
+ * canonicalize_authority and the canonicalization functions for the path. If the
+ * URI is opaque it canonicalizes the path of the URI.
+ */
+static BOOL canonicalize_hierpart(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
+    if(!data->is_opaque) {
+        /* "//" is only added for non-wildcard scheme types. */
+        if(data->scheme_type != URL_SCHEME_WILDCARD) {
+            if(!computeOnly) {
+                INT pos = uri->canon_len;
+
+                uri->canon_uri[pos] = '/';
+                uri->canon_uri[pos+1] = '/';
+           }
+           uri->canon_len += 2;
+        }
+
+        if(!canonicalize_authority(data, uri, flags, computeOnly))
+            return FALSE;
+
+       /* TODO: Canonicalize the path of the URI. */
+
+    } else {
+        /* Opaque URI's don't have userinfo. */
+        uri->userinfo_start = uri->userinfo_split = -1;
+        uri->userinfo_len = 0;
+    }
+
+    return TRUE;
+}
+
 /* Canonicalizes the scheme information specified in the parse_data using the specified flags. */
 static BOOL canonicalize_scheme(const parse_data *data, Uri *uri, DWORD flags, BOOL computeOnly) {
     uri->scheme_start = -1;
@@ -519,7 +697,7 @@ static BOOL canonicalize_scheme(const parse_data *data, Uri *uri, DWORD flags, B
                     debugstr_wn(uri->canon_uri,  uri->scheme_len), data->scheme_len);
         }
 
-        /* This happens in both compute only and non-compute only. */
+        /* This happens in both computation modes. */
         uri->canon_len += data->scheme_len + 1;
         uri->scheme_len = data->scheme_len;
     }
@@ -545,6 +723,11 @@ static int compute_canonicalized_length(const parse_data *data, DWORD flags) {
         return -1;
     }
 
+    if(!canonicalize_hierpart(data, &uri, flags, TRUE)) {
+        ERR("(%p %x): Failed to compute URI hierpart length.\n", data, flags);
+        return -1;
+    }
+
     TRACE("(%p %x): Finished computing canonicalized URI length. length=%d\n", data, flags, uri.canon_len);
 
     return uri.canon_len;
@@ -585,6 +768,12 @@ static HRESULT canonicalize_uri(const parse_data *data, Uri *uri, DWORD flags) {
     }
     uri->scheme_type = data->scheme_type;
 
+    if(!canonicalize_hierpart(data, uri, flags, FALSE)) {
+        ERR("(%p %p %x): Unable to canonicalize the heirpart of the URI\n", data, uri, flags);
+        heap_free(uri->canon_uri);
+        return E_INVALIDARG;
+    }
+
     uri->canon_uri[uri->canon_len] = '\0';
     TRACE("(%p %p %x): finished canonicalizing the URI.\n", data, uri, flags);
 




More information about the wine-cvs mailing list