[WININET] Sync with Wine Staging 3.9. CORE-14656
[reactos.git] / dll / win32 / wininet / internet.c
index b78e44f..3df84d1 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "config.h"
+
+#ifdef HAVE_CORESERVICES_CORESERVICES_H
+#define GetCurrentThread MacGetCurrentThread
+#define LoadResource MacLoadResource
+#include <CoreServices/CoreServices.h>
+#undef GetCurrentThread
+#undef LoadResource
+#undef DPRINTF
+#endif
+
+#include "winsock2.h"
+#include "ws2ipdef.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winreg.h"
+#include "winuser.h"
+#include "wininet.h"
+#include "winnls.h"
+#include "wine/debug.h"
+#include "winerror.h"
+#define NO_SHLWAPI_STREAM
+#include "shlwapi.h"
+
+#include "wine/exception.h"
+
 #include "internet.h"
+#include "resource.h"
 
-#define RESPONSE_TIMEOUT        30
+#include "wine/unicode.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(wininet);
 
 typedef struct
 {
@@ -57,6 +94,8 @@ typedef struct
     DWORD  proxyEnabled;
     LPWSTR proxy;
     LPWSTR proxyBypass;
+    LPWSTR proxyUsername;
+    LPWSTR proxyPassword;
 } proxyinfo_t;
 
 static ULONG max_conns = 2, max_1_0_conns = 4;
@@ -113,7 +152,7 @@ void *alloc_object(object_header_t *parent, const object_vtbl_t *vtbl, size_t si
         handle_table[handle] = ret;
         ret->valid_handle = TRUE;
 
-        while(handle_table[next_handle] && next_handle < handle_table_size)
+        while(next_handle < handle_table_size && handle_table[next_handle])
             next_handle++;
     }
 
@@ -245,9 +284,11 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
             if (g_dwTlsErrIndex == TLS_OUT_OF_INDEXES)
                 return FALSE;
 
-#ifndef __REACTOS__
-            URLCacheContainers_CreateDefaults();
-#endif
+            if(!init_urlcache())
+            {
+                TlsFree(g_dwTlsErrIndex);
+                return FALSE;
+            }
 
             WININET_hModule = hinstDLL;
             break;
@@ -279,6 +320,15 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
     return TRUE;
 }
 
+/***********************************************************************
+ *             DllInstall (WININET.@)
+ */
+HRESULT WINAPI DllInstall(BOOL bInstall, LPCWSTR cmdline)
+{
+    FIXME("(%x %s): stub\n", bInstall, debugstr_w(cmdline));
+    return S_OK;
+}
+
 /***********************************************************************
  *           INTERNET_SaveProxySettings
  *
@@ -311,7 +361,7 @@ static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi )
     }
     else
     {
-        if ((ret = RegDeleteValueW( key, szProxyServer )))
+        if ((ret = RegDeleteValueW( key, szProxyServer )) && ret != ERROR_FILE_NOT_FOUND)
         {
             RegCloseKey( key );
             return ret;
@@ -340,15 +390,15 @@ static LONG INTERNET_SaveProxySettings( proxyinfo_t *lpwpi )
  *     *foundProxyLen is set to the required size in WCHARs, including the
  *     NULL terminator, and the last error is set to ERROR_INSUFFICIENT_BUFFER.
  */
-BOOL INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto, WCHAR *foundProxy, DWORD *foundProxyLen)
+WCHAR *INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto)
 {
-    LPCWSTR ptr;
-    BOOL ret = FALSE;
+    WCHAR *ret = NULL;
+    const WCHAR *ptr;
 
     TRACE("(%s, %s)\n", debugstr_w(szProxy), debugstr_w(proto));
 
     /* First, look for the specified protocol (proto=scheme://host:port) */
-    for (ptr = szProxy; !ret && ptr && *ptr; )
+    for (ptr = szProxy; ptr && *ptr; )
     {
         LPCWSTR end, equal;
 
@@ -358,60 +408,36 @@ BOOL INTERNET_FindProxyForProtocol(LPCWSTR szProxy, LPCWSTR proto, WCHAR *foundP
              equal - ptr == strlenW(proto) &&
              !strncmpiW(proto, ptr, strlenW(proto)))
         {
-            if (end - equal > *foundProxyLen)
-            {
-                WARN("buffer too short for %s\n",
-                     debugstr_wn(equal + 1, end - equal - 1));
-                *foundProxyLen = end - equal;
-                SetLastError(ERROR_INSUFFICIENT_BUFFER);
-            }
-            else
-            {
-                memcpy(foundProxy, equal + 1, (end - equal) * sizeof(WCHAR));
-                foundProxy[end - equal] = 0;
-                ret = TRUE;
-            }
+            ret = heap_strndupW(equal + 1, end - equal - 1);
+            TRACE("found proxy for %s: %s\n", debugstr_w(proto), debugstr_w(ret));
+            return ret;
         }
         if (*end == ' ')
             ptr = end + 1;
         else
             ptr = end;
     }
-    if (!ret)
+
+    /* It wasn't found: look for no protocol */
+    for (ptr = szProxy; ptr && *ptr; )
     {
-        /* It wasn't found: look for no protocol */
-        for (ptr = szProxy; !ret && ptr && *ptr; )
-        {
-            LPCWSTR end;
+        LPCWSTR end;
 
-            if (!(end = strchrW(ptr, ' ')))
-                end = ptr + strlenW(ptr);
-            if (!strchrW(ptr, '='))
-            {
-                if (end - ptr + 1 > *foundProxyLen)
-                {
-                    WARN("buffer too short for %s\n",
-                         debugstr_wn(ptr, end - ptr));
-                    *foundProxyLen = end - ptr + 1;
-                    SetLastError(ERROR_INSUFFICIENT_BUFFER);
-                }
-                else
-                {
-                    memcpy(foundProxy, ptr, (end - ptr) * sizeof(WCHAR));
-                    foundProxy[end - ptr] = 0;
-                    ret = TRUE;
-                }
-            }
-            if (*end == ' ')
-                ptr = end + 1;
-            else
-                ptr = end;
+        if (!(end = strchrW(ptr, ' ')))
+            end = ptr + strlenW(ptr);
+        if (!strchrW(ptr, '='))
+        {
+            ret = heap_strndupW(ptr, end - ptr);
+            TRACE("found proxy for %s: %s\n", debugstr_w(proto), debugstr_w(ret));
+            return ret;
         }
+        if (*end == ' ')
+            ptr = end + 1;
+        else
+            ptr = end;
     }
-    if (ret)
-        TRACE("found proxy for %s: %s\n", debugstr_w(proto),
-              debugstr_w(foundProxy));
-    return ret;
+
+    return NULL;
 }
 
 /***********************************************************************
@@ -454,6 +480,8 @@ static void FreeProxyInfo( proxyinfo_t *lpwpi )
 {
     heap_free(lpwpi->proxy);
     heap_free(lpwpi->proxyBypass);
+    heap_free(lpwpi->proxyUsername);
+    heap_free(lpwpi->proxyPassword);
 }
 
 static proxyinfo_t *global_proxy;
@@ -469,6 +497,42 @@ static void free_global_proxy( void )
     LeaveCriticalSection( &WININET_cs );
 }
 
+static BOOL parse_proxy_url( proxyinfo_t *info, const WCHAR *url )
+{
+    static const WCHAR fmt[] = {'%','.','*','s',':','%','u',0};
+    URL_COMPONENTSW uc = {sizeof(uc)};
+
+    uc.dwHostNameLength = 1;
+    uc.dwUserNameLength = 1;
+    uc.dwPasswordLength = 1;
+
+    if (!InternetCrackUrlW( url, 0, 0, &uc )) return FALSE;
+    if (!uc.dwHostNameLength)
+    {
+        if (!(info->proxy = heap_strdupW( url ))) return FALSE;
+        info->proxyUsername = NULL;
+        info->proxyPassword = NULL;
+        return TRUE;
+    }
+    if (!(info->proxy = heap_alloc( (uc.dwHostNameLength + 12) * sizeof(WCHAR) ))) return FALSE;
+    sprintfW( info->proxy, fmt, uc.dwHostNameLength, uc.lpszHostName, uc.nPort );
+
+    if (!uc.dwUserNameLength) info->proxyUsername = NULL;
+    else if (!(info->proxyUsername = heap_strndupW( uc.lpszUserName, uc.dwUserNameLength )))
+    {
+        heap_free( info->proxy );
+        return FALSE;
+    }
+    if (!uc.dwPasswordLength) info->proxyPassword = NULL;
+    else if (!(info->proxyPassword = heap_strndupW( uc.lpszPassword, uc.dwPasswordLength )))
+    {
+        heap_free( info->proxyUsername );
+        heap_free( info->proxy );
+        return FALSE;
+    }
+    return TRUE;
+}
+
 /***********************************************************************
  *          INTERNET_LoadProxySettings
  *
@@ -488,6 +552,8 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
     LPCSTR envproxy;
     LONG ret;
 
+    memset( lpwpi, 0, sizeof(*lpwpi) );
+
     EnterCriticalSection( &WININET_cs );
     if (global_proxy)
     {
@@ -498,7 +564,10 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
     LeaveCriticalSection( &WININET_cs );
 
     if ((ret = RegOpenKeyW( HKEY_CURRENT_USER, szInternetSettings, &key )))
+    {
+        FreeProxyInfo( lpwpi );
         return ret;
+    }
 
     len = sizeof(DWORD);
     if (RegQueryValueExW( key, szProxyEnable, NULL, &type, (BYTE *)&lpwpi->proxyEnabled, &len ) || type != REG_DWORD)
@@ -506,6 +575,7 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
         lpwpi->proxyEnabled = 0;
         if((ret = RegSetValueExW( key, szProxyEnable, 0, REG_DWORD, (BYTE *)&lpwpi->proxyEnabled, sizeof(DWORD) )))
         {
+            FreeProxyInfo( lpwpi );
             RegCloseKey( key );
             return ret;
         }
@@ -513,8 +583,6 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
 
     if (!(envproxy = getenv( "http_proxy" )) || lpwpi->proxyEnabled)
     {
-        TRACE("Proxy is enabled.\n");
-
         /* figure out how much memory the proxy setting takes */
         if (!RegQueryValueExW( key, szProxyServer, NULL, &type, NULL, &len ) && len && (type == REG_SZ))
         {
@@ -524,6 +592,7 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
             if (!(szProxy = heap_alloc(len)))
             {
                 RegCloseKey( key );
+                FreeProxyInfo( lpwpi );
                 return ERROR_OUTOFMEMORY;
             }
             RegQueryValueExW( key, szProxyServer, NULL, &type, (BYTE*)szProxy, &len );
@@ -535,17 +604,21 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
                 p += lstrlenW( szHttp );
                 lstrcpyW( szProxy, p );
             }
-            p = strchrW( szProxy, ' ' );
+            p = strchrW( szProxy, ';' );
             if (p) *p = 0;
 
+            FreeProxyInfo( lpwpi );
             lpwpi->proxy = szProxy;
+            lpwpi->proxyBypass = NULL;
 
-            TRACE("http proxy = %s\n", debugstr_w(lpwpi->proxy));
+            TRACE("http proxy (from registry) = %s\n", debugstr_w(lpwpi->proxy));
         }
         else
         {
             TRACE("No proxy server settings in registry.\n");
+            FreeProxyInfo( lpwpi );
             lpwpi->proxy = NULL;
+            lpwpi->proxyBypass = NULL;
         }
     }
     else if (envproxy)
