Sync to trunk (r44371)
[reactos.git] / reactos / dll / win32 / wininet / http.c
index 87d5e72..0ab508d 100644 (file)
 #include "config.h"
 #include "wine/port.h"
 
-#if defined(__MINGW32__) || defined (_MSC_VER)
-#include <ws2tcpip.h>
-#endif
-
 #include <sys/types.h>
 #ifdef HAVE_SYS_SOCKET_H
 # include <sys/socket.h>
@@ -48,9 +44,6 @@
 #endif
 #include <time.h>
 #include <assert.h>
-#ifdef HAVE_ZLIB
-#  include <zlib.h>
-#endif
 
 #include "windef.h"
 #include "winbase.h"
@@ -66,7 +59,6 @@
 
 #include "internet.h"
 #include "wine/debug.h"
-#include "wine/exception.h"
 #include "wine/unicode.h"
 
 #include "inet_ntop.c"
@@ -75,75 +67,23 @@ 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 hostW[] = { 'H','o','s','t',0 };
+static const WCHAR g_szReferer[] = {'R','e','f','e','r','e','r',0};
+static const WCHAR g_szAccept[] = {'A','c','c','e','p','t',0};
+static const WCHAR g_szUserAgent[] = {'U','s','e','r','-','A','g','e','n','t',0};
+static const WCHAR szHost[] = { '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 };
 static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 };
 static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0};
 static const WCHAR szGET[] = { 'G','E','T', 0 };
-static const WCHAR szHEAD[] = { 'H','E','A','D', 0 };
-static const WCHAR szCrLf[] = {'\r','\n', 0};
-
-static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 };
-static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 };
-static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 };
-static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 };
-static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
-static const WCHAR szAge[] = { 'A','g','e',0 };
-static const WCHAR szAllow[] = { 'A','l','l','o','w',0 };
-static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 };
-static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 };
-static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 };
-static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 };
-static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 };
-static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 };
-static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 };
-static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 };
-static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 };
-static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 };
-static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
-static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 };
-static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 };
-static const WCHAR szDate[] = { 'D','a','t','e',0 };
-static const WCHAR szFrom[] = { 'F','r','o','m',0 };
-static const WCHAR szETag[] = { 'E','T','a','g',0 };
-static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 };
-static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
-static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 };
-static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
-static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 };
-static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 };
-static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
-static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 };
-static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 };
-static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 };
-static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 };
-static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 };
-static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
-static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 };
-static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 };
-static const WCHAR szRange[] = { 'R','a','n','g','e',0 };
-static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 };
-static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 };
-static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 };
-static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
-static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
-static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
-static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 };
-static const WCHAR szURI[] = { 'U','R','I',0 };
-static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 };
-static const WCHAR szVary[] = { 'V','a','r','y',0 };
-static const WCHAR szVia[] = { 'V','i','a',0 };
-static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 };
-static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
 
 #define MAXHOSTNAME 100
 #define MAX_FIELD_VALUE_LEN 256
 #define MAX_FIELD_LEN 256
 
-#define HTTP_REFERER    szReferer
-#define HTTP_ACCEPT     szAccept
-#define HTTP_USERAGENT  szUser_Agent
+#define HTTP_REFERER    g_szReferer
+#define HTTP_ACCEPT     g_szAccept
+#define HTTP_USERAGENT  g_szUserAgent
 
 #define HTTP_ADDHDR_FLAG_ADD                           0x20000000
 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW                    0x10000000
@@ -168,55 +108,23 @@ struct HttpAuthInfo
     BOOL finished; /* finished authenticating */
 };
 
-
-struct gzip_stream_t {
-#ifdef HAVE_ZLIB
-    z_stream zstream;
-#endif
-    BYTE buf[8192];
-    DWORD buf_size;
-    DWORD buf_pos;
-    BOOL end_of_data;
-};
-
-typedef struct _authorizationData
-{
-    struct list entry;
-
-    LPWSTR lpszwHost;
-    LPWSTR lpszwRealm;
-    LPSTR  lpszAuthorization;
-    UINT   AuthorizationLen;
-} authorizationData;
-
-static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache);
-
-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 BOOL 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 BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr);
+static BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear);
+static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
 static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
-static BOOL 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 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr);
+static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField, INT index, BOOL Request);
+static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index);
 static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
-static BOOL 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 BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW lpwhr, DWORD
+        dwInfoLevel, LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD
+        lpdwIndex);
+static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, 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);
-static BOOL HTTP_FinishedReading(http_request_t *req);
+static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field);
+static void HTTP_DrainContent(WININETHTTPREQW *req);
 
-static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head)
+LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head)
 {
     int HeaderIndex = 0;
     HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
@@ -226,91 +134,6 @@ static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head)
         return &req->pCustHeaders[HeaderIndex];
 }
 
-#ifdef HAVE_ZLIB
-
-static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size)
-{
-    return HeapAlloc(GetProcessHeap(), 0, items*size);
-}
-
-static void wininet_zfree(voidpf opaque, voidpf address)
-{
-    HeapFree(GetProcessHeap(), 0, address);
-}
-
-static void init_gzip_stream(http_request_t *req)
-{
-    gzip_stream_t *gzip_stream;
-    int index, zres;
-
-    gzip_stream = HeapAlloc(GetProcessHeap(), 0, sizeof(gzip_stream_t));
-    gzip_stream->zstream.zalloc = wininet_zalloc;
-    gzip_stream->zstream.zfree = wininet_zfree;
-    gzip_stream->zstream.opaque = NULL;
-    gzip_stream->zstream.next_in = NULL;
-    gzip_stream->zstream.avail_in = 0;
-    gzip_stream->zstream.next_out = NULL;
-    gzip_stream->zstream.avail_out = 0;
-    gzip_stream->buf_pos = 0;
-    gzip_stream->buf_size = 0;
-    gzip_stream->end_of_data = FALSE;
-
-    zres = inflateInit2(&gzip_stream->zstream, 0x1f);
-    if(zres != Z_OK) {
-        ERR("inflateInit failed: %d\n", zres);
-        HeapFree(GetProcessHeap(), 0, gzip_stream);
-        return;
-    }
-
-    req->gzip_stream = gzip_stream;
-
-    index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE);
-    if(index != -1)
-        HTTP_DeleteCustomHeader(req, index);
-}
-
-#else
-
-static void init_gzip_stream(http_request_t *req)
-{
-    ERR("gzip stream not supported, missing zlib.\n");
-}
-
-#endif
-
-/* set the request content length based on the headers */
-static DWORD set_content_length( http_request_t *lpwhr )
-{
-    static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
-    WCHAR encoding[20];
-    DWORD size;
-
-    size = sizeof(lpwhr->dwContentLength);
-    if (!HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
-                             &lpwhr->dwContentLength, &size, NULL))
-        lpwhr->dwContentLength = ~0u;
-
-    size = sizeof(encoding);
-    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) &&
-        !strcmpiW(encoding, szChunked))
-    {
-        lpwhr->dwContentLength = ~0u;
-        lpwhr->read_chunked = TRUE;
-    }
-
-    if(lpwhr->decoding) {
-        int encoding_idx;
-
-        static const WCHAR gzipW[] = {'g','z','i','p',0};
-
-        encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE);
-        if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW))
-            init_gzip_stream(lpwhr);
-    }
-
-    return lpwhr->dwContentLength;
-}
-
 /***********************************************************************
  *           HTTP_Tokenize (internal)
  *
@@ -323,14 +146,11 @@ static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string)
     int i;
     LPCWSTR next_token;
 
-    if (string)
-    {
         /* empty string has no tokens */
         if (*string)
             tokens++;
         /* count tokens */
         for (i = 0; string[i]; i++)
-        {
             if (!strncmpW(string+i, token_string, strlenW(token_string)))
             {
                 DWORD j;
@@ -341,8 +161,6 @@ static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string)
                         break;
                 i += j;
             }
-        }
-    }
 
     /* add 1 for terminating NULL */
     token_array = HeapAlloc(GetProcessHeap(), 0, (tokens+1) * sizeof(*token_array));
@@ -384,7 +202,7 @@ static void HTTP_FreeTokens(LPWSTR * token_array)
 static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
-    http_request_t *lpwhr = (http_request_t*) workRequest->hdr;
+    LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest->hdr;
 
     TRACE("%p\n", lpwhr);
 
@@ -395,14 +213,14 @@ static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
     HeapFree(GetProcessHeap(), 0, req->lpszHeader);
 }
 
-static void HTTP_FixURL(http_request_t *lpwhr)
+static void HTTP_FixURL( LPWININETHTTPREQW lpwhr)
 {
     static const WCHAR szSlash[] = { '/',0 };
     static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
 
     /* If we don't have a path we set it to root */
     if (NULL == lpwhr->lpszPath)
-        lpwhr->lpszPath = heap_strdupW(szSlash);
+        lpwhr->lpszPath = WININET_strdupW(szSlash);
     else /* remove \r and \n*/
     {
         int nLen = strlenW(lpwhr->lpszPath);
@@ -431,7 +249,7 @@ static void HTTP_FixURL(http_request_t *lpwhr)
     }
 }
 
-static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
+static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
 {
     LPWSTR requestString;
     DWORD len, n;
@@ -440,6 +258,7 @@ static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb
     LPWSTR p;
 
     static const WCHAR szSpace[] = { ' ',0 };
+    static const WCHAR szcrlf[] = {'\r','\n', 0};
     static const WCHAR szColon[] = { ':',' ',0 };
     static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
 
@@ -460,7 +279,7 @@ static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb
     {
         if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
         {
-            req[n++] = szCrLf;
+            req[n++] = szcrlf;
             req[n++] = lpwhr->pCustHeaders[i].lpszField;
             req[n++] = szColon;
             req[n++] = lpwhr->pCustHeaders[i].lpszValue;
@@ -490,176 +309,103 @@ static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb
     return requestString;
 }
 
-static void HTTP_ProcessCookies( http_request_t *lpwhr )
+static void HTTP_ProcessCookies( LPWININETHTTPREQW lpwhr )
 {
+    static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
     int HeaderIndex;
-    int numCookies = 0;
     LPHTTPHEADERW setCookieHeader;
 
-    while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1)
-    {
+    HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, 0, FALSE);
+    if (HeaderIndex == -1)
+            return;
         setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex];
 
         if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue)
         {
-            int len;
-            static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0};
+        int nPosStart = 0, nPosEnd = 0, len;
+        static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','/',0};
+
+        while (setCookieHeader->lpszValue[nPosEnd] != '\0')
+        {
+            LPWSTR buf_cookie, cookie_name, cookie_data;
             LPWSTR buf_url;
+            LPWSTR domain = NULL;
             LPHTTPHEADERW Host;
 
-            Host = HTTP_GetHeader(lpwhr, hostW);
-            len = lstrlenW(Host->lpszValue) + 9 + lstrlenW(lpwhr->lpszPath);
-            buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
-            sprintfW(buf_url, szFmt, Host->lpszValue, lpwhr->lpszPath);
-            InternetSetCookieW(buf_url, NULL, setCookieHeader->lpszValue);
-
-            HeapFree(GetProcessHeap(), 0, buf_url);
-        }
-        numCookies++;
-    }
-}
-
-static void strip_spaces(LPWSTR start)
+            int nEqualPos = 0;
+            while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' &&
+                   setCookieHeader->lpszValue[nPosEnd] != '\0')
 {
-    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--;
+                nPosEnd++;
     }
-}
-
-static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm )
+            if (setCookieHeader->lpszValue[nPosEnd] == ';')
 {
-    static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
-    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)
+                /* fixme: not case sensitive, strcasestr is gnu only */
+                int nDomainPosEnd = 0;
+                int nDomainPosStart = 0, nDomainLength = 0;
+                static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0};
+                LPWSTR lpszDomain = strstrW(&setCookieHeader->lpszValue[nPosEnd], szDomain);
+                if (lpszDomain)
+                { /* they have specified their own domain, lets use it */
+                    while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' &&
+                           lpszDomain[nDomainPosEnd] != '\0')
     {
-        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);
+                        nDomainPosEnd++;
         }
+                    nDomainPosStart = strlenW(szDomain);
+                    nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1;
+                    domain = HeapAlloc(GetProcessHeap(), 0, (nDomainLength + 1)*sizeof(WCHAR));
+                    lstrcpynW(domain, &lpszDomain[nDomainPosStart], nDomainLength + 1);
     }
-
-    return is_basic;
 }
