qedit: Convert dll registration to the IRegistrar mechanism.
[wine] / dlls / wininet / http.c
index f874920..9a49a94 100644 (file)
@@ -73,6 +73,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(wininet);
 
 static const WCHAR g_szHttp1_0[] = {'H','T','T','P','/','1','.','0',0};
 static const WCHAR g_szHttp1_1[] = {'H','T','T','P','/','1','.','1',0};
+static const WCHAR szOK[] = {'O','K',0};
+static const WCHAR szDefaultHeader[] = {'H','T','T','P','/','1','.','0',' ','2','0','0',' ','O','K',0};
 static const WCHAR hostW[] = { 'H','o','s','t',0 };
 static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
 static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
@@ -177,17 +179,52 @@ struct gzip_stream_t {
     BOOL end_of_data;
 };
 
-static BOOL HTTP_OpenConnection(http_request_t *req);
+typedef struct _basicAuthorizationData
+{
+    struct list entry;
+
+    LPWSTR lpszwHost;
+    LPWSTR lpszwRealm;
+    LPSTR  lpszAuthorization;
+    UINT   AuthorizationLen;
+} basicAuthorizationData;
+
+typedef struct _authorizationData
+{
+    struct list entry;
+
+    LPWSTR host;
+    LPWSTR scheme;
+    LPWSTR domain;
+    UINT   domain_len;
+    LPWSTR user;
+    UINT   user_len;
+    LPWSTR password;
+    UINT   password_len;
+} authorizationData;
+
+static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache);
+static struct list authorizationCache = LIST_INIT(authorizationCache);
+
+static CRITICAL_SECTION authcache_cs;
+static CRITICAL_SECTION_DEBUG critsect_debug =
+{
+    0, 0, &authcache_cs,
+    { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") }
+};
+static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
+
+static DWORD HTTP_OpenConnection(http_request_t *req);
 static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear);
-static BOOL HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
+static DWORD HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
 static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
-static BOOL HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr);
+static DWORD HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr);
 static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request);
 static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index);
 static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
-static BOOL HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD);
+static DWORD HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD);
 static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl);
-static BOOL HTTP_HandleRedirect(http_request_t *req, LPCWSTR lpszUrl);
 static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
 static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field);
 static void HTTP_DrainContent(http_request_t *req);
@@ -263,12 +300,12 @@ static DWORD set_content_length( http_request_t *lpwhr )
     DWORD size;
 
     size = sizeof(lpwhr->dwContentLength);
-    if (!HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
-                             &lpwhr->dwContentLength, &size, NULL))
+    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
+                            &lpwhr->dwContentLength, &size, NULL) != ERROR_SUCCESS)
         lpwhr->dwContentLength = ~0u;
 
     size = sizeof(encoding);
-    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) &&
+    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) == ERROR_SUCCESS &&
         !strcmpiW(encoding, szChunked))
     {
         lpwhr->dwContentLength = ~0u;
@@ -353,25 +390,6 @@ static void HTTP_FreeTokens(LPWSTR * token_array)
     HeapFree(GetProcessHeap(), 0, token_array);
 }
 
-/* **********************************************************************
- * 
- * Helper functions for the HttpSendRequest(Ex) functions
- * 
- */
-static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
-{
-    struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
-    http_request_t *lpwhr = (http_request_t*) workRequest->hdr;
-
-    TRACE("%p\n", lpwhr);
-
-    HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
-            req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
-            req->dwContentLength, req->bEndRequest);
-
-    HeapFree(GetProcessHeap(), 0, req->lpszHeader);
-}
-
 static void HTTP_FixURL(http_request_t *lpwhr)
 {
     static const WCHAR szSlash[] = { '/',0 };
@@ -496,11 +514,59 @@ static void HTTP_ProcessCookies( http_request_t *lpwhr )
     }
 }
 
-static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue )
+static void strip_spaces(LPWSTR start)
+{
+    LPWSTR str = start;
+    LPWSTR end;
+
+    while (*str == ' ' && *str != '\0')
+        str++;
+
+    if (str != start)
+        memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1));
+
+    end = start + strlenW(start) - 1;
+    while (end >= start && *end == ' ')
+    {
+        *end = '\0';
+        end--;
+    }
+}
+
+static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm )
 {
     static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
-    return !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) &&
+    static const WCHAR szRealm[] = {'r','e','a','l','m'}; /* Note: not nul-terminated */
+    BOOL is_basic;
+    is_basic = !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) &&
         ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]);
+    if (is_basic && pszRealm)
+    {
+        LPCWSTR token;
+        LPCWSTR ptr = &pszAuthValue[ARRAYSIZE(szBasic)];
+        LPCWSTR realm;
+        ptr++;
+        *pszRealm=NULL;
+        token = strchrW(ptr,'=');
+        if (!token)
+            return TRUE;
+        realm = ptr;
+        while (*realm == ' ' && *realm != '\0')
+            realm++;
+        if(!strncmpiW(realm, szRealm, ARRAYSIZE(szRealm)) &&
+            (realm[ARRAYSIZE(szRealm)] == ' ' || realm[ARRAYSIZE(szRealm)] == '='))
+        {
+            token++;
+            while (*token == ' ' && *token != '\0')
+                token++;
+            if (*token == '\0')
+                return TRUE;
+            *pszRealm = heap_strdupW(token);
+            strip_spaces(*pszRealm);
+        }
+    }
+
+    return is_basic;
 }
 
 static void destroy_authinfo( struct HttpAuthInfo *authinfo )
@@ -517,13 +583,167 @@ static void destroy_authinfo( struct HttpAuthInfo *authinfo )
     HeapFree(GetProcessHeap(), 0, authinfo);
 }
 
+static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data)
+{
+    basicAuthorizationData *ad;
+    UINT rc = 0;
+
+    TRACE("Looking for authorization for %s:%s\n",debugstr_w(host),debugstr_w(realm));
+
+    EnterCriticalSection(&authcache_cs);
+    LIST_FOR_EACH_ENTRY(ad, &basicAuthorizationCache, basicAuthorizationData, entry)
+    {
+        if (!strcmpiW(host,ad->lpszwHost) && !strcmpW(realm,ad->lpszwRealm))
+        {
+            TRACE("Authorization found in cache\n");
+            *auth_data = HeapAlloc(GetProcessHeap(),0,ad->AuthorizationLen);
+            memcpy(*auth_data,ad->lpszAuthorization,ad->AuthorizationLen);
+            rc = ad->AuthorizationLen;
+            break;
+        }
+    }
+    LeaveCriticalSection(&authcache_cs);
+    return rc;
+}
+
+static void cache_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR auth_data, UINT auth_data_len)
+{
+    struct list *cursor;
+    basicAuthorizationData* ad = NULL;
+
+    TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len));
+
+    EnterCriticalSection(&authcache_cs);
+    LIST_FOR_EACH(cursor, &basicAuthorizationCache)
+    {
+        basicAuthorizationData *check = LIST_ENTRY(cursor,basicAuthorizationData,entry);
+        if (!strcmpiW(host,check->lpszwHost) && !strcmpW(realm,check->lpszwRealm))
+        {
+            ad = check;
+            break;
+        }
+    }
+
+    if (ad)
+    {
+        TRACE("Found match in cache, replacing\n");
+        HeapFree(GetProcessHeap(),0,ad->lpszAuthorization);
+        ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len);
+        memcpy(ad->lpszAuthorization, auth_data, auth_data_len);
+        ad->AuthorizationLen = auth_data_len;
+    }
+    else
+    {
+        ad = HeapAlloc(GetProcessHeap(),0,sizeof(basicAuthorizationData));
+        ad->lpszwHost = heap_strdupW(host);
+        ad->lpszwRealm = heap_strdupW(realm);
+        ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len);
+        memcpy(ad->lpszAuthorization, auth_data, auth_data_len);
+        ad->AuthorizationLen = auth_data_len;
+        list_add_head(&basicAuthorizationCache,&ad->entry);
+        TRACE("authorization cached\n");
+    }
+    LeaveCriticalSection(&authcache_cs);
+}
+
+static BOOL retrieve_cached_authorization(LPWSTR host, LPWSTR scheme,
+        SEC_WINNT_AUTH_IDENTITY_W *nt_auth_identity)
+{
+    authorizationData *ad;
+
+    TRACE("Looking for authorization for %s:%s\n", debugstr_w(host), debugstr_w(scheme));
+
+    EnterCriticalSection(&authcache_cs);
+    LIST_FOR_EACH_ENTRY(ad, &authorizationCache, authorizationData, entry) {
+        if(!strcmpiW(host, ad->host) && !strcmpiW(scheme, ad->scheme)) {
+            TRACE("Authorization found in cache\n");
+
+            nt_auth_identity->User = heap_strdupW(ad->user);
+            nt_auth_identity->Password = heap_strdupW(ad->password);
+            nt_auth_identity->Domain = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*ad->domain_len);
+            if(!nt_auth_identity->User || !nt_auth_identity->Password ||
+                    (!nt_auth_identity->Domain && ad->domain_len)) {
+                HeapFree(GetProcessHeap(), 0, nt_auth_identity->User);
+                HeapFree(GetProcessHeap(), 0, nt_auth_identity->Password);
+                HeapFree(GetProcessHeap(), 0, nt_auth_identity->Domain);
+                break;
+            }
+
+            nt_auth_identity->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+            nt_auth_identity->UserLength = ad->user_len;
+            nt_auth_identity->PasswordLength = ad->password_len;
+            memcpy(nt_auth_identity->Domain, ad->domain, sizeof(WCHAR)*ad->domain_len);
+            nt_auth_identity->DomainLength = ad->domain_len;
+            LeaveCriticalSection(&authcache_cs);
+            return TRUE;
+        }
+    }
+    LeaveCriticalSection(&authcache_cs);
+
+    return FALSE;
+}
+
+static void cache_authorization(LPWSTR host, LPWSTR scheme,
+        SEC_WINNT_AUTH_IDENTITY_W *nt_auth_identity)
+{
+    authorizationData *ad;
+    BOOL found = FALSE;
+
+    TRACE("Caching authorization for %s:%s\n", debugstr_w(host), debugstr_w(scheme));
+
+    EnterCriticalSection(&authcache_cs);
+    LIST_FOR_EACH_ENTRY(ad, &authorizationCache, authorizationData, entry)
+        if(!strcmpiW(host, ad->host) && !strcmpiW(scheme, ad->scheme)) {
+            found = TRUE;
+            break;
+        }
+
+    if(found) {
+        HeapFree(GetProcessHeap(), 0, ad->user);
+        HeapFree(GetProcessHeap(), 0, ad->password);
+        HeapFree(GetProcessHeap(), 0, ad->domain);
+    } else {
+        ad = HeapAlloc(GetProcessHeap(), 0, sizeof(authorizationData));
+        if(!ad) {
+            LeaveCriticalSection(&authcache_cs);
+            return;
+        }
+
+        ad->host = heap_strdupW(host);
+        ad->scheme = heap_strdupW(scheme);
+        list_add_head(&authorizationCache, &ad->entry);
+    }
+
+    ad->user = heap_strndupW(nt_auth_identity->User, nt_auth_identity->UserLength);
+    ad->password = heap_strndupW(nt_auth_identity->Password, nt_auth_identity->PasswordLength);
+    ad->domain = heap_strndupW(nt_auth_identity->Domain, nt_auth_identity->DomainLength);
+    ad->user_len = nt_auth_identity->UserLength;
+    ad->password_len = nt_auth_identity->PasswordLength;
+    ad->domain_len = nt_auth_identity->DomainLength;
+
+    if(!ad->host || !ad->scheme || !ad->user || !ad->password
+            || (nt_auth_identity->Domain && !ad->domain)) {
+        HeapFree(GetProcessHeap(), 0, ad->host);
+        HeapFree(GetProcessHeap(), 0, ad->scheme);
+        HeapFree(GetProcessHeap(), 0, ad->user);
+        HeapFree(GetProcessHeap(), 0, ad->password);
+        HeapFree(GetProcessHeap(), 0, ad->domain);
+        list_remove(&ad->entry);
+        HeapFree(GetProcessHeap(), 0, ad);
+    }
+
+    LeaveCriticalSection(&authcache_cs);
+}
+
 static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
                                   struct HttpAuthInfo **ppAuthInfo,
-                                  LPWSTR domain_and_username, LPWSTR password )
+                                  LPWSTR domain_and_username, LPWSTR password,
+                                  LPWSTR host )
 {
     SECURITY_STATUS sec_status;
     struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
     BOOL first = FALSE;
+    LPWSTR szRealm = NULL;
 
     TRACE("%s\n", debugstr_w(pszAuthValue));
 
@@ -544,7 +764,7 @@ static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
         pAuthInfo->auth_data_len = 0;
         pAuthInfo->finished = FALSE;
 
-        if (is_basic_auth_value(pszAuthValue))
+        if (is_basic_auth_value(pszAuthValue,NULL))
         {
             static const WCHAR szBasic[] = {'B','a','s','i','c',0};
             pAuthInfo->scheme = heap_strdupW(szBasic);
@@ -589,7 +809,11 @@ static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
                 nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
                 nt_auth_identity.Password = password;
                 nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password);
+
+                cache_authorization(host, pAuthInfo->scheme, &nt_auth_identity);
             }
+            else if(retrieve_cached_authorization(host, pAuthInfo->scheme, &nt_auth_identity))
+                pAuthData = &nt_auth_identity;
             else
                 /* use default credentials */
                 pAuthData = NULL;
@@ -599,6 +823,13 @@ static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
                                                    pAuthData, NULL,
                                                    NULL, &pAuthInfo->cred,
                                                    &exp);
