[WINHTTP] Sync with Wine Staging 3.9. CORE-14656
[reactos.git] / dll / win32 / winhttp / url.c
index 07be103..32b30da 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "config.h"
+#include <stdarg.h>
+
+#include "wine/debug.h"
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winhttp.h"
+#include "shlwapi.h"
+
 #include "winhttp_private.h"
 
+WINE_DEFAULT_DEBUG_CHANNEL(winhttp);
+
 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, DWORD flags )
+static DWORD set_component( WCHAR **str, DWORD *str_len, WCHAR *value, DWORD len, DWORD flags, BOOL *overflow )
 {
-    if (*str && !*str_len)
-    {
-        set_last_error( ERROR_INVALID_PARAMETER );
-        return FALSE;
-    }
-    if (!*str_len) return TRUE;
+    if (*str && !*str_len) return ERROR_INVALID_PARAMETER;
+    if (!*str_len) return ERROR_SUCCESS;
     if (!*str)
     {
-        if (len && *str_len && (flags & (ICU_DECODE|ICU_ESCAPE)))
-        {
-            set_last_error( ERROR_INVALID_PARAMETER );
-            return FALSE;
-        }
+        if (len && *str_len && (flags & (ICU_DECODE|ICU_ESCAPE))) return ERROR_INVALID_PARAMETER;
         *str = value;
         *str_len = len;
     }
     else
     {
-        if (len > (*str_len) - 1)
+        if (len >= *str_len)
         {
-            *str_len = len + 1;
-            set_last_error( ERROR_INSUFFICIENT_BUFFER );
-            return FALSE;
+            *str_len = len+1;
+            *overflow = TRUE;
+            return ERROR_SUCCESS;
         }
         memcpy( *str, value, len * sizeof(WCHAR) );
         (*str)[len] = 0;
         *str_len = len;
     }
-    return TRUE;
+    return ERROR_SUCCESS;
 }
 
 static WCHAR *decode_url( LPCWSTR url, DWORD *len )
@@ -159,16 +164,30 @@ static WCHAR *escape_url( LPCWSTR url, DWORD *len )
     return ret;
 }
 