-
-static void destroy_authinfo( struct HttpAuthInfo *authinfo )
+            if (setCookieHeader->lpszValue[nPosEnd] == '\0') break;
+            buf_cookie = HeapAlloc(GetProcessHeap(), 0, ((nPosEnd - nPosStart) + 1)*sizeof(WCHAR));
+            lstrcpynW(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart) + 1);
+            TRACE("%s\n", debugstr_w(buf_cookie));
+            while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0')
 {
-    if (!authinfo) return;
-
-    if (SecIsValidHandle(&authinfo->ctx))
-        DeleteSecurityContext(&authinfo->ctx);
-    if (SecIsValidHandle(&authinfo->cred))
-        FreeCredentialsHandle(&authinfo->cred);
-
-    HeapFree(GetProcessHeap(), 0, authinfo->auth_data);
-    HeapFree(GetProcessHeap(), 0, authinfo->scheme);
-    HeapFree(GetProcessHeap(), 0, authinfo);
+                nEqualPos++;
 }
-
-static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data)
+            if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0')
 {
-    authorizationData *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, authorizationData, 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;
+                HeapFree(GetProcessHeap(), 0, buf_cookie);
             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;
-    authorizationData* ad = NULL;
+            cookie_name = HeapAlloc(GetProcessHeap(), 0, (nEqualPos + 1)*sizeof(WCHAR));
+            lstrcpynW(cookie_name, buf_cookie, nEqualPos + 1);
+            cookie_data = &buf_cookie[nEqualPos + 1];
 
-    TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len));
+            Host = HTTP_GetHeader(lpwhr,szHost);
+            len = lstrlenW((domain ? domain : (Host?Host->lpszValue:NULL))) + 
+                strlenW(lpwhr->lpszPath) + 9;
+            buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
+            sprintfW(buf_url, szFmt, (domain ? domain : (Host?Host->lpszValue:NULL))); /* FIXME PATH!!! */
+            InternetSetCookieW(buf_url, cookie_name, cookie_data);
 
-    EnterCriticalSection(&authcache_cs);
-    LIST_FOR_EACH(cursor, &basicAuthorizationCache)
-    {
-        authorizationData *check = LIST_ENTRY(cursor,authorizationData,entry);
-        if (!strcmpiW(host,check->lpszwHost) && !strcmpW(realm,check->lpszwRealm))
-        {
-            ad = check;
-            break;
+            HeapFree(GetProcessHeap(), 0, buf_url);
+            HeapFree(GetProcessHeap(), 0, buf_cookie);
+            HeapFree(GetProcessHeap(), 0, cookie_name);
+            HeapFree(GetProcessHeap(), 0, domain);
+            nPosStart = nPosEnd;
         }
     }
+}
 
-    if (ad)
+static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue )
     {
-        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(authorizationData));
-        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");
+    static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
+    return !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) &&
+        ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]);
     }
-    LeaveCriticalSection(&authcache_cs);
-}
 
-static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
+static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue,
                                   struct HttpAuthInfo **ppAuthInfo,
-                                  LPWSTR domain_and_username, LPWSTR password,
-                                  LPWSTR host )
+                                  LPWSTR domain_and_username, LPWSTR password )
 {
     SECURITY_STATUS sec_status;
     struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
     BOOL first = FALSE;
-    LPWSTR szRealm = NULL;
 
     TRACE("%s\n", debugstr_w(pszAuthValue));
 
@@ -680,10 +426,10 @@ static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
         pAuthInfo->auth_data_len = 0;
         pAuthInfo->finished = FALSE;
 
-        if (is_basic_auth_value(pszAuthValue,NULL))
+        if (is_basic_auth_value(pszAuthValue))
         {
             static const WCHAR szBasic[] = {'B','a','s','i','c',0};
-            pAuthInfo->scheme = heap_strdupW(szBasic);
+            pAuthInfo->scheme = WININET_strdupW(szBasic);
             if (!pAuthInfo->scheme)
             {
                 HeapFree(GetProcessHeap(), 0, pAuthInfo);
@@ -695,7 +441,7 @@ static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
             PVOID pAuthData;
             SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
 
-            pAuthInfo->scheme = heap_strdupW(pszAuthValue);
+            pAuthInfo->scheme = WININET_strdupW(pszAuthValue);
             if (!pAuthInfo->scheme)
             {
                 HeapFree(GetProcessHeap(), 0, pAuthInfo);
@@ -767,50 +513,33 @@ static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
         return FALSE;
     }
 
-    if (is_basic_auth_value(pszAuthValue,&szRealm))
+    if (is_basic_auth_value(pszAuthValue))
     {
         int userlen;
         int passlen;
-        char *auth_data = NULL;
-        UINT auth_data_len = 0;
+        char *auth_data;
 
-        TRACE("basic authentication realm %s\n",debugstr_w(szRealm));
+        TRACE("basic authentication\n");
+
+        /* 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;
 
-        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)
-            {
-                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);
-            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 = auth_data_len;
+        pAuthInfo->auth_data_len = userlen + 1 + passlen;
         pAuthInfo->finished = TRUE;
-        HeapFree(GetProcessHeap(),0,szRealm);
 
         return TRUE;
     }
@@ -873,9 +602,8 @@ static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
         else
         {
             ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
+            pAuthInfo->finished = TRUE;
             HeapFree(GetProcessHeap(), 0, out.pvBuffer);
-            destroy_authinfo(pAuthInfo);
-            *ppAuthInfo = NULL;
             return FALSE;
         }
     }
@@ -886,7 +614,7 @@ static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
 /***********************************************************************
  *           HTTP_HttpAddRequestHeadersW (internal)
  */
-static BOOL HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
+static BOOL WINAPI HTTP_HttpAddRequestHeadersW(LPWININETHTTPREQW lpwhr,
        LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
 {
     LPWSTR lpszStart;
@@ -914,7 +642,7 @@ static BOOL HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
 
         while (*lpszEnd != '\0')
         {
-            if (*lpszEnd == '\r' || *lpszEnd == '\n')
+            if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
                  break;
             lpszEnd++;
         }
@@ -922,19 +650,12 @@ static BOOL HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
         if (*lpszStart == '\0')
            break;
 
-        if (*lpszEnd == '\r' || *lpszEnd == '\n')
+        if (*lpszEnd == '\r')
         {
             *lpszEnd = '\0';
-            lpszEnd++; /* Jump over newline */
+            lpszEnd += 2; /* Jump over \r\n */
         }
         TRACE("interpreting header %s\n", debugstr_w(lpszStart));
-        if (*lpszStart == '\0')
-        {
-            /* Skip 0-length headers */
-            lpszStart = lpszEnd;
-            bSuccess = TRUE;
-            continue;
-        }
         pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart);
         if (pFieldAndValue)
         {
@@ -973,14 +694,14 @@ BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
        LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
 {
     BOOL bSuccess = FALSE;
-    http_request_t *lpwhr;
+    LPWININETHTTPREQW lpwhr;
 
     TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
 
     if (!lpszHeader) 
       return TRUE;
 
-    lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
+    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
     {
         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
@@ -1039,87 +760,57 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, 
         LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
 {
-    TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
+    LPINTERNET_BUFFERSA ptr;
+    LPINTERNET_BUFFERSW lpBuffersOutW,ptrW;
+    BOOL rc = FALSE;
 
-    if (lpBuffersOut)
-    {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
+    TRACE("(%p, %p, %08x, %08lx): stub\n", hRequest, lpBuffersOut, dwFlags,
+            dwContext);
 
-    return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
-}
+    ptr = lpBuffersOut;
+    if (ptr)
+        lpBuffersOutW = (LPINTERNET_BUFFERSW)HeapAlloc(GetProcessHeap(),
+                HEAP_ZERO_MEMORY, sizeof(INTERNET_BUFFERSW));
+    else
+        lpBuffersOutW = NULL;
 
-static BOOL HTTP_HttpEndRequestW(http_request_t *lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
+    ptrW = lpBuffersOutW;
+    while (ptr)
 {
-    BOOL rc = FALSE;
-    INT responseLen;
-    DWORD dwBufferSize;
-    INTERNET_ASYNC_RESULT iar;
-
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                  INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+        if (ptr->lpvBuffer && ptr->dwBufferLength)
+            ptrW->lpvBuffer = HeapAlloc(GetProcessHeap(),0,ptr->dwBufferLength);
+        ptrW->dwBufferLength = ptr->dwBufferLength;
+        ptrW->dwBufferTotal= ptr->dwBufferTotal;
 
-    responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
-    if (responseLen)
-        rc = TRUE;
-
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                  INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
+        if (ptr->Next)
+            ptrW->Next = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+                    sizeof(INTERNET_BUFFERSW));
 
-    /* process cookies here. Is this right? */
-    HTTP_ProcessCookies(lpwhr);
+        ptr = ptr->Next;
+        ptrW = ptrW->Next;
+    }
 
-    if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
+    rc = HttpEndRequestW(hRequest, lpBuffersOutW, dwFlags, dwContext);
 
-    if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
+    if (lpBuffersOutW)
     {
-        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))
+        ptrW = lpBuffersOutW;
+        while (ptrW)
         {
-            WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
-            dwBufferSize=sizeof(szNewLocation);
-            if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL))
-            {
-                if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD))
-                {
-                    HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
-                    lpwhr->lpszVerb = heap_strdupW(szGET);
+            LPINTERNET_BUFFERSW ptrW2;
+
+            FIXME("Do we need to translate info out of these buffer?\n");
+
+            HeapFree(GetProcessHeap(),0,ptrW->lpvBuffer);
+            ptrW2 = ptrW->Next;
+            HeapFree(GetProcessHeap(),0,ptrW);
+            ptrW = ptrW2;
                 }
-                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));
-                    rc = HTTP_HandleRedirect(lpwhr, new_url);
-                    if (rc)
-                        rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
-                    HeapFree( GetProcessHeap(), 0, new_url );
                 }
-            }
-        }
-    }
-
-    iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
-    iar.dwError = rc ? 0 : INTERNET_GetLastError();
 
-    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.@)
  *
@@ -1134,17 +825,12 @@ BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
         LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
 {
     BOOL rc = FALSE;
-    http_request_t *lpwhr;
+    LPWININETHTTPREQW lpwhr;
+    INT responseLen;
+    DWORD dwBufferSize;
 
     TRACE("-->\n");
-
-    if (lpBuffersOut)
-    {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
-
-    lpwhr = (http_request_t*) WININET_GetObject( hRequest );
+    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
 
     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
     {
@@ -1153,25 +839,56 @@ BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
             WININET_Release( &lpwhr->hdr );
         return FALSE;
     }
+
     lpwhr->hdr.dwFlags |= dwFlags;
+    lpwhr->hdr.dwContext = dwContext;
 
-    if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        WORKREQUEST work;
-        struct WORKREQ_HTTPENDREQUESTW *request;
+    /* We appear to do nothing with lpBuffersOut.. is that correct? */
 
-        work.asyncproc = AsyncHttpEndRequestProc;
-        work.hdr = WININET_AddRef( &lpwhr->hdr );
+    SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+            INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+
+    responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
+    if (responseLen)
+           rc = TRUE;
 
-        request = &work.u.HttpEndRequestW;
-        request->dwFlags = dwFlags;
-        request->dwContext = dwContext;
+    SendAsyncCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+            INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
 
-        INTERNET_AsyncCall(&work);
-        INTERNET_SetLastError(ERROR_IO_PENDING);
+    /* process cookies here. Is this right? */
+    HTTP_ProcessCookies(lpwhr);
+
+    dwBufferSize = sizeof(lpwhr->dwContentLength);
+    if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
+                             &lpwhr->dwContentLength,&dwBufferSize,NULL))
+        lpwhr->dwContentLength = -1;
+
+    if (lpwhr->dwContentLength == 0)
+        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) &&
+            (dwCode==302 || dwCode==301))
+        {
+            WCHAR szNewLocation[INTERNET_MAX_URL_LENGTH];
+            dwBufferSize=sizeof(szNewLocation);
+            if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL))
+            {
+                /* redirects are always GETs */
+                HeapFree(GetProcessHeap(),0,lpwhr->lpszVerb);
+                lpwhr->lpszVerb = WININET_strdupW(szGET);
+                HTTP_DrainContent(lpwhr);
+                INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                                      INTERNET_STATUS_REDIRECT, szNewLocation,
+                                      dwBufferSize);
+                rc = HTTP_HandleRedirect(lpwhr, szNewLocation);
+                if (rc)
+                    rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
+    }
+        }
     }
-    else
-        rc = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
 
     WININET_Release( &lpwhr->hdr );
     TRACE("%i <--\n",rc);
@@ -1193,7 +910,7 @@ HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
        LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
        DWORD dwFlags, DWORD_PTR dwContext)
 {
-    http_session_t *lpwhs;
+    LPWININETHTTPSESSIONW lpwhs;
     HINTERNET handle = NULL;
 
     TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
@@ -1207,7 +924,7 @@ HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
             TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
     }    
 