+
+            if(pAuthData && !domain_and_username) {
+                HeapFree(GetProcessHeap(), 0, nt_auth_identity.User);
+                HeapFree(GetProcessHeap(), 0, nt_auth_identity.Domain);
+                HeapFree(GetProcessHeap(), 0, nt_auth_identity.Password);
+            }
+
             if (sec_status == SEC_E_OK)
             {
                 PSecPkgInfoW sec_pkg_info;
@@ -631,33 +862,50 @@ static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
         return FALSE;
     }
 
-    if (is_basic_auth_value(pszAuthValue))
+    if (is_basic_auth_value(pszAuthValue,&szRealm))
     {
         int userlen;
         int passlen;
-        char *auth_data;
+        char *auth_data = NULL;
+        UINT auth_data_len = 0;
 
-        TRACE("basic authentication\n");
+        TRACE("basic authentication realm %s\n",debugstr_w(szRealm));
 
-        /* we don't cache credentials for basic authentication, so we can't
-         * retrieve them if the application didn't pass us any credentials */
-        if (!domain_and_username) return FALSE;
-
-        userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
-        passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL);
+        if (!domain_and_username)
+        {
+            if (host && szRealm)
+                auth_data_len = retrieve_cached_basic_authorization(host, szRealm,&auth_data);
+            if (auth_data_len == 0)
+            {
+                HeapFree(GetProcessHeap(),0,szRealm);
+                return FALSE;
+            }
+        }
+        else
+        {
+            userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
+            passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL);
 
-        /* length includes a nul terminator, which will be re-used for the ':' */
-        auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen);
-        if (!auth_data)
-            return FALSE;
+            /* length includes a nul terminator, which will be re-used for the ':' */
+            auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen);
+            if (!auth_data)
+            {
+                HeapFree(GetProcessHeap(),0,szRealm);
+                return FALSE;
+            }
 
-        WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL);
-        auth_data[userlen] = ':';
-        WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL);
+            WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL);
+            auth_data[userlen] = ':';
+            WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL);
+            auth_data_len = userlen + 1 + passlen;
+            if (host && szRealm)
+                cache_basic_authorization(host, szRealm, auth_data, auth_data_len);
+        }
 
         pAuthInfo->auth_data = auth_data;
-        pAuthInfo->auth_data_len = userlen + 1 + passlen;
+        pAuthInfo->auth_data_len = auth_data_len;
         pAuthInfo->finished = TRUE;
+        HeapFree(GetProcessHeap(),0,szRealm);
 
         return TRUE;
     }
@@ -733,14 +981,13 @@ static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
 /***********************************************************************
  *           HTTP_HttpAddRequestHeadersW (internal)
  */
-static BOOL HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
+static DWORD HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
        LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
 {
     LPWSTR lpszStart;
     LPWSTR lpszEnd;
     LPWSTR buffer;
-    BOOL bSuccess = FALSE;
-    DWORD len;
+    DWORD len, res = ERROR_HTTP_INVALID_HEADER;
 
     TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength));
 
@@ -779,25 +1026,25 @@ static BOOL HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
         {
             /* Skip 0-length headers */
             lpszStart = lpszEnd;
-            bSuccess = TRUE;
+            res = ERROR_SUCCESS;
             continue;
         }
         pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart);
         if (pFieldAndValue)
         {
-            bSuccess = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]);
-            if (bSuccess)
-                bSuccess = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0],
+            res = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]);
+            if (res == ERROR_SUCCESS)
+                res = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0],
                     pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ);
             HTTP_FreeTokens(pFieldAndValue);
         }
 
         lpszStart = lpszEnd;
-    } while (bSuccess);
+    } while (res == ERROR_SUCCESS);
 
     HeapFree(GetProcessHeap(), 0, buffer);
 
-    return bSuccess;
+    return res;
 }
 
 /***********************************************************************
@@ -819,8 +1066,8 @@ static BOOL HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
 BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
        LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
 {
-    BOOL bSuccess = FALSE;
     http_request_t *lpwhr;
+    DWORD res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
 
     TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
 
@@ -828,17 +1075,14 @@ BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
       return TRUE;
 
     lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
-    if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-        goto lend;
-    }
-    bSuccess = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier );
-lend:
+    if (lpwhr && lpwhr->hdr.htype == WH_HHTTPREQ)
+        res = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier );
     if( lpwhr )
         WININET_Release( &lpwhr->hdr );
 
-    return bSuccess;
+    if(res != ERROR_SUCCESS)
+        SetLastError(res);
+    return res == ERROR_SUCCESS;
 }
 
 /***********************************************************************
@@ -874,312 +1118,106 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
 }
 
 /***********************************************************************
- *           HttpEndRequestA (WININET.@)
+ *           HttpOpenRequestA (WININET.@)
  *
- * Ends an HTTP request that was started by HttpSendRequestEx
+ * Open a HTTP request handle
  *
  * RETURNS
- *    TRUE     if successful
- *    FALSE    on failure
+ *    HINTERNET  a HTTP request handle on success
+ *    NULL      on failure
  *
  */
-BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, 
-        LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
+HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
+       LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
+       LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
+       DWORD dwFlags, DWORD_PTR dwContext)
 {
-    TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
+    LPWSTR szVerb = NULL, szObjectName = NULL;
+    LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
+    INT acceptTypesCount;
+    HINTERNET rc = FALSE;
+    LPCSTR *types;
 
-    if (lpBuffersOut)
+    TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
+          debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
+          debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
+          dwFlags, dwContext);
+
+    if (lpszVerb)
     {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
+        szVerb = heap_strdupAtoW(lpszVerb);
+        if ( !szVerb )
+            goto end;
     }
 
-    return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
-}
-
-static BOOL HTTP_HttpEndRequestW(http_request_t *lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
-{
-    BOOL rc = FALSE;
-    INT responseLen;
-    DWORD dwBufferSize;
-    INTERNET_ASYNC_RESULT iar;
-
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                  INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
-
-    responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
-    if (responseLen)
-        rc = TRUE;
-
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                  INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
+    if (lpszObjectName)
+    {
+        szObjectName = heap_strdupAtoW(lpszObjectName);
+        if ( !szObjectName )
+            goto end;
+    }
 
-    /* process cookies here. Is this right? */
-    HTTP_ProcessCookies(lpwhr);
+    if (lpszVersion)
+    {
+        szVersion = heap_strdupAtoW(lpszVersion);
+        if ( !szVersion )
+            goto end;
+    }
 
-    if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
+    if (lpszReferrer)
+    {
+        szReferrer = heap_strdupAtoW(lpszReferrer);
+        if ( !szReferrer )
+            goto end;
+    }
 
-    if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
+    if (lpszAcceptTypes)
     {
-        DWORD dwCode,dwCodeLength = sizeof(DWORD);
-        if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) &&
-            (dwCode == 302 || dwCode == 301 || dwCode == 303))
+        acceptTypesCount = 0;
+        types = lpszAcceptTypes;
+        while (*types)
         {
-            WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
-            dwBufferSize=sizeof(szNewLocation);
-            if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL))
+            __TRY
             {
-                if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD))
-                {
-                    HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
-                    lpwhr->lpszVerb = heap_strdupW(szGET);
-                }
-                HTTP_DrainContent(lpwhr);
-                if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation )))
+                /* find out how many there are */
+                if (*types && **types)
                 {
-                    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT,
-                                          new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
-                    rc = HTTP_HandleRedirect(lpwhr, new_url);
-                    if (rc)
-                        rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
-                    HeapFree( GetProcessHeap(), 0, new_url );
+                    TRACE("accept type: %s\n", debugstr_a(*types));
+                    acceptTypesCount++;
                 }
             }
+            __EXCEPT_PAGE_FAULT
+            {
+                WARN("invalid accept type pointer\n");
+            }
+            __ENDTRY;
+            types++;
         }
-    }
+        szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
+        if (!szAcceptTypes) goto end;
 
-    iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
-    iar.dwError = rc ? 0 : INTERNET_GetLastError();
+        acceptTypesCount = 0;
+        types = lpszAcceptTypes;
+        while (*types)
+        {
+            __TRY
+            {
+                if (*types && **types)
+                    szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types);
+            }
+            __EXCEPT_PAGE_FAULT
+            {
+                /* ignore invalid pointer */
+            }
+            __ENDTRY;
+            types++;
+        }
+        szAcceptTypes[acceptTypesCount] = NULL;
+    }
 
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                          INTERNET_STATUS_REQUEST_COMPLETE, &iar,
-                          sizeof(INTERNET_ASYNC_RESULT));
-    return rc;
-}
-
-static void AsyncHttpEndRequestProc(WORKREQUEST *work)
-{
-    struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
-    http_request_t *lpwhr = (http_request_t*)work->hdr;
-
-    TRACE("%p\n", lpwhr);
-
-    HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext);
-}
-
-/***********************************************************************
- *           HttpEndRequestW (WININET.@)
- *
- * Ends an HTTP request that was started by HttpSendRequestEx
- *
- * RETURNS
- *    TRUE     if successful
- *    FALSE    on failure
- *
- */
-BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, 
-        LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
-{
-    BOOL rc = FALSE;
-    http_request_t *lpwhr;
-
-    TRACE("-->\n");
-
-    if (lpBuffersOut)
-    {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
-    lpwhr = (http_request_t*) WININET_GetObject( hRequest );
-
-    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-        if (lpwhr)
-            WININET_Release( &lpwhr->hdr );
-        return FALSE;
-    }
-    lpwhr->hdr.dwFlags |= dwFlags;
-
-    if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        WORKREQUEST work;
-        struct WORKREQ_HTTPENDREQUESTW *request;
-
-        work.asyncproc = AsyncHttpEndRequestProc;
-        work.hdr = WININET_AddRef( &lpwhr->hdr );
-
-        request = &work.u.HttpEndRequestW;
-        request->dwFlags = dwFlags;
-        request->dwContext = dwContext;
-
-        INTERNET_AsyncCall(&work);
-        INTERNET_SetLastError(ERROR_IO_PENDING);
-    }
-    else
-        rc = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
-
-    WININET_Release( &lpwhr->hdr );
-    TRACE("%i <--\n",rc);
-    return rc;
-}
-
-/***********************************************************************
- *           HttpOpenRequestW (WININET.@)
- *
- * Open a HTTP request handle
- *
- * RETURNS
- *    HINTERNET  a HTTP request handle on success
- *    NULL      on failure
- *
- */
-HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
-       LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
-       LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
-       DWORD dwFlags, DWORD_PTR dwContext)
-{
-    http_session_t *lpwhs;
-    HINTERNET handle = NULL;
-
-    TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
-          debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
-          debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
-          dwFlags, dwContext);
-    if(lpszAcceptTypes!=NULL)
-    {
-        int i;
-        for(i=0;lpszAcceptTypes[i]!=NULL;i++)
-            TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
-    }    
-
-    lpwhs = (http_session_t*) WININET_GetObject( hHttpSession );
-    if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-       goto lend;
-    }
-
-    /*
-     * My tests seem to show that the windows version does not
-     * become asynchronous until after this point. And anyhow
-     * if this call was asynchronous then how would you get the
-     * necessary HINTERNET pointer returned by this function.
-     *
-     */
-    handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName,
-                                   lpszVersion, lpszReferrer, lpszAcceptTypes,
-                                   dwFlags, dwContext);
-lend:
-    if( lpwhs )
-        WININET_Release( &lpwhs->hdr );
-    TRACE("returning %p\n", handle);
-    return handle;
-}
-
-
-/***********************************************************************
- *           HttpOpenRequestA (WININET.@)
- *
- * Open a HTTP request handle
- *
- * RETURNS
- *    HINTERNET  a HTTP request handle on success
- *    NULL      on failure
- *
- */
-HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
-       LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
-       LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
-       DWORD dwFlags, DWORD_PTR dwContext)
-{
-    LPWSTR szVerb = NULL, szObjectName = NULL;
-    LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
-    INT acceptTypesCount;
-    HINTERNET rc = FALSE;
-    LPCSTR *types;
-
-    TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
-          debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
-          debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
-          dwFlags, dwContext);
-
-    if (lpszVerb)
-    {
-        szVerb = heap_strdupAtoW(lpszVerb);
-        if ( !szVerb )
-            goto end;
-    }
-
-    if (lpszObjectName)
-    {
-        szObjectName = heap_strdupAtoW(lpszObjectName);
-        if ( !szObjectName )
-            goto end;
-    }
-
-    if (lpszVersion)
-    {
-        szVersion = heap_strdupAtoW(lpszVersion);
-        if ( !szVersion )
-            goto end;
-    }
-
-    if (lpszReferrer)
-    {
-        szReferrer = heap_strdupAtoW(lpszReferrer);
-        if ( !szReferrer )
-            goto end;
-    }
-
-    if (lpszAcceptTypes)
-    {
-        acceptTypesCount = 0;
-        types = lpszAcceptTypes;
-        while (*types)
-        {
-            __TRY
-            {
-                /* find out how many there are */
-                if (*types && **types)
-                {
-                    TRACE("accept type: %s\n", debugstr_a(*types));
-                    acceptTypesCount++;
-                }
-            }
-            __EXCEPT_PAGE_FAULT
-            {
-                WARN("invalid accept type pointer\n");
-            }
-            __ENDTRY;
-            types++;
-        }
-        szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
-        if (!szAcceptTypes) goto end;
-
-        acceptTypesCount = 0;
-        types = lpszAcceptTypes;
-        while (*types)
-        {
-            __TRY
-            {
-                if (*types && **types)
-                    szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types);
-            }
-            __EXCEPT_PAGE_FAULT
-            {
-                /* ignore invalid pointer */
-            }
-            __ENDTRY;
-            types++;
-        }
-        szAcceptTypes[acceptTypesCount] = NULL;
-    }
-
-    rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
-                          szVersion, szReferrer,
-                          (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
+    rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
+                          szVersion, szReferrer,
+                          (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
 
 end:
     if (szAcceptTypes)
@@ -1386,7 +1424,7 @@ static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
     DWORD size;
 
     size = sizeof(new_location);
-    if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL))
+    if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL) == ERROR_SUCCESS)
     {
         if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL;
         strcpyW( url, new_location );
@@ -1420,9 +1458,12 @@ static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
 static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_request_t *lpwhr)
 {
     WCHAR buf[MAXHOSTNAME];
+    WCHAR protoProxy[MAXHOSTNAME + 15];
+    DWORD protoProxyLen = sizeof(protoProxy) / sizeof(protoProxy[0]);
     WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
     static WCHAR szNul[] = { 0 };
     URL_COMPONENTSW UrlComponents;
+    static const WCHAR protoHttp[] = { 'h','t','t','p',0 };
     static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
     static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
 
@@ -1431,11 +1472,13 @@ static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_reque
     UrlComponents.lpszHostName = buf;
     UrlComponents.dwHostNameLength = MAXHOSTNAME;
 
+    if (!INTERNET_FindProxyForProtocol(hIC->lpszProxy, protoHttp, protoProxy, &protoProxyLen))
+        return FALSE;
     if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
-                                 hIC->lpszProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
-        sprintfW(proxy, szFormat, hIC->lpszProxy);
+                                 protoProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
+        sprintfW(proxy, szFormat, protoProxy);
     else
-       strcpyW(proxy, hIC->lpszProxy);
+       strcpyW(proxy, protoProxy);
     if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
         return FALSE;
     if( UrlComponents.dwHostNameLength == 0 )
@@ -1459,7 +1502,7 @@ static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_reque
 #define INET6_ADDRSTRLEN 46
 #endif
 
-static BOOL HTTP_ResolveName(http_request_t *lpwhr)
+static DWORD HTTP_ResolveName(http_request_t *lpwhr)
 {
     char szaddr[INET6_ADDRSTRLEN];
     http_session_t *lpwhs = lpwhr->lpHttpSession;
@@ -1468,15 +1511,12 @@ static BOOL HTTP_ResolveName(http_request_t *lpwhr)
     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                           INTERNET_STATUS_RESOLVING_NAME,
                           lpwhs->lpszServerName,
-                          strlenW(lpwhs->lpszServerName)+1);
+                          (strlenW(lpwhs->lpszServerName)+1) * sizeof(WCHAR));
 
     lpwhs->sa_len = sizeof(lpwhs->socketAddress);
     if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
                     (struct sockaddr *)&lpwhs->socketAddress, &lpwhs->sa_len))
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
-        return FALSE;
-    }
+        return ERROR_INTERNET_NAME_NOT_RESOLVED;
 
     switch (lpwhs->socketAddress.ss_family)
     {
@@ -1488,8 +1528,7 @@ static BOOL HTTP_ResolveName(http_request_t *lpwhr)
         break;
     default:
         WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family);