+static DWORD parse_port( const WCHAR *str, DWORD len, INTERNET_PORT *ret )
+{
+    const WCHAR *p = str;
+    DWORD port = 0;
+    while (len && isdigitW( *p ))
+    {
+        if ((port = port * 10 + *p - '0') > 65535) return ERROR_WINHTTP_INVALID_URL;
+        p++; len--;
+    }
+    *ret = port;
+    return ERROR_SUCCESS;
+}
+
 /***********************************************************************
  *          WinHttpCrackUrl (winhttp.@)
  */
 BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONENTSW uc )
 {
-    BOOL ret = FALSE;
     WCHAR *p, *q, *r, *url_decoded = NULL, *url_escaped = NULL;
     INTERNET_SCHEME scheme = 0;
+    BOOL overflow = FALSE;
+    DWORD err;
 
-    TRACE("%s, %d, %x, %p\n", debugstr_w(url), len, flags, uc);
+    TRACE("%s, %d, %x, %p\n", debugstr_wn(url, len), len, flags, uc);
 
     if (!url || !uc || uc->dwStructSize != sizeof(URL_COMPONENTS))
     {
@@ -204,94 +223,102 @@ BOOL WINAPI WinHttpCrackUrl( LPCWSTR url, DWORD len, DWORD flags, LPURL_COMPONEN
     else if (p - url == 5 && !strncmpiW( url, scheme_https, 5 )) scheme = INTERNET_SCHEME_HTTPS;
     else
     {
-        set_last_error( ERROR_WINHTTP_UNRECOGNIZED_SCHEME );
+        err = ERROR_WINHTTP_UNRECOGNIZED_SCHEME;
         goto exit;
     }
-    if (!(set_component( &uc->lpszScheme, &uc->dwSchemeLength, (WCHAR *)url, p - url, flags ))) goto exit;
+
+    if ((err = set_component( &uc->lpszScheme, &uc->dwSchemeLength, (WCHAR *)url, p - url, flags, &overflow ))) goto exit;
 
     p++; /* skip ':' */
-    if (!p[0] || p[0] != '/' || p[1] != '/') goto exit;
+    if (!p[0] || p[0] != '/' || p[1] != '/')
+    {
+        err = ERROR_WINHTTP_INVALID_URL;
+        goto exit;
+    }
     p += 2;
-
-    if (!p[0]) goto exit;
+    if (!p[0])
+    {
+        err = ERROR_WINHTTP_INVALID_URL;
+        goto exit;
+    }
     if ((q = memchrW( p, '@', len - (p - url) )) && !(memchrW( p, '/', q - p )))
     {
         if ((r = memchrW( p, ':', q - p )))
         {
-            if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, p, r - p, flags ))) goto exit;
+            if ((err = set_component( &uc->lpszUserName, &uc->dwUserNameLength, p, r - p, flags, &overflow ))) goto exit;
             r++;
-            if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, r, q - r, flags ))) goto exit;
+            if ((err = set_component( &uc->lpszPassword, &uc->dwPasswordLength, r, q - r, flags, &overflow ))) goto exit;
         }
         else
         {
-            if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, p, q - p, flags ))) goto exit;
-            if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, NULL, 0, flags ))) goto exit;
+            if ((err = set_component( &uc->lpszUserName, &uc->dwUserNameLength, p, q - p, flags, &overflow ))) goto exit;
+            if ((err = set_component( &uc->lpszPassword, &uc->dwPasswordLength, NULL, 0, flags, &overflow ))) goto exit;
         }
         p = q + 1;
     }
     else
     {
-        if (!(set_component( &uc->lpszUserName, &uc->dwUserNameLength, NULL, 0, flags ))) goto exit;
-        if (!(set_component( &uc->lpszPassword, &uc->dwPasswordLength, NULL, 0, flags ))) goto exit;
+        if ((err = set_component( &uc->lpszUserName, &uc->dwUserNameLength, NULL, 0, flags, &overflow ))) goto exit;
+        if ((err = set_component( &uc->lpszPassword, &uc->dwPasswordLength, NULL, 0, flags, &overflow ))) goto exit;
     }
     if ((q = memchrW( p, '/', len - (p - url) )))
     {
         if ((r = memchrW( p, ':', q - p )))
         {
-            if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, r - p, flags ))) goto exit;
+            if ((err = set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, r - p, flags, &overflow ))) goto exit;
             r++;
-            uc->nPort = atoiW( r );
+            if ((err = parse_port( r, q - r, &uc->nPort ))) goto exit;
         }
         else
         {
-            if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, q - p, flags ))) goto exit;
+            if ((err = set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, q - p, flags, &overflow ))) goto exit;
             if (scheme == INTERNET_SCHEME_HTTP) uc->nPort = INTERNET_DEFAULT_HTTP_PORT;
             if (scheme == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT;
         }
 
         if ((r = memchrW( q, '?', len - (q - url) )))
         {
-            if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, q, r - q, flags ))) goto exit;
-            if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, r, len - (r - url), flags ))) goto exit;
+            if ((err = set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, q, r - q, flags, &overflow ))) goto exit;
+            if ((err = set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, r, len - (r - url), flags, &overflow ))) goto exit;
         }
         else
         {
-            if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, q, len - (q - url), flags ))) goto exit;
-            if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, (WCHAR *)url + len, 0, flags ))) goto exit;
+            if ((err = set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, q, len - (q - url), flags, &overflow ))) goto exit;
+            if ((err = set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, (WCHAR *)url + len, 0, flags, &overflow ))) goto exit;
         }
     }
     else
     {
         if ((r = memchrW( p, ':', len - (p - url) )))
         {
-            if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, r - p, flags ))) goto exit;
+            if ((err = set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, r - p, flags, &overflow ))) goto exit;
             r++;
-            uc->nPort = atoiW( r );
+            if ((err = parse_port( r, len - (r - url), &uc->nPort ))) goto exit;
         }
         else
         {
-            if (!(set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, len - (p - url), flags ))) goto exit;
+            if ((err = set_component( &uc->lpszHostName, &uc->dwHostNameLength, p, len - (p - url), flags, &overflow ))) goto exit;
             if (scheme == INTERNET_SCHEME_HTTP) uc->nPort = INTERNET_DEFAULT_HTTP_PORT;
             if (scheme == INTERNET_SCHEME_HTTPS) uc->nPort = INTERNET_DEFAULT_HTTPS_PORT;
         }