-    lpwhs = (http_session_t*) WININET_GetObject( hHttpSession );
+    lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession );
     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
     {
         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
@@ -1249,7 +966,7 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
 {
     LPWSTR szVerb = NULL, szObjectName = NULL;
     LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
-    INT acceptTypesCount;
+    INT len, acceptTypesCount;
     HINTERNET rc = FALSE;
     LPCSTR *types;
 
@@ -1260,30 +977,38 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
 
     if (lpszVerb)
     {
-        szVerb = heap_strdupAtoW(lpszVerb);
+        len = MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, NULL, 0 );
+        szVerb = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
         if ( !szVerb )
             goto end;
+        MultiByteToWideChar(CP_ACP, 0, lpszVerb, -1, szVerb, len);
     }
 
     if (lpszObjectName)
     {
-        szObjectName = heap_strdupAtoW(lpszObjectName);
+        len = MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, NULL, 0 );
+        szObjectName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR) );
         if ( !szObjectName )
             goto end;
+        MultiByteToWideChar(CP_ACP, 0, lpszObjectName, -1, szObjectName, len );
     }
 
     if (lpszVersion)
     {
-        szVersion = heap_strdupAtoW(lpszVersion);
+        len = MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, NULL, 0 );
+        szVersion = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
         if ( !szVersion )
             goto end;
+        MultiByteToWideChar(CP_ACP, 0, lpszVersion, -1, szVersion, len );
     }
 
     if (lpszReferrer)
     {
-        szReferrer = heap_strdupAtoW(lpszReferrer);
+        len = MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, NULL, 0 );
+        szReferrer = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
         if ( !szReferrer )
             goto end;
+        MultiByteToWideChar(CP_ACP, 0, lpszReferrer, -1, szReferrer, len );
     }
 
     if (lpszAcceptTypes)
@@ -1292,20 +1017,12 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
         types = lpszAcceptTypes;
         while (*types)
         {
-            __TRY
-            {
                 /* find out how many there are */
-                if (*types && **types)
+            if (((ULONG_PTR)*types >> 16) && **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));
@@ -1315,20 +1032,20 @@ HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
         types = lpszAcceptTypes;
         while (*types)
         {
-            __TRY
+            if (((ULONG_PTR)*types >> 16) && **types)
             {
-                if (*types && **types)
-                    szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types);
-            }
-            __EXCEPT_PAGE_FAULT
-            {
-                /* ignore invalid pointer */
+                len = MultiByteToWideChar(CP_ACP, 0, *types, -1, NULL, 0 );
+                szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+                if (!szAcceptTypes[acceptTypesCount]) goto end;
+
+                MultiByteToWideChar(CP_ACP, 0, *types, -1, szAcceptTypes[acceptTypesCount], len);
+                acceptTypesCount++;
             }
-            __ENDTRY;
             types++;
         }
         szAcceptTypes[acceptTypesCount] = NULL;
     }
+    else szAcceptTypes = 0;
 
     rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
                           szVersion, szReferrer,
@@ -1490,7 +1207,7 @@ static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin )
  *
  *   Insert or delete the authorization field in the request header.
  */
-static BOOL HTTP_InsertAuthorization( http_request_t *lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
+static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
 {
     if (pAuthInfo)
     {
@@ -1533,7 +1250,7 @@ static BOOL HTTP_InsertAuthorization( http_request_t *lpwhr, struct HttpAuthInfo
     return TRUE;
 }
 
-static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
+static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req)
 {
     WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
     DWORD size;
@@ -1549,7 +1266,7 @@ static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
         static const WCHAR slash[] = { '/',0 };
         static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
         static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','d',0 };
-        http_session_t *session = req->lpHttpSession;
+        WININETHTTPSESSIONW *session = req->lpHttpSession;
 
         size = 16; /* "https://" + sizeof(port#) + ":/\0" */
         size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath );
@@ -1570,7 +1287,8 @@ static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
 /***********************************************************************
  *           HTTP_DealWithProxy
  */
-static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_request_t *lpwhr)
+static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC,
+    LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr)
 {
     WCHAR buf[MAXHOSTNAME];
     WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
@@ -1601,50 +1319,32 @@ static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_reque
         UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
 
     HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
-    lpwhs->lpszServerName = heap_strdupW(UrlComponents.lpszHostName);
+    lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName);
     lpwhs->nServerPort = UrlComponents.nPort;
 
     TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort);
     return TRUE;
 }
 
-#ifndef INET6_ADDRSTRLEN
-#define INET6_ADDRSTRLEN 46
-#endif
-
-static BOOL HTTP_ResolveName(http_request_t *lpwhr)
+static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr)
 {
-    char szaddr[INET6_ADDRSTRLEN];
-    http_session_t *lpwhs = lpwhr->lpHttpSession;
-    const void *addr;
+    char szaddr[32];
+    LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
 
     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                           INTERNET_STATUS_RESOLVING_NAME,
                           lpwhs->lpszServerName,
                           strlenW(lpwhs->lpszServerName)+1);
 
-    lpwhs->sa_len = sizeof(lpwhs->socketAddress);
     if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
-                    (struct sockaddr *)&lpwhs->socketAddress, &lpwhs->sa_len))
+                    &lpwhs->socketAddress))
     {
         INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
         return FALSE;
     }
 
-    switch (lpwhs->socketAddress.ss_family)
-    {
-    case AF_INET:
-        addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr;
-        break;
-    case AF_INET6:
-        addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr;
-        break;
-    default:
-        WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family);
-        INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
-        return FALSE;
-    }
-    inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr));
+    inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr,
+              szaddr, sizeof(szaddr));
     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                           INTERNET_STATUS_NAME_RESOLVED,
                           szaddr, strlen(szaddr)+1);
@@ -1660,9 +1360,9 @@ static BOOL HTTP_ResolveName(http_request_t *lpwhr)
  * Deallocate request handle
  *
  */
-static void HTTPREQ_Destroy(object_header_t *hdr)
+static void HTTPREQ_Destroy(WININETHANDLEHEADER *hdr)
 {
-    http_request_t *lpwhr = (http_request_t*) hdr;
+    LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr;
     DWORD i;
 
     TRACE("\n");
@@ -1670,14 +1370,13 @@ static void HTTPREQ_Destroy(object_header_t *hdr)
     if(lpwhr->hCacheFile)
         CloseHandle(lpwhr->hCacheFile);
 
+    if(lpwhr->lpszCacheFile) {
+        DeleteFileW(lpwhr->lpszCacheFile); /* FIXME */
     HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile);
+    }
 
-    DeleteCriticalSection( &lpwhr->read_section );
     WININET_Release(&lpwhr->lpHttpSession->hdr);
 
-    destroy_authinfo(lpwhr->pAuthInfo);
-    destroy_authinfo(lpwhr->pProxyAuthInfo);
-
     HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
     HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
     HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
@@ -1690,126 +1389,58 @@ static void HTTPREQ_Destroy(object_header_t *hdr)
         HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
     }
 
-#ifdef HAVE_ZLIB
-    if(lpwhr->gzip_stream) {
-        if(!lpwhr->gzip_stream->end_of_data)
-            inflateEnd(&lpwhr->gzip_stream->zstream);
-        HeapFree(GetProcessHeap(), 0, lpwhr->gzip_stream);
-    }
-#endif
-
     HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
     HeapFree(GetProcessHeap(), 0, lpwhr);
 }
 
-static void HTTPREQ_CloseConnection(object_header_t *hdr)
+static void HTTPREQ_CloseConnection(WININETHANDLEHEADER *hdr)
 {
-    http_request_t *lpwhr = (http_request_t*) hdr;
+    LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr;
 
     TRACE("%p\n",lpwhr);
 
     if (!NETCON_connected(&lpwhr->netConnection))
         return;
 
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                          INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
-
-    NETCON_close(&lpwhr->netConnection);
-
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                          INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
-}
-
-static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
+    if (lpwhr->pAuthInfo)
 {
-    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;
+        if (SecIsValidHandle(&lpwhr->pAuthInfo->ctx))
+            DeleteSecurityContext(&lpwhr->pAuthInfo->ctx);
+        if (SecIsValidHandle(&lpwhr->pAuthInfo->cred))
+            FreeCredentialsHandle(&lpwhr->pAuthInfo->cred);
+
+        HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->auth_data);
+        HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo->scheme);
+        HeapFree(GetProcessHeap(), 0, lpwhr->pAuthInfo);
+        lpwhr->pAuthInfo = NULL;
 }
-
-static BOOL HTTP_KeepAlive(http_request_t *lpwhr)
+    if (lpwhr->pProxyAuthInfo)
 {
-    WCHAR szVersion[10];
-    WCHAR szConnectionResponse[20];
-    DWORD dwBufferSize = sizeof(szVersion);
-    BOOL keepalive = FALSE;
+        if (SecIsValidHandle(&lpwhr->pProxyAuthInfo->ctx))
+            DeleteSecurityContext(&lpwhr->pProxyAuthInfo->ctx);
+        if (SecIsValidHandle(&lpwhr->pProxyAuthInfo->cred))
+            FreeCredentialsHandle(&lpwhr->pProxyAuthInfo->cred);
 
-    /* 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))
-    {
-        keepalive = TRUE;
+        HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->auth_data);
+        HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo->scheme);
+        HeapFree(GetProcessHeap(), 0, lpwhr->pProxyAuthInfo);
+        lpwhr->pProxyAuthInfo = NULL;
     }
 
-    dwBufferSize = sizeof(szConnectionResponse);
-    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) ||
-        HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL))
-    {
-        keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
-    }
-
-    return keepalive;
-}
-
-static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
-{
-    http_request_t *req = (http_request_t*)hdr;
-
-    switch(option) {
-    case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO:
-    {
-        http_session_t *lpwhs = req->lpHttpSession;
-        INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer;
-
-        FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n");
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                          INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
 
-        if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO))
-            return ERROR_INSUFFICIENT_BUFFER;
-        *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO);
-        /* FIXME: can't get a SOCKET from our connection since we don't use
-         * winsock
-         */
-        info->Socket = 0;
-        /* FIXME: get source port from req->netConnection */
-        info->SourcePort = 0;
-        info->DestPort = lpwhs->nHostPort;
-        info->Flags = 0;
-        if (HTTP_KeepAlive(req))
-            info->Flags |= IDSI_FLAG_KEEP_ALIVE;
-        if (lpwhs->lpAppInfo->lpszProxy && lpwhs->lpAppInfo->lpszProxy[0] != 0)
-            info->Flags |= IDSI_FLAG_PROXY;
-        if (req->netConnection.useSSL)
-            info->Flags |= IDSI_FLAG_SECURE;
+    NETCON_close(&lpwhr->netConnection);
 
-        return ERROR_SUCCESS;
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                          INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
     }
 
-    case INTERNET_OPTION_SECURITY_FLAGS:
+static DWORD HTTPREQ_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
     {
-        http_session_t *lpwhs;
-        lpwhs = req->lpHttpSession;
-
-        if (*size < sizeof(ULONG))
-            return ERROR_INSUFFICIENT_BUFFER;
-
-        *size = sizeof(DWORD);
-        if (lpwhs->hdr.dwFlags & INTERNET_FLAG_SECURE)
-            *(DWORD*)buffer = SECURITY_FLAG_SECURE;
-        else
-            *(DWORD*)buffer = 0;
-        FIXME("Semi-STUB INTERNET_OPTION_SECURITY_FLAGS: %x\n",*(DWORD*)buffer);
-        return ERROR_SUCCESS;
-    }
+    WININETHTTPREQW *req = (WININETHTTPREQW*)hdr;
 
+    switch(option) {
     case INTERNET_OPTION_HANDLE_TYPE:
         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
 
@@ -1827,6 +1458,7 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
         WCHAR *pch;
 
         static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
+        static const WCHAR hostW[] = {'H','o','s','t',0};
 
         TRACE("INTERNET_OPTION_URL\n");
 
@@ -1857,41 +1489,6 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
         }
     }
 
-    case INTERNET_OPTION_CACHE_TIMESTAMPS: {
-        INTERNET_CACHE_ENTRY_INFOW *info;
-        INTERNET_CACHE_TIMESTAMPS *ts = buffer;
-        WCHAR url[INTERNET_MAX_URL_LENGTH];
-        DWORD nbytes, error;
-        BOOL ret;
-
-        TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
-
-        if (*size < sizeof(*ts))
-        {
-            *size = sizeof(*ts);
-            return ERROR_INSUFFICIENT_BUFFER;
-        }
-        nbytes = 0;
-        HTTP_GetRequestURL(req, url);
-        ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes);
-        error = GetLastError();
-        if (!ret && error == ERROR_INSUFFICIENT_BUFFER)
-        {
-            if (!(info = HeapAlloc(GetProcessHeap(), 0, nbytes)))
-                return ERROR_OUTOFMEMORY;
-
-            GetUrlCacheEntryInfoW(url, info, &nbytes);
-
-            ts->ftExpires = info->ExpireTime;
-            ts->ftLastModified = info->LastModifiedTime;
-
-            HeapFree(GetProcessHeap(), 0, info);
-            *size = sizeof(*ts);
-            return ERROR_SUCCESS;
-        }
-        return error;
-    }
-
     case INTERNET_OPTION_DATAFILE_NAME: {
         DWORD req_size;
 
@@ -1987,9 +1584,9 @@ static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffe
     return INET_QueryOption(option, buffer, size, unicode);
 }
 
