Hans Leidekker : winhttp: Reimplement WinHttpCrackUrl.

Alexandre Julliard julliard at winehq.org
Tue Nov 18 09:27:11 CST 2008


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

Author: Hans Leidekker <hans at codeweavers.com>
Date:   Mon Nov 17 16:01:48 2008 +0100

winhttp: Reimplement WinHttpCrackUrl.

---

 dlls/winhttp/Makefile.in |    2 +-
 dlls/winhttp/url.c       |  165 ++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 139 insertions(+), 28 deletions(-)

diff --git a/dlls/winhttp/Makefile.in b/dlls/winhttp/Makefile.in
index 3d85c4d..40e8fa9 100644
--- a/dlls/winhttp/Makefile.in
+++ b/dlls/winhttp/Makefile.in
@@ -4,7 +4,7 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = winhttp.dll
 IMPORTLIB = winhttp
-IMPORTS   = wininet kernel32
+IMPORTS   = shlwapi kernel32
 DELAYIMPORTS = crypt32
 
 C_SRCS = \
diff --git a/dlls/winhttp/url.c b/dlls/winhttp/url.c
index ac25f2c..41a46b7 100644
--- a/dlls/winhttp/url.c
+++ b/dlls/winhttp/url.c
@@ -23,55 +23,166 @@
 
 #include "windef.h"
 #include "winbase.h"
+#include "winreg.h"
 #include "winhttp.h"
+#include "shlwapi.h"
 
 #include "winhttp_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
 
-#define SCHEME_HTTP  3
-#define SCHEME_HTTPS 4
+static const WCHAR scheme_http[] = {'h','t','t','p',0};
+static const WCHAR scheme_https[] = {'h','t','t','p','s',0};
+
+static BOOL set_component( WCHAR **str, DWORD *str_len, WCHAR *value, DWORD len )
+{
+    if (!*str)
+    {
+        *str = value;
+        *str_len = len;
+    }
+    else
+    {
+        if (len > (*str_len) - 1)
+        {
+            *str_len = len + 1;
+            set_last_error( ERROR_INSUFFICIENT_BUFFER );
+            return FALSE;
+        }
+        memcpy( *str, value, len * sizeof(WCHAR) );
+        (*str)[len] = 0;
+        *str_len = len;
+    }
+    return TRUE;
+}
 
-BOOL WINAPI InternetCrackUrlW( LPCWSTR, DWORD, DWORD, LPURL_COMPONENTSW );
+static BOOL decode_url( LPCWSTR url, LPWSTR buffer, LPDWORD buflen )
+{
+    HRESULT hr = UrlCanonicalizeW( url, buffer, buflen, URL_WININET_COMPATIBILITY | URL_UNESCAPE );
+    if (hr == E_POINTER) set_last_error( ERROR_INSUFFICIENT_BUFFER );
+    if (hr == E_INVALIDARG) set_last_error( ERROR_INVALID_PARAMETER );
+    return (SUCCEEDED(hr)) ? TRUE : FALSE;
+}
 
 /***********************************************************************
  *          WinHttpCrackUrl (winhttp.@)
  */
-BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW components )
+BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW uc )
 {
-    BOOL ret;
-    INT upLen;
-    INT exLen;
+    BOOL ret = FALSE;
+    WCHAR *p, *q, *r;
+    WCHAR *url_decoded = NULL;
 
-    TRACE("%s, %d, %x, %p\n", debugstr_w(url), len, flags, components);
-    upLen = components->dwUrlPathLength;
-    exLen = components->dwExtraInfoLength;
+    TRACE("%s, %d, %x, %p\n", debugstr_w(url), len, flags, uc);
 
-    if ((ret = InternetCrackUrlW( url, len, flags, components )))
+    if (flags & ICU_ESCAPE) FIXME("flag ICU_ESCAPE not supported\n");
+
+    if (!url || !url[0] || !uc || uc->dwStructSize != sizeof(URL_COMPONENTS))
     {
-        /* fix up an incompatibility between wininet and winhttp */
-        if (components->nScheme == SCHEME_HTTP) components->nScheme = INTERNET_SCHEME_HTTP;
-        else if (components->nScheme == SCHEME_HTTPS) components->nScheme = INTERNET_SCHEME_HTTPS;
-        else
+        set_last_error( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+    if (!len) len = strlenW( url );
+
+    if (flags & ICU_DECODE)
+    {
+        WCHAR *url_tmp;
+        DWORD url_len = len + 1;
+
+        if (!uc->lpszScheme || !uc->lpszUserName || !uc->lpszPassword ||
+            !uc->lpszHostName || !uc->lpszUrlPath || !uc-> lpszExtraInfo)
         {
-            set_last_error( ERROR_WINHTTP_UNRECOGNIZED_SCHEME );
+            set_last_error( ERROR_INVALID_PARAMETER );
+            return FALSE;
+        }
+        if (!(url_tmp = HeapAlloc( GetProcessHeap(), 0, url_len * sizeof(WCHAR) )))
+        {
+            set_last_error( ERROR_OUTOFMEMORY );
             return FALSE;
         }
-        if (!len)
-            len = lstrlenW(url);
-        /* WinHttpCrackUrl actually returns pointers to the end of the string for components,
-           other than UserName and Password, that are missing */
-        if (upLen && components->lpszUrlPath == NULL)
-            components->lpszUrlPath = (LPWSTR)&url[len];
-        if (exLen && components->lpszExtraInfo == NULL)
-            components->lpszExtraInfo = (LPWSTR)&url[len];
+        memcpy( url_tmp, url, len * sizeof(WCHAR) );
+        url_tmp[len] = 0;
+        if (!(url_decoded = HeapAlloc( GetProcessHeap(), 0, url_len * sizeof(WCHAR) )))
+        {
+            HeapFree( GetProcessHeap(), 0, url_tmp );
+            set_last_error( ERROR_OUTOFMEMORY );
+            return FALSE;
+        }
+        if (decode_url( url_tmp, url_decoded, &url_len ))
+        {
+            len = url_len;
+            url = url_decoded;
+        }
+        HeapFree( GetProcessHeap(), 0, url_tmp );
+    }
+    if (!(p = strchrW( url, ':' ))) return FALSE;
+
+    if (p - url == 4 && !strncmpiW( url, scheme_http, 4 )) uc->nScheme = INTERNET_SCHEME_HTTP;
+    else if (p - url == 5 && !strncmpiW( url, scheme_https, 5 )) uc->nScheme = INTERNET_SCHEME_HTTPS;
+    else goto exit;
+
+    if (!(set_component( &uc->lpszScheme, &uc->dwSchemeLength, (WCHAR *)url, p - url ))) goto exit;
+
+    p++; /* skip ':' */
+    if (!p[0] || p[0] != '/' || p[1] != '/') goto exit;
+    p += 2;
+
+    if (!p[0]) goto exit;
+    if ((q = memchrW( p, '@', len - (p - url) )))
+    {
+        if ((r = memchrW( p, ':', q - p )))
+        {
+            if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, p, r - p ))) goto exit;
+            r++;
+            if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, r, q - r ))) goto exit;
+        }
+        else
+        {
+            if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, p, q - p ))) goto exit;
+            if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, NULL, 0 ))) goto exit;
+        }
+        p = q + 1;
+    }
+    else
+    {
+        if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, NULL, 0 ))) goto exit;
+        if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, NULL, 0 ))) goto exit;
+    }
+    if ((q = memchrW( p, '/', len - (p - url) )))
+    {
+        if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, q - p ))) goto exit;
+
+        if ((r = memchrW( q, '?', len - (q - url) )))
+        {
+            if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, q, r - q ))) goto exit;
+            if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, r, len - (r - url) ))) goto exit;
+        }
+        else
+        {
+            if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, q, len - (q - url) ))) goto exit;
+            if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, (WCHAR *)url + len, 0 ))) goto exit;
+        }
+    }
+    else
+    {
+        if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, len - (p - url) ))) goto exit;
+        if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, (WCHAR *)url + len, 0 ))) goto exit;
+        if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, (WCHAR *)url + len, 0 ))) goto exit;
     }
+
+    ret = TRUE;
+
+    TRACE("scheme(%s) host(%s) path(%s) extra(%s)\n",
+          debugstr_wn( uc->lpszScheme, uc->dwSchemeLength ),
+          debugstr_wn( uc->lpszHostName, uc->dwHostNameLength ),
+          debugstr_wn( uc->lpszUrlPath, uc->dwUrlPathLength ),
+          debugstr_wn( uc->lpszExtraInfo, uc->dwExtraInfoLength ));
+
+exit:
+    HeapFree( GetProcessHeap(), 0, url_decoded );
     return ret;
 }
 
-static const WCHAR scheme_http[] = {'h','t','t','p',0};
-static const WCHAR scheme_https[] = {'h','t','t','p','s',0};
-
 static INTERNET_SCHEME get_scheme( const WCHAR *scheme, DWORD len )
 {
     if (!strncmpW( scheme, scheme_http, len )) return INTERNET_SCHEME_HTTP;




More information about the wine-cvs mailing list