-        INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
-        return FALSE;
+        return ERROR_INTERNET_NAME_NOT_RESOLVED;
     }
     inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr));
     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
@@ -1497,6 +1536,20 @@ static BOOL HTTP_ResolveName(http_request_t *lpwhr)
                           szaddr, strlen(szaddr)+1);
 
     TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr);
+    return ERROR_SUCCESS;
+}
+
+static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
+{
+    LPHTTPHEADERW host_header;
+
+    static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
+
+    host_header = HTTP_GetHeader(req, hostW);
+    if(!host_header)
+        return FALSE;
+
+    sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */
     return TRUE;
 }
 
@@ -1514,9 +1567,19 @@ static void HTTPREQ_Destroy(object_header_t *hdr)
 
     TRACE("\n");
 
-    if(lpwhr->hCacheFile)
+    if(lpwhr->hCacheFile) {
+        WCHAR url[INTERNET_MAX_URL_LENGTH];
+        FILETIME ft;
+
         CloseHandle(lpwhr->hCacheFile);
 
+        memset(&ft, 0, sizeof(FILETIME));
+        if(HTTP_GetRequestURL(lpwhr, url)) {
+            CommitUrlCacheEntryW(url, lpwhr->lpszCacheFile, ft, ft,
+                    NORMAL_CACHE_ENTRY, NULL, 0, NULL, 0);
+        }
+    }
+
     HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile);
 
     DeleteCriticalSection( &lpwhr->read_section );
@@ -1567,20 +1630,6 @@ static void HTTPREQ_CloseConnection(object_header_t *hdr)
                           INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
 }
 
-static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
-{
-    LPHTTPHEADERW host_header;
-
-    static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
-
-    host_header = HTTP_GetHeader(req, hostW);
-    if(!host_header)
-        return FALSE;
-
-    sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */
-    return TRUE;
-}
-
 static BOOL HTTP_KeepAlive(http_request_t *lpwhr)
 {
     WCHAR szVersion[10];
@@ -1590,16 +1639,15 @@ static BOOL HTTP_KeepAlive(http_request_t *lpwhr)
 
     /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
      * the connection is keep-alive by default */
-    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion,
-                             &dwBufferSize, NULL) &&
-        !strcmpiW(szVersion, g_szHttp1_1))
+    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion, &dwBufferSize, NULL) == ERROR_SUCCESS
+        && !strcmpiW(szVersion, g_szHttp1_1))
     {
         keepalive = TRUE;
     }
 
     dwBufferSize = sizeof(szConnectionResponse);
-    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) ||
-        HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL))
+    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS
+        || HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) == ERROR_SUCCESS)
     {
         keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
     }
@@ -1642,18 +1690,25 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
 
     case INTERNET_OPTION_SECURITY_FLAGS:
     {
-        http_session_t *lpwhs;
-        lpwhs = req->lpHttpSession;
+        DWORD flags;
+        int bits;
 
         if (*size < sizeof(ULONG))
             return ERROR_INSUFFICIENT_BUFFER;
 
         *size = sizeof(DWORD);
-        if (lpwhs->hdr.dwFlags & INTERNET_FLAG_SECURE)
-            *(DWORD*)buffer = SECURITY_FLAG_SECURE;
+        flags = 0;
+        if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
+            flags |= SECURITY_FLAG_SECURE;
+        flags |= req->netConnection.security_flags;
+        bits = NETCON_GetCipherStrength(&req->netConnection);
+        if (bits >= 128)
+            flags |= SECURITY_FLAG_STRENGTH_STRONG;
+        else if (bits >= 56)
+            flags |= SECURITY_FLAG_STRENGTH_MEDIUM;
         else
-            *(DWORD*)buffer = 0;
-        FIXME("Semi-STUB INTERNET_OPTION_SECURITY_FLAGS: %x\n",*(DWORD*)buffer);
+            flags |= SECURITY_FLAG_STRENGTH_WEAK;
+        *(DWORD *)buffer = flags;
         return ERROR_SUCCESS;
     }
 
@@ -1771,67 +1826,41 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
     case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: {
         PCCERT_CONTEXT context;
 
-        if(*size < sizeof(INTERNET_CERTIFICATE_INFOW)) {
-            *size = sizeof(INTERNET_CERTIFICATE_INFOW);
+        if(*size < sizeof(INTERNET_CERTIFICATE_INFOA)) {
+            *size = sizeof(INTERNET_CERTIFICATE_INFOA);
             return ERROR_INSUFFICIENT_BUFFER;
         }
 
         context = (PCCERT_CONTEXT)NETCON_GetCert(&(req->netConnection));
         if(context) {
-            INTERNET_CERTIFICATE_INFOW *info = (INTERNET_CERTIFICATE_INFOW*)buffer;
+            INTERNET_CERTIFICATE_INFOA *info = (INTERNET_CERTIFICATE_INFOA*)buffer;
             DWORD len;
 
             memset(info, 0, sizeof(INTERNET_CERTIFICATE_INFOW));
             info->ftExpiry = context->pCertInfo->NotAfter;
             info->ftStart = context->pCertInfo->NotBefore;
-            if(unicode) {
-                len = CertNameToStrW(context->dwCertEncodingType,
-                        &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
-                info->lpszSubjectInfo = LocalAlloc(0, len*sizeof(WCHAR));
-                if(info->lpszSubjectInfo)
-                    CertNameToStrW(context->dwCertEncodingType,
-                             &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
-                             info->lpszSubjectInfo, len);
-                len = CertNameToStrW(context->dwCertEncodingType,
-                         &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
-                info->lpszIssuerInfo = LocalAlloc(0, len*sizeof(WCHAR));
-                if (info->lpszIssuerInfo)
-                    CertNameToStrW(context->dwCertEncodingType,
-                             &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
-                             info->lpszIssuerInfo, len);
-            }else {
-                INTERNET_CERTIFICATE_INFOA *infoA = (INTERNET_CERTIFICATE_INFOA*)info;
-
-                len = CertNameToStrA(context->dwCertEncodingType,
-                         &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
-                infoA->lpszSubjectInfo = LocalAlloc(0, len);
-                if(infoA->lpszSubjectInfo)
-                    CertNameToStrA(context->dwCertEncodingType,
-                             &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
-                             infoA->lpszSubjectInfo, len);
-                len = CertNameToStrA(context->dwCertEncodingType,
-                         &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
-                infoA->lpszIssuerInfo = LocalAlloc(0, len);
-                if(infoA->lpszIssuerInfo)
-                    CertNameToStrA(context->dwCertEncodingType,
-                             &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
-                             infoA->lpszIssuerInfo, len);
-            }
-
-            /*
-             * Contrary to MSDN, these do not appear to be set.
-             * lpszProtocolName
-             * lpszSignatureAlgName
-             * lpszEncryptionAlgName
-             * dwKeySize
-             */
+            len = CertNameToStrA(context->dwCertEncodingType,
+                     &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
+            info->lpszSubjectInfo = LocalAlloc(0, len);
+            if(info->lpszSubjectInfo)
+                CertNameToStrA(context->dwCertEncodingType,
+                         &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
+                         info->lpszSubjectInfo, len);
+            len = CertNameToStrA(context->dwCertEncodingType,
+                     &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
+            info->lpszIssuerInfo = LocalAlloc(0, len);
+            if(info->lpszIssuerInfo)
+                CertNameToStrA(context->dwCertEncodingType,
+                         &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
+                         info->lpszIssuerInfo, len);
+            info->dwKeySize = NETCON_GetCipherStrength(&req->netConnection);
             CertFreeCertificateContext(context);
             return ERROR_SUCCESS;
         }
     }
     }
 
-    return INET_QueryOption(option, buffer, size, unicode);
+    return INET_QueryOption(hdr, option, buffer, size, unicode);
 }
 
 static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
@@ -1839,9 +1868,20 @@ static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer,
     http_request_t *req = (http_request_t*)hdr;
 
     switch(option) {
-    case INTERNET_OPTION_SEND_TIMEOUT:
-    case INTERNET_OPTION_RECEIVE_TIMEOUT:
-        TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
+    case INTERNET_OPTION_SECURITY_FLAGS:
+    {
+        DWORD flags;
+
+        if (!buffer || size != sizeof(DWORD))
+            return ERROR_INVALID_PARAMETER;
+        flags = *(DWORD *)buffer;
+        TRACE("%08x\n", flags);
+        req->netConnection.security_flags = flags;
+        return ERROR_SUCCESS;
+    }
+    case INTERNET_OPTION_SEND_TIMEOUT:
+    case INTERNET_OPTION_RECEIVE_TIMEOUT:
+        TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
 
         if (size != sizeof(DWORD))
             return ERROR_INVALID_PARAMETER;
@@ -1869,8 +1909,9 @@ static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer,
 }
 
 /* read some more data into the read buffer (the read section must be held) */
-static BOOL read_more_data( http_request_t *req, int maxlen )
+static DWORD read_more_data( http_request_t *req, int maxlen )
 {
+    DWORD res;
     int len;
 
     if (req->read_pos)
@@ -1883,12 +1924,12 @@ static BOOL read_more_data( http_request_t *req, int maxlen )
 
     if (maxlen == -1) maxlen = sizeof(req->read_buf);
 
-    if(!NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
-                     maxlen - req->read_size, 0, &len ))
-        return FALSE;
+    res = NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
+                       maxlen - req->read_size, 0, &len );
+    if(res == ERROR_SUCCESS)
+        req->read_size += len;
 
-    req->read_size += len;
-    return TRUE;
+    return res;
 }
 
 /* remove some amount of data from the read buffer (the read section must be held) */
@@ -1901,6 +1942,7 @@ static void remove_data( http_request_t *req, int count )
 static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
 {
     int count, bytes_read, pos = 0;
+    DWORD res;
 
     EnterCriticalSection( &req->read_section );
     for (;;)
@@ -1920,11 +1962,12 @@ static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
         remove_data( req, bytes_read );
         if (eol) break;
 
-        if (!read_more_data( req, -1 ) || !req->read_size)
+        if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size)
         {
             *len = 0;
             TRACE( "returning empty string\n" );
             LeaveCriticalSection( &req->read_section );
+            INTERNET_SetLastError(res);
             return FALSE;
         }
     }
@@ -1941,8 +1984,10 @@ static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
 }
 
 /* discard data contents until we reach end of line (the read section must be held) */
-static BOOL discard_eol( http_request_t *req )
+static DWORD discard_eol( http_request_t *req )
 {
+    DWORD res;
+
     do
     {
         BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
@@ -1952,21 +1997,21 @@ static BOOL discard_eol( http_request_t *req )
             break;
         }
         req->read_pos = req->read_size = 0;  /* discard everything */
-        if (!read_more_data( req, -1 )) return FALSE;
+        if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res;
     } while (req->read_size);
-    return TRUE;
+    return ERROR_SUCCESS;
 }
 
 /* read the size of the next chunk (the read section must be held) */