-static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
+static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD size)
 {
-    http_request_t *req = (http_request_t*)hdr;
+    WININETHTTPREQW *req = (WININETHTTPREQW*)hdr;
 
     switch(option) {
     case INTERNET_OPTION_SEND_TIMEOUT:
@@ -2001,355 +1598,151 @@ static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer,
 
         return NETCON_set_timeout(&req->netConnection, option == INTERNET_OPTION_SEND_TIMEOUT,
                     *(DWORD*)buffer);
-
-    case INTERNET_OPTION_USERNAME:
-        HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszUserName);
-        if (!(req->lpHttpSession->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
-        return ERROR_SUCCESS;
-
-    case INTERNET_OPTION_PASSWORD:
-        HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszPassword);
-        if (!(req->lpHttpSession->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
-        return ERROR_SUCCESS;
-    case INTERNET_OPTION_HTTP_DECODING:
-        if(size != sizeof(BOOL))
-            return ERROR_INVALID_PARAMETER;
-        req->decoding = *(BOOL*)buffer;
-        return ERROR_SUCCESS;
     }
 
     return ERROR_INTERNET_INVALID_OPTION;
 }
 
-/* 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 HTTP_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
 {
-    int len;
-
-    if (req->read_pos)
-    {
-        /* move existing data to the start of the buffer */
-        if(req->read_size)
-            memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
-        req->read_pos = 0;
-    }
+    int bytes_read;
 
-    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;
-
-    req->read_size += len;
-    return TRUE;
-}
+    if(!NETCON_recv(&req->netConnection, buffer, min(size, req->dwContentLength - req->dwContentRead),
+                     sync ? MSG_WAITALL : 0, &bytes_read)) {
+        if(req->dwContentLength != -1 && req->dwContentRead != req->dwContentLength)
+            ERR("not all data received %d/%d\n", req->dwContentRead, req->dwContentLength);
 
-/* remove some amount of data from the read buffer (the read section must be held) */
-static void remove_data( http_request_t *req, int count )
-{
-    if (!(req->read_size -= count)) req->read_pos = 0;
-    else req->read_pos += count;
+        /* always return success, even if the network layer returns an error */
+        *read = 0;
+        HTTP_FinishedReading(req);
+        return ERROR_SUCCESS;
 }
 
-static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
-{
-    int count, bytes_read, pos = 0;
+    req->dwContentRead += bytes_read;
+    *read = bytes_read;
 
-    EnterCriticalSection( &req->read_section );
-    for (;;)
-    {
-        BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
+    if(req->lpszCacheFile) {
+        BOOL res;
+        DWORD dwBytesWritten;
 
-        if (eol)
-        {
-            count = eol - (req->read_buf + req->read_pos);
-            bytes_read = count + 1;
+        res = WriteFile(req->hCacheFile, buffer, bytes_read, &dwBytesWritten, NULL);
+        if(!res)
+            WARN("WriteFile failed: %u\n", GetLastError());
         }
-        else count = bytes_read = req->read_size;
 
-        count = min( count, *len - pos );
-        memcpy( buffer + pos, req->read_buf + req->read_pos, count );
-        pos += count;
-        remove_data( req, bytes_read );
-        if (eol) break;
+    if(!bytes_read && (req->dwContentRead == req->dwContentLength))
+        HTTP_FinishedReading(req);
 
-        if (!read_more_data( req, -1 ) || !req->read_size)
-        {
-            *len = 0;
-            TRACE( "returning empty string\n" );
-            LeaveCriticalSection( &req->read_section );
-            return FALSE;
+    return ERROR_SUCCESS;
         }
-    }
-    LeaveCriticalSection( &req->read_section );
 
-    if (pos < *len)
+static DWORD get_chunk_size(const char *buffer)
     {
-        if (pos && buffer[pos - 1] == '\r') pos--;
-        *len = pos + 1;
-    }
-    buffer[*len - 1] = 0;
-    TRACE( "returning %s\n", debugstr_a(buffer));
-    return TRUE;
-}
+    const char *p;
+    DWORD size = 0;
 
-/* discard data contents until we reach end of line (the read section must be held) */
-static BOOL discard_eol( http_request_t *req )
+    for (p = buffer; *p; p++)
 {
-    do
-    {
-        BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
-        if (eol)
-        {
-            remove_data( req, (eol + 1) - (req->read_buf + req->read_pos) );
-            break;
+        if (*p >= '0' && *p <= '9') size = size * 16 + *p - '0';
+        else if (*p >= 'a' && *p <= 'f') size = size * 16 + *p - 'a' + 10;
+        else if (*p >= 'A' && *p <= 'F') size = size * 16 + *p - 'A' + 10;
+        else if (*p == ';') break;
         }
-        req->read_pos = req->read_size = 0;  /* discard everything */
-        if (!read_more_data( req, -1 )) return FALSE;
-    } while (req->read_size);
-    return TRUE;
+    return size;
 }
 
-/* read the size of the next chunk (the read section must be held) */
-static BOOL start_next_chunk( http_request_t *req )
+static DWORD HTTP_ReadChunked(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
 {
-    DWORD chunk_size = 0;
+    char reply[MAX_REPLY_LEN], *p = buffer;
+    DWORD buflen, to_read, to_write = size;
+    int bytes_read;
 
-    if (!req->dwContentLength) return TRUE;
-    if (req->dwContentLength == req->dwContentRead)
-    {
-        /* read terminator for the previous chunk */
-        if (!discard_eol( req )) return FALSE;
-        req->dwContentLength = ~0u;
-        req->dwContentRead = 0;
-    }
+    *read = 0;
     for (;;)
     {
-        while (req->read_size)
-        {
-            char ch = req->read_buf[req->read_pos];
-            if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0';
-            else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10;
-            else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10;
-            else if (ch == ';' || ch == '\r' || ch == '\n')
-            {
-                TRACE( "reading %u byte chunk\n", chunk_size );
-                req->dwContentLength = chunk_size;
-                req->dwContentRead = 0;
-                if (!discard_eol( req )) return FALSE;
-                return TRUE;
-            }
-            remove_data( req, 1 );
-        }
-        if (!read_more_data( req, -1 )) return FALSE;
-        if (!req->read_size)
-        {
-            req->dwContentLength = req->dwContentRead = 0;
-            return TRUE;
-        }
-    }
-}
+        if (*read == size) break;
 
-/* check if we have reached the end of the data to read (the read section must be held) */
-static BOOL end_of_read_data( http_request_t *req )
+        if (req->dwContentLength == ~0UL) /* new chunk */
 {
-    if (req->gzip_stream) return req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
-    if (req->read_chunked) return (req->dwContentLength == 0);
-    if (req->dwContentLength == ~0u) return FALSE;
-    return (req->dwContentLength == req->dwContentRead);
-}
+            buflen = sizeof(reply);
+            if (!NETCON_getNextLine(&req->netConnection, reply, &buflen)) break;
 
-/* fetch some more data into the read buffer (the read section must be held) */
-static BOOL refill_buffer( http_request_t *req )
+            if (!(req->dwContentLength = get_chunk_size(reply)))
 {
-    int len = sizeof(req->read_buf);
-
-    if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
-    {
-        if (!start_next_chunk( req )) return FALSE;
+                /* zero sized chunk marks end of transfer; read any trailing headers and return */
+                HTTP_GetResponseHeaders(req, FALSE);
+                break;
     }
-
-    if (req->dwContentLength != ~0u) len = min( len, req->dwContentLength - req->dwContentRead );
-    if (len <= req->read_size) return TRUE;
-
-    if (!read_more_data( req, len )) return FALSE;
-    if (!req->read_size) req->dwContentLength = req->dwContentRead = 0;
-    return TRUE;
 }
+        to_read = min(to_write, req->dwContentLength - req->dwContentRead);
 
-static DWORD read_gzip_data(http_request_t *req, BYTE *buf, int size, BOOL sync, int *read_ret)
+        if (!NETCON_recv(&req->netConnection, p, to_read, sync ? MSG_WAITALL : 0, &bytes_read))
 {
-    DWORD ret = ERROR_SUCCESS;
-    int read = 0;
-
-#ifdef HAVE_ZLIB
-    z_stream *zstream = &req->gzip_stream->zstream;
-    int zres;
+            if (bytes_read != to_read)
+                ERR("Not all data received %d/%d\n", bytes_read, to_read);
 
-    while(read < size && !req->gzip_stream->end_of_data) {
-        if(!req->read_size) {
-            if(!sync || !refill_buffer(req))
+            /* always return success, even if the network layer returns an error */
+            *read = 0;
                 break;
         }
+        if (!bytes_read) break;
 
-        zstream->next_in = req->read_buf+req->read_pos;
-        zstream->avail_in = req->read_size;
-        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);
-        if(zres == Z_STREAM_END) {
-            TRACE("end of data\n");
-            req->gzip_stream->end_of_data = TRUE;
-            inflateEnd(&req->gzip_stream->zstream);
-        }else if(zres != Z_OK) {
-            WARN("inflate failed %d\n", zres);
-            if(!read)
-                ret = ERROR_INTERNET_DECODING_FAILED;
-            break;
-        }
-    }
-#endif
-
-    *read_ret = read;
-    return ret;
-}
+        req->dwContentRead += bytes_read;
+        to_write -= bytes_read;
+        *read += bytes_read;
 
-static void refill_gzip_buffer(http_request_t *req)
+        if (req->lpszCacheFile)
 {
-    DWORD res;
-    int len;
-
-    if(!req->gzip_stream || !req->read_size || req->gzip_stream->buf_size == sizeof(req->gzip_stream->buf))
-        return;
+            DWORD dwBytesWritten;
 
-    if(req->gzip_stream->buf_pos) {
-        if(req->gzip_stream->buf_size)
-            memmove(req->gzip_stream->buf, req->gzip_stream->buf + req->gzip_stream->buf_pos, req->gzip_stream->buf_size);
-        req->gzip_stream->buf_pos = 0;
+            if (!WriteFile(req->hCacheFile, p, bytes_read, &dwBytesWritten, NULL))
+                WARN("WriteFile failed: %u\n", GetLastError());
     }
+        p += bytes_read;
 
-    res = read_gzip_data(req, req->gzip_stream->buf + req->gzip_stream->buf_size,
-            sizeof(req->gzip_stream->buf) - req->gzip_stream->buf_size, FALSE, &len);
-    if(res == ERROR_SUCCESS)
-        req->gzip_stream->buf_size += len;
-}
+        if (req->dwContentRead == req->dwContentLength) /* chunk complete */
+        {
+            req->dwContentRead = 0;
+            req->dwContentLength = ~0UL;
 
-/* return the size of data available to be read immediately (the read section must be held) */
-static DWORD get_avail_data( http_request_t *req )
+            buflen = sizeof(reply);
+            if (!NETCON_getNextLine(&req->netConnection, reply, &buflen))
 {
-    if (req->gzip_stream) {
-        refill_gzip_buffer(req);
-        return req->gzip_stream->buf_size;
+                ERR("Malformed chunk\n");
+                *read = 0;
+                break;
     }
-    if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
-        return 0;
-    return min( req->read_size, req->dwContentLength - req->dwContentRead );
 }
-
-static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif)
-{
-    INTERNET_ASYNC_RESULT iar;
-
-    TRACE("%p\n", req);
-
-    EnterCriticalSection( &req->read_section );
-    if (refill_buffer( req )) {
-        iar.dwResult = (DWORD_PTR)req->hdr.hInternet;
-        iar.dwError = first_notif ? 0 : get_avail_data(req);
-    }else {
-        iar.dwResult = 0;
-        iar.dwError = INTERNET_GetLastError();
     }
-    LeaveCriticalSection( &req->read_section );
-
-    INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
-                          sizeof(INTERNET_ASYNC_RESULT));
+    if (!*read) HTTP_FinishedReading(req);
+    return ERROR_SUCCESS;
 }
 
-/* read data from the http connection (the read section must be held) */
-static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
+static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
 {
-    BOOL finished_reading = FALSE;
-    int len, bytes_read = 0;
-    DWORD ret = ERROR_SUCCESS;
-
-    EnterCriticalSection( &req->read_section );
+    WCHAR encoding[20];
+    DWORD buflen = sizeof(encoding);
+    static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
 
-    if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
+    if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_TRANSFER_ENCODING, encoding, &buflen, NULL) &&
+        !strcmpiW(encoding, szChunked))
     {
-        if (!start_next_chunk( req )) goto done;
+        return HTTP_ReadChunked(req, buffer, size, read, sync);
     }