-        if (!(set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, (WCHAR *)url + len, 0, flags ))) goto exit;
-        if (!(set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, (WCHAR *)url + len, 0, flags ))) goto exit;
+        if ((err = set_component( &uc->lpszUrlPath, &uc->dwUrlPathLength, (WCHAR *)url + len, 0, flags, &overflow ))) goto exit;
+        if ((err = set_component( &uc->lpszExtraInfo, &uc->dwExtraInfoLength, (WCHAR *)url + len, 0, flags, &overflow ))) goto exit;
     }
 
-    ret = TRUE;
-
-    TRACE("scheme(%s) host(%s) port(%d) path(%s) extra(%s)\n",
-          debugstr_wn( uc->lpszScheme, uc->dwSchemeLength ),
-          debugstr_wn( uc->lpszHostName, uc->dwHostNameLength ),
-          uc->nPort,
-          debugstr_wn( uc->lpszUrlPath, uc->dwUrlPathLength ),
+    TRACE("scheme(%s) host(%s) port(%d) path(%s) extra(%s)\n", debugstr_wn( uc->lpszScheme, uc->dwSchemeLength ),
+          debugstr_wn( uc->lpszHostName, uc->dwHostNameLength ), uc->nPort, debugstr_wn( uc->lpszUrlPath, uc->dwUrlPathLength ),
           debugstr_wn( uc->lpszExtraInfo, uc->dwExtraInfoLength ));
 
 exit:
-    if (ret) uc->nScheme = scheme;
+    if (!err)
+    {
+        if (overflow) err = ERROR_INSUFFICIENT_BUFFER;
+        uc->nScheme = scheme;
+    }
     heap_free( url_decoded );
     heap_free( url_escaped );
-    return ret;
+    set_last_error( err );
+    return !err;
 }
 
 static INTERNET_SCHEME get_scheme( const WCHAR *scheme, DWORD len )
@@ -373,8 +400,7 @@ static BOOL calc_length( URL_COMPONENTS *uc, DWORD flags, LPDWORD len )
         {
             WCHAR port[sizeof("65535")];
 
-            sprintfW( port, formatW, uc->nPort );
-            *len += strlenW( port );
+            *len += sprintfW( port, formatW, uc->nPort );
             *len += 1; /* ":" */
         }
         if (uc->lpszUrlPath && *uc->lpszUrlPath != '/') *len += 1; /* '/' */
@@ -391,13 +417,12 @@ BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDW
 {
     static const WCHAR formatW[] = {'%','u',0};
     static const WCHAR twoslashW[] = {'/','/'};
-
     DWORD len;
     INTERNET_SCHEME scheme;
 
     TRACE("%p, 0x%08x, %p, %p\n", uc, flags, url, required);
 
-    if (!uc || uc->dwStructSize != sizeof(URL_COMPONENTS) || !required || !url)
+    if (!uc || uc->dwStructSize != sizeof(URL_COMPONENTS) || !required)
     {
         set_last_error( ERROR_INVALID_PARAMETER );
         return FALSE;
@@ -411,6 +436,11 @@ BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDW
         set_last_error( ERROR_INSUFFICIENT_BUFFER );
         return FALSE;
     }
+    if (!url)
+    {
+        set_last_error( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
 
     url[0] = 0;
     *required = len;
@@ -470,15 +500,10 @@ BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDW
 
         if (!uses_default_port( scheme, uc->nPort ))
         {
-            WCHAR port[sizeof("65535")];
-
-            sprintfW( port, formatW, uc->nPort );
             *url = ':';
             url++;
 
-            len = strlenW( port );
-            memcpy( url, port, len * sizeof(WCHAR) );
-            url += len;
+            url += sprintfW( url, formatW, uc->nPort );
         }
 
         /* add slash between hostname and path if necessary */
@@ -509,5 +534,6 @@ BOOL WINAPI WinHttpCreateUrl( LPURL_COMPONENTS uc, DWORD flags, LPWSTR url, LPDW
         }
     }
     *url = 0;
+    set_last_error( ERROR_SUCCESS );
     return TRUE;
 }