@@ -554,18 +627,33 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
 
         len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
         if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
+        {
+            RegCloseKey( key );
             return ERROR_OUTOFMEMORY;
+        }
         MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
 
-        lpwpi->proxyEnabled = 1;
-        lpwpi->proxy = envproxyW;
-
-        TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->proxy));
+        FreeProxyInfo( lpwpi );
+        if (parse_proxy_url( lpwpi, envproxyW ))
+        {
+            TRACE("http proxy (from environment) = %s\n", debugstr_w(lpwpi->proxy));
+            lpwpi->proxyEnabled = 1;
+            lpwpi->proxyBypass = NULL;
+        }
+        else
+        {
+            WARN("failed to parse http_proxy value %s\n", debugstr_w(envproxyW));
+            lpwpi->proxyEnabled = 0;
+            lpwpi->proxy = NULL;
+            lpwpi->proxyBypass = NULL;
+        }
+        heap_free( envproxyW );
     }
 
-    lpwpi->proxyBypass = NULL;
     if (lpwpi->proxyEnabled)
     {
+        TRACE("Proxy is enabled.\n");
+
         if (!(envproxy = getenv( "no_proxy" )))
         {
             /* figure out how much memory the proxy setting takes */
@@ -580,32 +668,40 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
                 }
                 RegQueryValueExW( key, szProxyOverride, NULL, &type, (BYTE*)szProxy, &len );
 
+                heap_free( lpwpi->proxyBypass );
                 lpwpi->proxyBypass = szProxy;
 
-                TRACE("http proxy bypass = %s\n", debugstr_w(lpwpi->proxyBypass));
+                TRACE("http proxy bypass (from registry) = %s\n", debugstr_w(lpwpi->proxyBypass));
             }
             else
             {
+                heap_free( lpwpi->proxyBypass );
+                lpwpi->proxyBypass = NULL;
+
                 TRACE("No proxy bypass server settings in registry.\n");
             }
         }
-        else if (envproxy)
+        else
         {
             WCHAR *envproxyW;
 
             len = MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, NULL, 0 );
             if (!(envproxyW = heap_alloc(len * sizeof(WCHAR))))
+            {
+                RegCloseKey( key );
                 return ERROR_OUTOFMEMORY;
+            }
             MultiByteToWideChar( CP_UNIXCP, 0, envproxy, -1, envproxyW, len );
 
+            heap_free( lpwpi->proxyBypass );
             lpwpi->proxyBypass = envproxyW;
 
             TRACE("http proxy bypass (from environment) = %s\n", debugstr_w(lpwpi->proxyBypass));
         }
     }
+    else TRACE("Proxy is disabled.\n");
 
     RegCloseKey( key );
-
     return ERROR_SUCCESS;
 }
 
@@ -614,56 +710,21 @@ static LONG INTERNET_LoadProxySettings( proxyinfo_t *lpwpi )
  */
 static BOOL INTERNET_ConfigureProxy( appinfo_t *lpwai )
 {
-    proxyinfo_t wpi = {0};
+    proxyinfo_t wpi;
 
     if (INTERNET_LoadProxySettings( &wpi ))
         return FALSE;
 
     if (wpi.proxyEnabled)
     {
-        WCHAR proxyurl[INTERNET_MAX_URL_LENGTH];
-        WCHAR username[INTERNET_MAX_USER_NAME_LENGTH];
-        WCHAR password[INTERNET_MAX_PASSWORD_LENGTH];
-        WCHAR hostname[INTERNET_MAX_HOST_NAME_LENGTH];
-        URL_COMPONENTSW UrlComponents;
-
-        UrlComponents.dwStructSize = sizeof UrlComponents;
-        UrlComponents.dwSchemeLength = 0;
-        UrlComponents.lpszHostName = hostname;
-        UrlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
-        UrlComponents.lpszUserName = username;
-        UrlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
-        UrlComponents.lpszPassword = password;
-        UrlComponents.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;
-        UrlComponents.dwUrlPathLength = 0;
-        UrlComponents.dwExtraInfoLength = 0;
-
-        if(InternetCrackUrlW(wpi.proxy, 0, 0, &UrlComponents))
-        {
-            static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',':','%','u',0 };
-
-            if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
-                UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
-            sprintfW(proxyurl, szFormat, hostname, UrlComponents.nPort);
+        TRACE("http proxy = %s bypass = %s\n", debugstr_w(wpi.proxy), debugstr_w(wpi.proxyBypass));
 
-            lpwai->accessType = INTERNET_OPEN_TYPE_PROXY;
-            lpwai->proxy = heap_strdupW(proxyurl);
-            lpwai->proxyBypass = heap_strdupW(wpi.proxyBypass);
-            if (UrlComponents.dwUserNameLength)
-            {
-                lpwai->proxyUsername = heap_strdupW(UrlComponents.lpszUserName);
-                lpwai->proxyPassword = heap_strdupW(UrlComponents.lpszPassword);
-            }
-
-            TRACE("http proxy = %s bypass = %s\n", debugstr_w(lpwai->proxy), debugstr_w(lpwai->proxyBypass));
-            FreeProxyInfo(&wpi);
-            return TRUE;
-        }
-        else
-        {
-            TRACE("Failed to parse proxy: %s\n", debugstr_w(wpi.proxy));
-            lpwai->proxy = NULL;
-        }
+        lpwai->accessType    = INTERNET_OPEN_TYPE_PROXY;
+        lpwai->proxy         = wpi.proxy;
+        lpwai->proxyBypass   = wpi.proxyBypass;
+        lpwai->proxyUsername = wpi.proxyUsername;
+        lpwai->proxyPassword = wpi.proxyPassword;
+        return TRUE;
     }
 
     lpwai->accessType = INTERNET_OPEN_TYPE_DIRECT;
@@ -745,9 +806,6 @@ static VOID APPINFO_Destroy(object_header_t *hdr)
     heap_free(lpwai->proxyBypass);
     heap_free(lpwai->proxyUsername);
     heap_free(lpwai->proxyPassword);
-#ifdef __REACTOS__
-    WSACleanup();
-#endif
 }
 
 static DWORD APPINFO_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
@@ -912,6 +970,9 @@ static DWORD APPINFO_SetOption(object_header_t *hdr, DWORD option, void *buf, DW
         heap_free(ai->agent);
         if (!(ai->agent = heap_strdupW(buf))) return ERROR_OUTOFMEMORY;
         return ERROR_SUCCESS;
+    case INTERNET_OPTION_REFRESH:
+        FIXME("INTERNET_OPTION_REFRESH\n");
+        return ERROR_SUCCESS;
     }
 
     return INET_SetOption(hdr, option, buf, size);
@@ -924,7 +985,6 @@ static const object_vtbl_t APPINFOVtbl = {
     APPINFO_SetOption,
     NULL,
     NULL,
-    NULL,
     NULL
 };
 