-
-    if(req->gzip_stream) {
-        if(req->gzip_stream->buf_size) {
-            bytes_read = min(req->gzip_stream->buf_size, size);
-            memcpy(buffer, req->gzip_stream->buf + req->gzip_stream->buf_pos, bytes_read);
-            req->gzip_stream->buf_pos += bytes_read;
-            req->gzip_stream->buf_size -= bytes_read;
-        }else if(!req->read_size && !req->gzip_stream->end_of_data) {
-            refill_buffer(req);
-        }
-
-        if(size > bytes_read) {
-            ret = read_gzip_data(req, (BYTE*)buffer+bytes_read, size-bytes_read, sync, &len);
-            if(ret == ERROR_SUCCESS)
-                bytes_read += len;
-        }
-
-        finished_reading = req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
-    }else {
-        if (req->dwContentLength != ~0u) size = min( size, req->dwContentLength - req->dwContentRead );
-
-        if (req->read_size) {
-            bytes_read = min( req->read_size, size );
-            memcpy( buffer, req->read_buf + req->read_pos, bytes_read );
-            remove_data( req, bytes_read );
-        }
-
-        if (size > bytes_read && (!bytes_read || sync)) {
-            if (NETCON_recv( &req->netConnection, (char *)buffer + bytes_read, size - bytes_read,
-                             sync ? MSG_WAITALL : 0, &len))
-                bytes_read += len;
-            /* always return success, even if the network layer returns an error */
+    else
+        return HTTP_Read(req, buffer, size, read, sync);
         }
 
-        finished_reading = !bytes_read && req->dwContentRead == req->dwContentLength;
-    }
-done:
-    req->dwContentRead += bytes_read;
-    *read = bytes_read;
-
-    TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength );
-    LeaveCriticalSection( &req->read_section );
-
-    if(ret == ERROR_SUCCESS && req->lpszCacheFile) {
-        BOOL res;
-        DWORD dwBytesWritten;
-
-        res = WriteFile(req->hCacheFile, buffer, bytes_read, &dwBytesWritten, NULL);
-        if(!res)
-            WARN("WriteFile failed: %u\n", GetLastError());
-    }
-
-    if(finished_reading)
-        HTTP_FinishedReading(req);
-
-    return ret;
-}
-
-
-static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
+static DWORD HTTPREQ_ReadFile(WININETHANDLEHEADER *hdr, void *buffer, DWORD size, DWORD *read)
 {
-    http_request_t *req = (http_request_t*)hdr;
+    WININETHTTPREQW *req = (WININETHTTPREQW*)hdr;
     return HTTPREQ_Read(req, buffer, size, read, TRUE);
 }
 
-static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest)
+static void HTTPREQ_AsyncReadFileExProc(WORKREQUEST *workRequest)
 {
     struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA;
-    http_request_t *req = (http_request_t*)workRequest->hdr;
+    WININETHTTPREQW *req = (WININETHTTPREQW*)workRequest->hdr;
     INTERNET_ASYNC_RESULT iar;
     DWORD res;
 
@@ -2366,10 +1759,11 @@ static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest)
                           sizeof(INTERNET_ASYNC_RESULT));
 }
 
-static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers,
+static DWORD HTTPREQ_ReadFileExA(WININETHANDLEHEADER *hdr, INTERNET_BUFFERSA *buffers,
         DWORD flags, DWORD_PTR context)
 {
-    http_request_t *req = (http_request_t*)hdr;
+
+    WININETHTTPREQW *req = (WININETHTTPREQW*)hdr;
     DWORD res;
 
     if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
@@ -2380,23 +1774,15 @@ 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) {
+        DWORD available = 0;
+
+        NETCON_query_data_available(&req->netConnection, &available);
+        if (!available)
     {
         WORKREQUEST workRequest;
 
-        if (TryEnterCriticalSection( &req->read_section ))
-        {
-            if (get_avail_data(req))
-            {
-                res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
-                                   &buffers->dwBufferLength, FALSE);
-                LeaveCriticalSection( &req->read_section );
-                goto done;
-            }
-            LeaveCriticalSection( &req->read_section );
-        }
-
-        workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc;
+            workRequest.asyncproc = HTTPREQ_AsyncReadFileExProc;
         workRequest.hdr = WININET_AddRef(&req->hdr);
         workRequest.u.InternetReadFileExA.lpBuffersOut = buffers;
 
@@ -2404,11 +1790,11 @@ 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));
 
-done:
     if (res == ERROR_SUCCESS) {
         DWORD size = buffers->dwBufferLength;
         INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
@@ -2418,119 +1804,52 @@ done:
     return res;
 }
 
-static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest)
+static BOOL HTTPREQ_WriteFile(WININETHANDLEHEADER *hdr, const void *buffer, DWORD size, DWORD *written)
 {
-    struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW;
-    http_request_t *req = (http_request_t*)workRequest->hdr;
-    INTERNET_ASYNC_RESULT iar;
-    DWORD res;
-
-    TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr);
-
-    res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
-            data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
+    LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW)hdr;
 
-    iar.dwResult = res == ERROR_SUCCESS;
-    iar.dwError = res;
-
-    INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
-                          INTERNET_STATUS_REQUEST_COMPLETE, &iar,
-                          sizeof(INTERNET_ASYNC_RESULT));
+    return NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written);
 }
 
-static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers,
-        DWORD flags, DWORD_PTR context)
+static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
 {
+    WININETHTTPREQW *req = (WININETHTTPREQW*)workRequest->hdr;
+    INTERNET_ASYNC_RESULT iar;
+    char buffer[4048];
 
-    http_request_t *req = (http_request_t*)hdr;
-    DWORD res;
-
-    if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
-        FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
+    TRACE("%p\n", workRequest->hdr);
 
-    if (buffers->dwStructSize != sizeof(*buffers))
-        return ERROR_INVALID_PARAMETER;
+    iar.dwResult = NETCON_recv(&req->netConnection, buffer,
+                               min(sizeof(buffer), req->dwContentLength - req->dwContentRead),
+                               MSG_PEEK, (int *)&iar.dwError);
 
-    INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
-
-    if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        WORKREQUEST workRequest;
-
-        if (TryEnterCriticalSection( &req->read_section ))
-        {
-            if (get_avail_data(req))
-            {
-                res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
-                                   &buffers->dwBufferLength, FALSE);
-                LeaveCriticalSection( &req->read_section );
-                goto done;
+    INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+                          sizeof(INTERNET_ASYNC_RESULT));
             }
-            LeaveCriticalSection( &req->read_section );
-        }
-
-        workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc;
-        workRequest.hdr = WININET_AddRef(&req->hdr);
-        workRequest.u.InternetReadFileExW.lpBuffersOut = buffers;
-
-        INTERNET_AsyncCall(&workRequest);
 
-        return ERROR_IO_PENDING;
-    }
-
-    res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
-            !(flags & IRF_NO_WAIT));
-
-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;
-}
-
-static BOOL HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
+static DWORD HTTPREQ_QueryDataAvailable(WININETHANDLEHEADER *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
 {
-    BOOL ret;
-    http_request_t *lpwhr = (http_request_t*)hdr;
-
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
+    WININETHTTPREQW *req = (WININETHTTPREQW*)hdr;
+    BYTE buffer[4048];
+    BOOL async;
 
-    *written = 0;
-    if ((ret = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written)))
-        lpwhr->dwBytesWritten += *written;
-
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD));
-    return ret;
-}
+    TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
 
-static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
-{
-    http_request_t *req = (http_request_t*)workRequest->hdr;
+    if(!NETCON_query_data_available(&req->netConnection, available) || *available)
+        return ERROR_SUCCESS;
 
-    HTTP_ReceiveRequestData(req, FALSE);
-}
+    /* Even if we are in async mode, we need to determine whether
+     * there is actually more data available. We do this by trying
+     * to peek only a single byte in async mode. */
+    async = (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) != 0;
 
-static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
+    if (NETCON_recv(&req->netConnection, buffer,
+                    min(async ? 1 : sizeof(buffer), req->dwContentLength - req->dwContentRead),
+                    MSG_PEEK, (int *)available) && async && *available)
 {
-    http_request_t *req = (http_request_t*)hdr;
-
-    TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
-
-    if (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
         WORKREQUEST workRequest;
 
-        /* never wait, if we can't enter the section we queue an async request right away */
-        if (TryEnterCriticalSection( &req->read_section ))
-        {
-            if ((*available = get_avail_data( req ))) goto done;
-            if (end_of_read_data( req )) goto done;
-            LeaveCriticalSection( &req->read_section );
-        }
-
+        *available = 0;
         workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc;
         workRequest.hdr = WININET_AddRef( &req->hdr );
 
@@ -2539,35 +1858,16 @@ static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available,
         return ERROR_IO_PENDING;
     }
 
-    EnterCriticalSection( &req->read_section );
-
-    if (!(*available = get_avail_data( req )) && !end_of_read_data( req ))
-    {
-        refill_buffer( req );
-        *available = get_avail_data( req );
-    }
-
-done:
-    if (*available == sizeof(req->read_buf) && !req->gzip_stream)  /* check if we have even more pending in the socket */
-    {
-        DWORD extra;
-        if (NETCON_query_data_available(&req->netConnection, &extra))
-            *available = min( *available + extra, req->dwContentLength - req->dwContentRead );
-    }
-    LeaveCriticalSection( &req->read_section );
-
-    TRACE( "returning %u\n", *available );
     return ERROR_SUCCESS;
 }
 
-static const object_vtbl_t HTTPREQVtbl = {
+static const HANDLEHEADERVtbl HTTPREQVtbl = {
     HTTPREQ_Destroy,
     HTTPREQ_CloseConnection,
     HTTPREQ_QueryOption,
     HTTPREQ_SetOption,
     HTTPREQ_ReadFile,
     HTTPREQ_ReadFileExA,
-    HTTPREQ_ReadFileExW,
     HTTPREQ_WriteFile,
     HTTPREQ_QueryDataAvailable,
     NULL
@@ -2583,13 +1883,13 @@ static const object_vtbl_t HTTPREQVtbl = {
  *    NULL      on failure
  *
  */
-HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
+HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs,
        LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
        LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
        DWORD dwFlags, DWORD_PTR dwContext)
 {
-    appinfo_t *hIC = NULL;
-    http_request_t *lpwhr;
+    LPWININETAPPINFOW hIC = NULL;
+    LPWININETHTTPREQW lpwhr;
     LPWSTR lpszHostName = NULL;
     HINTERNET handle = NULL;
     static const WCHAR szHostForm[] = {'%','s',':','%','u',0};
@@ -2600,7 +1900,7 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
     assert( lpwhs->hdr.htype == WH_HHTTPSESSION );
     hIC = lpwhs->lpAppInfo;
 
-    lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_request_t));
+    lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW));
     if (NULL == lpwhr)
     {
         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
@@ -2613,8 +1913,6 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
     lpwhr->hdr.refs = 1;
     lpwhr->hdr.lpfnStatusCB = lpwhs->hdr.lpfnStatusCB;
     lpwhr->hdr.dwInternalFlags = lpwhs->hdr.dwInternalFlags & INET_CALLBACKW;
-    lpwhr->dwContentLength = ~0u;
-    InitializeCriticalSection( &lpwhr->read_section );
 
     WININET_AddRef( &lpwhs->hdr );
     lpwhr->lpHttpSession = lpwhs;
@@ -2652,15 +1950,11 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
         lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
         rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len,
                    URL_ESCAPE_SPACES_ONLY);
-        if (rc != S_OK)
+        if (rc)
         {
             ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
             strcpyW(lpwhr->lpszPath,lpszObjectName);
         }
-    }else {
-        static const WCHAR slashW[] = {'/',0};
-
-        lpwhr->lpszPath = heap_strdupW(slashW);
     }
 
     if (lpszReferrer && *lpszReferrer)
@@ -2679,19 +1973,23 @@ HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
         }
     }
 