-static BOOL start_next_chunk( http_request_t *req )
+static DWORD start_next_chunk( http_request_t *req )
 {
-    DWORD chunk_size = 0;
+    DWORD chunk_size = 0, res;
 
-    if (!req->dwContentLength) return TRUE;
+    if (!req->dwContentLength) return ERROR_SUCCESS;
     if (req->dwContentLength == req->dwContentRead)
     {
         /* read terminator for the previous chunk */
-        if (!discard_eol( req )) return FALSE;
+        if ((res = discard_eol( req )) != ERROR_SUCCESS) return res;
         req->dwContentLength = ~0u;
         req->dwContentRead = 0;
     }
@@ -1983,16 +2028,15 @@ static BOOL start_next_chunk( http_request_t *req )
                 TRACE( "reading %u byte chunk\n", chunk_size );
                 req->dwContentLength = chunk_size;
                 req->dwContentRead = 0;
-                if (!discard_eol( req )) return FALSE;
-                return TRUE;
+                return discard_eol( req );
             }
             remove_data( req, 1 );
         }
-        if (!read_more_data( req, -1 )) return FALSE;
+        if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res;
         if (!req->read_size)
         {
             req->dwContentLength = req->dwContentRead = 0;
-            return TRUE;
+            return ERROR_SUCCESS;
         }
     }
 }
@@ -2007,21 +2051,22 @@ static BOOL end_of_read_data( http_request_t *req )
 }
 
 /* fetch some more data into the read buffer (the read section must be held) */
-static BOOL refill_buffer( http_request_t *req )
+static DWORD refill_buffer( http_request_t *req )
 {
     int len = sizeof(req->read_buf);
+    DWORD res;
 
     if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
     {
-        if (!start_next_chunk( req )) return FALSE;
+        if ((res = start_next_chunk( req )) != ERROR_SUCCESS) return res;
     }
 
     if (req->dwContentLength != ~0u) len = min( len, req->dwContentLength - req->dwContentRead );
-    if (len <= req->read_size) return TRUE;
+    if (len <= req->read_size) return ERROR_SUCCESS;
 
-    if (!read_more_data( req, len )) return FALSE;
+    if ((res = read_more_data( req, len )) != ERROR_SUCCESS) return res;
     if (!req->read_size) req->dwContentLength = req->dwContentRead = 0;
-    return TRUE;
+    return ERROR_SUCCESS;
 }
 
 static DWORD read_gzip_data(http_request_t *req, BYTE *buf, int size, BOOL sync, int *read_ret)
@@ -2031,21 +2076,28 @@ static DWORD read_gzip_data(http_request_t *req, BYTE *buf, int size, BOOL sync,
 
 #ifdef HAVE_ZLIB
     z_stream *zstream = &req->gzip_stream->zstream;
+    DWORD buf_avail;
     int zres;
 
     while(read < size && !req->gzip_stream->end_of_data) {
         if(!req->read_size) {
-            if(!sync || !refill_buffer(req))
+            if(!sync || refill_buffer(req) != ERROR_SUCCESS)
                 break;
         }
 
+        if(req->dwContentRead == req->dwContentLength)
+            break;
+
+        buf_avail = req->dwContentLength == ~0 ? req->read_size : min(req->read_size, req->dwContentLength-req->dwContentRead);
+
         zstream->next_in = req->read_buf+req->read_pos;
-        zstream->avail_in = req->read_size;
+        zstream->avail_in = buf_avail;
         zstream->next_out = buf+read;
         zstream->avail_out = size-read;
         zres = inflate(zstream, Z_FULL_FLUSH);
         read = size - zstream->avail_out;
-        remove_data(req, req->read_size-zstream->avail_in);
+        req->dwContentRead += buf_avail-zstream->avail_in;
+        remove_data(req, buf_avail-zstream->avail_in);
         if(zres == Z_STREAM_END) {
             TRACE("end of data\n");
             req->gzip_stream->end_of_data = TRUE;
@@ -2098,16 +2150,17 @@ static DWORD get_avail_data( http_request_t *req )
 static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif)
 {
     INTERNET_ASYNC_RESULT iar;
+    DWORD res;
 
     TRACE("%p\n", req);
 
     EnterCriticalSection( &req->read_section );
-    if (refill_buffer( req )) {
+    if ((res = refill_buffer( req )) == ERROR_SUCCESS) {
         iar.dwResult = (DWORD_PTR)req->hdr.hInternet;
         iar.dwError = first_notif ? 0 : get_avail_data(req);
     }else {
         iar.dwResult = 0;
-        iar.dwError = INTERNET_GetLastError();
+        iar.dwError = res;
     }
     LeaveCriticalSection( &req->read_section );
 
@@ -2126,7 +2179,7 @@ static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *
 
     if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
     {
-        if (!start_next_chunk( req )) goto done;
+        if (start_next_chunk( req ) != ERROR_SUCCESS) goto done;
     }
 
     if(req->gzip_stream) {
@@ -2157,15 +2210,15 @@ static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *
 
         if (size > bytes_read && (!bytes_read || sync)) {
             if (NETCON_recv( &req->netConnection, (char *)buffer + bytes_read, size - bytes_read,
-                             sync ? MSG_WAITALL : 0, &len))
+                             sync ? MSG_WAITALL : 0, &len) == ERROR_SUCCESS)
                 bytes_read += len;
             /* always return success, even if the network layer returns an error */
         }
 
         finished_reading = !bytes_read && req->dwContentRead == req->dwContentLength;
+        req->dwContentRead += bytes_read;
     }
 done:
-    req->dwContentRead += bytes_read;
     *read = bytes_read;
 
     TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength );
@@ -2190,7 +2243,18 @@ done:
 static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
 {
     http_request_t *req = (http_request_t*)hdr;
-    return HTTPREQ_Read(req, buffer, size, read, TRUE);
+    DWORD res;
+
+    EnterCriticalSection( &req->read_section );
+    if(hdr->dwError == INTERNET_HANDLE_IN_USE)
+        hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
+
+    res = HTTPREQ_Read(req, buffer, size, read, TRUE);
+    if(res == ERROR_SUCCESS)
+        res = hdr->dwError;
+    LeaveCriticalSection( &req->read_section );
+
+    return res;
 }
 
 static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest)
@@ -2217,7 +2281,7 @@ static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffer
         DWORD flags, DWORD_PTR context)
 {
     http_request_t *req = (http_request_t*)hdr;
-    DWORD res;
+    DWORD res, size, read, error = ERROR_SUCCESS;
 
     if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
         FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
@@ -2227,7 +2291,7 @@ static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffer
 
     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
 
-    if ((hdr->dwFlags & INTERNET_FLAG_ASYNC) && !get_avail_data(req))
+    if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
     {
         WORKREQUEST workRequest;
 
@@ -2237,6 +2301,7 @@ static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffer
             {
                 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
                                    &buffers->dwBufferLength, FALSE);
+                size = buffers->dwBufferLength;
                 LeaveCriticalSection( &req->read_section );
                 goto done;
             }
@@ -2252,17 +2317,52 @@ static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffer
         return ERROR_IO_PENDING;
     }
 
-    res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
-            !(flags & IRF_NO_WAIT));
+    read = 0;
+    size = buffers->dwBufferLength;
+
+    EnterCriticalSection( &req->read_section );
+    if(hdr->dwError == ERROR_SUCCESS)
+        hdr->dwError = INTERNET_HANDLE_IN_USE;
+    else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
+        hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
+
+    while(1) {
+        res = HTTPREQ_Read(req, (char*)buffers->lpvBuffer+read, size-read,
+                &buffers->dwBufferLength, !(flags & IRF_NO_WAIT));
+        if(res == ERROR_SUCCESS)
+            read += buffers->dwBufferLength;
+        else
+            break;
+
+        if(!req->read_chunked || read==size || req->dwContentLength!=req->dwContentRead
+                || !req->dwContentLength || (req->gzip_stream && req->gzip_stream->end_of_data))
+            break;
+        LeaveCriticalSection( &req->read_section );
+
+        INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
+                &buffers->dwBufferLength, sizeof(buffers->dwBufferLength));
+        INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
+                INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+
+        EnterCriticalSection( &req->read_section );
+    }
+
+    if(hdr->dwError == INTERNET_HANDLE_IN_USE)
+        hdr->dwError = ERROR_SUCCESS;
+    else
+        error = hdr->dwError;
+
+    LeaveCriticalSection( &req->read_section );
+    size = buffers->dwBufferLength;
+    buffers->dwBufferLength = read;
 
 done:
     if (res == ERROR_SUCCESS) {
-        DWORD size = buffers->dwBufferLength;
         INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
                 &size, sizeof(size));
     }
 
-    return res;
+    return res==ERROR_SUCCESS ? error : res;
 }
 
 static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest)
@@ -2290,7 +2390,7 @@ static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffer
 {
 
     http_request_t *req = (http_request_t*)hdr;
-    DWORD res;
+    DWORD res, size, read, error = ERROR_SUCCESS;
 
     if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
         FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
@@ -2310,6 +2410,7 @@ static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffer
             {
                 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
                                    &buffers->dwBufferLength, FALSE);
+                size = buffers->dwBufferLength;
                 LeaveCriticalSection( &req->read_section );
                 goto done;
             }
@@ -2325,32 +2426,68 @@ static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffer
         return ERROR_IO_PENDING;
     }
 
-    res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
-            !(flags & IRF_NO_WAIT));
+    read = 0;
+    size = buffers->dwBufferLength;
+
+    EnterCriticalSection( &req->read_section );
+    if(hdr->dwError == ERROR_SUCCESS)
+        hdr->dwError = INTERNET_HANDLE_IN_USE;
+    else if(hdr->dwError == INTERNET_HANDLE_IN_USE)
+        hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
+
+    while(1) {
+        res = HTTPREQ_Read(req, (char*)buffers->lpvBuffer+read, size-read,
+                &buffers->dwBufferLength, !(flags & IRF_NO_WAIT));
+        if(res == ERROR_SUCCESS)
+            read += buffers->dwBufferLength;
+        else
+            break;
+
+        if(!req->read_chunked || read==size || req->dwContentLength!=req->dwContentRead
+                || !req->dwContentLength || (req->gzip_stream && req->gzip_stream->end_of_data))
+            break;
+        LeaveCriticalSection( &req->read_section );
+
+        INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
+                &buffers->dwBufferLength, sizeof(buffers->dwBufferLength));
+        INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
+                INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+
+        EnterCriticalSection( &req->read_section );
+    }
+
+    if(hdr->dwError == INTERNET_HANDLE_IN_USE)
+        hdr->dwError = ERROR_SUCCESS;
+    else
+        error = hdr->dwError;
+
+    LeaveCriticalSection( &req->read_section );
+    size = buffers->dwBufferLength;
+    buffers->dwBufferLength = read;
 
 done:
     if (res == ERROR_SUCCESS) {
-        DWORD size = buffers->dwBufferLength;
         INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
                 &size, sizeof(size));
     }
 
-    return res;
+    return res==ERROR_SUCCESS ? error : res;
 }
 
-static BOOL HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
+static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
 {
-    BOOL ret;
+    DWORD res;
     http_request_t *lpwhr = (http_request_t*)hdr;
 
     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
 
     *written = 0;
-    if ((ret = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written)))
+    res = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written);
+    if (res == ERROR_SUCCESS)
         lpwhr->dwBytesWritten += *written;
 
     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD));
-    return ret;
+    return res;
 }
 
 static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
@@ -2430,17 +2567,17 @@ static const object_vtbl_t HTTPREQVtbl = {
  *    NULL      on failure
  *
  */
-HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
-       LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
-       LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
-       DWORD dwFlags, DWORD_PTR dwContext)
+static DWORD HTTP_HttpOpenRequestW(http_session_t *lpwhs,
+        LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
+        LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
+        DWORD dwFlags, DWORD_PTR dwContext, HINTERNET *ret)
 {
     appinfo_t *hIC = NULL;
     http_request_t *lpwhr;
     LPWSTR lpszHostName = NULL;
     HINTERNET handle = NULL;
     static const WCHAR szHostForm[] = {'%','s',':','%','u',0};
-    DWORD len;
+    DWORD len, res;
 
     TRACE("-->\n");
 
@@ -2450,7 +2587,7 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
     lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_request_t));
     if (NULL == lpwhr)
     {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+        res = ERROR_OUTOFMEMORY;
         goto lend;
     }
     lpwhr->hdr.htype = WH_HHTTPREQ;
@@ -2471,18 +2608,18 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
             (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */));
     if (NULL == lpszHostName)
     {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+        res = ERROR_OUTOFMEMORY;
         goto lend;
     }
 
     handle = WININET_AllocHandle( &lpwhr->hdr );
     if (NULL == handle)
     {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+        res = ERROR_OUTOFMEMORY;
         goto lend;
     }
 
-    if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE))
+    if ((res = NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE)) != ERROR_SUCCESS)
     {
         InternetCloseHandle( handle );
         handle = NULL;
@@ -2564,6 +2701,63 @@ lend:
         WININET_Release( &lpwhr->hdr );
 
     TRACE("<-- %p (%p)\n", handle, lpwhr);
+    *ret = handle;
+    return res;
+}
+
+/***********************************************************************
+ *           HttpOpenRequestW (WININET.@)
+ *
+ * Open a HTTP request handle
+ *
+ * RETURNS
+ *    HINTERNET  a HTTP request handle on success
+ *    NULL      on failure
+ *
+ */
+HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
+       LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
+       LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
+       DWORD dwFlags, DWORD_PTR dwContext)
+{
+    http_session_t *lpwhs;
+    HINTERNET handle = NULL;
+    DWORD res;
+
+    TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
+          debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
+          debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
+          dwFlags, dwContext);
+    if(lpszAcceptTypes!=NULL)
+    {
+        int i;
+        for(i=0;lpszAcceptTypes[i]!=NULL;i++)
+            TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
+    }
+
+    lpwhs = (http_session_t*) WININET_GetObject( hHttpSession );
+    if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
+    {
+        res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+        goto lend;
+    }
+
+    /*
+     * My tests seem to show that the windows version does not
+     * become asynchronous until after this point. And anyhow
+     * if this call was asynchronous then how would you get the
+     * necessary HINTERNET pointer returned by this function.
+     *
+     */
+    res = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName,
+                                lpszVersion, lpszReferrer, lpszAcceptTypes,
+                                dwFlags, dwContext, &handle);
+lend:
+    if( lpwhs )
+        WININET_Release( &lpwhs->hdr );
+    TRACE("returning %p\n", handle);
+    if(res != ERROR_SUCCESS)
+        SetLastError(res);
     return handle;
 }
 