@@ -943,12 +1003,10 @@ HINTERNET WINAPI InternetOpenW(LPCWSTR lpszAgent, DWORD dwAccessType,
     LPCWSTR lpszProxy, LPCWSTR lpszProxyBypass, DWORD dwFlags)
 {
     appinfo_t *lpwai = NULL;
+
 #ifdef __REACTOS__
-    WSADATA wsaData;
-    int error = WSAStartup(MAKEWORD(2, 2), &wsaData);
-    if (error) ERR("WSAStartup failed: %d\n", error);
+    init_winsock();
 #endif
-
     if (TRACE_ON(wininet)) {
 #define FE(x) { x, #x }
        static const wininet_flag_info access_type[] = {
@@ -1129,11 +1187,7 @@ BOOL WINAPI InternetGetConnectedState(LPDWORD lpdwStatus, DWORD dwReserved)
 {
     TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved);
 
-    if (lpdwStatus) {
-       WARN("always returning LAN connection.\n");
-       *lpdwStatus = INTERNET_CONNECTION_LAN;
-    }
-    return TRUE;
+    return InternetGetConnectedStateExW(lpdwStatus, NULL, 0, dwReserved);
 }
 
 
@@ -1171,13 +1225,21 @@ BOOL WINAPI InternetGetConnectedStateExW(LPDWORD lpdwStatus, LPWSTR lpszConnecti
 
     /* Must be zero */
     if(dwReserved)
-       return FALSE;
+        return FALSE;
 
     if (lpdwStatus) {
         WARN("always returning LAN connection.\n");
         *lpdwStatus = INTERNET_CONNECTION_LAN;
     }
-    return LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen) > 0;
+
+    /* When the buffer size is zero LoadStringW fills the buffer with a pointer to
+     * the resource, avoid it as we must not change the buffer in this case */
+    if(lpszConnectionName && dwNameLen) {
+        *lpszConnectionName = '\0';
+        LoadStringW(WININET_hModule, IDS_LANCONNECTION, lpszConnectionName, dwNameLen);
+    }
+
+    return TRUE;
 }
 
 
@@ -1198,11 +1260,10 @@ BOOL WINAPI InternetGetConnectedStateExA(LPDWORD lpdwStatus, LPSTR lpszConnectio
     rc = InternetGetConnectedStateExW(lpdwStatus,lpwszConnectionName, dwNameLen,
                                       dwReserved);
     if (rc && lpwszConnectionName)
-    {
         WideCharToMultiByte(CP_ACP,0,lpwszConnectionName,-1,lpszConnectionName,
                             dwNameLen, NULL, NULL);
-        heap_free(lpwszConnectionName);
-    }
+
+    heap_free(lpwszConnectionName);
     return rc;
 }
 
@@ -1226,9 +1287,8 @@ HINTERNET WINAPI InternetConnectW(HINTERNET hInternet,
     HINTERNET rc = NULL;
     DWORD res = ERROR_SUCCESS;
 
-    TRACE("(%p, %s, %i, %s, %s, %i, %x, %lx)\n", hInternet, debugstr_w(lpszServerName),
-         nServerPort, debugstr_w(lpszUserName), debugstr_w(lpszPassword),
-         dwService, dwFlags, dwContext);
+    TRACE("(%p, %s, %u, %s, %p, %u, %x, %lx)\n", hInternet, debugstr_w(lpszServerName),
+          nServerPort, debugstr_w(lpszUserName), lpszPassword, dwService, dwFlags, dwContext);
 
     if (!lpszServerName)
     {
@@ -1392,169 +1452,147 @@ BOOL WINAPI InternetCloseHandle(HINTERNET hInternet)
     return TRUE;
 }
 
+static BOOL set_url_component(WCHAR **component, DWORD *component_length, const WCHAR *value, DWORD len)
+{
+    TRACE("%s (%d)\n", debugstr_wn(value, len), len);
 
-/***********************************************************************
- *           ConvertUrlComponentValue (Internal)
- *
- * Helper function for InternetCrackUrlA
- *
- */
-static void ConvertUrlComponentValue(LPSTR* lppszComponent, LPDWORD dwComponentLen,
-                                     LPWSTR lpwszComponent, DWORD dwwComponentLen,
-                                     LPCSTR lpszStart, LPCWSTR lpwszStart)
+    if (!*component_length)
+        return TRUE;
+
+    if (!*component) {
+        *(const WCHAR**)component = value;
+        *component_length = len;
+        return TRUE;
+    }
+
+    if (*component_length < len+1) {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        return FALSE;
+    }
+
+    *component_length = len;
+    if(len)
+        memcpy(*component, value, len*sizeof(WCHAR));
+    (*component)[len] = 0;
+    return TRUE;
+}
+
+static BOOL set_url_component_WtoA(const WCHAR *comp_w, DWORD length, const WCHAR *url_w, char **comp, DWORD *ret_length,
+                                   const char *url_a)
 {
-    TRACE("%p %d %p %d %p %p\n", *lppszComponent, *dwComponentLen, lpwszComponent, dwwComponentLen, lpszStart, lpwszStart);
-    if (*dwComponentLen != 0)
-    {
-        DWORD nASCIILength=WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,NULL,0,NULL,NULL);
-        if (*lppszComponent == NULL)
-        {
-            if (lpwszComponent)
-            {
-                int offset = WideCharToMultiByte(CP_ACP, 0, lpwszStart, lpwszComponent-lpwszStart, NULL, 0, NULL, NULL);
-                *lppszComponent = (LPSTR)lpszStart + offset;
-            }
-            else
-                *lppszComponent = NULL;
+    size_t size, ret_size = *ret_length;
 
-            *dwComponentLen = nASCIILength;
-        }
-        else
-        {
-            DWORD ncpylen = min((*dwComponentLen)-1, nASCIILength);
-            WideCharToMultiByte(CP_ACP,0,lpwszComponent,dwwComponentLen,*lppszComponent,ncpylen+1,NULL,NULL);
-            (*lppszComponent)[ncpylen]=0;
-            *dwComponentLen = ncpylen;
-        }
+    if (!*ret_length)
+        return TRUE;
+    size = WideCharToMultiByte(CP_ACP, 0, comp_w, length, NULL, 0, NULL, NULL);
+
+    if (!*comp) {
+        *comp = comp_w ? (char*)url_a + WideCharToMultiByte(CP_ACP, 0, url_w, comp_w-url_w, NULL, 0, NULL, NULL) : NULL;
+        *ret_length = size;
+        return TRUE;
     }
+
+    if (size+1 > ret_size) {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        *ret_length = size+1;
+        return FALSE;
+    }
+
+    *ret_length = size;
+    WideCharToMultiByte(CP_ACP, 0, comp_w, length, *comp, ret_size-1, NULL, NULL);
+    (*comp)[size] = 0;
+    return TRUE;
 }
 
+static BOOL set_url_component_AtoW(const char *comp_a, DWORD len_a, WCHAR **comp_w, DWORD *len_w, WCHAR **buf)
+{
+    *len_w = len_a;
+
+    if(!comp_a) {
+        *comp_w = NULL;
+        return TRUE;
+    }
+
+    if(!(*comp_w = *buf = heap_alloc(len_a*sizeof(WCHAR)))) {
+        SetLastError(ERROR_OUTOFMEMORY);
+        return FALSE;
+    }
+
+    return TRUE;
+}
 
 /***********************************************************************
  *           InternetCrackUrlA (WININET.@)
  *
  * See InternetCrackUrlW.
  */
-BOOL WINAPI InternetCrackUrlA(LPCSTR lpszUrl, DWORD dwUrlLength, DWORD dwFlags,
-    LPURL_COMPONENTSA lpUrlComponents)
+BOOL WINAPI InternetCrackUrlA(const char *url, DWORD url_length, DWORD flags, URL_COMPONENTSA *ret_comp)
 {
-  DWORD nLength;
-  URL_COMPONENTSW UCW;
-  BOOL ret = FALSE;
-  WCHAR *lpwszUrl, *hostname = NULL, *username = NULL, *password = NULL, *path = NULL,
-        *scheme = NULL, *extra = NULL;
-
-  TRACE("(%s %u %x %p)\n",
-        lpszUrl ? debugstr_an(lpszUrl, dwUrlLength ? dwUrlLength : strlen(lpszUrl)) : "(null)",
-        dwUrlLength, dwFlags, lpUrlComponents);
-
-  if (!lpszUrl || !*lpszUrl || !lpUrlComponents ||
-          lpUrlComponents->dwStructSize != sizeof(URL_COMPONENTSA))
-  {
-      INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
-      return FALSE;
-  }
+    WCHAR *host = NULL, *user = NULL, *pass = NULL, *path = NULL, *scheme = NULL, *extra = NULL;
+    URL_COMPONENTSW comp;
+    WCHAR *url_w = NULL;
+    BOOL ret;
 
-  if(dwUrlLength<=0)
-      dwUrlLength=-1;
-  nLength=MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,NULL,0);
+    TRACE("(%s %u %x %p)\n", url_length ? debugstr_an(url, url_length) : debugstr_a(url), url_length, flags, ret_comp);
 
-  /* if dwUrlLength=-1 then nLength includes null but length to 
-       InternetCrackUrlW should not include it                  */
-  if (dwUrlLength == -1) nLength--;
+    if (!url || !*url || !ret_comp || ret_comp->dwStructSize != sizeof(URL_COMPONENTSA)) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
 
-  lpwszUrl = heap_alloc((nLength + 1) * sizeof(WCHAR));
-  MultiByteToWideChar(CP_ACP,0,lpszUrl,dwUrlLength,lpwszUrl,nLength + 1);
-  lpwszUrl[nLength] = '\0';
+    comp.dwStructSize = sizeof(comp);
 
-  memset(&UCW,0,sizeof(UCW));
-  UCW.dwStructSize = sizeof(URL_COMPONENTSW);
-  if (lpUrlComponents->dwHostNameLength)
-  {
-    UCW.dwHostNameLength = lpUrlComponents->dwHostNameLength;
-    if (lpUrlComponents->lpszHostName)
-    {
-      hostname = heap_alloc(UCW.dwHostNameLength * sizeof(WCHAR));
-      UCW.lpszHostName = hostname;
-    }
-  }
-  if (lpUrlComponents->dwUserNameLength)
-  {
-    UCW.dwUserNameLength = lpUrlComponents->dwUserNameLength;
-    if (lpUrlComponents->lpszUserName)
-    {
-      username = heap_alloc(UCW.dwUserNameLength * sizeof(WCHAR));
-      UCW.lpszUserName = username;
-    }
-  }
-  if (lpUrlComponents->dwPasswordLength)
-  {
-    UCW.dwPasswordLength = lpUrlComponents->dwPasswordLength;
-    if (lpUrlComponents->lpszPassword)
-    {
-      password = heap_alloc(UCW.dwPasswordLength * sizeof(WCHAR));
-      UCW.lpszPassword = password;
-    }
-  }
-  if (lpUrlComponents->dwUrlPathLength)
-  {
-    UCW.dwUrlPathLength = lpUrlComponents->dwUrlPathLength;
-    if (lpUrlComponents->lpszUrlPath)
-    {
-      path = heap_alloc(UCW.dwUrlPathLength * sizeof(WCHAR));
-      UCW.lpszUrlPath = path;
-    }
-  }
-  if (lpUrlComponents->dwSchemeLength)
-  {
-    UCW.dwSchemeLength = lpUrlComponents->dwSchemeLength;
-    if (lpUrlComponents->lpszScheme)
-    {
-      scheme = heap_alloc(UCW.dwSchemeLength * sizeof(WCHAR));
-      UCW.lpszScheme = scheme;
-    }
-  }
-  if (lpUrlComponents->dwExtraInfoLength)
-  {
-    UCW.dwExtraInfoLength = lpUrlComponents->dwExtraInfoLength;
-    if (lpUrlComponents->lpszExtraInfo)
-    {
-      extra = heap_alloc(UCW.dwExtraInfoLength * sizeof(WCHAR));
-      UCW.lpszExtraInfo = extra;
+    ret = set_url_component_AtoW(ret_comp->lpszHostName, ret_comp->dwHostNameLength,
+                                 &comp.lpszHostName, &comp.dwHostNameLength, &host)
+        && set_url_component_AtoW(ret_comp->lpszUserName, ret_comp->dwUserNameLength,
+                                  &comp.lpszUserName, &comp.dwUserNameLength, &user)
+        && set_url_component_AtoW(ret_comp->lpszPassword, ret_comp->dwPasswordLength,
+                                  &comp.lpszPassword, &comp.dwPasswordLength, &pass)
+        && set_url_component_AtoW(ret_comp->lpszUrlPath, ret_comp->dwUrlPathLength,
+                                  &comp.lpszUrlPath, &comp.dwUrlPathLength, &path)
+        && set_url_component_AtoW(ret_comp->lpszScheme, ret_comp->dwSchemeLength,
+                                  &comp.lpszScheme, &comp.dwSchemeLength, &scheme)
+        && set_url_component_AtoW(ret_comp->lpszExtraInfo, ret_comp->dwExtraInfoLength,
+                                  &comp.lpszExtraInfo, &comp.dwExtraInfoLength, &extra);
+
+    if(ret && !(url_w = heap_strndupAtoW(url, url_length ? url_length : -1, &url_length))) {
+        SetLastError(ERROR_OUTOFMEMORY);
+        ret = FALSE;
     }
-  }
-  if ((ret = InternetCrackUrlW(lpwszUrl, nLength, dwFlags, &UCW)))
-  {
-    ConvertUrlComponentValue(&lpUrlComponents->lpszHostName, &lpUrlComponents->dwHostNameLength,
-                             UCW.lpszHostName, UCW.dwHostNameLength, lpszUrl, lpwszUrl);
-    ConvertUrlComponentValue(&lpUrlComponents->lpszUserName, &lpUrlComponents->dwUserNameLength,
-                             UCW.lpszUserName, UCW.dwUserNameLength, lpszUrl, lpwszUrl);
-    ConvertUrlComponentValue(&lpUrlComponents->lpszPassword, &lpUrlComponents->dwPasswordLength,
-                             UCW.lpszPassword, UCW.dwPasswordLength, lpszUrl, lpwszUrl);
-    ConvertUrlComponentValue(&lpUrlComponents->lpszUrlPath, &lpUrlComponents->dwUrlPathLength,
-                             UCW.lpszUrlPath, UCW.dwUrlPathLength, lpszUrl, lpwszUrl);
-    ConvertUrlComponentValue(&lpUrlComponents->lpszScheme, &lpUrlComponents->dwSchemeLength,
-                             UCW.lpszScheme, UCW.dwSchemeLength, lpszUrl, lpwszUrl);
-    ConvertUrlComponentValue(&lpUrlComponents->lpszExtraInfo, &lpUrlComponents->dwExtraInfoLength,
-                             UCW.lpszExtraInfo, UCW.dwExtraInfoLength, lpszUrl, lpwszUrl);
-
-    lpUrlComponents->nScheme = UCW.nScheme;
-    lpUrlComponents->nPort = UCW.nPort;
-
-    TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_a(lpszUrl),
-          debugstr_an(lpUrlComponents->lpszScheme, lpUrlComponents->dwSchemeLength),
-          debugstr_an(lpUrlComponents->lpszHostName, lpUrlComponents->dwHostNameLength),
-          debugstr_an(lpUrlComponents->lpszUrlPath, lpUrlComponents->dwUrlPathLength),
-          debugstr_an(lpUrlComponents->lpszExtraInfo, lpUrlComponents->dwExtraInfoLength));
-  }
-  heap_free(lpwszUrl);
-  heap_free(hostname);
-  heap_free(username);
-  heap_free(password);
-  heap_free(path);
-  heap_free(scheme);
-  heap_free(extra);
-  return ret;
+
+    if (ret && (ret = InternetCrackUrlW(url_w, url_length, flags, &comp))) {
+        ret_comp->nScheme = comp.nScheme;
+        ret_comp->nPort = comp.nPort;
+
+        ret = set_url_component_WtoA(comp.lpszHostName, comp.dwHostNameLength, url_w,
+                                     &ret_comp->lpszHostName, &ret_comp->dwHostNameLength, url)
+            && set_url_component_WtoA(comp.lpszUserName, comp.dwUserNameLength, url_w,
+                                      &ret_comp->lpszUserName, &ret_comp->dwUserNameLength, url)
+            && set_url_component_WtoA(comp.lpszPassword, comp.dwPasswordLength, url_w,
+                                      &ret_comp->lpszPassword, &ret_comp->dwPasswordLength, url)
+            && set_url_component_WtoA(comp.lpszUrlPath, comp.dwUrlPathLength, url_w,
+                                      &ret_comp->lpszUrlPath, &ret_comp->dwUrlPathLength, url)
+            && set_url_component_WtoA(comp.lpszScheme, comp.dwSchemeLength, url_w,
+                                      &ret_comp->lpszScheme, &ret_comp->dwSchemeLength, url)
+            && set_url_component_WtoA(comp.lpszExtraInfo, comp.dwExtraInfoLength, url_w,
+                                      &ret_comp->lpszExtraInfo, &ret_comp->dwExtraInfoLength, url);
+
+        if(ret)
+            TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_a(url),
+                  debugstr_an(ret_comp->lpszScheme, ret_comp->dwSchemeLength),
+                  debugstr_an(ret_comp->lpszHostName, ret_comp->dwHostNameLength),
+                  debugstr_an(ret_comp->lpszUrlPath, ret_comp->dwUrlPathLength),
+                  debugstr_an(ret_comp->lpszExtraInfo, ret_comp->dwExtraInfoLength));
+    }
+
+    heap_free(host);
+    heap_free(user);
+    heap_free(pass);
+    heap_free(path);
+    heap_free(scheme);
+    heap_free(extra);
+    heap_free(url_w);
+    return ret;
 }
 
 static const WCHAR url_schemes[][7] =