-    lpwhr->lpszVerb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
-    lpwhr->lpszVersion = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1);
+    lpwhr->lpszVerb = WININET_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
+
+    if (lpszVersion)
+        lpwhr->lpszVersion = WININET_strdupW(lpszVersion);
+    else
+        lpwhr->lpszVersion = WININET_strdupW(g_szHttp1_1);
 
     if (lpwhs->nHostPort != INTERNET_INVALID_PORT_NUMBER &&
         lpwhs->nHostPort != INTERNET_DEFAULT_HTTP_PORT &&
         lpwhs->nHostPort != INTERNET_DEFAULT_HTTPS_PORT)
     {
         sprintfW(lpszHostName, szHostForm, lpwhs->lpszHostName, lpwhs->nHostPort);
-        HTTP_ProcessHeader(lpwhr, hostW, lpszHostName,
+        HTTP_ProcessHeader(lpwhr, szHost, lpszHostName,
                 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
     }
     else
-        HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName,
+        HTTP_ProcessHeader(lpwhr, szHost, lpwhs->lpszHostName,
                 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
 
     if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER)
@@ -2722,27 +2020,76 @@ lend:
 
 /* read any content returned by the server so that the connection can be
  * reused */
-static void HTTP_DrainContent(http_request_t *req)
+static void HTTP_DrainContent(WININETHTTPREQW *req)
 {
     DWORD bytes_read;
 
     if (!NETCON_connected(&req->netConnection)) return;
 
     if (req->dwContentLength == -1)
-    {
         NETCON_close(&req->netConnection);
-        return;
-    }
-    if (!strcmpW(req->lpszVerb, szHEAD)) return;
 
     do
     {
         char buffer[2048];
-        if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS)
+        if (HTTP_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS)
             return;
     } while (bytes_read);
 }
 
+static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 };
+static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 };
+static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 };
+static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 };
+static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
+static const WCHAR szAge[] = { 'A','g','e',0 };
+static const WCHAR szAllow[] = { 'A','l','l','o','w',0 };
+static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 };
+static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 };
+static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 };
+static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 };
+static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 };
+static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 };
+static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 };
+static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 };
+static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 };
+static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 };
+static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
+static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 };
+static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 };
+static const WCHAR szDate[] = { 'D','a','t','e',0 };
+static const WCHAR szFrom[] = { 'F','r','o','m',0 };
+static const WCHAR szETag[] = { 'E','T','a','g',0 };
+static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 };
+static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
+static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 };
+static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
+static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 };
+static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 };
+static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
+static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 };
+static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 };
+static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 };
+static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 };
+static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 };
+static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
+static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 };
+static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 };
+static const WCHAR szRange[] = { 'R','a','n','g','e',0 };
+static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 };
+static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 };
+static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 };
+static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
+static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
+static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
+static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 };
+static const WCHAR szURI[] = { 'U','R','I',0 };
+static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 };
+static const WCHAR szVary[] = { 'V','a','r','y',0 };
+static const WCHAR szVia[] = { 'V','i','a',0 };
+static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 };
+static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
+
 static const LPCWSTR header_lookup[] = {
     szMime_Version,            /* HTTP_QUERY_MIME_VERSION = 0 */
     szContent_Type,            /* HTTP_QUERY_CONTENT_TYPE = 1 */
@@ -2799,7 +2146,7 @@ static const LPCWSTR header_lookup[] = {
     szContent_MD5,             /* HTTP_QUERY_CONTENT_MD5 = 52 */
     szContent_Range,           /* HTTP_QUERY_CONTENT_RANGE = 53 */
     szETag,                    /* HTTP_QUERY_ETAG = 54 */
-    hostW,                     /* HTTP_QUERY_HOST = 55 */
+    szHost,                    /* HTTP_QUERY_HOST = 55 */
     szIf_Match,                        /* HTTP_QUERY_IF_MATCH = 56 */
     szIf_None_Match,           /* HTTP_QUERY_IF_NONE_MATCH = 57 */
     szIf_Range,                        /* HTTP_QUERY_IF_RANGE = 58 */
@@ -2822,27 +2169,27 @@ static const LPCWSTR header_lookup[] = {
 /***********************************************************************
  *           HTTP_HttpQueryInfoW (internal)
  */
-static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
+static BOOL WINAPI HTTP_HttpQueryInfoW( LPWININETHTTPREQW 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);
+    INT level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
     INT index = -1;
 
     /* Find requested header structure */
     switch (level)
     {
     case HTTP_QUERY_CUSTOM:
-        if (!lpBuffer) return FALSE;
         index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
         break;
+
     case HTTP_QUERY_RAW_HEADERS_CRLF:
         {
             LPWSTR headers;
-            DWORD len = 0;
+            DWORD len;
             BOOL ret = FALSE;
 
             if (request_only)
@@ -2850,24 +2197,15 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
             else
                 headers = lpwhr->lpszRawHeaders;
 
-            if (headers)
-                len = strlenW(headers) * sizeof(WCHAR);
-
-            if (len + sizeof(WCHAR) > *lpdwBufferLength)
+            len = (strlenW(headers) + 1) * sizeof(WCHAR);
+            if (len > *lpdwBufferLength)
             {
-                len += sizeof(WCHAR);
                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
                 ret = FALSE;
             }
             else if (lpBuffer)
             {
-                if (headers)
-                    memcpy(lpBuffer, headers, len + sizeof(WCHAR));
-                else
-                {
-                    len = strlenW(szCrLf) * sizeof(WCHAR);
-                    memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
-                }
+                memcpy(lpBuffer, headers, len);
                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
                 ret = TRUE;
             }
@@ -2879,9 +2217,10 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
         }
     case HTTP_QUERY_RAW_HEADERS:
         {
+            static const WCHAR szCrLf[] = {'\r','\n',0};
             LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf);
             DWORD i, size = 0;
-            LPWSTR pszString = lpBuffer;
+            LPWSTR pszString = (WCHAR*)lpBuffer;
 
             for (i = 0; ppszRawHeaderLines[i]; i++)
                 size += strlenW(ppszRawHeaderLines[i]) + 1;
@@ -2893,8 +2232,7 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
                 return FALSE;
             }
-            if (pszString)
-            {
+
                 for (i = 0; ppszRawHeaderLines[i]; i++)
                 {
                     DWORD len = strlenW(ppszRawHeaderLines[i]);
@@ -2902,8 +2240,9 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
                     pszString += len+1;
                 }
                 *pszString = '\0';
-                TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
-            }
+
+            TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, size));
+
             *lpdwBufferLength = size * sizeof(WCHAR);
             HTTP_FreeTokens(ppszRawHeaderLines);
 
@@ -2919,12 +2258,11 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
                 return FALSE;
             }
-            if (lpBuffer)
-            {
                 memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR));
-                TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
-            }
             *lpdwBufferLength = len * sizeof(WCHAR);
+
+            TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len));
+
             return TRUE;
         }
         break;
@@ -2938,23 +2276,18 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
                 return FALSE;
             }
-            if (lpBuffer)
-            {
                 memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR));
-                TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
-            }
             *lpdwBufferLength = len * sizeof(WCHAR);
+
+            TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, len));
+
             return TRUE;
         }
         break;
-    case HTTP_QUERY_CONTENT_ENCODING:
-        index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[lpwhr->gzip_stream ? HTTP_QUERY_CONTENT_TYPE : level],
-                requested_index,request_only);
-        break;
     default:
         assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1));
 
-        if (level < LAST_TABLE_HEADER && header_lookup[level])
+        if (level >= 0 && level < LAST_TABLE_HEADER && header_lookup[level])
             index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
                                               requested_index,request_only);
     }
@@ -2971,16 +2304,18 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
         return bSuccess;
     }
 
-    if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++;
+    if (lpdwIndex)
+        (*lpdwIndex)++;
 
     /* coalesce value to requested type */
-    if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
+    if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
     {
         *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
-        TRACE(" returning number: %d\n", *(int *)lpBuffer);
         bSuccess = TRUE;
+
+       TRACE(" returning number : %d\n", *(int *)lpBuffer);
     }
-    else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
+    else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
     {
         time_t tmpTime;
         struct tm tmpTM;
@@ -2990,6 +2325,9 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
 
         tmpTM = *gmtime(&tmpTime);
         STHook = (SYSTEMTIME *)lpBuffer;
+        if(STHook==NULL)
+            return bSuccess;
+
         STHook->wDay = tmpTM.tm_mday;
         STHook->wHour = tmpTM.tm_hour;
         STHook->wMilliseconds = 0;
@@ -2998,6 +2336,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",
@@ -3014,13 +2353,12 @@ static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
             INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
             return bSuccess;
         }
-        if (lpBuffer)
-        {
+
             memcpy(lpBuffer, lphttpHdr->lpszValue, len);
-            TRACE(" returning string: %s\n", debugstr_w(lpBuffer));
-        }
         *lpdwBufferLength = len - sizeof(WCHAR);
         bSuccess = TRUE;
+
+       TRACE(" returning string : %s\n", debugstr_w(lpBuffer));
     }
     return bSuccess;
 }
@@ -3039,7 +2377,7 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
        LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
 {
     BOOL bSuccess = FALSE;
-    http_request_t *lpwhr;
+    LPWININETHTTPREQW lpwhr;
 
     if (TRACE_ON(wininet)) {
 #define FE(x) { x, #x }
@@ -3151,7 +2489,7 @@ BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
        TRACE("\n");
     }
     
-    lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
+    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
     {
         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
@@ -3310,14 +2648,14 @@ BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
                    DWORD dwFlags, DWORD_PTR dwContext)
 {
     BOOL ret = FALSE;
-    http_request_t *lpwhr;
-    http_session_t *lpwhs;
-    appinfo_t *hIC;
+    LPWININETHTTPREQW lpwhr;
+    LPWININETHTTPSESSIONW lpwhs;
+    LPWININETAPPINFOW hIC;
 
     TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
             lpBuffersOut, dwFlags, dwContext);
 
-    lpwhr = (http_request_t*) WININET_GetObject( hRequest );
+    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
 
     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
     {
@@ -3340,8 +2678,11 @@ BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
         req = &workRequest.u.HttpSendRequestW;
         if (lpBuffersIn)
         {
+            if (lpBuffersIn->lpcszHeader)
             /* FIXME: this should use dwHeadersLength or may not be necessary at all */
-            req->lpszHeader = heap_strdupW(lpBuffersIn->lpcszHeader);
+                req->lpszHeader = WININET_strdupW(lpBuffersIn->lpcszHeader);
+            else
+                req->lpszHeader = NULL;
             req->dwHeaderLength = lpBuffersIn->dwHeadersLength;
             req->lpOptional = lpBuffersIn->lpvBuffer;
             req->dwOptionalLength = lpBuffersIn->dwBufferLength;
@@ -3395,15 +2736,15 @@ lend:
 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;
+    LPWININETHTTPREQW lpwhr;
+    LPWININETHTTPSESSIONW lpwhs = NULL;
+    LPWININETAPPINFOW 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 );
+    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
     {
         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
@@ -3437,13 +2778,8 @@ BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
         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);
+            req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, dwHeaderLength * sizeof(WCHAR));
+            memcpy(req->lpszHeader, lpszHeaders, dwHeaderLength * sizeof(WCHAR));
         }
         else
             req->lpszHeader = 0;
@@ -3499,15 +2835,44 @@ BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
     return result;
 }
 
+static BOOL HTTP_GetRequestURL(WININETHTTPREQW *req, LPWSTR buf)
+{
+    LPHTTPHEADERW host_header;
+
+    static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
+
+    host_header = HTTP_GetHeader(req, szHost);
+    if(!host_header)
+        return FALSE;
+
+    sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */
+    return TRUE;
+}
+
 /***********************************************************************
- *           HTTP_GetRedirectURL (internal)
+ *           HTTP_HandleRedirect (internal)
  */
-static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl)
+static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
 {
+    static const WCHAR szContentType[] = {'C','o','n','t','e','n','t','-','T','y','p','e',0};
+    static const WCHAR szContentLength[] = {'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
+    LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
+    LPWININETAPPINFOW hIC = lpwhs->lpAppInfo;
+    BOOL using_proxy = hIC->lpszProxy && hIC->lpszProxy[0];
+    WCHAR path[INTERNET_MAX_URL_LENGTH];
+    int index;
+
+    if(lpszUrl[0]=='/')
+    {
+        /* if it's an absolute path, keep the same session info */
+        lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH);
+    }
+    else
+    {
+        URL_COMPONENTSW urlComponents;
+        WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
     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;
@@ -3529,7 +2894,7 @@ static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl)
 
     if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) &&
         (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
-        return NULL;
+            return FALSE;
 
     orig_url = HeapAlloc(GetProcessHeap(), 0, url_length);
 
@@ -3538,7 +2903,7 @@ static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl)
     if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length))
     {
         HeapFree(GetProcessHeap(), 0, orig_url);
-        return NULL;
+            return FALSE;
     }
 
     url_length = 0;
@@ -3546,7 +2911,7 @@ static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl)
         (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
     {
         HeapFree(GetProcessHeap(), 0, orig_url);
-        return NULL;
+            return FALSE;
     }
     combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR));
 