@@ -2669,11 +2863,10 @@ static const LPCWSTR header_lookup[] = {
 /***********************************************************************
  *           HTTP_HttpQueryInfoW (internal)
  */
-static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
-       LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
+static DWORD HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
+        LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
 {
     LPHTTPHEADERW lphttpHdr = NULL;
-    BOOL bSuccess = FALSE;
     BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS;
     INT requested_index = lpdwIndex ? *lpdwIndex : 0;
     DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
@@ -2683,14 +2876,14 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
     switch (level)
     {
     case HTTP_QUERY_CUSTOM:
-        if (!lpBuffer) return FALSE;
+        if (!lpBuffer) return ERROR_INVALID_PARAMETER;
         index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
         break;
     case HTTP_QUERY_RAW_HEADERS_CRLF:
         {
             LPWSTR headers;
             DWORD len = 0;
-            BOOL ret = FALSE;
+            DWORD res = ERROR_INVALID_PARAMETER;
 
             if (request_only)
                 headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
@@ -2703,8 +2896,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
             if (len + sizeof(WCHAR) > *lpdwBufferLength)
             {
                 len += sizeof(WCHAR);
-                INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
-                ret = FALSE;
+                res = ERROR_INSUFFICIENT_BUFFER;
             }
             else if (lpBuffer)
             {
@@ -2716,13 +2908,13 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
                     memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
                 }
                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
-                ret = TRUE;
+                res = ERROR_SUCCESS;
             }
             *lpdwBufferLength = len;
 
             if (request_only)
                 HeapFree(GetProcessHeap(), 0, headers);
-            return ret;
+            return res;
         }
     case HTTP_QUERY_RAW_HEADERS:
         {
@@ -2737,8 +2929,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
             {
                 HTTP_FreeTokens(ppszRawHeaderLines);
                 *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
-                INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
-                return FALSE;
+                return ERROR_INSUFFICIENT_BUFFER;
             }
             if (pszString)
             {
@@ -2754,7 +2945,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
             *lpdwBufferLength = size * sizeof(WCHAR);
             HTTP_FreeTokens(ppszRawHeaderLines);
 
-            return TRUE;
+            return ERROR_SUCCESS;
         }
     case HTTP_QUERY_STATUS_TEXT:
         if (lpwhr->lpszStatusText)
@@ -2763,8 +2954,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
             if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
             {
                 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
-                INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
-                return FALSE;
+                return ERROR_INSUFFICIENT_BUFFER;
             }
             if (lpBuffer)
             {
@@ -2772,7 +2962,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
             }
             *lpdwBufferLength = len * sizeof(WCHAR);
-            return TRUE;
+            return ERROR_SUCCESS;
         }
         break;
     case HTTP_QUERY_VERSION:
@@ -2782,8 +2972,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
             if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
             {
                 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
-                INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
-                return FALSE;
+                return ERROR_INSUFFICIENT_BUFFER;
             }
             if (lpBuffer)
             {
@@ -2791,7 +2980,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
             }
             *lpdwBufferLength = len * sizeof(WCHAR);
-            return TRUE;
+            return ERROR_SUCCESS;
         }
         break;
     case HTTP_QUERY_CONTENT_ENCODING:
@@ -2814,8 +3003,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
         ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
          (~lphttpHdr->wFlags & HDR_ISREQUEST)))
     {
-        INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
-        return bSuccess;
+        return ERROR_HTTP_HEADER_NOT_FOUND;
     }
 
     if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++;
@@ -2825,8 +3013,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
     {
         *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
         TRACE(" returning number: %d\n", *(int *)lpBuffer);
-        bSuccess = TRUE;
-    }
+     }
     else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
     {
         time_t tmpTime;
@@ -2845,8 +3032,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
         STHook->wMonth = tmpTM.tm_mon + 1;
         STHook->wSecond = tmpTM.tm_sec;
         STHook->wYear = tmpTM.tm_year;
-        bSuccess = TRUE;
-       
+
         TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
               STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
               STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
@@ -2858,18 +3044,16 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
         if (len > *lpdwBufferLength)
         {
             *lpdwBufferLength = len;
-            INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
-            return bSuccess;
+            return ERROR_INSUFFICIENT_BUFFER;
         }
         if (lpBuffer)
         {
             memcpy(lpBuffer, lphttpHdr->lpszValue, len);
-            TRACE(" returning string: %s\n", debugstr_w(lpBuffer));
+            TRACE("! returning string: %s\n", debugstr_w(lpBuffer));
         }
         *lpdwBufferLength = len - sizeof(WCHAR);
-        bSuccess = TRUE;
     }
-    return bSuccess;
+    return ERROR_SUCCESS;
 }
 
 /***********************************************************************
@@ -2883,10 +3067,10 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
  *
  */
 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
-       LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
+        LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
 {
-    BOOL bSuccess = FALSE;
     http_request_t *lpwhr;
+    DWORD res;
 
     if (TRACE_ON(wininet)) {
 #define FE(x) { x, #x }
@@ -2972,7 +3156,7 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
        DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
        DWORD i;
 
-       TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
+       TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, info);
        TRACE("  Attribute:");
        for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
            if (query_flags[i].val == info) {
@@ -3001,21 +3185,23 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
     lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
     {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-       goto lend;
+        res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+        goto lend;
     }
 
     if (lpBuffer == NULL)
         *lpdwBufferLength = 0;
-    bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
-                                   lpBuffer, lpdwBufferLength, lpdwIndex);
+    res = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
+                               lpBuffer, lpdwBufferLength, lpdwIndex);
 
 lend:
     if( lpwhr )
          WININET_Release( &lpwhr->hdr );
 
-    TRACE("%d <--\n", bSuccess);
-    return bSuccess;
+    TRACE("%u <--\n", res);
+    if(res != ERROR_SUCCESS)
+        SetLastError(res);
+    return res == ERROR_SUCCESS;
 }
 
 /***********************************************************************
@@ -3086,332 +3272,71 @@ BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
 }
 
 /***********************************************************************
- *           HttpSendRequestExA (WININET.@)
- *
- * Sends the specified request to the HTTP server and allows chunked
- * transfers.
- *
- * RETURNS
- *  Success: TRUE
- *  Failure: FALSE, call GetLastError() for more information.
+ *           HTTP_GetRedirectURL (internal)
  */
-BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
-                              LPINTERNET_BUFFERSA lpBuffersIn,
-                              LPINTERNET_BUFFERSA lpBuffersOut,
-                              DWORD dwFlags, DWORD_PTR dwContext)
+static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl)
 {
-    INTERNET_BUFFERSW BuffersInW;
-    BOOL rc = FALSE;
-    DWORD headerlen;
-    LPWSTR header = NULL;
+    static WCHAR szHttp[] = {'h','t','t','p',0};
+    static WCHAR szHttps[] = {'h','t','t','p','s',0};
+    http_session_t *lpwhs = lpwhr->lpHttpSession;
+    URL_COMPONENTSW urlComponents;
+    DWORD url_length = 0;
+    LPWSTR orig_url;
+    LPWSTR combined_url;
 
-    TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
-           lpBuffersOut, dwFlags, dwContext);
+    urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
+    urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
+    urlComponents.dwSchemeLength = 0;
+    urlComponents.lpszHostName = lpwhs->lpszHostName;
+    urlComponents.dwHostNameLength = 0;
+    urlComponents.nPort = lpwhs->nHostPort;
+    urlComponents.lpszUserName = lpwhs->lpszUserName;
+    urlComponents.dwUserNameLength = 0;
+    urlComponents.lpszPassword = NULL;
+    urlComponents.dwPasswordLength = 0;
+    urlComponents.lpszUrlPath = lpwhr->lpszPath;
+    urlComponents.dwUrlPathLength = 0;
+    urlComponents.lpszExtraInfo = NULL;
+    urlComponents.dwExtraInfoLength = 0;
 
-    if (lpBuffersIn)
+    if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) &&
+        (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
+        return NULL;
+
+    orig_url = HeapAlloc(GetProcessHeap(), 0, url_length);
+
+    /* convert from bytes to characters */
+    url_length = url_length / sizeof(WCHAR) - 1;
+    if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length))
     {
-        BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
-        if (lpBuffersIn->lpcszHeader)
-        {
-            headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
-                    lpBuffersIn->dwHeadersLength,0,0);
-            header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR));
-            if (!(BuffersInW.lpcszHeader = header))
-            {
-                INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-                return FALSE;
-            }
-            BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
-                    lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
-                    header, headerlen);
-        }
-        else
-            BuffersInW.lpcszHeader = NULL;
-        BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
-        BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
-        BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
-        BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
-        BuffersInW.Next = NULL;
+        HeapFree(GetProcessHeap(), 0, orig_url);
+        return NULL;
     }
 
-    rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
-
-    HeapFree(GetProcessHeap(),0,header);
+    url_length = 0;
+    if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) &&
+        (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
+    {
+        HeapFree(GetProcessHeap(), 0, orig_url);
+        return NULL;
+    }
+    combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR));
 
-    return rc;
+    if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY))
+    {
+        HeapFree(GetProcessHeap(), 0, orig_url);
+        HeapFree(GetProcessHeap(), 0, combined_url);
+        return NULL;
+    }
+    HeapFree(GetProcessHeap(), 0, orig_url);
+    return combined_url;
 }
 
+
 /***********************************************************************
- *           HttpSendRequestExW (WININET.@)
- *
- * Sends the specified request to the HTTP server and allows chunked
- * transfers
- *
- * RETURNS
- *  Success: TRUE
- *  Failure: FALSE, call GetLastError() for more information.
+ *           HTTP_HandleRedirect (internal)
  */
-BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
-                   LPINTERNET_BUFFERSW lpBuffersIn,
-                   LPINTERNET_BUFFERSW lpBuffersOut,
-                   DWORD dwFlags, DWORD_PTR dwContext)
-{
-    BOOL ret = FALSE;
-    http_request_t *lpwhr;
-    http_session_t *lpwhs;
-    appinfo_t *hIC;
-
-    TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
-            lpBuffersOut, dwFlags, dwContext);
-
-    lpwhr = (http_request_t*) WININET_GetObject( hRequest );
-
-    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-        goto lend;
-    }
-
-    lpwhs = lpwhr->lpHttpSession;
-    assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
-    hIC = lpwhs->lpAppInfo;
-    assert(hIC->hdr.htype == WH_HINIT);
-
-    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        WORKREQUEST workRequest;
-        struct WORKREQ_HTTPSENDREQUESTW *req;
-
-        workRequest.asyncproc = AsyncHttpSendRequestProc;
-        workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
-        req = &workRequest.u.HttpSendRequestW;
-        if (lpBuffersIn)
-        {
-            /* FIXME: this should use dwHeadersLength or may not be necessary at all */
-            req->lpszHeader = heap_strdupW(lpBuffersIn->lpcszHeader);
-            req->dwHeaderLength = lpBuffersIn->dwHeadersLength;
-            req->lpOptional = lpBuffersIn->lpvBuffer;
-            req->dwOptionalLength = lpBuffersIn->dwBufferLength;
-            req->dwContentLength = lpBuffersIn->dwBufferTotal;
-        }
-        else
-        {
-            req->lpszHeader = NULL;
-            req->dwHeaderLength = 0;
-            req->lpOptional = NULL;
-            req->dwOptionalLength = 0;
-            req->dwContentLength = 0;
-        }
-
-        req->bEndRequest = FALSE;
-
-        INTERNET_AsyncCall(&workRequest);
-        /*
-         * This is from windows.
-         */
-        INTERNET_SetLastError(ERROR_IO_PENDING);
-    }
-    else
-    {
-        if (lpBuffersIn)
-            ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
-                                        lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
-                                        lpBuffersIn->dwBufferTotal, FALSE);
-        else
-            ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
-    }
-
-lend:
-    if ( lpwhr )
-        WININET_Release( &lpwhr->hdr );
-
-    TRACE("<---\n");
-    return ret;
-}
-
-/***********************************************************************
- *           HttpSendRequestW (WININET.@)
- *
- * Sends the specified request to the HTTP server
- *
- * RETURNS
- *    TRUE  on success
- *    FALSE on failure
- *
- */
-BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
-       DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
-{
-    http_request_t *lpwhr;
-    http_session_t *lpwhs = NULL;
-    appinfo_t *hIC = NULL;
-    BOOL r;
-
-    TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
-            debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
-
-    lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
-    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-       r = FALSE;
-        goto lend;
-    }
-
-    lpwhs = lpwhr->lpHttpSession;
-    if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-       r = FALSE;
-        goto lend;
-    }
-
-    hIC = lpwhs->lpAppInfo;
-    if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-       r = FALSE;
-        goto lend;
-    }
-
-    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        WORKREQUEST workRequest;
-        struct WORKREQ_HTTPSENDREQUESTW *req;
-
-        workRequest.asyncproc = AsyncHttpSendRequestProc;
-        workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
-        req = &workRequest.u.HttpSendRequestW;
-        if (lpszHeaders)
-        {
-            DWORD size;
-
-            if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
-            else size = dwHeaderLength * sizeof(WCHAR);
-
-            req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, size);
-            memcpy(req->lpszHeader, lpszHeaders, size);
-        }
-        else
-            req->lpszHeader = 0;
-        req->dwHeaderLength = dwHeaderLength;
-        req->lpOptional = lpOptional;
-        req->dwOptionalLength = dwOptionalLength;
-        req->dwContentLength = dwOptionalLength;
-        req->bEndRequest = TRUE;
-
-        INTERNET_AsyncCall(&workRequest);
-        /*
-         * This is from windows.
-         */
-        INTERNET_SetLastError(ERROR_IO_PENDING);
-        r = FALSE;
-    }
-    else
-    {
-       r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders,
-               dwHeaderLength, lpOptional, dwOptionalLength,
-               dwOptionalLength, TRUE);
-    }
-lend:
-    if( lpwhr )
-        WININET_Release( &lpwhr->hdr );
-    return r;
-}
-
-/***********************************************************************
- *           HttpSendRequestA (WININET.@)
- *
- * Sends the specified request to the HTTP server
- *
- * RETURNS
- *    TRUE  on success
- *    FALSE on failure
- *
- */
-BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
-       DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
-{
-    BOOL result;
-    LPWSTR szHeaders=NULL;
-    DWORD nLen=dwHeaderLength;
-    if(lpszHeaders!=NULL)
-    {
-        nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
-        szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR));
-        MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
-    }
-    result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
-    HeapFree(GetProcessHeap(),0,szHeaders);
-    return result;
-}
-
-/***********************************************************************
- *           HTTP_GetRedirectURL (internal)
- */
-static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl)
-{
-    static WCHAR szHttp[] = {'h','t','t','p',0};
-    static WCHAR szHttps[] = {'h','t','t','p','s',0};
-    http_session_t *lpwhs = lpwhr->lpHttpSession;
-    URL_COMPONENTSW urlComponents;
-    DWORD url_length = 0;
-    LPWSTR orig_url;
-    LPWSTR combined_url;
-
-    urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
-    urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
-    urlComponents.dwSchemeLength = 0;
-    urlComponents.lpszHostName = lpwhs->lpszHostName;
-    urlComponents.dwHostNameLength = 0;
-    urlComponents.nPort = lpwhs->nHostPort;
-    urlComponents.lpszUserName = lpwhs->lpszUserName;
-    urlComponents.dwUserNameLength = 0;
-    urlComponents.lpszPassword = NULL;
-    urlComponents.dwPasswordLength = 0;
-    urlComponents.lpszUrlPath = lpwhr->lpszPath;
-    urlComponents.dwUrlPathLength = 0;
-    urlComponents.lpszExtraInfo = NULL;
-    urlComponents.dwExtraInfoLength = 0;
-
-    if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) &&
-        (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
-        return NULL;
-
-    orig_url = HeapAlloc(GetProcessHeap(), 0, url_length);
-
-    /* convert from bytes to characters */
-    url_length = url_length / sizeof(WCHAR) - 1;
-    if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length))
-    {
-        HeapFree(GetProcessHeap(), 0, orig_url);
-        return NULL;
-    }
-
-    url_length = 0;
-    if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) &&
-        (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
-    {
-        HeapFree(GetProcessHeap(), 0, orig_url);
-        return NULL;
-    }
-    combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR));
-
-    if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY))
-    {
-        HeapFree(GetProcessHeap(), 0, orig_url);
-        HeapFree(GetProcessHeap(), 0, combined_url);
-        return NULL;
-    }
-    HeapFree(GetProcessHeap(), 0, orig_url);
-    return combined_url;
-}
-
-
-/***********************************************************************
- *           HTTP_HandleRedirect (internal)
- */
-static BOOL HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
+static DWORD HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
 {
     http_session_t *lpwhs = lpwhr->lpHttpSession;
     appinfo_t *hIC = lpwhs->lpAppInfo;
@@ -3449,7 +3374,7 @@ static BOOL HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
         urlComponents.lpszExtraInfo = NULL;
         urlComponents.dwExtraInfoLength = 0;
         if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
-            return FALSE;
+            return INTERNET_GetLastError();
 
         if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) &&
             (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE))
@@ -3516,13 +3441,20 @@ static BOOL HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
         {
             if (strcmpiW(lpwhs->lpszServerName, hostName) || lpwhs->nServerPort != urlComponents.nPort)
             {
+                DWORD res;
+
                 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
                 lpwhs->lpszServerName = heap_strdupW(hostName);
                 lpwhs->nServerPort = urlComponents.nPort;
 
                 NETCON_close(&lpwhr->netConnection);
-                if (!HTTP_ResolveName(lpwhr)) return FALSE;
-                if (!NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) return FALSE;
+                if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS)
+                    return res;
+
+                res = NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE);
+                if (res != ERROR_SUCCESS)
+                    return res;
+
                 lpwhr->read_pos = lpwhr->read_size = 0;
                 lpwhr->read_chunked = FALSE;
             }
@@ -3559,7 +3491,7 @@ static BOOL HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
     if (0 <= index)
         HTTP_DeleteCustomHeader(lpwhr, index);
 
-    return TRUE;
+    return ERROR_SUCCESS;
 }
 
 /***********************************************************************
@@ -3585,7 +3517,7 @@ static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
     return str;
 }
 
-static BOOL HTTP_SecureProxyConnect(http_request_t *lpwhr)
+static DWORD HTTP_SecureProxyConnect(http_request_t *lpwhr)
 {
     LPWSTR lpszPath;
     LPWSTR requestString;
@@ -3593,7 +3525,7 @@ static BOOL HTTP_SecureProxyConnect(http_request_t *lpwhr)
     INT cnt;
     INT responseLen;
     char *ascii_req;
-    BOOL ret;
+    DWORD res;
     static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0};
     static const WCHAR szFormat[] = {'%','s',':','%','d',0};
     http_session_t *lpwhs = lpwhr->lpHttpSession;
@@ -3615,16 +3547,16 @@ static BOOL HTTP_SecureProxyConnect(http_request_t *lpwhr)
 
     TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
 
-    ret = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt );
+    res = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt );
     HeapFree( GetProcessHeap(), 0, ascii_req );
-    if (!ret || cnt < 0)
-        return FALSE;
+    if (res != ERROR_SUCCESS)
+        return res;
 
     responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE );
     if (!responseLen)
-        return FALSE;
+        return ERROR_HTTP_INVALID_HEADER;
 
-    return TRUE;
+    return ERROR_SUCCESS;
 }
 
 static void HTTP_InsertCookies(http_request_t *lpwhr)
@@ -3667,12 +3599,12 @@ static void HTTP_InsertCookies(http_request_t *lpwhr)
  *    FALSE on failure
  *
  */
-BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
+static DWORD HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
        DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
        DWORD dwContentLength, BOOL bEndRequest)
 {
     INT cnt;
-    BOOL bSuccess = FALSE, redirected = FALSE;
+    BOOL redirected = FALSE;
     LPWSTR requestString = NULL;
     INT responseLen;
     BOOL loop_next;
@@ -3681,6 +3613,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
     static const WCHAR szContentLength[] =
         { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
     WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ];
+    DWORD res;
 
     TRACE("--> %p\n", lpwhr);
 
@@ -3724,6 +3657,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
     do
     {
         DWORD len;
+        BOOL reusing_connection;
         char *ascii_req;
 
         loop_next = FALSE;
@@ -3732,6 +3666,10 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
          * for all the data */
         HTTP_DrainContent(lpwhr);
         lpwhr->dwContentRead = 0;
+        if(redirected) {
+            lpwhr->dwContentLength = ~0u;
+            lpwhr->dwBytesToWrite = 0;
+        }
 
         if (TRACE_ON(wininet))
         {
@@ -3770,7 +3708,12 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
         TRACE("Request header -> %s\n", debugstr_w(requestString) );
 
         /* Send the request and store the results */
-        if (!HTTP_OpenConnection(lpwhr))
+        if(NETCON_connected(&lpwhr->netConnection))
+            reusing_connection = TRUE;
+        else
+            reusing_connection = FALSE;
+
+        if ((res = HTTP_OpenConnection(lpwhr)) != ERROR_SUCCESS)
             goto lend;
 
         /* send the request as ASCII, tack on the optional data */
@@ -3790,7 +3733,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
         INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                               INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
 
-        NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt);
+        res = NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt);
         HeapFree( GetProcessHeap(), 0, ascii_req );
 
         lpwhr->dwBytesWritten = dwOptionalLength;
@@ -3807,12 +3750,17 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
             INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                                 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
     
-            if (cnt < 0)
+            if (res != ERROR_SUCCESS)
                 goto lend;
     
             responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
-            if (responseLen)
-                bSuccess = TRUE;
+            /* FIXME: We should know that connection is closed before sending
+             * headers. Otherwise wrong callbacks are executed */
+            if(!responseLen && reusing_connection) {
+                TRACE("Connection closed by server, reconnecting\n");
+                loop_next = TRUE;
+                continue;
+            }
     
             INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                                 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
@@ -3823,16 +3771,18 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
             if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
 
             dwBufferSize = sizeof(dwStatusCode);
-            if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
-                                     &dwStatusCode,&dwBufferSize,NULL))
+            if (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
+                                    &dwStatusCode,&dwBufferSize,NULL) != ERROR_SUCCESS)
                 dwStatusCode = 0;
 
-            if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
+            if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && responseLen)
             {
                 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
                 dwBufferSize=sizeof(szNewLocation);
-                if ((dwStatusCode==HTTP_STATUS_REDIRECT || dwStatusCode==HTTP_STATUS_MOVED) &&
-                    HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL))
+                if ((dwStatusCode == HTTP_STATUS_REDIRECT ||
+                     dwStatusCode == HTTP_STATUS_MOVED ||
+                     dwStatusCode == HTTP_STATUS_REDIRECT_METHOD) &&
+                    HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL) == ERROR_SUCCESS)
                 {
                     if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD))
                     {
@@ -3844,8 +3794,8 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
                     {
                         INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT,
                                               new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
-                        bSuccess = HTTP_HandleRedirect(lpwhr, new_url);
-                        if (bSuccess)
+                        res = HTTP_HandleRedirect(lpwhr, new_url);
+                        if (res == ERROR_SUCCESS)
                         {
                             HeapFree(GetProcessHeap(), 0, requestString);
                             loop_next = TRUE;
@@ -3855,107 +3805,560 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
                     redirected = TRUE;
                 }
             }
-            if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && bSuccess)
+            if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && res == ERROR_SUCCESS)
             {
                 WCHAR szAuthValue[2048];
                 dwBufferSize=2048;
                 if (dwStatusCode == HTTP_STATUS_DENIED)
                 {
+                    LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
                     DWORD dwIndex = 0;
-                    while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex))
+                    while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS)
                     {
                         if (HTTP_DoAuthorization(lpwhr, szAuthValue,
                                                  &lpwhr->pAuthInfo,
                                                  lpwhr->lpHttpSession->lpszUserName,
-                                                 lpwhr->lpHttpSession->lpszPassword))
+                                                 lpwhr->lpHttpSession->lpszPassword,
+                                                 Host->lpszValue))
                         {
+                            HeapFree(GetProcessHeap(), 0, requestString);
                             loop_next = TRUE;
                             break;
                         }
                     }
+
+                    if(!loop_next) {
+                        TRACE("Cleaning wrong authorization data\n");
+                        destroy_authinfo(lpwhr->pAuthInfo);
+                        lpwhr->pAuthInfo = NULL;
+                    }
                 }
                 if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ)
                 {
                     DWORD dwIndex = 0;
-                    while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex))
+                    while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex) == ERROR_SUCCESS)
                     {
                         if (HTTP_DoAuthorization(lpwhr, szAuthValue,
                                                  &lpwhr->pProxyAuthInfo,
                                                  lpwhr->lpHttpSession->lpAppInfo->lpszProxyUsername,
-                                                 lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword))
+                                                 lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword,
+                                                 NULL))
                         {
                             loop_next = TRUE;
                             break;
                         }
                     }
+
+                    if(!loop_next) {
+                        TRACE("Cleaning wrong proxy authorization data\n");
+                        destroy_authinfo(lpwhr->pProxyAuthInfo);
+                        lpwhr->pProxyAuthInfo = NULL;
+                    }
                 }
             }
         }
         else
-            bSuccess = TRUE;
+            res = ERROR_SUCCESS;
     }
     while (loop_next);
 