@@ -1595,49 +1633,6 @@ static INTERNET_SCHEME GetInternetSchemeW(LPCWSTR lpszScheme, DWORD nMaxCmp)
     return INTERNET_SCHEME_UNKNOWN;
 }
 
-/***********************************************************************
- *           SetUrlComponentValueW (Internal)
- *
- * Helper function for InternetCrackUrlW
- *
- * PARAMS
- *     lppszComponent [O] Holds the returned string
- *     dwComponentLen [I] Holds the size of lppszComponent
- *                    [O] Holds the length of the string in lppszComponent without '\0'
- *     lpszStart      [I] Holds the string to copy from
- *     len            [I] Holds the length of lpszStart without '\0'
- *
- * RETURNS
- *    TRUE on success
- *    FALSE on failure
- *
- */
-static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen, LPCWSTR lpszStart, DWORD len)
-{
-    TRACE("%s (%d)\n", debugstr_wn(lpszStart,len), len);
-
-    if ( (*dwComponentLen == 0) && (*lppszComponent == NULL) )
-        return FALSE;
-
-    if (*dwComponentLen != 0 || *lppszComponent == NULL)
-    {
-        if (*lppszComponent == NULL)
-        {
-            *lppszComponent = (LPWSTR)lpszStart;
-            *dwComponentLen = len;
-        }
-        else
-        {
-            DWORD ncpylen = min((*dwComponentLen)-1, len);
-            memcpy(*lppszComponent, lpszStart, ncpylen*sizeof(WCHAR));
-            (*lppszComponent)[ncpylen] = '\0';
-            *dwComponentLen = ncpylen;
-        }
-    }
-
-    return TRUE;
-}
-
 /***********************************************************************
  *           InternetCrackUrlW   (WININET.@)
  *
@@ -1647,8 +1642,7 @@ static BOOL SetUrlComponentValueW(LPWSTR* lppszComponent, LPDWORD dwComponentLen
  *    TRUE on success
  *    FALSE on failure
  */
-BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWORD dwFlags,
-                              LPURL_COMPONENTSW lpUC)
+BOOL WINAPI InternetCrackUrlW(const WCHAR *lpszUrl, DWORD dwUrlLength, DWORD dwFlags, URL_COMPONENTSW *lpUC)
 {
   /*
    * RFC 1808
@@ -1657,46 +1651,51 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
    */
     LPCWSTR lpszParam    = NULL;
     BOOL  found_colon = FALSE;
-    LPCWSTR lpszap, lpszUrl = lpszUrl_orig;
+    LPCWSTR lpszap;
     LPCWSTR lpszcp = NULL, lpszNetLoc;
-    LPWSTR  lpszUrl_decode = NULL;
-    DWORD dwUrlLength = dwUrlLength_orig;
 
     TRACE("(%s %u %x %p)\n",
           lpszUrl ? debugstr_wn(lpszUrl, dwUrlLength ? dwUrlLength : strlenW(lpszUrl)) : "(null)",
           dwUrlLength, dwFlags, lpUC);
 
-    if (!lpszUrl_orig || !*lpszUrl_orig || !lpUC)
+    if (!lpszUrl || !*lpszUrl || !lpUC)
     {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
     if (!dwUrlLength) dwUrlLength = strlenW(lpszUrl);
 
     if (dwFlags & ICU_DECODE)
     {
-        WCHAR *url_tmp;
+        WCHAR *url_tmp, *buffer;
         DWORD len = dwUrlLength + 1;
+        BOOL ret;
 
-        if (!(url_tmp = heap_alloc(len * sizeof(WCHAR))))
+        if (!(url_tmp = heap_strndupW(lpszUrl, dwUrlLength)))
         {
-            INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+            SetLastError(ERROR_OUTOFMEMORY);
             return FALSE;
         }
-        memcpy(url_tmp, lpszUrl_orig, dwUrlLength * sizeof(WCHAR));
-        url_tmp[dwUrlLength] = 0;
-        if (!(lpszUrl_decode = heap_alloc(len * sizeof(WCHAR))))
-        {
-            heap_free(url_tmp);
-            INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-            return FALSE;
-        }
-        if (InternetCanonicalizeUrlW(url_tmp, lpszUrl_decode, &len, ICU_DECODE | ICU_NO_ENCODE))
+
+        buffer = url_tmp;
+        ret = InternetCanonicalizeUrlW(url_tmp, buffer, &len, ICU_DECODE | ICU_NO_ENCODE);
+        if (!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
         {
-            dwUrlLength = len;
-            lpszUrl = lpszUrl_decode;
+            buffer = heap_alloc(len * sizeof(WCHAR));
+            if (!buffer)
+            {
+                SetLastError(ERROR_OUTOFMEMORY);
+                heap_free(url_tmp);
+                return FALSE;
+            }
+            ret = InternetCanonicalizeUrlW(url_tmp, buffer, &len, ICU_DECODE | ICU_NO_ENCODE);
         }
+        if (ret)
+            ret = InternetCrackUrlW(buffer, len, dwFlags & ~ICU_DECODE, lpUC);
+
+        if (buffer != url_tmp) heap_free(buffer);
         heap_free(url_tmp);
+        return ret;
     }
     lpszap = lpszUrl;
     
@@ -1734,14 +1733,15 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
     if(!lpszParam)
         lpszParam = memchrW(lpszap, '#', dwUrlLength - (lpszap - lpszUrl));
 
-    SetUrlComponentValueW(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
-                          lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0);
+    if(!set_url_component(&lpUC->lpszExtraInfo, &lpUC->dwExtraInfoLength,
+                          lpszParam, lpszParam ? dwUrlLength-(lpszParam-lpszUrl) : 0))
+        return FALSE;
 
 
     /* Get scheme first. */
     lpUC->nScheme = GetInternetSchemeW(lpszUrl, lpszcp - lpszUrl);
-    SetUrlComponentValueW(&lpUC->lpszScheme, &lpUC->dwSchemeLength,
-                               lpszUrl, lpszcp - lpszUrl);
+    if(!set_url_component(&lpUC->lpszScheme, &lpUC->dwSchemeLength, lpszUrl, lpszcp - lpszUrl))
+        return FALSE;
 
     /* Eat ':' in protocol. */
     lpszcp++;
@@ -1775,8 +1775,8 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
             if (lpszHost == NULL || lpszHost > lpszNetLoc)
             {
                 /* username and password not specified. */
-                SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
-                SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
+                set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
+                set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
             }
             else /* Parse out username and password */
             {
@@ -1791,14 +1791,14 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
                     lpszcp++;
                 }
 
-                SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength,
-                                      lpszUser, lpszPasswd - lpszUser);
+                if(!set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, lpszUser, lpszPasswd - lpszUser))
+                    return FALSE;
 
                 if (lpszPasswd != lpszHost)
                     lpszPasswd++;
-                SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
-                                      lpszPasswd == lpszHost ? NULL : lpszPasswd,
-                                      lpszHost - lpszPasswd);
+                if(!set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength,
+                                      lpszPasswd == lpszHost ? NULL : lpszPasswd, lpszHost - lpszPasswd))
+                    return FALSE;
 
                 lpszcp++; /* Advance to beginning of host */
             }
@@ -1812,8 +1812,8 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
                entire string up to the first '/' */
             if(lpUC->nScheme==INTERNET_SCHEME_RES)
             {
-                SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
-                                      lpszHost, lpszPort - lpszHost);
+                if(!set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, lpszHost, lpszPort - lpszHost))
+                    return FALSE;
                 lpszcp=lpszNetLoc;
             }
             else
@@ -1830,13 +1830,12 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
                 if(lpUC->nScheme==INTERNET_SCHEME_FILE && lpszPort <= lpszHost+1)
                 {
                     lpszcp=lpszHost;
-                    SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
-                                          NULL, 0);
+                    set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
                 }
                 else
                 {
-                    SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength,
-                                          lpszHost, lpszPort - lpszHost);
+                    if(!set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, lpszHost, lpszPort - lpszHost))
+                        return FALSE;
                     if (lpszPort != lpszNetLoc)
                         lpUC->nPort = atoiW(++lpszPort);
                     else switch (lpUC->nScheme)