@@ -3554,35 +2919,9 @@ static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl)
     {
         HeapFree(GetProcessHeap(), 0, orig_url);
         HeapFree(GetProcessHeap(), 0, combined_url);
-        return NULL;
+            return FALSE;
     }
     HeapFree(GetProcessHeap(), 0, orig_url);
-    return combined_url;
-}
-
-
-/***********************************************************************
- *           HTTP_HandleRedirect (internal)
- */
-static BOOL HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
-{
-    http_session_t *lpwhs = lpwhr->lpHttpSession;
-    appinfo_t *hIC = lpwhs->lpAppInfo;
-    BOOL using_proxy = hIC->lpszProxy && hIC->lpszProxy[0];
-    WCHAR path[INTERNET_MAX_URL_LENGTH];
-    int index;
-
-    if(lpszUrl[0]=='/')
-    {
-        /* if it's an absolute path, keep the same session info */
-        lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH);
-    }
-    else
-    {
-        URL_COMPONENTSW urlComponents;
-        WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
-        static WCHAR szHttp[] = {'h','t','t','p',0};
-        static WCHAR szHttps[] = {'h','t','t','p','s',0};
 
         userName[0] = 0;
         hostName[0] = 0;
@@ -3601,8 +2940,13 @@ static BOOL HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
         urlComponents.dwUrlPathLength = 2048;
         urlComponents.lpszExtraInfo = NULL;
         urlComponents.dwExtraInfoLength = 0;
-        if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
+        if(!InternetCrackUrlW(combined_url, strlenW(combined_url), 0, &urlComponents))
+        {
+            HeapFree(GetProcessHeap(), 0, combined_url);
             return FALSE;
+        }
+
+        HeapFree(GetProcessHeap(), 0, combined_url);
 
         if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) &&
             (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE))
@@ -3656,28 +3000,26 @@ static BOOL HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
             sprintfW(lpwhs->lpszHostName, fmt, hostName, urlComponents.nPort);
         }
         else
-            lpwhs->lpszHostName = heap_strdupW(hostName);
+            lpwhs->lpszHostName = WININET_strdupW(hostName);
 
-        HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
+        HTTP_ProcessHeader(lpwhr, szHost, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
 
         HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
         lpwhs->lpszUserName = NULL;
         if (userName[0])
-            lpwhs->lpszUserName = heap_strdupW(userName);
+            lpwhs->lpszUserName = WININET_strdupW(userName);
 
         if (!using_proxy)
         {
             if (strcmpiW(lpwhs->lpszServerName, hostName) || lpwhs->nServerPort != urlComponents.nPort)
             {
                 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
-                lpwhs->lpszServerName = heap_strdupW(hostName);
+                lpwhs->lpszServerName = WININET_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;
-                lpwhr->read_pos = lpwhr->read_size = 0;
-                lpwhr->read_chunked = FALSE;
             }
         }
         else
@@ -3697,7 +3039,7 @@ static BOOL HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
         lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR));
         rc = UrlEscapeW(path, lpwhr->lpszPath, &needed,
                         URL_ESCAPE_SPACES_ONLY);
-        if (rc != S_OK)
+        if (rc)
         {
             ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc);
             strcpyW(lpwhr->lpszPath,path);
@@ -3705,10 +3047,10 @@ static BOOL HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
     }
 
     /* Remove custom content-type/length headers on redirects.  */
-    index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Type, 0, TRUE);
+    index = HTTP_GetCustomHeaderIndex(lpwhr, szContentType, 0, TRUE);
     if (0 <= index)
         HTTP_DeleteCustomHeader(lpwhr, index);
-    index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Length, 0, TRUE);
+    index = HTTP_GetCustomHeaderIndex(lpwhr, szContentLength, 0, TRUE);
     if (0 <= index)
         HTTP_DeleteCustomHeader(lpwhr, index);
 
@@ -3738,7 +3080,7 @@ static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
     return str;
 }
 
-static BOOL HTTP_SecureProxyConnect(http_request_t *lpwhr)
+static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr)
 {
     LPWSTR lpszPath;
     LPWSTR requestString;
@@ -3749,7 +3091,7 @@ static BOOL HTTP_SecureProxyConnect(http_request_t *lpwhr)
     BOOL ret;
     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;
+    LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
 
     TRACE("\n");
 
@@ -3780,30 +3122,31 @@ static BOOL HTTP_SecureProxyConnect(http_request_t *lpwhr)
     return TRUE;
 }
 
-static void HTTP_InsertCookies(http_request_t *lpwhr)
+static void HTTP_InsertCookies(LPWININETHTTPREQW lpwhr)
 {
-    static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
+    static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s',0};
     LPWSTR lpszCookies, lpszUrl = NULL;
     DWORD nCookieSize, size;
-    LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
+    LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr,szHost);
 
-    size = (strlenW(Host->lpszValue) + strlenW(szUrlForm) + strlenW(lpwhr->lpszPath)) * sizeof(WCHAR);
+    size = (strlenW(Host->lpszValue) + strlenW(szUrlForm)) * sizeof(WCHAR);
     if (!(lpszUrl = HeapAlloc(GetProcessHeap(), 0, size))) return;
-    sprintfW( lpszUrl, szUrlForm, Host->lpszValue, lpwhr->lpszPath);
+    sprintfW( lpszUrl, szUrlForm, Host->lpszValue );
 
     if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize))
     {
         int cnt = 0;
         static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0};
+        static const WCHAR szcrlf[] = {'\r','\n',0};
 
-        size = sizeof(szCookie) + nCookieSize * sizeof(WCHAR) + sizeof(szCrLf);
+        size = sizeof(szCookie) + nCookieSize * sizeof(WCHAR) + sizeof(szcrlf);
         if ((lpszCookies = HeapAlloc(GetProcessHeap(), 0, size)))
         {
             cnt += sprintfW(lpszCookies, szCookie);
             InternetGetCookieW(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize);
-            strcatW(lpszCookies, szCrLf);
+            strcatW(lpszCookies, szcrlf);
 
-            HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_REPLACE);
+            HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_ADD);
             HeapFree(GetProcessHeap(), 0, lpszCookies);
         }
     }
@@ -3820,12 +3163,12 @@ static void HTTP_InsertCookies(http_request_t *lpwhr)
  *    FALSE on failure
  *
  */
-BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
+BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders,
        DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
        DWORD dwContentLength, BOOL bEndRequest)
 {
     INT cnt;
-    BOOL bSuccess = FALSE, redirected = FALSE;
+    BOOL bSuccess = FALSE;
     LPWSTR requestString = NULL;
     INT responseLen;
     BOOL loop_next;
@@ -3841,13 +3184,12 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
 
     /* if the verb is NULL default to GET */
     if (!lpwhr->lpszVerb)
-        lpwhr->lpszVerb = heap_strdupW(szGET);
+        lpwhr->lpszVerb = WININET_strdupW(szGET);
 
-    if (dwContentLength || strcmpW(lpwhr->lpszVerb, szGET))
+    if (dwContentLength || !strcmpW(lpwhr->lpszVerb, szPost))
     {
         sprintfW(contentLengthStr, szContentLength, dwContentLength);
-        HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE);
-        lpwhr->dwBytesToWrite = dwContentLength;
+        HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD_IF_NEW);
     }
     if (lpwhr->lpHttpSession->lpAppInfo->lpszAgent)
     {
@@ -3888,7 +3230,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
 
         if (TRACE_ON(wininet))
         {
-            LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
+            LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr,szHost);
             TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(lpwhr->lpszPath));
         }
 
@@ -3927,7 +3269,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
             goto lend;
 
         /* send the request as ASCII, tack on the optional data */
-        if (!lpOptional || redirected)
+        if( !lpOptional )
             dwOptionalLength = 0;
         len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
                                    NULL, 0, NULL, NULL );
@@ -3946,8 +3288,6 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
         NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt);
         HeapFree( GetProcessHeap(), 0, ascii_req );
 
-        lpwhr->dwBytesWritten = dwOptionalLength;
-
         INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                               INTERNET_STATUS_REQUEST_SENT,
                               &len, sizeof(DWORD));
@@ -3956,6 +3296,8 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
         {
             DWORD dwBufferSize;
             DWORD dwStatusCode;
+            WCHAR encoding[20];
+            static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
 
             INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                                 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
@@ -3973,7 +3315,22 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
 
             HTTP_ProcessCookies(lpwhr);
 
-            if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
+            dwBufferSize = sizeof(lpwhr->dwContentLength);
+            if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
+                                     &lpwhr->dwContentLength,&dwBufferSize,NULL))
+                lpwhr->dwContentLength = -1;
+
+            if (lpwhr->dwContentLength == 0)
+                HTTP_FinishedReading(lpwhr);
+
+            /* Correct the case where both a Content-Length and Transfer-encoding = chunked are set */
+
+            dwBufferSize = sizeof(encoding);
+            if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &dwBufferSize, NULL) &&
+                !strcmpiW(encoding, szChunked))
+            {
+                lpwhr->dwContentLength = -1;
+            }
 
             dwBufferSize = sizeof(dwStatusCode);
             if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
@@ -3982,47 +3339,36 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
 
             if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
             {
-                WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
+                WCHAR 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 (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));
-                        bSuccess = HTTP_HandleRedirect(lpwhr, new_url);
+                    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                                          INTERNET_STATUS_REDIRECT, szNewLocation,
+                                          dwBufferSize);
+                    bSuccess = HTTP_HandleRedirect(lpwhr, szNewLocation);
                         if (bSuccess)
                         {
                             HeapFree(GetProcessHeap(), 0, requestString);
                             loop_next = TRUE;
                         }
-                        HeapFree( GetProcessHeap(), 0, new_url );
                     }
-                    redirected = TRUE;
                 }
-            }
             if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && bSuccess)
             {
                 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))
                     {
                         if (HTTP_DoAuthorization(lpwhr, szAuthValue,
                                                  &lpwhr->pAuthInfo,
                                                  lpwhr->lpHttpSession->lpszUserName,
-                                                 lpwhr->lpHttpSession->lpszPassword,
-                                                 Host->lpszValue))
+                                                 lpwhr->lpHttpSession->lpszPassword))
                         {
                             loop_next = TRUE;
                             break;
@@ -4037,8 +3383,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
                         if (HTTP_DoAuthorization(lpwhr, szAuthValue,
                                                  &lpwhr->pProxyAuthInfo,
                                                  lpwhr->lpHttpSession->lpAppInfo->lpszProxyUsername,
-                                                 lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword,
-                                                 NULL))
+                                                 lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword))
                         {
                             loop_next = TRUE;
                             break;
@@ -4052,7 +3397,8 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
     }
     while (loop_next);
 
-    if(bSuccess) {
+    /* FIXME: Better check, when we have to create the cache file */
+    if(bSuccess && (lpwhr->hdr.dwFlags & INTERNET_FLAG_NEED_FILE)) {
         WCHAR url[INTERNET_MAX_URL_LENGTH];
         WCHAR cacheFileName[MAX_PATH+1];
         BOOL b;
@@ -4065,7 +3411,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
 
         b = CreateUrlCacheEntryW(url, lpwhr->dwContentLength > 0 ? lpwhr->dwContentLength : 0, NULL, cacheFileName, 0);
         if(b) {
-            lpwhr->lpszCacheFile = heap_strdupW(cacheFileName);
+            lpwhr->lpszCacheFile = WININET_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) {
@@ -4083,31 +3429,12 @@ lend:
 
     /* TODO: send notification for P3P header */
 
-    if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        if (bSuccess)
-        {
-            if (lpwhr->dwBytesWritten == lpwhr->dwBytesToWrite) HTTP_ReceiveRequestData(lpwhr, TRUE);
-            else
-            {
                 iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
-                iar.dwError = 0;
+    iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
 
                 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                                   INTERNET_STATUS_REQUEST_COMPLETE, &iar,
                                   sizeof(INTERNET_ASYNC_RESULT));
-            }
-        }
-        else
-        {
-            iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
-            iar.dwError = INTERNET_GetLastError();
-
-            INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                                  INTERNET_STATUS_REQUEST_COMPLETE, &iar,
-                                  sizeof(INTERNET_ASYNC_RESULT));
-        }
-    }
 
     TRACE("<--\n");
     if (bSuccess) INTERNET_SetLastError(ERROR_SUCCESS);
@@ -4120,9 +3447,9 @@ lend:
  * Deallocate session handle
  *
  */
-static void HTTPSESSION_Destroy(object_header_t *hdr)
+static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr)
 {
-    http_session_t *lpwhs = (http_session_t*) hdr;
+    LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr;
 
     TRACE("%p\n", lpwhs);
 
@@ -4135,7 +3462,7 @@ static void HTTPSESSION_Destroy(object_header_t *hdr)
     HeapFree(GetProcessHeap(), 0, lpwhs);
 }
 