-    if(bSuccess) {
-        WCHAR url[INTERNET_MAX_URL_LENGTH];
-        WCHAR cacheFileName[MAX_PATH+1];
-        BOOL b;
+    if(res == ERROR_SUCCESS) {
+        WCHAR url[INTERNET_MAX_URL_LENGTH];
+        WCHAR cacheFileName[MAX_PATH+1];
+        BOOL b;
+
+        b = HTTP_GetRequestURL(lpwhr, url);
+        if(!b) {
+            WARN("Could not get URL\n");
+            goto lend;
+        }
+
+        b = CreateUrlCacheEntryW(url, lpwhr->dwContentLength > 0 ? lpwhr->dwContentLength : 0, NULL, cacheFileName, 0);
+        if(b) {
+            HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile);
+            CloseHandle(lpwhr->hCacheFile);
+
+            lpwhr->lpszCacheFile = heap_strdupW(cacheFileName);
+            lpwhr->hCacheFile = CreateFileW(lpwhr->lpszCacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
+                      NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+            if(lpwhr->hCacheFile == INVALID_HANDLE_VALUE) {
+                WARN("Could not create file: %u\n", GetLastError());
+                lpwhr->hCacheFile = NULL;
+            }
+        }else {
+            WARN("Could not create cache entry: %08x\n", GetLastError());
+        }
+    }
+
+lend:
+
+    HeapFree(GetProcessHeap(), 0, requestString);
+
+    /* TODO: send notification for P3P header */
+
+    if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
+    {
+        if (res == ERROR_SUCCESS && lpwhr->dwBytesWritten == lpwhr->dwBytesToWrite)
+            HTTP_ReceiveRequestData(lpwhr, TRUE);
+        else
+        {
+            iar.dwResult = (res==ERROR_SUCCESS ? (DWORD_PTR)lpwhr->hdr.hInternet : 0);
+            iar.dwError = res;
+
+            INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                                  INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+                                  sizeof(INTERNET_ASYNC_RESULT));
+        }
+    }
+
+    TRACE("<--\n");
+    return res;
+}
+
+/***********************************************************************
+ *
+ * Helper functions for the HttpSendRequest(Ex) functions
+ *
+ */
+static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
+{
+    struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
+    http_request_t *lpwhr = (http_request_t*) workRequest->hdr;
+
+    TRACE("%p\n", lpwhr);
+
+    HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
+            req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
+            req->dwContentLength, req->bEndRequest);
+
+    HeapFree(GetProcessHeap(), 0, req->lpszHeader);
+}
+
+
+static DWORD HTTP_HttpEndRequestW(http_request_t *lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
+{
+    INT responseLen;
+    DWORD dwBufferSize;
+    INTERNET_ASYNC_RESULT iar;
+    DWORD res = ERROR_SUCCESS;
+
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                  INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+
+    responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
+    if (!responseLen)
+        res = ERROR_HTTP_HEADER_NOT_FOUND;
+
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                  INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
+
+    /* process cookies here. Is this right? */
+    HTTP_ProcessCookies(lpwhr);
+
+    if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
+
+    if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
+    {
+        DWORD dwCode,dwCodeLength = sizeof(DWORD);
+        if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) == ERROR_SUCCESS
+            && (dwCode == 302 || dwCode == 301 || dwCode == 303))
+        {
+            WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
+            dwBufferSize=sizeof(szNewLocation);
+            if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL) == ERROR_SUCCESS)
+            {
+                if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD))
+                {
+                    HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
+                    lpwhr->lpszVerb = heap_strdupW(szGET);
+                }
+                HTTP_DrainContent(lpwhr);
+                if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation )))
+                {
+                    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT,
+                                          new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
+                    res = HTTP_HandleRedirect(lpwhr, new_url);
+                    if (res == ERROR_SUCCESS)
+                        res = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
+                    HeapFree( GetProcessHeap(), 0, new_url );
+                }
+            }
+        }
+    }
+
+    iar.dwResult = (res==ERROR_SUCCESS ? (DWORD_PTR)lpwhr->hdr.hInternet : 0);
+    iar.dwError = res;
+
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                          INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+                          sizeof(INTERNET_ASYNC_RESULT));
+    return res;
+}
+
+/***********************************************************************
+ *           HttpEndRequestA (WININET.@)
+ *
+ * Ends an HTTP request that was started by HttpSendRequestEx
+ *
+ * RETURNS
+ *    TRUE     if successful
+ *    FALSE    on failure
+ *
+ */
+BOOL WINAPI HttpEndRequestA(HINTERNET hRequest,
+        LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
+{
+    TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
+
+    if (lpBuffersOut)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
+}
+
+static void AsyncHttpEndRequestProc(WORKREQUEST *work)
+{
+    struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
+    http_request_t *lpwhr = (http_request_t*)work->hdr;
+
+    TRACE("%p\n", lpwhr);
+
+    HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext);
+}
+
+/***********************************************************************
+ *           HttpEndRequestW (WININET.@)
+ *
+ * Ends an HTTP request that was started by HttpSendRequestEx
+ *
+ * RETURNS
+ *    TRUE     if successful
+ *    FALSE    on failure
+ *
+ */
+BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
+        LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
+{
+    http_request_t *lpwhr;
+    DWORD res;
+
+    TRACE("-->\n");
+
+    if (lpBuffersOut)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    lpwhr = (http_request_t*) WININET_GetObject( hRequest );
+
+    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+    {
+        SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+        if (lpwhr)
+            WININET_Release( &lpwhr->hdr );
+        return FALSE;
+    }
+    lpwhr->hdr.dwFlags |= dwFlags;
+
+    if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
+    {
+        WORKREQUEST work;
+        struct WORKREQ_HTTPENDREQUESTW *request;
+
+        work.asyncproc = AsyncHttpEndRequestProc;
+        work.hdr = WININET_AddRef( &lpwhr->hdr );
+
+        request = &work.u.HttpEndRequestW;
+        request->dwFlags = dwFlags;
+        request->dwContext = dwContext;
+
+        INTERNET_AsyncCall(&work);
+        res = ERROR_IO_PENDING;
+    }
+    else
+        res = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
+
+    WININET_Release( &lpwhr->hdr );
+    TRACE("%u <--\n", res);
+    if(res != ERROR_SUCCESS)
+        SetLastError(res);
+    return res == ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ *           HttpSendRequestExA (WININET.@)
+ *
+ * Sends the specified request to the HTTP server and allows chunked
+ * transfers.
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE, call GetLastError() for more information.
+ */
+BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
+                              LPINTERNET_BUFFERSA lpBuffersIn,
+                              LPINTERNET_BUFFERSA lpBuffersOut,
+                              DWORD dwFlags, DWORD_PTR dwContext)
+{
+    INTERNET_BUFFERSW BuffersInW;
+    BOOL rc = FALSE;
+    DWORD headerlen;
+    LPWSTR header = NULL;
+
+    TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
+           lpBuffersOut, dwFlags, dwContext);
+
+    if (lpBuffersIn)
+    {
+        BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
+        if (lpBuffersIn->lpcszHeader)
+        {
+            headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
+                    lpBuffersIn->dwHeadersLength,0,0);
+            header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR));
+            if (!(BuffersInW.lpcszHeader = header))
+            {
+                SetLastError(ERROR_OUTOFMEMORY);
+                return FALSE;
+            }
+            BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
+                    lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
+                    header, headerlen);
+        }
+        else
+            BuffersInW.lpcszHeader = NULL;
+        BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
+        BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
+        BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
+        BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
+        BuffersInW.Next = NULL;
+    }
+
+    rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
+
+    HeapFree(GetProcessHeap(),0,header);
+
+    return rc;
+}
+
+/***********************************************************************
+ *           HttpSendRequestExW (WININET.@)
+ *
+ * Sends the specified request to the HTTP server and allows chunked
+ * transfers
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE, call GetLastError() for more information.
+ */
+BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
+                   LPINTERNET_BUFFERSW lpBuffersIn,
+                   LPINTERNET_BUFFERSW lpBuffersOut,
+                   DWORD dwFlags, DWORD_PTR dwContext)
+{
+    http_request_t *lpwhr;
+    http_session_t *lpwhs;
+    appinfo_t *hIC;
+    DWORD res;
+
+    TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
+            lpBuffersOut, dwFlags, dwContext);
+
+    lpwhr = (http_request_t*) WININET_GetObject( hRequest );
+
+    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+    {
+        res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+        goto lend;
+    }
+
+    lpwhs = lpwhr->lpHttpSession;
+    assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
+    hIC = lpwhs->lpAppInfo;
+    assert(hIC->hdr.htype == WH_HINIT);
+
+    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
+    {
+        WORKREQUEST workRequest;
+        struct WORKREQ_HTTPSENDREQUESTW *req;
+
+        workRequest.asyncproc = AsyncHttpSendRequestProc;
+        workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
+        req = &workRequest.u.HttpSendRequestW;
+        if (lpBuffersIn)
+        {
+            DWORD size = 0;
 
-        b = HTTP_GetRequestURL(lpwhr, url);
-        if(!b) {
-            WARN("Could not get URL\n");
-            goto lend;
-        }
+            if (lpBuffersIn->lpcszHeader)
+            {
+                if (lpBuffersIn->dwHeadersLength == ~0u)
+                    size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR);
+                else
+                    size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR);
 
-        b = CreateUrlCacheEntryW(url, lpwhr->dwContentLength > 0 ? lpwhr->dwContentLength : 0, NULL, cacheFileName, 0);
-        if(b) {
-            lpwhr->lpszCacheFile = heap_strdupW(cacheFileName);
-            lpwhr->hCacheFile = CreateFileW(lpwhr->lpszCacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
-                      NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
-            if(lpwhr->hCacheFile == INVALID_HANDLE_VALUE) {
-                WARN("Could not create file: %u\n", GetLastError());
-                lpwhr->hCacheFile = NULL;
+                req->lpszHeader = HeapAlloc( GetProcessHeap(), 0, size );
+                memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size );
             }
-        }else {
-            WARN("Could not create cache entry: %08x\n", GetLastError());
+            else req->lpszHeader = NULL;
+
+            req->dwHeaderLength = size / sizeof(WCHAR);
+            req->lpOptional = lpBuffersIn->lpvBuffer;
+            req->dwOptionalLength = lpBuffersIn->dwBufferLength;
+            req->dwContentLength = lpBuffersIn->dwBufferTotal;
         }
+        else
+        {
+            req->lpszHeader = NULL;
+            req->dwHeaderLength = 0;
+            req->lpOptional = NULL;
+            req->dwOptionalLength = 0;
+            req->dwContentLength = 0;
+        }
+
+        req->bEndRequest = FALSE;
+
+        INTERNET_AsyncCall(&workRequest);
+        /*
+         * This is from windows.
+         */
+        res = ERROR_IO_PENDING;
+    }
+    else
+    {
+        if (lpBuffersIn)
+            res = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
+                                        lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
+                                        lpBuffersIn->dwBufferTotal, FALSE);
+        else
+            res = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
     }
 
 lend:
+    if ( lpwhr )
+        WININET_Release( &lpwhr->hdr );
 
-    HeapFree(GetProcessHeap(), 0, requestString);
+    TRACE("<---\n");
+    SetLastError(res);
+    return res == ERROR_SUCCESS;
+}
 
-    /* TODO: send notification for P3P header */
+/***********************************************************************
+ *           HttpSendRequestW (WININET.@)
+ *
+ * Sends the specified request to the HTTP server
+ *
+ * RETURNS
+ *    TRUE  on success
+ *    FALSE on failure
+ *
+ */
+BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
+       DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
+{
+    http_request_t *lpwhr;
+    http_session_t *lpwhs = NULL;
+    appinfo_t *hIC = NULL;
+    DWORD res = ERROR_SUCCESS;
 
-    if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
+    TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
+            debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
+
+    lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
+    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+    {
+        res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+        goto lend;
+    }
+
+    lpwhs = lpwhr->lpHttpSession;
+    if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
+    {
+        res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+        goto lend;
+    }
+
+    hIC = lpwhs->lpAppInfo;
+    if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT)
+    {
+        res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
+        goto lend;
+    }
+
+    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
     {
-        if (bSuccess)
+        WORKREQUEST workRequest;
+        struct WORKREQ_HTTPSENDREQUESTW *req;
+
+        workRequest.asyncproc = AsyncHttpSendRequestProc;
+        workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
+        req = &workRequest.u.HttpSendRequestW;
+        if (lpszHeaders)
         {
-            if (lpwhr->dwBytesWritten == lpwhr->dwBytesToWrite) HTTP_ReceiveRequestData(lpwhr, TRUE);
-            else
-            {
-                iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
-                iar.dwError = 0;
+            DWORD size;
 
-                INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                                  INTERNET_STATUS_REQUEST_COMPLETE, &iar,
-                                  sizeof(INTERNET_ASYNC_RESULT));
-            }
+            if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
+            else size = dwHeaderLength * sizeof(WCHAR);
+
+            req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, size);
+            memcpy(req->lpszHeader, lpszHeaders, size);
         }
         else
-        {
-            iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
-            iar.dwError = INTERNET_GetLastError();
+            req->lpszHeader = 0;
+        req->dwHeaderLength = dwHeaderLength;
+        req->lpOptional = lpOptional;
+        req->dwOptionalLength = dwOptionalLength;
+        req->dwContentLength = dwOptionalLength;
+        req->bEndRequest = TRUE;
 
-            INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                                  INTERNET_STATUS_REQUEST_COMPLETE, &iar,
-                                  sizeof(INTERNET_ASYNC_RESULT));
-        }
+        INTERNET_AsyncCall(&workRequest);
+        /*
+         * This is from windows.
+         */
+        res = ERROR_IO_PENDING;
+    }
+    else
+    {
+       res = HTTP_HttpSendRequestW(lpwhr, lpszHeaders,
+               dwHeaderLength, lpOptional, dwOptionalLength,
+               dwOptionalLength, TRUE);
     }
+lend:
+    if( lpwhr )
+        WININET_Release( &lpwhr->hdr );
 
-    TRACE("<--\n");
-    if (bSuccess) INTERNET_SetLastError(ERROR_SUCCESS);
-    return bSuccess;
+    SetLastError(res);
+    return res == ERROR_SUCCESS;
+}
+
+/***********************************************************************
+ *           HttpSendRequestA (WININET.@)
+ *
+ * Sends the specified request to the HTTP server
+ *
+ * RETURNS
+ *    TRUE  on success
+ *    FALSE on failure
+ *
+ */
+BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
+       DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
+{
+    BOOL result;
+    LPWSTR szHeaders=NULL;
+    DWORD nLen=dwHeaderLength;
+    if(lpszHeaders!=NULL)
+    {
+        nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
+        szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
+    }
+    result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
+    HeapFree(GetProcessHeap(),0,szHeaders);
+    return result;
 }
 
 /***********************************************************************
@@ -3993,7 +4396,7 @@ static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *b
         return ERROR_SUCCESS;
     }
 
-    return INET_QueryOption(option, buffer, size, unicode);
+    return INET_QueryOption(hdr, option, buffer, size, unicode);
 }
 
 static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
@@ -4042,30 +4445,25 @@ static const object_vtbl_t HTTPSESSIONVtbl = {
  *   NULL on failure
  *
  */