@@ -1862,9 +1861,9 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
     }
     else
     {
-        SetUrlComponentValueW(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
-        SetUrlComponentValueW(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
-        SetUrlComponentValueW(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
+        set_url_component(&lpUC->lpszUserName, &lpUC->dwUserNameLength, NULL, 0);
+        set_url_component(&lpUC->lpszPassword, &lpUC->dwPasswordLength, NULL, 0);
+        set_url_component(&lpUC->lpszHostName, &lpUC->dwHostNameLength, NULL, 0);
     }
 
     /* Here lpszcp points to:
@@ -1899,7 +1898,7 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
             if (*lpszcp == '/')
             {
                 len = MAX_PATH;
-                PathCreateFromUrlW(lpszUrl_orig, tmppath, &len, 0);
+                PathCreateFromUrlW(lpszUrl, tmppath, &len, 0);
             }
             else
             {
@@ -1926,18 +1925,15 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
                     ++len;
                 }
             }
-            SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
-                                       tmppath, len);
+            if(!set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, tmppath, len))
+                return FALSE;
         }
-        else
-            SetUrlComponentValueW(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength,
-                                       lpszcp, len);
+        else if(!set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, lpszcp, len))
+            return FALSE;
     }
     else
     {
-        if (lpUC->lpszUrlPath && (lpUC->dwUrlPathLength > 0))
-            lpUC->lpszUrlPath[0] = 0;
-        lpUC->dwUrlPathLength = 0;
+        set_url_component(&lpUC->lpszUrlPath, &lpUC->dwUrlPathLength, lpszcp, 0);
     }
 
     TRACE("%s: scheme(%s) host(%s) path(%s) extra(%s)\n", debugstr_wn(lpszUrl,dwUrlLength),
@@ -1946,7 +1942,6 @@ BOOL WINAPI InternetCrackUrlW(LPCWSTR lpszUrl_orig, DWORD dwUrlLength_orig, DWOR
              debugstr_wn(lpUC->lpszUrlPath,lpUC->dwUrlPathLength),
              debugstr_wn(lpUC->lpszExtraInfo,lpUC->dwExtraInfoLength));
 
-    heap_free( lpszUrl_decode );
     return TRUE;
 }
 
@@ -2008,7 +2003,7 @@ BOOL WINAPI InternetCanonicalizeUrlA(LPCSTR lpszUrl, LPSTR lpszBuffer,
 {
     HRESULT hr;
 
-    TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_a(lpszUrl), lpszBuffer,
+    TRACE("(%s, %p, %p, 0x%08x) buffer length: %d\n", debugstr_a(lpszUrl), lpszBuffer,
         lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
 
     dwFlags = convert_url_canonicalization_flags(dwFlags);
@@ -2034,7 +2029,7 @@ BOOL WINAPI InternetCanonicalizeUrlW(LPCWSTR lpszUrl, LPWSTR lpszBuffer,
 {
     HRESULT hr;
 
-    TRACE("(%s, %p, %p, 0x%08x) bufferlength: %d\n", debugstr_w(lpszUrl), lpszBuffer,
+    TRACE("(%s, %p, %p, 0x%08x) buffer length: %d\n", debugstr_w(lpszUrl), lpszBuffer,
           lpdwBufferLength, dwFlags, lpdwBufferLength ? *lpdwBufferLength : -1);
 
     dwFlags = convert_url_canonicalization_flags(dwFlags);
@@ -2191,8 +2186,11 @@ BOOL WINAPI InternetReadFile(HINTERNET hFile, LPVOID lpBuffer,
         return FALSE;
     }
 
-    if(hdr->vtbl->ReadFile)
-        res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead);
+    if(hdr->vtbl->ReadFile) {
+        res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead, 0, 0);
+        if(res == ERROR_IO_PENDING)
+            *pdwNumOfBytesRead = 0;
+    }
 
     WININET_Release(hdr);
 
@@ -2250,8 +2248,8 @@ BOOL WINAPI InternetReadFileExA(HINTERNET hFile, LPINTERNET_BUFFERSA lpBuffersOu
         return FALSE;
     }
 
-    if(hdr->vtbl->ReadFileEx)
-        res = hdr->vtbl->ReadFileEx(hdr, lpBuffersOut->lpvBuffer, lpBuffersOut->dwBufferLength,
+    if(hdr->vtbl->ReadFile)
+        res = hdr->vtbl->ReadFile(hdr, lpBuffersOut->lpvBuffer, lpBuffersOut->dwBufferLength,
                 &lpBuffersOut->dwBufferLength, dwFlags, dwContext);
 
     WININET_Release(hdr);
@@ -2277,7 +2275,7 @@ BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
 
     TRACE("(%p %p 0x%x 0x%lx)\n", hFile, lpBuffer, dwFlags, dwContext);
 
-    if (lpBuffer->dwStructSize != sizeof(*lpBuffer)) {
+    if (!lpBuffer || lpBuffer->dwStructSize != sizeof(*lpBuffer)) {
         SetLastError(ERROR_INVALID_PARAMETER);
         return FALSE;
     }
@@ -2288,8 +2286,8 @@ BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
         return FALSE;
     }
 
-    if(hdr->vtbl->ReadFileEx)
-        res = hdr->vtbl->ReadFileEx(hdr, lpBuffer->lpvBuffer, lpBuffer->dwBufferLength, &lpBuffer->dwBufferLength,
+    if(hdr->vtbl->ReadFile)
+        res = hdr->vtbl->ReadFile(hdr, lpBuffer->lpvBuffer, lpBuffer->dwBufferLength, &lpBuffer->dwBufferLength,
                 dwFlags, dwContext);
 
     WININET_Release(hdr);
@@ -2302,6 +2300,40 @@ BOOL WINAPI InternetReadFileExW(HINTERNET hFile, LPINTERNET_BUFFERSW lpBuffer,
     return res == ERROR_SUCCESS;
 }
 
+static WCHAR *get_proxy_autoconfig_url(void)
+{
+#if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+
+    CFDictionaryRef settings = CFNetworkCopySystemProxySettings();
+    WCHAR *ret = NULL;
+    SIZE_T len;
+    const void *ref;
+
+    if (!settings) return NULL;
+
+    if (!(ref = CFDictionaryGetValue( settings, kCFNetworkProxiesProxyAutoConfigURLString )))
+    {
+        CFRelease( settings );
+        return NULL;
+    }
+    len = CFStringGetLength( ref );
+    if (len)
+        ret = heap_alloc( (len+1) * sizeof(WCHAR) );
+    if (ret)
+    {
+        CFStringGetCharacters( ref, CFRangeMake(0, len), ret );
+        ret[len] = 0;
+    }
+    TRACE( "returning %s\n", debugstr_w(ret) );
+    CFRelease( settings );
+    return ret;
+#else
+    static int once;
+    if (!once++) FIXME( "no support on this platform\n" );
+    return NULL;
+#endif
+}
+
 static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL unicode)
 {
     /* FIXME: This function currently handles more options than it should. Options requiring
@@ -2385,6 +2417,7 @@ static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL u
     }
 
     case INTERNET_OPTION_PER_CONNECTION_OPTION: {
+        WCHAR *url;
         INTERNET_PER_CONN_OPTION_LISTW *con = buffer;
         INTERNET_PER_CONN_OPTION_LISTA *conA = buffer;
         DWORD res = ERROR_SUCCESS, i;
@@ -2395,13 +2428,19 @@ static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL u
         if((ret = INTERNET_LoadProxySettings(&pi)))
             return ret;
 
+#ifdef __REACTOS__
+        WARN("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
+#else
         FIXME("INTERNET_OPTION_PER_CONNECTION_OPTION stub\n");
+#endif
 
         if (*size < sizeof(INTERNET_PER_CONN_OPTION_LISTW)) {
             FreeProxyInfo(&pi);
             return ERROR_INSUFFICIENT_BUFFER;
         }
 
+        url = get_proxy_autoconfig_url();
+
         for (i = 0; i < con->dwOptionCount; i++) {
             INTERNET_PER_CONN_OPTIONW *optionW = con->pOptions + i;
             INTERNET_PER_CONN_OPTIONA *optionA = conA->pOptions + i;
@@ -2412,6 +2451,9 @@ static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL u
                     optionW->Value.dwValue = PROXY_TYPE_PROXY;
                 else
                     optionW->Value.dwValue = PROXY_TYPE_DIRECT;
+                if (url)
+                    /* native includes PROXY_TYPE_DIRECT even if PROXY_TYPE_PROXY is set */
+                    optionW->Value.dwValue |= PROXY_TYPE_DIRECT|PROXY_TYPE_AUTO_PROXY_URL;
                 break;
 
             case INTERNET_PER_CONN_PROXY_SERVER:
@@ -2429,7 +2471,18 @@ static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL u
                 break;
 
             case INTERNET_PER_CONN_AUTOCONFIG_URL:
+                if (!url)
+                    optionW->Value.pszValue = NULL;
+                else if (unicode)
+                    optionW->Value.pszValue = heap_strdupW(url);
+                else
+                    optionA->Value.pszValue = heap_strdupWtoA(url);
+                break;
+
             case INTERNET_PER_CONN_AUTODISCOVERY_FLAGS:
+                optionW->Value.dwValue = AUTO_PROXY_FLAG_ALWAYS_DETECT;
+                break;
+
             case INTERNET_PER_CONN_AUTOCONFIG_SECONDARY_URL:
             case INTERNET_PER_CONN_AUTOCONFIG_RELOAD_DELAY_MINS:
             case INTERNET_PER_CONN_AUTOCONFIG_LAST_DETECT_TIME:
@@ -2438,12 +2491,19 @@ static DWORD query_global_option(DWORD option, void *buffer, DWORD *size, BOOL u
                 memset(&optionW->Value, 0, sizeof(optionW->Value));
                 break;
 
+#ifdef __REACTOS__
+            case INTERNET_PER_CONN_FLAGS_UI:
+                WARN("Unhandled dwOption %d\n", optionW->dwOption);
+                break;
+
+#endif
             default:
                 FIXME("Unknown dwOption %d\n", optionW->dwOption);
                 res = ERROR_INVALID_PARAMETER;
                 break;
             }
         }
+        heap_free(url);
         FreeProxyInfo(&pi);
 
         return res;
@@ -2572,6 +2632,10 @@ BOOL WINAPI InternetQueryOptionA(HINTERNET hInternet, DWORD dwOption,
 DWORD INET_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
 {
     switch(option) {
+    case INTERNET_OPTION_SETTINGS_CHANGED:
+        FIXME("INTERNETOPTION_SETTINGS_CHANGED semi-stub\n");
+        collect_connections(COLLECT_CONNECTIONS);
+        return ERROR_SUCCESS;
     case INTERNET_OPTION_CALLBACK:
         WARN("Not settable option %u\n", option);
         return ERROR_INTERNET_OPTION_NOT_SETTABLE;
@@ -2579,6 +2643,8 @@ DWORD INET_SetOption(object_header_t *hdr, DWORD option, void *buf, DWORD size)
     case INTERNET_OPTION_MAX_CONNS_PER_1_0_SERVER:
         WARN("Called on global option %u\n", option);
         return ERROR_INTERNET_INVALID_OPERATION;
+    case INTERNET_OPTION_REFRESH:
+        return ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
     }
 
     return ERROR_INTERNET_INVALID_OPTION;
@@ -2624,13 +2690,17 @@ static DWORD set_global_option(DWORD option, void *buf, DWORD size)
         connect_timeout = *(ULONG*)buf;
         return ERROR_SUCCESS;
 
-    case INTERNET_OPTION_SETTINGS_CHANGED:
-        FIXME("INTERNETOPTION_SETTINGS_CHANGED semi-stub\n");
-        collect_connections(COLLECT_CONNECTIONS);
+    case INTERNET_OPTION_SUPPRESS_BEHAVIOR:
+        FIXME("INTERNET_OPTION_SUPPRESS_BEHAVIOR stub\n");
+
+        if(size != sizeof(ULONG))
+            return ERROR_INTERNET_BAD_OPTION_LENGTH;
+
+        FIXME("%08x\n", *(ULONG*)buf);
         return ERROR_SUCCESS;
     }
 
-    return ERROR_INTERNET_INVALID_OPTION;
+    return INET_SetOption(NULL, option, buf, size);
 }
 
 /***********************************************************************
@@ -2764,7 +2834,8 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
         FIXME("Option INTERNET_OPTION_RESET_URLCACHE_SESSION: STUB\n");
         break;
     case INTERNET_OPTION_END_BROWSER_SESSION:
-        FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: STUB\n");
+        FIXME("Option INTERNET_OPTION_END_BROWSER_SESSION: semi-stub\n");
+        free_cookie();
         break;
     case INTERNET_OPTION_CONNECTED_STATE:
         FIXME("Option INTERNET_OPTION_CONNECTED_STATE: STUB\n");
@@ -2809,10 +2880,21 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
         FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n");
         break;
     case INTERNET_OPTION_HTTP_DECODING:
-        FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n");
-        SetLastError(ERROR_INTERNET_INVALID_OPTION);
-        ret = FALSE;
+    {
+        if (!lpwhh)
+        {
+            SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+            return FALSE;
+        }
+        if (!lpBuffer || dwBufferLength != sizeof(BOOL))
+        {
+            SetLastError(ERROR_INVALID_PARAMETER);
+            ret = FALSE;
+        }
+        else
+            lpwhh->decoding = *(BOOL *)lpBuffer;
         break;
+    }
     case INTERNET_OPTION_COOKIES_3RD_PARTY:
         FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n");
         SetLastError(ERROR_INTERNET_INVALID_OPTION);
@@ -2848,7 +2930,7 @@ BOOL WINAPI InternetSetOptionW(HINTERNET hInternet, DWORD dwOption,
         unsigned int i;
         proxyinfo_t pi;
 
-        INTERNET_LoadProxySettings(&pi);
+        if (INTERNET_LoadProxySettings(&pi)) return FALSE;
 
         for (i = 0; i < con->dwOptionCount; i++) {
             INTERNET_PER_CONN_OPTIONW *option = con->pOptions + i;
@@ -3272,13 +3354,12 @@ BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRe
   BOOL   rc = FALSE;
   static const CHAR ping[] = "ping -c 1 ";
   static const CHAR redirect[] = " >/dev/null 2>/dev/null";
-  CHAR *command = NULL;
-  WCHAR hostW[INTERNET_MAX_HOST_NAME_LENGTH];
-  DWORD len;
+  WCHAR *host;
+  DWORD len, host_len;
   INTERNET_PORT port;
   int status = -1;
 
-  FIXME("\n");
+  FIXME("(%s %x %x)\n", debugstr_w(lpszUrl), dwFlags, dwReserved);
 
   /*
    * Crack or set the Address
@@ -3297,34 +3378,42 @@ BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRe
   }
   else
   {
-     URL_COMPONENTSW components;
+     URL_COMPONENTSW components = {sizeof(components)};
 
-     ZeroMemory(&components,sizeof(URL_COMPONENTSW));
-     components.lpszHostName = (LPWSTR)hostW;
-     components.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
+     components.dwHostNameLength = 1;
 
      if (!InternetCrackUrlW(lpszUrl,0,0,&components))
        goto End;
 
-     TRACE("host name : %s\n",debugstr_w(components.lpszHostName));
+     host = components.lpszHostName;
+     host_len = components.dwHostNameLength;
      port = components.nPort;
-     TRACE("port: %d\n", port);
+     TRACE("host name: %s port: %d\n",debugstr_wn(host, host_len), port);
   }
 
   if (dwFlags & FLAG_ICC_FORCE_CONNECTION)
   {
       struct sockaddr_storage saddr;
-      socklen_t sa_len = sizeof(saddr);
+      int sa_len = sizeof(saddr);
+      WCHAR *host_z;
       int fd;
+      BOOL b;
+
+      host_z = heap_strndupW(host, host_len);
+      if (!host_z)
+          return FALSE;
 
-      if (!GetAddress(hostW, port, (struct sockaddr *)&saddr, &sa_len))
+      b = GetAddress(host_z, port, (struct sockaddr *)&saddr, &sa_len, NULL);
+      heap_free(host_z);
+      if(!b)
           goto End;
+      init_winsock();
       fd = socket(saddr.ss_family, SOCK_STREAM, 0);
       if (fd != -1)
       {
           if (connect(fd, (struct sockaddr *)&saddr, sa_len) == 0)
               rc = TRUE;
-          close(fd);
+          closesocket(fd);
       }
   }
   else
@@ -3332,15 +3421,18 @@ BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRe
       /*
        * Build our ping command
        */
-      len = WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, NULL, 0, NULL, NULL);
-      command = heap_alloc(strlen(ping)+len+strlen(redirect));
-      strcpy(command,ping);
-      WideCharToMultiByte(CP_UNIXCP, 0, hostW, -1, command+strlen(ping), len, NULL, NULL);
-      strcat(command,redirect);
+      char *command;
+
+      len = WideCharToMultiByte(CP_UNIXCP, 0, host, host_len, NULL, 0, NULL, NULL);
+      command = heap_alloc(strlen(ping)+len+strlen(redirect)+1);
+      strcpy(command, ping);
+      WideCharToMultiByte(CP_UNIXCP, 0, host, host_len, command+sizeof(ping)-1, len, NULL, NULL);
+      strcpy(command+sizeof(ping)-1+len, redirect);
 
       TRACE("Ping command is : %s\n",command);
 
       status = system(command);
+      heap_free( command );
 
       TRACE("Ping returned a code of %i\n",status);
 
@@ -3350,7 +3442,6 @@ BOOL WINAPI InternetCheckConnectionW( LPCWSTR lpszUrl, DWORD dwFlags, DWORD dwRe
   }
 
 End:
-  heap_free( command );
   if (rc == FALSE)
     INTERNET_SetLastError(ERROR_NOT_CONNECTED);
 
@@ -3397,40 +3488,40 @@ BOOL WINAPI InternetCheckConnectionA(LPCSTR lpszUrl, DWORD dwFlags, DWORD dwRese
 static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
     LPCWSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
 {
-    URL_COMPONENTSW urlComponents;
-    WCHAR protocol[INTERNET_MAX_SCHEME_LENGTH];
-    WCHAR hostName[INTERNET_MAX_HOST_NAME_LENGTH];
-    WCHAR userName[INTERNET_MAX_USER_NAME_LENGTH];
-    WCHAR password[INTERNET_MAX_PASSWORD_LENGTH];
-    WCHAR path[INTERNET_MAX_PATH_LENGTH];
-    WCHAR extra[1024];
+    URL_COMPONENTSW urlComponents = { sizeof(urlComponents) };
+    WCHAR *host, *user = NULL, *pass = NULL, *path;
     HINTERNET client = NULL, client1 = NULL;
     DWORD res;
     
     TRACE("(%p, %s, %s, %08x, %08x, %08lx)\n", hIC, debugstr_w(lpszUrl), debugstr_w(lpszHeaders),
          dwHeadersLength, dwFlags, dwContext);
     
-    urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
-    urlComponents.lpszScheme = protocol;
-    urlComponents.dwSchemeLength = INTERNET_MAX_SCHEME_LENGTH;
-    urlComponents.lpszHostName = hostName;
-    urlComponents.dwHostNameLength = INTERNET_MAX_HOST_NAME_LENGTH;
-    urlComponents.lpszUserName = userName;
-    urlComponents.dwUserNameLength = INTERNET_MAX_USER_NAME_LENGTH;
-    urlComponents.lpszPassword = password;
-    urlComponents.dwPasswordLength = INTERNET_MAX_PASSWORD_LENGTH;
-    urlComponents.lpszUrlPath = path;
-    urlComponents.dwUrlPathLength = INTERNET_MAX_PATH_LENGTH;
-    urlComponents.lpszExtraInfo = extra;
-    urlComponents.dwExtraInfoLength = 1024;
+    urlComponents.dwHostNameLength = 1;
+    urlComponents.dwUserNameLength = 1;
+    urlComponents.dwPasswordLength = 1;
+    urlComponents.dwUrlPathLength = 1;
+    urlComponents.dwExtraInfoLength = 1;
     if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
        return NULL;
+
+    if ((urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS) &&
+        urlComponents.dwExtraInfoLength)
+    {
+        assert(urlComponents.lpszUrlPath + urlComponents.dwUrlPathLength == urlComponents.lpszExtraInfo);
+        urlComponents.dwUrlPathLength += urlComponents.dwExtraInfoLength;
+    }
+
+    host = heap_strndupW(urlComponents.lpszHostName, urlComponents.dwHostNameLength);
+    path = heap_strndupW(urlComponents.lpszUrlPath, urlComponents.dwUrlPathLength);
+    if(urlComponents.dwUserNameLength)
+        user = heap_strndupW(urlComponents.lpszUserName, urlComponents.dwUserNameLength);
+    if(urlComponents.dwPasswordLength)
+        pass = heap_strndupW(urlComponents.lpszPassword, urlComponents.dwPasswordLength);
+
     switch(urlComponents.nScheme) {
     case INTERNET_SCHEME_FTP:
-       if(urlComponents.nPort == 0)
-           urlComponents.nPort = INTERNET_DEFAULT_FTP_PORT;
-       client = FTP_Connect(hIC, hostName, urlComponents.nPort,
-                            userName, password, dwFlags, dwContext, INET_OPENURL);
+       client = FTP_Connect(hIC, host, urlComponents.nPort,
+                            user, pass, dwFlags, dwContext, INET_OPENURL);
        if(client == NULL)
            break;
        client1 = FtpOpenFileW(client, path, GENERIC_READ, dwFlags, dwContext);
@@ -3444,39 +3535,18 @@ static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
     case INTERNET_SCHEME_HTTPS: {
        static const WCHAR szStars[] = { '*','/','*', 0 };
        LPCWSTR accept[2] = { szStars, NULL };
-       if(urlComponents.nPort == 0) {
-           if(urlComponents.nScheme == INTERNET_SCHEME_HTTP)
-               urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
-           else
-               urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
-       }
+
         if (urlComponents.nScheme == INTERNET_SCHEME_HTTPS) dwFlags |= INTERNET_FLAG_SECURE;
 
         /* FIXME: should use pointers, not handles, as handles are not thread-safe */
-       res = HTTP_Connect(hIC, hostName, urlComponents.nPort,
-                           userName, password, dwFlags, dwContext, INET_OPENURL, &client);
+       res = HTTP_Connect(hIC, host, urlComponents.nPort,
+                           user, pass, dwFlags, dwContext, INET_OPENURL, &client);
         if(res != ERROR_SUCCESS) {
             INTERNET_SetLastError(res);
            break;
         }
 
-       if (urlComponents.dwExtraInfoLength) {
-               WCHAR *path_extra;
-               DWORD len = urlComponents.dwUrlPathLength + urlComponents.dwExtraInfoLength + 1;
-
-               if (!(path_extra = heap_alloc(len * sizeof(WCHAR))))
-               {
-                       InternetCloseHandle(client);
-                       break;
-               }
-               strcpyW(path_extra, urlComponents.lpszUrlPath);
-               strcatW(path_extra, urlComponents.lpszExtraInfo);
-               client1 = HttpOpenRequestW(client, NULL, path_extra, NULL, NULL, accept, dwFlags, dwContext);
-               heap_free(path_extra);
-       }
-       else
-               client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
-
+        client1 = HttpOpenRequestW(client, NULL, path, NULL, NULL, accept, dwFlags, dwContext);
        if(client1 == NULL) {
            InternetCloseHandle(client);
            break;
@@ -3498,7 +3568,11 @@ static HINTERNET INTERNET_InternetOpenUrlW(appinfo_t *hIC, LPCWSTR lpszUrl,
     }
 
     TRACE(" %p <--\n", client1);
-    
+
+    heap_free(host);
+    heap_free(path);
+    heap_free(user);
+    heap_free(pass);
     return client1;
 }
 
@@ -3592,9 +3666,8 @@ HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
     LPCSTR lpszHeaders, DWORD dwHeadersLength, DWORD dwFlags, DWORD_PTR dwContext)
 {
     HINTERNET rc = NULL;
-    DWORD lenHeaders = 0;
     LPWSTR szUrl = NULL;
-    LPWSTR szHeaders = NULL;
+    WCHAR *headers = NULL;
 
     TRACE("\n");
 
@@ -3605,20 +3678,17 @@ HINTERNET WINAPI InternetOpenUrlA(HINTERNET hInternet, LPCSTR lpszUrl,
     }
 
     if(lpszHeaders) {
-        lenHeaders = MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, NULL, 0 );
-        szHeaders = heap_alloc(lenHeaders*sizeof(WCHAR));
-        if(!szHeaders) {
+        headers = heap_strndupAtoW(lpszHeaders, dwHeadersLength, &dwHeadersLength);
+        if(!headers) {
             heap_free(szUrl);
             return NULL;
         }
-        MultiByteToWideChar(CP_ACP, 0, lpszHeaders, dwHeadersLength, szHeaders, lenHeaders);
     }
     
-    rc = InternetOpenUrlW(hInternet, szUrl, szHeaders,
-        lenHeaders, dwFlags, dwContext);
+    rc = InternetOpenUrlW(hInternet, szUrl, headers, dwHeadersLength, dwFlags, dwContext);
 
     heap_free(szUrl);
-    heap_free(szHeaders);
+    heap_free(headers);
     return rc;
 }
 
@@ -3759,72 +3829,6 @@ LPSTR INTERNET_GetResponseBuffer(void)
     return lpwite->response;
 }
 
-/***********************************************************************
- *           INTERNET_GetNextLine  (internal)
- *
- * Parse next line in directory string listing
- *
- * RETURNS
- *   Pointer to beginning of next line
- *   NULL on failure
- *
- */
-
-LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen)
-{
-    // ReactOS: use select instead of poll
-    fd_set infd;
-    struct timeval tv;
-    BOOL bSuccess = FALSE;
-    INT nRecv = 0;
-    LPSTR lpszBuffer = INTERNET_GetResponseBuffer();
-
-    TRACE("\n");
-
-    FD_ZERO(&infd);
-    FD_SET(nSocket,&infd);
-    tv.tv_sec = RESPONSE_TIMEOUT;
-    tv.tv_usec = 0;
-
-    while (nRecv < MAX_REPLY_LEN)
-    {
-        if (select(0, &infd, NULL, NULL, &tv) > 0)
-        {
-            if (recv(nSocket, &lpszBuffer[nRecv], 1, 0) <= 0)
-            {
-                INTERNET_SetLastError(ERROR_FTP_TRANSFER_IN_PROGRESS);
-                goto lend;
-            }
-
-            if (lpszBuffer[nRecv] == '\n')
-           {
-               bSuccess = TRUE;
-                break;
-           }
-            if (lpszBuffer[nRecv] != '\r')
-                nRecv++;
-        }
-       else
-       {
-            INTERNET_SetLastError(ERROR_INTERNET_TIMEOUT);
-            goto lend;
-        }
-    }
-
-lend:
-    if (bSuccess)
-    {
-        lpszBuffer[nRecv] = '\0';
-       *dwLen = nRecv - 1;
-        TRACE(":%d %s\n", nRecv, lpszBuffer);
-        return lpszBuffer;
-    }
-    else
-    {
-        return NULL;
-    }
-}
-
 /**********************************************************
  *     InternetQueryDataAvailable (WININET.@)
  *
@@ -3904,6 +3908,7 @@ void req_file_release(req_file_t *req_file)
     if(req_file->file_handle && req_file->file_handle != INVALID_HANDLE_VALUE)
         CloseHandle(req_file->file_handle);
     heap_free(req_file->file_name);
+    heap_free(req_file->url);
     heap_free(req_file);
 }
 
@@ -4151,8 +4156,7 @@ static BOOL calc_url_length(LPURL_COMPONENTSW lpUrlComponents,
         {
             char szPort[MAX_WORD_DIGITS+1];
 
-            sprintf(szPort, "%d", lpUrlComponents->nPort);
-            *lpdwUrlLength += strlen(szPort);
+            *lpdwUrlLength += sprintf(szPort, "%d", lpUrlComponents->nPort);
             *lpdwUrlLength += strlen(":");
         }
 
@@ -4395,14 +4399,9 @@ BOOL WINAPI InternetCreateUrlW(LPURL_COMPONENTSW lpUrlComponents, DWORD dwFlags,
 
         if (!url_uses_default_port(nScheme, lpUrlComponents->nPort))
         {
-            WCHAR szPort[MAX_WORD_DIGITS+1];
-
-            sprintfW(szPort, fmtW, lpUrlComponents->nPort);
             *lpszUrl = ':';
             lpszUrl++;
-            dwLen = strlenW(szPort);
-            memcpy(lpszUrl, szPort, dwLen * sizeof(WCHAR));
-            lpszUrl += dwLen;
+            lpszUrl += sprintfW(lpszUrl, fmtW, lpUrlComponents->nPort);
         }
 
         /* add slash between hostname and path if necessary */
@@ -4501,38 +4500,36 @@ BOOL WINAPI InternetGetSecurityInfoByURLA(LPSTR lpszURL, PCCERT_CHAIN_CONTEXT *p
  */
 BOOL WINAPI InternetGetSecurityInfoByURLW(LPCWSTR lpszURL, PCCERT_CHAIN_CONTEXT *ppCertChain, DWORD *pdwSecureFlags)
 {
-    WCHAR hostname[INTERNET_MAX_HOST_NAME_LENGTH];
     URL_COMPONENTSW url = {sizeof(url)};
     server_t *server;
-    BOOL res = FALSE;
+    BOOL res;
 
     TRACE("(%s %p %p)\n", debugstr_w(lpszURL), ppCertChain, pdwSecureFlags);
 
-    url.lpszHostName = hostname;
-    url.dwHostNameLength = sizeof(hostname)/sizeof(WCHAR);
+    if (!ppCertChain && !pdwSecureFlags) {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
 
+    url.dwHostNameLength = 1;
     res = InternetCrackUrlW(lpszURL, 0, 0, &url);
     if(!res || url.nScheme != INTERNET_SCHEME_HTTPS) {
         SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
         return FALSE;
     }
 
-    server = get_server(hostname, url.nPort, TRUE, FALSE);
+    server = get_server(substr(url.lpszHostName, url.dwHostNameLength), url.nPort, TRUE, FALSE);
     if(!server) {
         SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
         return FALSE;
     }
 
     if(server->cert_chain) {
-        const CERT_CHAIN_CONTEXT *chain_dup;
-
-        chain_dup = CertDuplicateCertificateChain(server->cert_chain);
-        if(chain_dup) {
-            *ppCertChain = chain_dup;
+        if(pdwSecureFlags)
             *pdwSecureFlags = server->security_flags & _SECURITY_ERROR_FLAGS_MASK;
-        }else {
+
+        if(ppCertChain && !(*ppCertChain = CertDuplicateCertificateChain(server->cert_chain)))
             res = FALSE;
-        }
     }else {
         SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
         res = FALSE;