-static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
+static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
 {
     switch(option) {
     case INTERNET_OPTION_HANDLE_TYPE:
@@ -4152,34 +3479,11 @@ static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *b
     return INET_QueryOption(option, buffer, size, unicode);
 }
 
-static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
-{
-    http_session_t *ses = (http_session_t*)hdr;
-
-    switch(option) {
-    case INTERNET_OPTION_USERNAME:
-    {
-        HeapFree(GetProcessHeap(), 0, ses->lpszUserName);
-        if (!(ses->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
-        return ERROR_SUCCESS;
-    }
-    case INTERNET_OPTION_PASSWORD:
-    {
-        HeapFree(GetProcessHeap(), 0, ses->lpszPassword);
-        if (!(ses->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
-        return ERROR_SUCCESS;
-    }
-    default: break;
-    }
-
-    return ERROR_INTERNET_INVALID_OPTION;
-}
-
-static const object_vtbl_t HTTPSESSIONVtbl = {
+static const HANDLEHEADERVtbl HTTPSESSIONVtbl = {
     HTTPSESSION_Destroy,
     NULL,
     HTTPSESSION_QueryOption,
-    HTTPSESSION_SetOption,
+    NULL,
     NULL,
     NULL,
     NULL,
@@ -4198,12 +3502,12 @@ static const object_vtbl_t HTTPSESSIONVtbl = {
  *   NULL on failure
  *
  */
-HINTERNET HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
+HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
        INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
        LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
        DWORD dwInternalFlags)
 {
-    http_session_t *lpwhs = NULL;
+    LPWININETHTTPSESSIONW lpwhs = NULL;
     HINTERNET handle = NULL;
 
     TRACE("-->\n");
@@ -4216,7 +3520,7 @@ HINTERNET HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
 
     assert( hIC->hdr.htype == WH_HINIT );
 
-    lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_session_t));
+    lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW));
     if (NULL == lpwhs)
     {
         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
@@ -4255,13 +3559,13 @@ HINTERNET HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
     }
     if (lpszServerName && lpszServerName[0])
     {
-        lpwhs->lpszServerName = heap_strdupW(lpszServerName);
-        lpwhs->lpszHostName = heap_strdupW(lpszServerName);
+        lpwhs->lpszServerName = WININET_strdupW(lpszServerName);
+        lpwhs->lpszHostName = WININET_strdupW(lpszServerName);
     }
     if (lpszUserName && lpszUserName[0])
-        lpwhs->lpszUserName = heap_strdupW(lpszUserName);
+        lpwhs->lpszUserName = WININET_strdupW(lpszUserName);
     if (lpszPassword && lpszPassword[0])
-        lpwhs->lpszPassword = heap_strdupW(lpszPassword);
+        lpwhs->lpszPassword = WININET_strdupW(lpszPassword);
     lpwhs->nServerPort = nServerPort;
     lpwhs->nHostPort = nServerPort;
 
@@ -4297,18 +3601,17 @@ lerror:
  *   TRUE  on success
  *   FALSE on failure
  */
-static BOOL HTTP_OpenConnection(http_request_t *lpwhr)
+static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr)
 {
     BOOL bSuccess = FALSE;
-    http_session_t *lpwhs;
-    appinfo_t *hIC = NULL;
-    char szaddr[INET6_ADDRSTRLEN];
-    const void *addr;
+    LPWININETHTTPSESSIONW lpwhs;
+    LPWININETAPPINFOW hIC = NULL;
+    char szaddr[32];
 
     TRACE("-->\n");
 
 
-    if (lpwhr->hdr.htype != WH_HHTTPREQ)
+    if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
     {
         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
         goto lend;
@@ -4324,26 +3627,14 @@ static BOOL HTTP_OpenConnection(http_request_t *lpwhr)
     lpwhs = lpwhr->lpHttpSession;
 
     hIC = lpwhs->lpAppInfo;
-    switch (lpwhs->socketAddress.ss_family)
-    {
-    case AF_INET:
-        addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr;
-        break;
-    case AF_INET6:
-        addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr;
-        break;
-    default:
-        WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family);
-        INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
-        return FALSE;
-    }
-    inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr));
+    inet_ntop(lpwhs->socketAddress.sin_family, &lpwhs->socketAddress.sin_addr,
+              szaddr, sizeof(szaddr));
     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                           INTERNET_STATUS_CONNECTING_TO_SERVER,
                           szaddr,
                           strlen(szaddr)+1);
 
-    if (!NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.ss_family,
+    if (!NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.sin_family,
                          SOCK_STREAM, 0))
     {
         WARN("Socket creation failed: %u\n", INTERNET_GetLastError());
@@ -4351,7 +3642,7 @@ static BOOL HTTP_OpenConnection(http_request_t *lpwhr)
     }
 
     if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
-                      lpwhs->sa_len))
+                      sizeof(lpwhs->socketAddress)))
        goto lend;
 
     if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)
@@ -4379,9 +3670,6 @@ static BOOL HTTP_OpenConnection(http_request_t *lpwhr)
     bSuccess = TRUE;
 
 lend:
-    lpwhr->read_pos = lpwhr->read_size = 0;
-    lpwhr->read_chunked = FALSE;
-
     TRACE("%d <--\n", bSuccess);
     return bSuccess;
 }
@@ -4392,7 +3680,7 @@ lend:
  *
  * clear out any old response headers
  */
-static void HTTP_clear_response_headers( http_request_t *lpwhr )
+static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr )
 {
     DWORD i;
 
@@ -4419,20 +3707,20 @@ static void HTTP_clear_response_headers( http_request_t *lpwhr )
  *   TRUE  on success
  *   FALSE on error
  */
-static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
+static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear)
 {
     INT cbreaks = 0;
     WCHAR buffer[MAX_REPLY_LEN];
     DWORD buflen = MAX_REPLY_LEN;
     BOOL bSuccess = FALSE;
     INT  rc = 0;
+    static const WCHAR szCrLf[] = {'\r','\n',0};
+    static const WCHAR szHundred[] = {'1','0','0',0};
     char bufferA[MAX_REPLY_LEN];
-    LPWSTR status_code = NULL, status_text = NULL;
+    LPWSTR status_code, status_text;
     DWORD cchMaxRawHeaders = 1024;
     LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR));
-    LPWSTR temp;
     DWORD cchRawHeaders = 0;
-    BOOL codeHundred = FALSE;
 
     TRACE("-->\n");
 
@@ -4443,18 +3731,20 @@ static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
         goto lend;
 
     do {
-        static const WCHAR szHundred[] = {'1','0','0',0};
         /*
-         * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
+         * HACK peek at the buffer
          */
         buflen = MAX_REPLY_LEN;
-        if (!read_line(lpwhr, bufferA, &buflen))
+        NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc);
+
+        /*
+         * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
+         */
+        memset(buffer, 0, MAX_REPLY_LEN);
+        if (!NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
             goto lend;
-        rc += buflen;
         MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
-        /* check is this a status code line? */
-        if (!strncmpW(buffer, g_szHttp1_0, 4))
-        {
+
             /* split the version from the status code */
             status_code = strchrW( buffer, ' ' );
             if( !status_code )
@@ -4470,14 +3760,7 @@ static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
             TRACE("version [%s] status code [%s] status text [%s]\n",
                debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
 
-            codeHundred = (!strcmpW(status_code, szHundred));
-        }
-        else if (!codeHundred)
-        {
-            FIXME("Non status line at head of response (%s)\n",debugstr_w(buffer));
-            goto lend;
-        }
-    } while (codeHundred);
+    } while (!strcmpW(status_code, szHundred)); /* ignore "100 Continue" responses */
 
     /* Add status code */
     HTTP_ProcessHeader(lpwhr, szStatus, status_code,
@@ -4486,8 +3769,8 @@ static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
     HeapFree(GetProcessHeap(),0,lpwhr->lpszVersion);
     HeapFree(GetProcessHeap(),0,lpwhr->lpszStatusText);
 
-    lpwhr->lpszVersion = heap_strdupW(buffer);
-    lpwhr->lpszStatusText = heap_strdupW(status_text);
+    lpwhr->lpszVersion= WININET_strdupW(buffer);
+    lpwhr->lpszStatusText = WININET_strdupW(status_text);
 
     /* Restore the spaces */
     *(status_code-1) = ' ';
@@ -4495,10 +3778,10 @@ static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
 
     /* regenerate raw headers */
     while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
+    {
         cchMaxRawHeaders *= 2;
-    temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
-    if (temp == NULL) goto lend;
-    lpszRawHeaders = temp;
+        lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+    }
     memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
     cchRawHeaders += (buflen-1);
     memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
@@ -4509,35 +3792,33 @@ static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
     do
     {
        buflen = MAX_REPLY_LEN;
-        if (read_line(lpwhr, bufferA, &buflen))
+        if (NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
         {
             LPWSTR * pFieldAndValue;
 
             TRACE("got line %s, now interpreting\n", debugstr_a(bufferA));
-
-            if (!bufferA[0]) break;
             MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
 
-            pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
-            if (pFieldAndValue)
-            {
                 while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
+            {
                     cchMaxRawHeaders *= 2;
-                temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
-                if (temp == NULL) goto lend;
-                lpszRawHeaders = temp;
+                lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+            }
                 memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
                 cchRawHeaders += (buflen-1);
                 memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
                 cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
                 lpszRawHeaders[cchRawHeaders] = '\0';
 
+            pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
+            if (!pFieldAndValue)
+                break;
+
                 HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1],
                                    HTTP_ADDREQ_FLAG_ADD );
 
                 HTTP_FreeTokens(pFieldAndValue);
             }
-        }
        else
        {
            cbreaks++;
@@ -4546,19 +3827,6 @@ static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
        }
     }while(1);
 
-    /* make sure the response header is terminated with an empty line.  Some apps really
-       truly care about that empty line being there for some reason.  Just add it to the
-       header. */
-    if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders)
-    {
-        cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf);
-        temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR));
-        if (temp == NULL) goto lend;
-        lpszRawHeaders = temp;
-    }
-
-    memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf));
-
     HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
     lpwhr->lpszRawHeaders = lpszRawHeaders;
     TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
@@ -4576,6 +3844,27 @@ 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)
  *
@@ -4640,7 +3929,7 @@ 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 BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
 {
     LPHTTPHEADERW lphttpHdr = NULL;
     BOOL bSuccess = FALSE;
@@ -4762,12 +4051,30 @@ static BOOL HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR val
  * Called when all content from server has been read by client.
  *
  */
-static BOOL HTTP_FinishedReading(http_request_t *lpwhr)
+BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr)
 {
-    BOOL keepalive = HTTP_KeepAlive(lpwhr);
+    WCHAR szVersion[10];
+    WCHAR szConnectionResponse[20];
+    DWORD dwBufferSize = sizeof(szVersion);
+    BOOL keepalive = FALSE;
 
     TRACE("\n");
 
+    /* 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))
+    {
+        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))
+    {
+        keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
+    }
 
     if (!keepalive)
     {
@@ -4786,7 +4093,7 @@ static BOOL HTTP_FinishedReading(http_request_t *lpwhr)
  * Return index of custom header from header array
  *
  */
-static INT HTTP_GetCustomHeaderIndex(http_request_t *lpwhr, LPCWSTR lpszField,
+static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField,
                                      int requested_index, BOOL request_only)
 {
     DWORD index;
@@ -4823,7 +4130,7 @@ 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 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr)
 {
     INT count;
     LPHTTPHEADERW lph = NULL;
@@ -4839,8 +4146,8 @@ static BOOL HTTP_InsertCustomHeader(http_request_t *lpwhr, LPHTTPHEADERW lpHdr)
     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].lpszField = WININET_strdupW(lpHdr->lpszField);
+        lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdupW(lpHdr->lpszValue);
         lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
         lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
        lpwhr->nCustHeaders++;
@@ -4861,7 +4168,7 @@ static BOOL HTTP_InsertCustomHeader(http_request_t *lpwhr, LPHTTPHEADERW lpHdr)
  * Delete header from array
  *  If this function is called, the indexs may change.
  */
-static BOOL HTTP_DeleteCustomHeader(http_request_t *lpwhr, DWORD index)
+static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index)
 {
     if( lpwhr->nCustHeaders <= 0 )
         return FALSE;
@@ -4886,7 +4193,7 @@ static BOOL HTTP_DeleteCustomHeader(http_request_t *lpwhr, DWORD index)
  * Verify the given header is not invalid for the given http request
  *
  */
-static BOOL HTTP_VerifyValidHeader(http_request_t *lpwhr, LPCWSTR field)
+static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW 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))