-HINTERNET HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
-       INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
-       LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
-       DWORD dwInternalFlags)
+DWORD HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
+        INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
+        LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
+        DWORD dwInternalFlags, HINTERNET *ret)
 {
     http_session_t *lpwhs = NULL;
     HINTERNET handle = NULL;
+    DWORD res = ERROR_SUCCESS;
 
     TRACE("-->\n");
 
     if (!lpszServerName || !lpszServerName[0])
-    {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
-        goto lerror;
-    }
+        return ERROR_INVALID_PARAMETER;
 
     assert( hIC->hdr.htype == WH_HINIT );
 
     lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_session_t));
-    if (NULL == lpwhs)
-    {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-       goto lerror;
-    }
+    if (!lpwhs)
+        return ERROR_OUTOFMEMORY;
 
    /*
     * According to my tests. The name is not resolved until a request is sent
@@ -4087,21 +4485,16 @@ HINTERNET HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
     if (NULL == handle)
     {
         ERR("Failed to alloc handle\n");
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-       goto lerror;
+        res = ERROR_OUTOFMEMORY;
+        goto lerror;
     }
 
     if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
-        if(strchrW(hIC->lpszProxy, ' '))
-            FIXME("Several proxies not implemented.\n");
         if(hIC->lpszProxyBypass)
             FIXME("Proxy bypass is ignored.\n");
     }
-    if (lpszServerName && lpszServerName[0])
-    {
-        lpwhs->lpszServerName = heap_strdupW(lpszServerName);
-        lpwhs->lpszHostName = heap_strdupW(lpszServerName);
-    }
+    lpwhs->lpszServerName = heap_strdupW(lpszServerName);
+    lpwhs->lpszHostName = heap_strdupW(lpszServerName);
     if (lpszUserName && lpszUserName[0])
         lpwhs->lpszUserName = heap_strdupW(lpszUserName);
     if (lpszPassword && lpszPassword[0])
@@ -4127,7 +4520,10 @@ lerror:
  */
 
     TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs);
-    return handle;
+
+    if(res == ERROR_SUCCESS)
+        *ret = handle;
+    return res;
 }
 
 
@@ -4141,29 +4537,26 @@ lerror:
  *   TRUE  on success
  *   FALSE on failure
  */
-static BOOL HTTP_OpenConnection(http_request_t *lpwhr)
+static DWORD HTTP_OpenConnection(http_request_t *lpwhr)
 {
-    BOOL bSuccess = FALSE;
     http_session_t *lpwhs;
     appinfo_t *hIC = NULL;
     char szaddr[INET6_ADDRSTRLEN];
     const void *addr;
+    DWORD res = ERROR_SUCCESS;
 
     TRACE("-->\n");
 
 
     if (lpwhr->hdr.htype != WH_HHTTPREQ)
     {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        res = ERROR_INVALID_PARAMETER;
         goto lend;
     }
 
     if (NETCON_connected(&lpwhr->netConnection))
-    {
-        bSuccess = TRUE;
         goto lend;
-    }
-    if (!HTTP_ResolveName(lpwhr)) goto lend;
+    if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS) goto lend;
 
     lpwhs = lpwhr->lpHttpSession;
 
@@ -4178,8 +4571,7 @@ static BOOL HTTP_OpenConnection(http_request_t *lpwhr)
         break;
     default:
         WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family);
-        INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
-        return FALSE;
+        return ERROR_INTERNET_NAME_NOT_RESOLVED;
     }
     inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr));
     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
@@ -4187,17 +4579,22 @@ static BOOL HTTP_OpenConnection(http_request_t *lpwhr)
                           szaddr,
                           strlen(szaddr)+1);
 
-    if (!NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.ss_family,
-                         SOCK_STREAM, 0))
+    res = NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.ss_family, SOCK_STREAM, 0);
+    if (res != ERROR_SUCCESS)
     {
-        WARN("Socket creation failed: %u\n", INTERNET_GetLastError());
+        WARN("Socket creation failed: %u\n", res);
         goto lend;
     }
 
-    if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
-                      lpwhs->sa_len))
+    res = NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
+                         lpwhs->sa_len);
+    if(res != ERROR_SUCCESS)
        goto lend;
 
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+            INTERNET_STATUS_CONNECTED_TO_SERVER,
+            szaddr, strlen(szaddr)+1);
+
     if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)
     {
         /* Note: we differ from Microsoft's WinINet here. they seem to have
@@ -4206,28 +4603,38 @@ static BOOL HTTP_OpenConnection(http_request_t *lpwhr)
          * behaviour to be more correct and to not cause any incompatibilities
          * because using a secure connection through a proxy server is a rare
          * case that would be hard for anyone to depend on */
-        if (hIC->lpszProxy && !HTTP_SecureProxyConnect(lpwhr))
+        if (hIC->lpszProxy && (res = HTTP_SecureProxyConnect(lpwhr)) != ERROR_SUCCESS) {
+            HTTPREQ_CloseConnection(&lpwhr->hdr);
             goto lend;
+        }
 
-        if (!NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName))
+        res = NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName);
+        if(res != ERROR_SUCCESS)
         {
             WARN("Couldn't connect securely to host\n");
+
+            if((lpwhr->hdr.ErrorMask&INTERNET_ERROR_MASK_COMBINED_SEC_CERT) && (
+                    res == ERROR_INTERNET_SEC_CERT_DATE_INVALID
+                    || res == ERROR_INTERNET_INVALID_CA
+                    || res == ERROR_INTERNET_SEC_CERT_NO_REV
+                    || res == ERROR_INTERNET_SEC_CERT_REV_FAILED
+                    || res == ERROR_INTERNET_SEC_CERT_REVOKED
+                    || res == ERROR_INTERNET_SEC_INVALID_CERT
+                    || res == ERROR_INTERNET_SEC_CERT_CN_INVALID))
+                res = ERROR_INTERNET_SEC_CERT_ERRORS;
+
+            HTTPREQ_CloseConnection(&lpwhr->hdr);
             goto lend;
         }
     }
 
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                          INTERNET_STATUS_CONNECTED_TO_SERVER,
-                          szaddr, strlen(szaddr)+1);
-
-    bSuccess = TRUE;
 
 lend:
     lpwhr->read_pos = lpwhr->read_size = 0;
     lpwhr->read_chunked = FALSE;
 
-    TRACE("%d <--\n", bSuccess);
-    return bSuccess;
+    TRACE("%d <--\n", res);
+    return res;
 }
 
 
@@ -4273,16 +4680,13 @@ static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
     char bufferA[MAX_REPLY_LEN];
     LPWSTR status_code = NULL, status_text = NULL;
     DWORD cchMaxRawHeaders = 1024;
-    LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+    LPWSTR lpszRawHeaders = NULL;
     LPWSTR temp;
     DWORD cchRawHeaders = 0;
     BOOL codeHundred = FALSE;
 
     TRACE("-->\n");
 
-    /* clear old response headers (eg. from a redirect response) */
-    if (clear) HTTP_clear_response_headers( lpwhr );
-
     if (!NETCON_connected(&lpwhr->netConnection))
         goto lend;
 
@@ -4294,6 +4698,13 @@ static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
         buflen = MAX_REPLY_LEN;
         if (!read_line(lpwhr, bufferA, &buflen))
             goto lend;
+
+        /* clear old response headers (eg. from a redirect response) */
+        if (clear) {
+            HTTP_clear_response_headers( lpwhr );
+            clear = FALSE;
+        }
+
         rc += buflen;
         MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
         /* check is this a status code line? */
@@ -4318,7 +4729,18 @@ static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
         }
         else if (!codeHundred)
         {
-            FIXME("Non status line at head of response (%s)\n",debugstr_w(buffer));
+            WARN("No status line at head of response (%s)\n", debugstr_w(buffer));
+
+            HeapFree(GetProcessHeap(), 0, lpwhr->lpszVersion);
+            HeapFree(GetProcessHeap(), 0, lpwhr->lpszStatusText);
+
+            lpwhr->lpszVersion = heap_strdupW(g_szHttp1_0);
+            lpwhr->lpszStatusText = heap_strdupW(szOK);
+
+            HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
+            lpwhr->lpszRawHeaders = heap_strdupW(szDefaultHeader);
+
+            bSuccess = TRUE;
             goto lend;
         }
     } while (codeHundred);
@@ -4338,6 +4760,9 @@ static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
     *(status_text-1) = ' ';
 
     /* regenerate raw headers */
+    lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders + 1) * sizeof(WCHAR));
+    if (!lpszRawHeaders) goto lend;
+
     while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
         cchMaxRawHeaders *= 2;
     temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
@@ -4420,27 +4845,6 @@ lend:
     }
 }
 
-
-static void strip_spaces(LPWSTR start)
-{
-    LPWSTR str = start;
-    LPWSTR end;
-
-    while (*str == ' ' && *str != '\0')
-        str++;
-
-    if (str != start)
-        memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1));
-
-    end = start + strlenW(start) - 1;
-    while (end >= start && *end == ' ')
-    {
-        *end = '\0';
-        end--;
-    }
-}
-
-
 /***********************************************************************
  *           HTTP_InterpretHttpHeader (internal)
  *
@@ -4505,12 +4909,12 @@ static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer)
 
 #define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
 
-static BOOL HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
+static DWORD HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
 {
     LPHTTPHEADERW lphttpHdr = NULL;
-    BOOL bSuccess = FALSE;
     INT index = -1;
     BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ;
+    DWORD res = ERROR_HTTP_INVALID_HEADER;
 
     TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier);
 
@@ -4526,9 +4930,7 @@ static BOOL HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR val
     if (index >= 0)
     {
         if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
-        {
-            return FALSE;
-        }
+            return ERROR_HTTP_INVALID_HEADER;
         lphttpHdr = &lpwhr->pCustHeaders[index];
     }
     else if (value)
@@ -4545,7 +4947,7 @@ static BOOL HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR val
         return HTTP_InsertCustomHeader(lpwhr, &hdr);
     }
     /* no value to delete */
-    else return TRUE;
+    else return ERROR_SUCCESS;
 
     if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
            lphttpHdr->wFlags |= HDR_ISREQUEST;
@@ -4570,7 +4972,7 @@ static BOOL HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR val
             return HTTP_InsertCustomHeader(lpwhr, &hdr);
         }
 
-        return TRUE;
+        return ERROR_SUCCESS;
     }
     else if (dwModifier & COALESCEFLAGS)
     {
@@ -4608,16 +5010,16 @@ static BOOL HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR val
 
             memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
             lphttpHdr->lpszValue[len] = '\0';
-            bSuccess = TRUE;
+            res = ERROR_SUCCESS;
         }
         else
         {
             WARN("HeapReAlloc (%d bytes) failed\n",len+1);
-            INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+            res = ERROR_OUTOFMEMORY;
         }
     }
-    TRACE("<-- %d\n",bSuccess);
-    return bSuccess;
+    TRACE("<-- %d\n", res);
+    return res;
 }
 
 
@@ -4656,7 +5058,7 @@ static INT HTTP_GetCustomHeaderIndex(http_request_t *lpwhr, LPCWSTR lpszField,
 {
     DWORD index;
 
-    TRACE("%s\n", debugstr_w(lpszField));
+    TRACE("%s, %d, %d\n", debugstr_w(lpszField), requested_index, request_only);
 
     for (index = 0; index < lpwhr->nCustHeaders; index++)
     {
@@ -4688,11 +5090,10 @@ static INT HTTP_GetCustomHeaderIndex(http_request_t *lpwhr, LPCWSTR lpszField,
  * Insert header into array
  *
  */
-static BOOL HTTP_InsertCustomHeader(http_request_t *lpwhr, LPHTTPHEADERW lpHdr)
+static DWORD HTTP_InsertCustomHeader(http_request_t *lpwhr, LPHTTPHEADERW lpHdr)
 {
     INT count;
     LPHTTPHEADERW lph = NULL;
-    BOOL r = FALSE;
 
     TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
     count = lpwhr->nCustHeaders + 1;
@@ -4701,22 +5102,17 @@ static BOOL HTTP_InsertCustomHeader(http_request_t *lpwhr, LPHTTPHEADERW lpHdr)
     else
        lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
 
-    if (NULL != lph)
-    {
-       lpwhr->pCustHeaders = lph;
-        lpwhr->pCustHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField);
-        lpwhr->pCustHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue);
-        lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
-        lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
-       lpwhr->nCustHeaders++;
-        r = TRUE;
-    }
-    else
-    {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-    }
+    if (!lph)
+        return ERROR_OUTOFMEMORY;
 
-    return r;
+    lpwhr->pCustHeaders = lph;
+    lpwhr->pCustHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField);
+    lpwhr->pCustHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue);
+    lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
+    lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
+    lpwhr->nCustHeaders++;
+
+    return ERROR_SUCCESS;
 }
 
 
@@ -4755,9 +5151,9 @@ static BOOL HTTP_VerifyValidHeader(http_request_t *lpwhr, LPCWSTR field)
 {
     /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */
     if (!strcmpW(lpwhr->lpszVersion, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding))
-        return FALSE;
+        return ERROR_HTTP_INVALID_HEADER;
 
-    return TRUE;
+    return ERROR_SUCCESS;
 }
 
 /***********************************************************************
@@ -4771,3 +5167,21 @@ BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
    FIXME("STUB: flags=%d host=%s length=%d\n",flags,szHost,length);
    return FALSE;
 }
+
+/***********************************************************************
+ *           InternetShowSecurityInfoByURLA (@)
+ */
+BOOL WINAPI InternetShowSecurityInfoByURLA(LPCSTR url, HWND window)
+{
+   FIXME("stub: %s %p\n", url, window);
+   return FALSE;
+}
+
+/***********************************************************************
+ *           InternetShowSecurityInfoByURLW (@)
+ */
+BOOL WINAPI InternetShowSecurityInfoByURLW(LPCWSTR url, HWND window)
+{
+   FIXME("stub: %s %p\n", debugstr_w(url), window);
+   return FALSE;
+}