[1/2] wininet: Reorder the http functions to avoid forward declarations.

Francois Gouget fgouget at free.fr
Mon Jun 22 03:46:17 CDT 2009


---
 dlls/wininet/http.c     | 4801 +++++++++++++++++++++++------------------------
 dlls/wininet/internet.h |    8 -
 2 files changed, 2394 insertions(+), 2415 deletions(-)

diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c
index e1a7ddc..2c72827 100644
--- a/dlls/wininet/http.c
+++ b/dlls/wininet/http.c
@@ -176,113 +175,80 @@ struct gzip_stream_t {
     BOOL end_of_data;
 };
 
-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(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(LPWININETHTTPREQW, DWORD, LPVOID, LPDWORD, LPDWORD);
-static LPWSTR HTTP_GetRedirectURL(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl);
-static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl);
-static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
-static BOOL HTTP_VerifyValidHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field);
-static void HTTP_DrainContent(WININETHTTPREQW *req);
-static BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr);
 
-static LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head)
-{
-    int HeaderIndex = 0;
-    HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
-    if (HeaderIndex == -1)
-        return NULL;
-    else
-        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)
+/* read some more data into the read buffer (the read section must be held) */
+static BOOL read_more_data( WININETHTTPREQW *req, int maxlen )
 {
-    HeapFree(GetProcessHeap(), 0, address);
-}
+    int len;
 
-static void init_gzip_stream(WININETHTTPREQW *req)
-{
-    gzip_stream_t *gzip_stream;
-    int zres;
+    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;
+    }
 
-    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;
+    if (maxlen == -1) maxlen = sizeof(req->read_buf);
 
-    zres = inflateInit2(&gzip_stream->zstream, 0x1f);
-    if(zres != Z_OK) {
-        ERR("inflateInit failed: %d\n", zres);
-        HeapFree(GetProcessHeap(), 0, gzip_stream);
-        return;
-    }
+    if(!NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
+                     maxlen - req->read_size, 0, &len ))
+        return FALSE;
 
-    req->gzip_stream = gzip_stream;
+    req->read_size += len;
+    return TRUE;
 }
 
-#else
-
-static void init_gzip_stream(WININETHTTPREQW *req)
+/* remove some amount of data from the read buffer (the read section must be held) */
+static void remove_data( WININETHTTPREQW *req, int count )
 {
-    ERR("gzip stream not supported, missing zlib.\n");
+    if (!(req->read_size -= count)) req->read_pos = 0;
+    else req->read_pos += count;
 }
 
-#endif
-
-/* set the request content length based on the headers */
-static DWORD set_content_length( LPWININETHTTPREQW lpwhr )
+static BOOL read_line( WININETHTTPREQW *req, LPSTR buffer, DWORD *len )
 {
-    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;
+    int count, bytes_read, pos = 0;
 
-    size = sizeof(encoding);
-    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) &&
-        !strcmpiW(encoding, szChunked))
+    EnterCriticalSection( &req->read_section );
+    for (;;)
     {
-        lpwhr->dwContentLength = ~0u;
-        lpwhr->read_chunked = TRUE;
-    }
+        BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
 
-    if(lpwhr->decoding) {
-        int encoding_idx;
+        if (eol)
+        {
+            count = eol - (req->read_buf + req->read_pos);
+            bytes_read = count + 1;
+        }
+        else count = bytes_read = req->read_size;
 
-        static const WCHAR gzipW[] = {'g','z','i','p',0};
+        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;
 
-        encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE);
-        if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW))
-            init_gzip_stream(lpwhr);
+        if (!read_more_data( req, -1 ) || !req->read_size)
+        {
+            *len = 0;
+            TRACE( "returning empty string\n" );
+            LeaveCriticalSection( &req->read_section );
+            return FALSE;
+        }
     }
+    LeaveCriticalSection( &req->read_section );
 
-    return lpwhr->dwContentLength;
+    if (pos < *len)
+    {
+        if (pos && buffer[pos - 1] == '\r') pos--;
+        *len = pos + 1;
+    }
+    buffer[*len - 1] = 0;
+    TRACE( "returning %s\n", debugstr_a(buffer));
+    return TRUE;
 }
 
+
 /***********************************************************************
  *           HTTP_Tokenize (internal)
  *
@@ -348,366 +314,498 @@ static void HTTP_FreeTokens(LPWSTR * token_array)
     HeapFree(GetProcessHeap(), 0, token_array);
 }
 
-/* **********************************************************************
- * 
- * Helper functions for the HttpSendRequest(Ex) functions
- * 
+
+/***********************************************************************
+ *           HTTP_GetCustomHeaderIndex (internal)
+ *
+ * Return index of custom header from header array
+ *
  */
-static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
+static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField,
+                                     int requested_index, BOOL request_only)
 {
-    struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
-    LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest->hdr;
+    DWORD index;
 
-    TRACE("%p\n", lpwhr);
+    TRACE("%s\n", debugstr_w(lpszField));
 
-    HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
-            req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
-            req->dwContentLength, req->bEndRequest);
+    for (index = 0; index < lpwhr->nCustHeaders; index++)
+    {
+        if (strcmpiW(lpwhr->pCustHeaders[index].lpszField, lpszField))
+            continue;
 
-    HeapFree(GetProcessHeap(), 0, req->lpszHeader);
+        if (request_only && !(lpwhr->pCustHeaders[index].wFlags & HDR_ISREQUEST))
+            continue;
+
+        if (!request_only && (lpwhr->pCustHeaders[index].wFlags & HDR_ISREQUEST))
+            continue;
+
+        if (requested_index == 0)
+            break;
+        requested_index --;
+    }
+
+    if (index >= lpwhr->nCustHeaders)
+	index = -1;
+
+    TRACE("Return: %d\n", index);
+    return index;
 }
 
-static void HTTP_FixURL( LPWININETHTTPREQW lpwhr)
+
+static LPHTTPHEADERW HTTP_GetHeader(LPWININETHTTPREQW req, LPCWSTR head)
 {
-    static const WCHAR szSlash[] = { '/',0 };
-    static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
+    int HeaderIndex = 0;
+    HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
+    if (HeaderIndex == -1)
+        return NULL;
+    else
+        return &req->pCustHeaders[HeaderIndex];
+}
 
-    /* If we don't have a path we set it to root */
-    if (NULL == lpwhr->lpszPath)
-        lpwhr->lpszPath = WININET_strdupW(szSlash);
-    else /* remove \r and \n*/
+
+/***********************************************************************
+ *           HTTP_InsertCustomHeader (internal)
+ *
+ * Insert header into array
+ *
+ */
+static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr)
+{
+    INT count;
+    LPHTTPHEADERW lph = NULL;
+    BOOL r = FALSE;
+
+    TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
+    count = lpwhr->nCustHeaders + 1;
+    if (count > 1)
+	lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERW) * count);
+    else
+	lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
+
+    if (NULL != lph)
     {
-        int nLen = strlenW(lpwhr->lpszPath);
-        while ((nLen >0 ) && ((lpwhr->lpszPath[nLen-1] == '\r')||(lpwhr->lpszPath[nLen-1] == '\n')))
-        {
-            nLen--;
-            lpwhr->lpszPath[nLen]='\0';
-        }
-        /* Replace '\' with '/' */
-        while (nLen>0) {
-            nLen--;
-            if (lpwhr->lpszPath[nLen] == '\\') lpwhr->lpszPath[nLen]='/';
-        }
+	lpwhr->pCustHeaders = lph;
+        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++;
+        r = TRUE;
     }
-
-    if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
-                       lpwhr->lpszPath, strlenW(lpwhr->lpszPath), szHttp, strlenW(szHttp) )
-       && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
+    else
     {
-        WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0, 
-                             (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR));
-        *fixurl = '/';
-        strcpyW(fixurl + 1, lpwhr->lpszPath);
-        HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
-        lpwhr->lpszPath = fixurl;
+        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
     }
+
+    return r;
 }
 
-static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
+
+/***********************************************************************
+ *           HTTP_DeleteCustomHeader (internal)
+ *
+ * Delete header from array
+ *  If this function is called, the indexs may change.
+ */
+static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index)
 {
-    LPWSTR requestString;
-    DWORD len, n;
-    LPCWSTR *req;
-    UINT i;
-    LPWSTR p;
+    if( lpwhr->nCustHeaders <= 0 )
+        return FALSE;
+    if( index >= lpwhr->nCustHeaders )
+        return FALSE;
+    lpwhr->nCustHeaders--;
 
-    static const WCHAR szSpace[] = { ' ',0 };
-    static const WCHAR szColon[] = { ':',' ',0 };
-    static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
+    HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszField);
+    HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszValue);
 
-    /* allocate space for an array of all the string pointers to be added */
-    len = (lpwhr->nCustHeaders)*4 + 10;
-    req = HeapAlloc( GetProcessHeap(), 0, len*sizeof(LPCWSTR) );
+    memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
+             (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) );
+    memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) );
 
-    /* add the verb, path and HTTP version string */
-    n = 0;
-    req[n++] = verb;
-    req[n++] = szSpace;
-    req[n++] = path;
-    req[n++] = szSpace;
-    req[n++] = version;
+    return TRUE;
+}
 
-    /* Append custom request headers */
-    for (i = 0; i < lpwhr->nCustHeaders; i++)
-    {
-        if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
-        {
-            req[n++] = szCrLf;
-            req[n++] = lpwhr->pCustHeaders[i].lpszField;
-            req[n++] = szColon;
-            req[n++] = lpwhr->pCustHeaders[i].lpszValue;
 
-            TRACE("Adding custom header %s (%s)\n",
-                   debugstr_w(lpwhr->pCustHeaders[i].lpszField),
-                   debugstr_w(lpwhr->pCustHeaders[i].lpszValue));
-        }
-    }
+/***********************************************************************
+ *           HTTP_VerifyValidHeader (internal)
+ *
+ * Verify the given header is not invalid for the given http request
+ *
+ */
+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))
+        return FALSE;
 
-    if( n >= len )
-        ERR("oops. buffer overrun\n");
+    return TRUE;
+}
 
-    req[n] = NULL;
-    requestString = HTTP_build_req( req, 4 );
-    HeapFree( GetProcessHeap(), 0, req );
 
-    /*
-     * Set (header) termination string for request
-     * Make sure there's exactly two new lines at the end of the request
-     */
-    p = &requestString[strlenW(requestString)-1];
-    while ( (*p == '\n') || (*p == '\r') )
-       p--;
-    strcpyW( p+1, sztwocrlf );
-    
-    return requestString;
+static void strip_spaces(LPWSTR start)
+{
+    LPWSTR str = start;
+    LPWSTR end;
+
+    while (*str == ' ' && *str != '\0')
+        str++;
+
+    if (str != start)
+        memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1));
+
+    end = start + strlenW(start) - 1;
+    while (end >= start && *end == ' ')
+    {
+        *end = '\0';
+        end--;
+    }
 }
 
-static void HTTP_ProcessCookies( LPWININETHTTPREQW lpwhr )
+
+/***********************************************************************
+ *           HTTP_InterpretHttpHeader (internal)
+ *
+ * Parse server response
+ *
+ * RETURNS
+ *
+ *   Pointer to array of field, value, NULL on success.
+ *   NULL on error.
+ */
+static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer)
 {
-    int HeaderIndex;
-    int numCookies = 0;
-    LPHTTPHEADERW setCookieHeader;
+    LPWSTR * pTokenPair;
+    LPWSTR pszColon;
+    INT len;
 
-    while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1)
-    {
-        setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex];
+    pTokenPair = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTokenPair)*3);
 
-        if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue)
-        {
-            int len;
-            static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0};
-            LPWSTR buf_url;
-            LPHTTPHEADERW Host;
+    pszColon = strchrW(buffer, ':');
+    /* must have two tokens */
+    if (!pszColon)
+    {
+        HTTP_FreeTokens(pTokenPair);
+        if (buffer[0])
+            TRACE("No ':' in line: %s\n", debugstr_w(buffer));
+        return NULL;
+    }
 
-            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);
+    pTokenPair[0] = HeapAlloc(GetProcessHeap(), 0, (pszColon - buffer + 1) * sizeof(WCHAR));
+    if (!pTokenPair[0])
+    {
+        HTTP_FreeTokens(pTokenPair);
+        return NULL;
+    }
+    memcpy(pTokenPair[0], buffer, (pszColon - buffer) * sizeof(WCHAR));
+    pTokenPair[0][pszColon - buffer] = '\0';
 
-            HeapFree(GetProcessHeap(), 0, buf_url);
-        }
-        numCookies++;
+    /* skip colon */
+    pszColon++;
+    len = strlenW(pszColon);
+    pTokenPair[1] = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+    if (!pTokenPair[1])
+    {
+        HTTP_FreeTokens(pTokenPair);
+        return NULL;
     }
-}
+    memcpy(pTokenPair[1], pszColon, (len + 1) * sizeof(WCHAR));
 
-static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue )
-{
-    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)]);
+    strip_spaces(pTokenPair[0]);
+    strip_spaces(pTokenPair[1]);
+
+    TRACE("field(%s) Value(%s)\n", debugstr_w(pTokenPair[0]), debugstr_w(pTokenPair[1]));
+    return pTokenPair;
 }
 
-static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue,
-                                  struct HttpAuthInfo **ppAuthInfo,
-                                  LPWSTR domain_and_username, LPWSTR password )
-{
-    SECURITY_STATUS sec_status;
-    struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
-    BOOL first = FALSE;
+/***********************************************************************
+ *           HTTP_ProcessHeader (internal)
+ *
+ * Stuff header into header tables according to <dwModifier>
+ *
+ */
 
-    TRACE("%s\n", debugstr_w(pszAuthValue));
+#define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
 
-    if (!pAuthInfo)
-    {
-        TimeStamp exp;
+static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
+{
+    LPHTTPHEADERW lphttpHdr = NULL;
+    BOOL bSuccess = FALSE;
+    INT index = -1;
+    BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ;
 
-        first = TRUE;
-        pAuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*pAuthInfo));
-        if (!pAuthInfo)
-            return FALSE;
+    TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier);
 
-        SecInvalidateHandle(&pAuthInfo->cred);
-        SecInvalidateHandle(&pAuthInfo->ctx);
-        memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp));
-        pAuthInfo->attr = 0;
-        pAuthInfo->auth_data = NULL;
-        pAuthInfo->auth_data_len = 0;
-        pAuthInfo->finished = FALSE;
+    /* REPLACE wins out over ADD */
+    if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
+        dwModifier &= ~HTTP_ADDHDR_FLAG_ADD;
 
-        if (is_basic_auth_value(pszAuthValue))
+    if (dwModifier & HTTP_ADDHDR_FLAG_ADD)
+        index = -1;
+    else
+        index = HTTP_GetCustomHeaderIndex(lpwhr, field, 0, request_only);
+
+    if (index >= 0)
+    {
+        if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
         {
-            static const WCHAR szBasic[] = {'B','a','s','i','c',0};
-            pAuthInfo->scheme = WININET_strdupW(szBasic);
-            if (!pAuthInfo->scheme)
-            {
-                HeapFree(GetProcessHeap(), 0, pAuthInfo);
-                return FALSE;
-            }
+            return FALSE;
         }
-        else
+        lphttpHdr = &lpwhr->pCustHeaders[index];
+    }
+    else if (value)
+    {
+        HTTPHEADERW hdr;
+
+        hdr.lpszField = (LPWSTR)field;
+        hdr.lpszValue = (LPWSTR)value;
+        hdr.wFlags = hdr.wCount = 0;
+
+        if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
+            hdr.wFlags |= HDR_ISREQUEST;
+
+        return HTTP_InsertCustomHeader(lpwhr, &hdr);
+    }
+    /* no value to delete */
+    else return TRUE;
+
+    if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
+	    lphttpHdr->wFlags |= HDR_ISREQUEST;
+    else
+        lphttpHdr->wFlags &= ~HDR_ISREQUEST;
+
+    if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
+    {
+        HTTP_DeleteCustomHeader( lpwhr, index );
+
+        if (value)
         {
-            PVOID pAuthData;
-            SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
+            HTTPHEADERW hdr;
 
-            pAuthInfo->scheme = WININET_strdupW(pszAuthValue);
-            if (!pAuthInfo->scheme)
-            {
-                HeapFree(GetProcessHeap(), 0, pAuthInfo);
-                return FALSE;
-            }
+            hdr.lpszField = (LPWSTR)field;
+            hdr.lpszValue = (LPWSTR)value;
+            hdr.wFlags = hdr.wCount = 0;
 
-            if (domain_and_username)
-            {
-                WCHAR *user = strchrW(domain_and_username, '\\');
-                WCHAR *domain = domain_and_username;
+            if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
+                hdr.wFlags |= HDR_ISREQUEST;
 
-                /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
+            return HTTP_InsertCustomHeader(lpwhr, &hdr);
+        }
 
-                pAuthData = &nt_auth_identity;
+        return TRUE;
+    }
+    else if (dwModifier & COALESCEFLAGS)
+    {
+        LPWSTR lpsztmp;
+        WCHAR ch = 0;
+        INT len = 0;
+        INT origlen = strlenW(lphttpHdr->lpszValue);
+        INT valuelen = strlenW(value);
 
-                if (user) user++;
-                else
-                {
-                    user = domain_and_username;
-                    domain = NULL;
-                }
+        if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
+        {
+            ch = ',';
+            lphttpHdr->wFlags |= HDR_COMMADELIMITED;
+        }
+        else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
+        {
+            ch = ';';
+            lphttpHdr->wFlags |= HDR_COMMADELIMITED;
+        }
 
-                nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
-                nt_auth_identity.User = user;
-                nt_auth_identity.UserLength = strlenW(nt_auth_identity.User);
-                nt_auth_identity.Domain = domain;
-                nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
-                nt_auth_identity.Password = password;
-                nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password);
-            }
-            else
-                /* use default credentials */
-                pAuthData = NULL;
+        len = origlen + valuelen + ((ch > 0) ? 2 : 0);
 
-            sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
-                                                   SECPKG_CRED_OUTBOUND, NULL,
-                                                   pAuthData, NULL,
-                                                   NULL, &pAuthInfo->cred,
-                                                   &exp);
-            if (sec_status == SEC_E_OK)
-            {
-                PSecPkgInfoW sec_pkg_info;
-                sec_status = QuerySecurityPackageInfoW(pAuthInfo->scheme, &sec_pkg_info);
-                if (sec_status == SEC_E_OK)
-                {
-                    pAuthInfo->max_token = sec_pkg_info->cbMaxToken;
-                    FreeContextBuffer(sec_pkg_info);
-                }
-            }
-            if (sec_status != SEC_E_OK)
+        lpsztmp = HeapReAlloc(GetProcessHeap(), 0, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
+        if (lpsztmp)
+        {
+            lphttpHdr->lpszValue = lpsztmp;
+    /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
+            if (ch > 0)
             {
-                WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
-                     debugstr_w(pAuthInfo->scheme), sec_status);
-                HeapFree(GetProcessHeap(), 0, pAuthInfo->scheme);
-                HeapFree(GetProcessHeap(), 0, pAuthInfo);
-                return FALSE;
+                lphttpHdr->lpszValue[origlen] = ch;
+                origlen++;
+                lphttpHdr->lpszValue[origlen] = ' ';
+                origlen++;
             }
+
+            memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
+            lphttpHdr->lpszValue[len] = '\0';
+            bSuccess = TRUE;
+        }
+        else
+        {
+            WARN("HeapReAlloc (%d bytes) failed\n",len+1);
+            INTERNET_SetLastError(ERROR_OUTOFMEMORY);
         }
-        *ppAuthInfo = pAuthInfo;
     }
-    else if (pAuthInfo->finished)
-        return FALSE;
+    TRACE("<-- %d\n",bSuccess);
+    return bSuccess;
+}
 
-    if ((strlenW(pszAuthValue) < strlenW(pAuthInfo->scheme)) ||
-        strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme)))
+
+/***********************************************************************
+ *           HTTP_clear_response_headers (internal)
+ *
+ * clear out any old response headers
+ */
+static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr )
+{
+    DWORD i;
+
+    for( i=0; i<lpwhr->nCustHeaders; i++)
     {
-        ERR("authentication scheme changed from %s to %s\n",
-            debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue));
-        return FALSE;
+        if( !lpwhr->pCustHeaders[i].lpszField )
+            continue;
+        if( !lpwhr->pCustHeaders[i].lpszValue )
+            continue;
+        if ( lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST )
+            continue;
+        HTTP_DeleteCustomHeader( lpwhr, i );
+        i--;
     }
+}
 
-    if (is_basic_auth_value(pszAuthValue))
-    {
-        int userlen;
-        int passlen;
-        char *auth_data;
+/***********************************************************************
+ *           HTTP_GetResponseHeaders (internal)
+ *
+ * Read server response
+ *
+ * RETURNS
+ *
+ *   TRUE  on success
+ *   FALSE on error
+ */
+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 szHundred[] = {'1','0','0',0};
+    char bufferA[MAX_REPLY_LEN];
+    LPWSTR status_code, status_text;
+    DWORD cchMaxRawHeaders = 1024;
+    LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR));
+    LPWSTR temp;
+    DWORD cchRawHeaders = 0;
 
-        TRACE("basic authentication\n");
+    TRACE("-->\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;
+    /* clear old response headers (eg. from a redirect response) */
+    if (clear) HTTP_clear_response_headers( lpwhr );
 
-        userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
-        passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL);
+    if (!NETCON_connected(&lpwhr->netConnection))
+        goto lend;
 
-        /* length includes a nul terminator, which will be re-used for the ':' */
-        auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen);
-        if (!auth_data)
-            return FALSE;
+    do {
+        /*
+         * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
+         */
+        buflen = MAX_REPLY_LEN;
+        if (!read_line(lpwhr, bufferA, &buflen))
+            goto lend;
+        rc += buflen;
+        MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
 
-        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);
+        /* split the version from the status code */
+        status_code = strchrW( buffer, ' ' );
+        if( !status_code )
+            goto lend;
+        *status_code++=0;
 
-        pAuthInfo->auth_data = auth_data;
-        pAuthInfo->auth_data_len = userlen + 1 + passlen;
-        pAuthInfo->finished = TRUE;
+        /* split the status code from the status text */
+        status_text = strchrW( status_code, ' ' );
+        if( !status_text )
+            goto lend;
+        *status_text++=0;
 
-        return TRUE;
-    }
-    else
-    {
-        LPCWSTR pszAuthData;
-        SecBufferDesc out_desc, in_desc;
-        SecBuffer out, in;
-        unsigned char *buffer;
-        ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
-            ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
+        TRACE("version [%s] status code [%s] status text [%s]\n",
+           debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
 
-        in.BufferType = SECBUFFER_TOKEN;
-        in.cbBuffer = 0;
-        in.pvBuffer = NULL;
+    } while (!strcmpW(status_code, szHundred)); /* ignore "100 Continue" responses */
 
-        in_desc.ulVersion = 0;
-        in_desc.cBuffers = 1;
-        in_desc.pBuffers = &in;
+    /* Add status code */
+    HTTP_ProcessHeader(lpwhr, szStatus, status_code,
+            HTTP_ADDHDR_FLAG_REPLACE);
 
-        pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme);
-        if (*pszAuthData == ' ')
-        {
-            pszAuthData++;
-            in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL);
-            in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer);
-            HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
-        }
+    HeapFree(GetProcessHeap(),0,lpwhr->lpszVersion);
+    HeapFree(GetProcessHeap(),0,lpwhr->lpszStatusText);
 
-        buffer = HeapAlloc(GetProcessHeap(), 0, pAuthInfo->max_token);
+    lpwhr->lpszVersion= WININET_strdupW(buffer);
+    lpwhr->lpszStatusText = WININET_strdupW(status_text);
 
-        out.BufferType = SECBUFFER_TOKEN;
-        out.cbBuffer = pAuthInfo->max_token;
-        out.pvBuffer = buffer;
+    /* Restore the spaces */
+    *(status_code-1) = ' ';
+    *(status_text-1) = ' ';
 
-        out_desc.ulVersion = 0;
-        out_desc.cBuffers = 1;
-        out_desc.pBuffers = &out;
+    /* 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;
+    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';
 
-        sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL,
-                                                first ? NULL : &pAuthInfo->ctx,
-                                                first ? lpwhr->lpHttpSession->lpszServerName : NULL,
-                                                context_req, 0, SECURITY_NETWORK_DREP,
-                                                in.pvBuffer ? &in_desc : NULL,
-                                                0, &pAuthInfo->ctx, &out_desc,
-                                                &pAuthInfo->attr, &pAuthInfo->exp);
-        if (sec_status == SEC_E_OK)
-        {
-            pAuthInfo->finished = TRUE;
-            pAuthInfo->auth_data = out.pvBuffer;
-            pAuthInfo->auth_data_len = out.cbBuffer;
-            TRACE("sending last auth packet\n");
-        }
-        else if (sec_status == SEC_I_CONTINUE_NEEDED)
-        {
-            pAuthInfo->auth_data = out.pvBuffer;
-            pAuthInfo->auth_data_len = out.cbBuffer;
-            TRACE("sending next auth packet\n");
-        }
-        else
+    /* Parse each response line */
+    do
+    {
+	buflen = MAX_REPLY_LEN;
+        if (read_line(lpwhr, bufferA, &buflen))
         {
-            ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
-            pAuthInfo->finished = TRUE;
-            HeapFree(GetProcessHeap(), 0, out.pvBuffer);
-            return FALSE;
+            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;
+                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';
+
+                HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1],
+                                   HTTP_ADDREQ_FLAG_ADD );
+
+                HTTP_FreeTokens(pFieldAndValue);
+            }
         }
-    }
+	else
+	{
+	    cbreaks++;
+	    if (cbreaks >= 2)
+	       break;
+	}
+    }while(1);
 
-    return TRUE;
+    HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
+    lpwhr->lpszRawHeaders = lpszRawHeaders;
+    TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
+    bSuccess = TRUE;
+
+lend:
+
+    TRACE("<--\n");
+    if (bSuccess)
+        return rc;
+    else
+    {
+        HeapFree(GetProcessHeap(), 0, lpszRawHeaders);
+        return 0;
+    }
 }
 
 /***********************************************************************
@@ -804,7 +902,7 @@ BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
 
     TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
 
-    if (!lpszHeader) 
+    if (!lpszHeader)
       return TRUE;
 
     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
@@ -853,343 +951,982 @@ BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
     return r;
 }
 
-/***********************************************************************
- *           HttpEndRequestA (WININET.@)
- *
- * Ends an HTTP request that was started by HttpSendRequestEx
- *
- * RETURNS
- *    TRUE	if successful
- *    FALSE	on failure
- *
- */
-BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, 
-        LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
+
+
+static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr)
 {
-    TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
+    char szaddr[32];
+    LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
 
-    if (lpBuffersOut)
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                          INTERNET_STATUS_RESOLVING_NAME,
+                          lpwhs->lpszServerName,
+                          strlenW(lpwhs->lpszServerName)+1);
+
+    if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
+                    &lpwhs->socketAddress))
     {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
         return FALSE;
     }
 
-    return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
+    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);
+
+    TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr);
+    return TRUE;
 }
 
-static BOOL HTTP_HttpEndRequestW(LPWININETHTTPREQW lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
+/***********************************************************************
+ *           HTTP_build_req (internal)
+ *
+ *  concatenate all the strings in the request together
+ */
+static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
 {
-    BOOL rc = FALSE;
-    INT responseLen;
-    DWORD dwBufferSize;
-    INTERNET_ASYNC_RESULT iar;
+    LPCWSTR *t;
+    LPWSTR str;
 
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                  INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
+    for( t = list; *t ; t++  )
+        len += strlenW( *t );
+    len++;
 
-    responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
-    if (responseLen)
-        rc = TRUE;
+    str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
+    *str = 0;
 
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                  INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
+    for( t = list; *t ; t++ )
+        strcatW( str, *t );
 
-    /* process cookies here. Is this right? */
-    HTTP_ProcessCookies(lpwhr);
+    return str;
+}
 
-    if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
+static LPWSTR HTTP_BuildHeaderRequestString( LPWININETHTTPREQW lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
+{
+    LPWSTR requestString;
+    DWORD len, n;
+    LPCWSTR *req;
+    UINT i;
+    LPWSTR p;
 
-    if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
+    static const WCHAR szSpace[] = { ' ',0 };
+    static const WCHAR szColon[] = { ':',' ',0 };
+    static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
+
+    /* allocate space for an array of all the string pointers to be added */
+    len = (lpwhr->nCustHeaders)*4 + 10;
+    req = HeapAlloc( GetProcessHeap(), 0, len*sizeof(LPCWSTR) );
+
+    /* add the verb, path and HTTP version string */
+    n = 0;
+    req[n++] = verb;
+    req[n++] = szSpace;
+    req[n++] = path;
+    req[n++] = szSpace;
+    req[n++] = version;
+
+    /* Append custom request headers */
+    for (i = 0; i < lpwhr->nCustHeaders; i++)
     {
-        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))
+        if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
         {
-            WCHAR *new_url, 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);
-                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 );
-                }
-            }
+            req[n++] = szCrLf;
+            req[n++] = lpwhr->pCustHeaders[i].lpszField;
+            req[n++] = szColon;
+            req[n++] = lpwhr->pCustHeaders[i].lpszValue;
+
+            TRACE("Adding custom header %s (%s)\n",
+                   debugstr_w(lpwhr->pCustHeaders[i].lpszField),
+                   debugstr_w(lpwhr->pCustHeaders[i].lpszValue));
         }
     }
 
-    iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
-    iar.dwError = rc ? 0 : INTERNET_GetLastError();
+    if( n >= len )
+        ERR("oops. buffer overrun\n");
 
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                          INTERNET_STATUS_REQUEST_COMPLETE, &iar,
-                          sizeof(INTERNET_ASYNC_RESULT));
-    return rc;
+    req[n] = NULL;
+    requestString = HTTP_build_req( req, 4 );
+    HeapFree( GetProcessHeap(), 0, req );
+
+    /*
+     * Set (header) termination string for request
+     * Make sure there's exactly two new lines at the end of the request
+     */
+    p = &requestString[strlenW(requestString)-1];
+    while ( (*p == '\n') || (*p == '\r') )
+       p--;
+    strcpyW( p+1, sztwocrlf );
+
+    return requestString;
 }
 
-static void AsyncHttpEndRequestProc(WORKREQUEST *work)
+static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr)
 {
-    struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
-    LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW)work->hdr;
+    LPWSTR lpszPath;
+    LPWSTR requestString;
+    INT len;
+    INT cnt;
+    INT responseLen;
+    char *ascii_req;
+    BOOL ret;
+    static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0};
+    static const WCHAR szFormat[] = {'%','s',':','%','d',0};
+    LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
 
-    TRACE("%p\n", lpwhr);
+    TRACE("\n");
 
-    HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext);
+    lpszPath = HeapAlloc( GetProcessHeap(), 0, (lstrlenW( lpwhs->lpszHostName ) + 13)*sizeof(WCHAR) );
+    sprintfW( lpszPath, szFormat, lpwhs->lpszHostName, lpwhs->nHostPort );
+    requestString = HTTP_BuildHeaderRequestString( lpwhr, szConnect, lpszPath, g_szHttp1_1 );
+    HeapFree( GetProcessHeap(), 0, lpszPath );
+
+    len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
+                                NULL, 0, NULL, NULL );
+    len--; /* the nul terminator isn't needed */
+    ascii_req = HeapAlloc( GetProcessHeap(), 0, len );
+    WideCharToMultiByte( CP_ACP, 0, requestString, -1,
+                            ascii_req, len, NULL, NULL );
+    HeapFree( GetProcessHeap(), 0, requestString );
+
+    TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
+
+    ret = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt );
+    HeapFree( GetProcessHeap(), 0, ascii_req );
+    if (!ret || cnt < 0)
+        return FALSE;
+
+    responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE );
+    if (!responseLen)
+        return FALSE;
+
+    return TRUE;
 }
 
 /***********************************************************************
- *           HttpEndRequestW (WININET.@)
- *
- * Ends an HTTP request that was started by HttpSendRequestEx
+ *           HTTPSESSION_Destroy (internal)
  *
- * RETURNS
- *    TRUE	if successful
- *    FALSE	on failure
+ * Deallocate session handle
  *
  */
-BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, 
-        LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
+static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr)
 {
-    BOOL rc = FALSE;
-    LPWININETHTTPREQW lpwhr;
+    LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr;
 
-    TRACE("-->\n");
+    TRACE("%p\n", lpwhs);
 
-    if (lpBuffersOut)
-    {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
-        return FALSE;
-    }
+    WININET_Release(&lpwhs->lpAppInfo->hdr);
 
-    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
+    HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName);
+    HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
+    HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword);
+    HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
+    HeapFree(GetProcessHeap(), 0, lpwhs);
+}
 
-    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-        if (lpwhr)
-            WININET_Release( &lpwhr->hdr );
-        return FALSE;
-    }
-    lpwhr->hdr.dwFlags |= dwFlags;
+static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
+{
+    switch(option) {
+    case INTERNET_OPTION_HANDLE_TYPE:
+        TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
 
-    if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        WORKREQUEST work;
-        struct WORKREQ_HTTPENDREQUESTW *request;
+        if (*size < sizeof(ULONG))
+            return ERROR_INSUFFICIENT_BUFFER;
 
-        work.asyncproc = AsyncHttpEndRequestProc;
-        work.hdr = WININET_AddRef( &lpwhr->hdr );
+        *size = sizeof(DWORD);
+        *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP;
+        return ERROR_SUCCESS;
+    }
 
-        request = &work.u.HttpEndRequestW;
-        request->dwFlags = dwFlags;
-        request->dwContext = dwContext;
+    return INET_QueryOption(option, buffer, size, unicode);
+}
 
-        INTERNET_AsyncCall(&work);
-        INTERNET_SetLastError(ERROR_IO_PENDING);
+static DWORD HTTPSESSION_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD size)
+{
+    WININETHTTPSESSIONW *ses = (WININETHTTPSESSIONW*)hdr;
+
+    switch(option) {
+    case INTERNET_OPTION_USERNAME:
+    {
+        HeapFree(GetProcessHeap(), 0, ses->lpszUserName);
+        if (!(ses->lpszUserName = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY;
+        return ERROR_SUCCESS;
+    }
+    case INTERNET_OPTION_PASSWORD:
+    {
+        HeapFree(GetProcessHeap(), 0, ses->lpszPassword);
+        if (!(ses->lpszPassword = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY;
+        return ERROR_SUCCESS;
+    }
+    default: break;
     }
-    else
-        rc = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
 
-    WININET_Release( &lpwhr->hdr );
-    TRACE("%i <--\n",rc);
-    return rc;
+    return ERROR_INTERNET_INVALID_OPTION;
 }
 
+static const HANDLEHEADERVtbl HTTPSESSIONVtbl = {
+    HTTPSESSION_Destroy,
+    NULL,
+    HTTPSESSION_QueryOption,
+    HTTPSESSION_SetOption,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL
+};
+
+
 /***********************************************************************
- *           HttpOpenRequestW (WININET.@)
+ *           HTTP_Connect  (internal)
  *
- * Open a HTTP request handle
+ * Create http session handle
  *
  * RETURNS
- *    HINTERNET  a HTTP request handle on success
- *    NULL 	 on failure
+ *   HINTERNET a session handle on success
+ *   NULL on failure
  *
  */
-HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
-	LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
-	LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
-	DWORD dwFlags, DWORD_PTR dwContext)
+HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
+	INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
+	LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
+	DWORD dwInternalFlags)
 {
-    LPWININETHTTPSESSIONW lpwhs;
+    LPWININETHTTPSESSIONW lpwhs = NULL;
     HINTERNET handle = NULL;
 
-    TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
-          debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
-          debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
-          dwFlags, dwContext);
-    if(lpszAcceptTypes!=NULL)
+    TRACE("-->\n");
+
+    if (!lpszServerName || !lpszServerName[0])
     {
-        int i;
-        for(i=0;lpszAcceptTypes[i]!=NULL;i++)
-            TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
-    }    
+        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        goto lerror;
+    }
 
-    lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession );
-    if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
+    assert( hIC->hdr.htype == WH_HINIT );
+
+    lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW));
+    if (NULL == lpwhs)
     {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-	goto lend;
+        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+	goto lerror;
     }
 
-    /*
-     * My tests seem to show that the windows version does not
-     * become asynchronous until after this point. And anyhow
-     * if this call was asynchronous then how would you get the
-     * necessary HINTERNET pointer returned by this function.
-     *
-     */
-    handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName,
-                                   lpszVersion, lpszReferrer, lpszAcceptTypes,
-                                   dwFlags, dwContext);
-lend:
+   /*
+    * According to my tests. The name is not resolved until a request is sent
+    */
+
+    lpwhs->hdr.htype = WH_HHTTPSESSION;
+    lpwhs->hdr.vtbl = &HTTPSESSIONVtbl;
+    lpwhs->hdr.dwFlags = dwFlags;
+    lpwhs->hdr.dwContext = dwContext;
+    lpwhs->hdr.dwInternalFlags = dwInternalFlags | (hIC->hdr.dwInternalFlags & INET_CALLBACKW);
+    lpwhs->hdr.refs = 1;
+    lpwhs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
+
+    WININET_AddRef( &hIC->hdr );
+    lpwhs->lpAppInfo = hIC;
+    list_add_head( &hIC->hdr.children, &lpwhs->hdr.entry );
+
+    handle = WININET_AllocHandle( &lpwhs->hdr );
+    if (NULL == handle)
+    {
+        ERR("Failed to alloc handle\n");
+        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+	goto lerror;
+    }
+
+    if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
+        if(strchrW(hIC->lpszProxy, ' '))
+            FIXME("Several proxies not implemented.\n");
+        if(hIC->lpszProxyBypass)
+            FIXME("Proxy bypass is ignored.\n");
+    }
+    if (lpszServerName && lpszServerName[0])
+    {
+        lpwhs->lpszServerName = WININET_strdupW(lpszServerName);
+        lpwhs->lpszHostName = WININET_strdupW(lpszServerName);
+    }
+    if (lpszUserName && lpszUserName[0])
+        lpwhs->lpszUserName = WININET_strdupW(lpszUserName);
+    if (lpszPassword && lpszPassword[0])
+        lpwhs->lpszPassword = WININET_strdupW(lpszPassword);
+    lpwhs->nServerPort = nServerPort;
+    lpwhs->nHostPort = nServerPort;
+
+    /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
+    if (!(lpwhs->hdr.dwInternalFlags & INET_OPENURL))
+    {
+        INTERNET_SendCallback(&hIC->hdr, dwContext,
+                              INTERNET_STATUS_HANDLE_CREATED, &handle,
+                              sizeof(handle));
+    }
+
+lerror:
     if( lpwhs )
         WININET_Release( &lpwhs->hdr );
-    TRACE("returning %p\n", handle);
+
+/*
+ * an INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
+ * windows
+ */
+
+    TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs);
     return handle;
 }
 
 
 /***********************************************************************
- *           HttpOpenRequestA (WININET.@)
+ *           HTTP_OpenConnection (internal)
  *
- * Open a HTTP request handle
+ * Connect to a web server
  *
  * RETURNS
- *    HINTERNET  a HTTP request handle on success
- *    NULL 	 on failure
  *
+ *   TRUE  on success
+ *   FALSE on failure
  */
-HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
-	LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
-	LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
-	DWORD dwFlags, DWORD_PTR dwContext)
+static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr)
 {
-    LPWSTR szVerb = NULL, szObjectName = NULL;
-    LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
-    INT len, acceptTypesCount;
-    HINTERNET rc = FALSE;
-    LPCSTR *types;
+    BOOL bSuccess = FALSE;
+    LPWININETHTTPSESSIONW lpwhs;
+    LPWININETAPPINFOW hIC = NULL;
+    char szaddr[32];
 
-    TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
-          debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
-          debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
-          dwFlags, dwContext);
+    TRACE("-->\n");
 
-    if (lpszVerb)
+
+    if (lpwhr->hdr.htype != WH_HHTTPREQ)
     {
-        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);
+        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        goto lend;
     }
 
-    if (lpszObjectName)
+    if (NETCON_connected(&lpwhr->netConnection))
     {
-        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 );
+        bSuccess = TRUE;
+        goto lend;
     }
+    if (!HTTP_ResolveName(lpwhr)) goto lend;
 
-    if (lpszVersion)
+    lpwhs = lpwhr->lpHttpSession;
+
+    hIC = lpwhs->lpAppInfo;
+    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.sin_family,
+                         SOCK_STREAM, 0))
     {
-        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 );
+        WARN("Socket creation failed: %u\n", INTERNET_GetLastError());
+        goto lend;
     }
 
-    if (lpszReferrer)
+    if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
+                      sizeof(lpwhs->socketAddress)))
+       goto lend;
+
+    if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)
     {
-        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 );
+        /* Note: we differ from Microsoft's WinINet here. they seem to have
+         * a bug that causes no status callbacks to be sent when starting
+         * a tunnel to a proxy server using the CONNECT verb. i believe our
+         * behaviour to be more correct and to not cause any incompatibilities
+         * because using a secure connection through a proxy server is a rare
+         * case that would be hard for anyone to depend on */
+        if (hIC->lpszProxy && !HTTP_SecureProxyConnect(lpwhr))
+            goto lend;
+
+        if (!NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName))
+        {
+            WARN("Couldn't connect securely to host\n");
+            goto lend;
+        }
     }
 
-    if (lpszAcceptTypes)
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                          INTERNET_STATUS_CONNECTED_TO_SERVER,
+                          szaddr, strlen(szaddr)+1);
+
+    bSuccess = TRUE;
+
+lend:
+    lpwhr->read_pos = lpwhr->read_size = 0;
+    lpwhr->read_chunked = FALSE;
+
+    TRACE("%d <--\n", bSuccess);
+    return bSuccess;
+}
+
+
+static const LPCWSTR header_lookup[] = {
+    szMime_Version,		/* HTTP_QUERY_MIME_VERSION = 0 */
+    szContent_Type,		/* HTTP_QUERY_CONTENT_TYPE = 1 */
+    szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
+    szContent_ID,		/* HTTP_QUERY_CONTENT_ID = 3 */
+    NULL,			/* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
+    szContent_Length,		/* HTTP_QUERY_CONTENT_LENGTH =  5 */
+    szContent_Language,		/* HTTP_QUERY_CONTENT_LANGUAGE =  6 */
+    szAllow,			/* HTTP_QUERY_ALLOW = 7 */
+    szPublic,			/* HTTP_QUERY_PUBLIC = 8 */
+    szDate,			/* HTTP_QUERY_DATE = 9 */
+    szExpires,			/* HTTP_QUERY_EXPIRES = 10 */
+    szLast_Modified,		/* HTTP_QUERY_LAST_MODIFIED = 11 */
+    NULL,			/* HTTP_QUERY_MESSAGE_ID = 12 */
+    szURI,			/* HTTP_QUERY_URI = 13 */
+    szFrom,			/* HTTP_QUERY_DERIVED_FROM = 14 */
+    NULL,			/* HTTP_QUERY_COST = 15 */
+    NULL,			/* HTTP_QUERY_LINK = 16 */
+    szPragma,			/* HTTP_QUERY_PRAGMA = 17 */
+    NULL,			/* HTTP_QUERY_VERSION = 18 */
+    szStatus,			/* HTTP_QUERY_STATUS_CODE = 19 */
+    NULL,			/* HTTP_QUERY_STATUS_TEXT = 20 */
+    NULL,			/* HTTP_QUERY_RAW_HEADERS = 21 */
+    NULL,			/* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
+    szConnection,		/* HTTP_QUERY_CONNECTION = 23 */
+    szAccept,			/* HTTP_QUERY_ACCEPT = 24 */
+    szAccept_Charset,		/* HTTP_QUERY_ACCEPT_CHARSET = 25 */
+    szAccept_Encoding,		/* HTTP_QUERY_ACCEPT_ENCODING = 26 */
+    szAccept_Language,		/* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
+    szAuthorization,		/* HTTP_QUERY_AUTHORIZATION = 28 */
+    szContent_Encoding,		/* HTTP_QUERY_CONTENT_ENCODING = 29 */
+    NULL,			/* HTTP_QUERY_FORWARDED = 30 */
+    NULL,			/* HTTP_QUERY_FROM = 31 */
+    szIf_Modified_Since,	/* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
+    szLocation,			/* HTTP_QUERY_LOCATION = 33 */
+    NULL,			/* HTTP_QUERY_ORIG_URI = 34 */
+    szReferer,			/* HTTP_QUERY_REFERER = 35 */
+    szRetry_After,		/* HTTP_QUERY_RETRY_AFTER = 36 */
+    szServer,			/* HTTP_QUERY_SERVER = 37 */
+    NULL,			/* HTTP_TITLE = 38 */
+    szUser_Agent,		/* HTTP_QUERY_USER_AGENT = 39 */
+    szWWW_Authenticate,		/* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
+    szProxy_Authenticate,	/* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
+    szAccept_Ranges,		/* HTTP_QUERY_ACCEPT_RANGES = 42 */
+    szSet_Cookie,		/* HTTP_QUERY_SET_COOKIE = 43 */
+    szCookie,			/* HTTP_QUERY_COOKIE = 44 */
+    NULL,			/* HTTP_QUERY_REQUEST_METHOD = 45 */
+    NULL,			/* HTTP_QUERY_REFRESH = 46 */
+    NULL,			/* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
+    szAge,			/* HTTP_QUERY_AGE = 48 */
+    szCache_Control,		/* HTTP_QUERY_CACHE_CONTROL = 49 */
+    szContent_Base,		/* HTTP_QUERY_CONTENT_BASE = 50 */
+    szContent_Location,		/* HTTP_QUERY_CONTENT_LOCATION = 51 */
+    szContent_MD5,		/* HTTP_QUERY_CONTENT_MD5 = 52 */
+    szContent_Range,		/* HTTP_QUERY_CONTENT_RANGE = 53 */
+    szETag,			/* HTTP_QUERY_ETAG = 54 */
+    hostW,			/* 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 */
+    szIf_Unmodified_Since,	/* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
+    szMax_Forwards,		/* HTTP_QUERY_MAX_FORWARDS = 60 */
+    szProxy_Authorization,	/* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
+    szRange,			/* HTTP_QUERY_RANGE = 62 */
+    szTransfer_Encoding,	/* HTTP_QUERY_TRANSFER_ENCODING = 63 */
+    szUpgrade,			/* HTTP_QUERY_UPGRADE = 64 */
+    szVary,			/* HTTP_QUERY_VARY = 65 */
+    szVia,			/* HTTP_QUERY_VIA = 66 */
+    szWarning,			/* HTTP_QUERY_WARNING = 67 */
+    szExpect,			/* HTTP_QUERY_EXPECT = 68 */
+    szProxy_Connection,		/* HTTP_QUERY_PROXY_CONNECTION = 69 */
+    szUnless_Modified_Since,	/* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
+};
+
+#define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
+
+/***********************************************************************
+ *           HTTP_HttpQueryInfoW (internal)
+ */
+static BOOL 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 index = -1;
+
+    /* Find requested header structure */
+    switch (level)
     {
-        acceptTypesCount = 0;
-        types = lpszAcceptTypes;
-        while (*types)
+    case HTTP_QUERY_CUSTOM:
+        if (!lpBuffer) return FALSE;
+        index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
+        break;
+
+    case HTTP_QUERY_CONTENT_LENGTH:
+        if(lpwhr->gzip_stream) {
+            INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
+            return FALSE;
+        }
+
+        index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
+                                          requested_index,request_only);
+        break;
+
+    case HTTP_QUERY_RAW_HEADERS_CRLF:
         {
-            __TRY
+            LPWSTR headers;
+            DWORD len = 0;
+            BOOL ret = FALSE;
+
+            if (request_only)
+                headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
+            else
+                headers = lpwhr->lpszRawHeaders;
+
+            if (headers)
+                len = strlenW(headers) * sizeof(WCHAR);
+
+            if (len + sizeof(WCHAR) > *lpdwBufferLength)
             {
-                /* find out how many there are */
-                if (*types && **types)
-                {
-                    TRACE("accept type: %s\n", debugstr_a(*types));
-                    acceptTypesCount++;
-                }
+                len += sizeof(WCHAR);
+                INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                ret = FALSE;
             }
-            __EXCEPT_PAGE_FAULT
+            else if (lpBuffer)
             {
-                WARN("invalid accept type pointer\n");
+                if (headers)
+                    memcpy(lpBuffer, headers, len + sizeof(WCHAR));
+                else
+                {
+                    len = strlenW(szCrLf) * sizeof(WCHAR);
+                    memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
+                }
+                TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
+                ret = TRUE;
             }
-            __ENDTRY;
-            types++;
-        }
-        szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
-        if (!szAcceptTypes) goto end;
+            *lpdwBufferLength = len;
 
-        acceptTypesCount = 0;
-        types = lpszAcceptTypes;
-        while (*types)
+            if (request_only)
+                HeapFree(GetProcessHeap(), 0, headers);
+            return ret;
+        }
+    case HTTP_QUERY_RAW_HEADERS:
         {
-            __TRY
+            LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf);
+            DWORD i, size = 0;
+            LPWSTR pszString = lpBuffer;
+
+            for (i = 0; ppszRawHeaderLines[i]; i++)
+                size += strlenW(ppszRawHeaderLines[i]) + 1;
+
+            if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
             {
-                if (*types && **types)
+                HTTP_FreeTokens(ppszRawHeaderLines);
+                *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
+                INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                return FALSE;
+            }
+            if (pszString)
+            {
+                for (i = 0; ppszRawHeaderLines[i]; i++)
                 {
-                    len = MultiByteToWideChar(CP_ACP, 0, *types, -1, NULL, 0 );
-                    szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
-
-                    MultiByteToWideChar(CP_ACP, 0, *types, -1, szAcceptTypes[acceptTypesCount], len);
-                    acceptTypesCount++;
+                    DWORD len = strlenW(ppszRawHeaderLines[i]);
+                    memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
+                    pszString += len+1;
                 }
+                *pszString = '\0';
+                TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
             }
-            __EXCEPT_PAGE_FAULT
+            *lpdwBufferLength = size * sizeof(WCHAR);
+            HTTP_FreeTokens(ppszRawHeaderLines);
+
+            return TRUE;
+        }
+    case HTTP_QUERY_STATUS_TEXT:
+        if (lpwhr->lpszStatusText)
+        {
+            DWORD len = strlenW(lpwhr->lpszStatusText);
+            if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
             {
-                /* ignore invalid pointer */
+                *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
+                INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+                return FALSE;
             }
-            __ENDTRY;
-            types++;
+            if (lpBuffer)
+            {
+                memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR));
+                TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
+            }
+            *lpdwBufferLength = len * sizeof(WCHAR);
+            return TRUE;
         }
-        szAcceptTypes[acceptTypesCount] = NULL;
+        break;
+    case HTTP_QUERY_VERSION:
+        if (lpwhr->lpszVersion)
+        {
+            DWORD len = strlenW(lpwhr->lpszVersion);
+            if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
+            {
+                *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
+                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);
+            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])
+            index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
+                                              requested_index,request_only);
     }
 
-    rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
-                          szVersion, szReferrer,
-                          (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
+    if (index >= 0)
+        lphttpHdr = &lpwhr->pCustHeaders[index];
 
-end:
-    if (szAcceptTypes)
+    /* Ensure header satisfies requested attributes */
+    if (!lphttpHdr ||
+        ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
+         (~lphttpHdr->wFlags & HDR_ISREQUEST)))
     {
-        acceptTypesCount = 0;
-        while (szAcceptTypes[acceptTypesCount])
+        INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
+        return bSuccess;
+    }
+
+    if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++;
+
+    /* coalesce value to requested type */
+    if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
+    {
+        *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
+        TRACE(" returning number: %d\n", *(int *)lpBuffer);
+        bSuccess = TRUE;
+    }
+    else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
+    {
+        time_t tmpTime;
+        struct tm tmpTM;
+        SYSTEMTIME *STHook;
+
+        tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
+
+        tmpTM = *gmtime(&tmpTime);
+        STHook = (SYSTEMTIME *)lpBuffer;
+        STHook->wDay = tmpTM.tm_mday;
+        STHook->wHour = tmpTM.tm_hour;
+        STHook->wMilliseconds = 0;
+        STHook->wMinute = tmpTM.tm_min;
+        STHook->wDayOfWeek = tmpTM.tm_wday;
+        STHook->wMonth = tmpTM.tm_mon + 1;
+        STHook->wSecond = tmpTM.tm_sec;
+        STHook->wYear = tmpTM.tm_year;
+        bSuccess = TRUE;
+
+        TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
+              STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
+              STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
+    }
+    else if (lphttpHdr->lpszValue)
+    {
+        DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
+
+        if (len > *lpdwBufferLength)
         {
-            HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
-            acceptTypesCount++;
+            *lpdwBufferLength = len;
+            INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
+            return bSuccess;
         }
-        HeapFree(GetProcessHeap(), 0, szAcceptTypes);
+        if (lpBuffer)
+        {
+            memcpy(lpBuffer, lphttpHdr->lpszValue, len);
+            TRACE(" returning string: %s\n", debugstr_w(lpBuffer));
+        }
+        *lpdwBufferLength = len - sizeof(WCHAR);
+        bSuccess = TRUE;
     }
-    HeapFree(GetProcessHeap(), 0, szReferrer);
-    HeapFree(GetProcessHeap(), 0, szVersion);
-    HeapFree(GetProcessHeap(), 0, szObjectName);
-    HeapFree(GetProcessHeap(), 0, szVerb);
+    return bSuccess;
+}
 
-    return rc;
+/***********************************************************************
+ *           HttpQueryInfoW (WININET.@)
+ *
+ * Queries for information about an HTTP request
+ *
+ * RETURNS
+ *    TRUE  on success
+ *    FALSE on failure
+ *
+ */
+BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
+	LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
+{
+    BOOL bSuccess = FALSE;
+    LPWININETHTTPREQW lpwhr;
+
+    if (TRACE_ON(wininet)) {
+#define FE(x) { x, #x }
+	static const wininet_flag_info query_flags[] = {
+	    FE(HTTP_QUERY_MIME_VERSION),
+	    FE(HTTP_QUERY_CONTENT_TYPE),
+	    FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
+	    FE(HTTP_QUERY_CONTENT_ID),
+	    FE(HTTP_QUERY_CONTENT_DESCRIPTION),
+	    FE(HTTP_QUERY_CONTENT_LENGTH),
+	    FE(HTTP_QUERY_CONTENT_LANGUAGE),
+	    FE(HTTP_QUERY_ALLOW),
+	    FE(HTTP_QUERY_PUBLIC),
+	    FE(HTTP_QUERY_DATE),
+	    FE(HTTP_QUERY_EXPIRES),
+	    FE(HTTP_QUERY_LAST_MODIFIED),
+	    FE(HTTP_QUERY_MESSAGE_ID),
+	    FE(HTTP_QUERY_URI),
+	    FE(HTTP_QUERY_DERIVED_FROM),
+	    FE(HTTP_QUERY_COST),
+	    FE(HTTP_QUERY_LINK),
+	    FE(HTTP_QUERY_PRAGMA),
+	    FE(HTTP_QUERY_VERSION),
+	    FE(HTTP_QUERY_STATUS_CODE),
+	    FE(HTTP_QUERY_STATUS_TEXT),
+	    FE(HTTP_QUERY_RAW_HEADERS),
+	    FE(HTTP_QUERY_RAW_HEADERS_CRLF),
+	    FE(HTTP_QUERY_CONNECTION),
+	    FE(HTTP_QUERY_ACCEPT),
+	    FE(HTTP_QUERY_ACCEPT_CHARSET),
+	    FE(HTTP_QUERY_ACCEPT_ENCODING),
+	    FE(HTTP_QUERY_ACCEPT_LANGUAGE),
+	    FE(HTTP_QUERY_AUTHORIZATION),
+	    FE(HTTP_QUERY_CONTENT_ENCODING),
+	    FE(HTTP_QUERY_FORWARDED),
+	    FE(HTTP_QUERY_FROM),
+	    FE(HTTP_QUERY_IF_MODIFIED_SINCE),
+	    FE(HTTP_QUERY_LOCATION),
+	    FE(HTTP_QUERY_ORIG_URI),
+	    FE(HTTP_QUERY_REFERER),
+	    FE(HTTP_QUERY_RETRY_AFTER),
+	    FE(HTTP_QUERY_SERVER),
+	    FE(HTTP_QUERY_TITLE),
+	    FE(HTTP_QUERY_USER_AGENT),
+	    FE(HTTP_QUERY_WWW_AUTHENTICATE),
+	    FE(HTTP_QUERY_PROXY_AUTHENTICATE),
+	    FE(HTTP_QUERY_ACCEPT_RANGES),
+        FE(HTTP_QUERY_SET_COOKIE),
+        FE(HTTP_QUERY_COOKIE),
+	    FE(HTTP_QUERY_REQUEST_METHOD),
+	    FE(HTTP_QUERY_REFRESH),
+	    FE(HTTP_QUERY_CONTENT_DISPOSITION),
+	    FE(HTTP_QUERY_AGE),
+	    FE(HTTP_QUERY_CACHE_CONTROL),
+	    FE(HTTP_QUERY_CONTENT_BASE),
+	    FE(HTTP_QUERY_CONTENT_LOCATION),
+	    FE(HTTP_QUERY_CONTENT_MD5),
+	    FE(HTTP_QUERY_CONTENT_RANGE),
+	    FE(HTTP_QUERY_ETAG),
+	    FE(HTTP_QUERY_HOST),
+	    FE(HTTP_QUERY_IF_MATCH),
+	    FE(HTTP_QUERY_IF_NONE_MATCH),
+	    FE(HTTP_QUERY_IF_RANGE),
+	    FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
+	    FE(HTTP_QUERY_MAX_FORWARDS),
+	    FE(HTTP_QUERY_PROXY_AUTHORIZATION),
+	    FE(HTTP_QUERY_RANGE),
+	    FE(HTTP_QUERY_TRANSFER_ENCODING),
+	    FE(HTTP_QUERY_UPGRADE),
+	    FE(HTTP_QUERY_VARY),
+	    FE(HTTP_QUERY_VIA),
+	    FE(HTTP_QUERY_WARNING),
+	    FE(HTTP_QUERY_CUSTOM)
+	};
+	static const wininet_flag_info modifier_flags[] = {
+	    FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
+	    FE(HTTP_QUERY_FLAG_SYSTEMTIME),
+	    FE(HTTP_QUERY_FLAG_NUMBER),
+	    FE(HTTP_QUERY_FLAG_COALESCE)
+	};
+#undef FE
+	DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
+	DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
+	DWORD i;
+
+	TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
+	TRACE("  Attribute:");
+	for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
+	    if (query_flags[i].val == info) {
+		TRACE(" %s", query_flags[i].name);
+		break;
+	    }
+	}
+	if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
+	    TRACE(" Unknown (%08x)", info);
+	}
+
+	TRACE(" Modifier:");
+	for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
+	    if (modifier_flags[i].val & info_mod) {
+		TRACE(" %s", modifier_flags[i].name);
+		info_mod &= ~ modifier_flags[i].val;
+	    }
+	}
+
+	if (info_mod) {
+	    TRACE(" Unknown (%08x)", info_mod);
+	}
+	TRACE("\n");
+    }
+
+    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
+    if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
+    {
+        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+	goto lend;
+    }
+
+    if (lpBuffer == NULL)
+        *lpdwBufferLength = 0;
+    bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
+	                            lpBuffer, lpdwBufferLength, lpdwIndex);
+
+lend:
+    if( lpwhr )
+         WININET_Release( &lpwhr->hdr );
+
+    TRACE("%d <--\n", bSuccess);
+    return bSuccess;
+}
+
+/***********************************************************************
+ *           HttpQueryInfoA (WININET.@)
+ *
+ * Queries for information about an HTTP request
+ *
+ * RETURNS
+ *    TRUE  on success
+ *    FALSE on failure
+ *
+ */
+BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
+	LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
+{
+    BOOL result;
+    DWORD len;
+    WCHAR* bufferW;
+
+    if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
+       (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
+    {
+        return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
+                               lpdwBufferLength, lpdwIndex );
+    }
+
+    if (lpBuffer)
+    {
+        DWORD alloclen;
+        len = (*lpdwBufferLength)*sizeof(WCHAR);
+        if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
+        {
+            alloclen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ) * sizeof(WCHAR);
+            if (alloclen < len)
+                alloclen = len;
+        }
+        else
+            alloclen = len;
+        bufferW = HeapAlloc( GetProcessHeap(), 0, alloclen );
+        /* buffer is in/out because of HTTP_QUERY_CUSTOM */
+        if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
+            MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, bufferW, alloclen / sizeof(WCHAR) );
+    } else
+    {
+        bufferW = NULL;
+        len = 0;
+    }
+
+    result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
+                           &len, lpdwIndex );
+    if( result )
+    {
+        len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1,
+                                     lpBuffer, *lpdwBufferLength, NULL, NULL );
+        *lpdwBufferLength = len - 1;
+
+        TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer));
+    }
+    else
+        /* since the strings being returned from HttpQueryInfoW should be
+         * only ASCII characters, it is reasonable to assume that all of
+         * the Unicode characters can be reduced to a single byte */
+        *lpdwBufferLength = len / sizeof(WCHAR);
+
+    HeapFree(GetProcessHeap(), 0, bufferW );
+
+    return result;
+}
+
+static void HTTP_InsertCookies(LPWININETHTTPREQW lpwhr)
+{
+    static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
+    LPWSTR lpszCookies, lpszUrl = NULL;
+    DWORD nCookieSize, size;
+    LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
+
+    size = (strlenW(Host->lpszValue) + strlenW(szUrlForm) + strlenW(lpwhr->lpszPath)) * sizeof(WCHAR);
+    if (!(lpszUrl = HeapAlloc(GetProcessHeap(), 0, size))) return;
+    sprintfW( lpszUrl, szUrlForm, Host->lpszValue, lpwhr->lpszPath);
+
+    if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize))
+    {
+        int cnt = 0;
+        static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0};
+
+        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);
+
+            HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_REPLACE);
+            HeapFree(GetProcessHeap(), 0, lpszCookies);
+        }
+    }
+    HeapFree(GetProcessHeap(), 0, lpszUrl);
+}
+
+static void HTTP_ProcessCookies( LPWININETHTTPREQW lpwhr )
+{
+    int HeaderIndex;
+    int numCookies = 0;
+    LPHTTPHEADERW setCookieHeader;
+
+    while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1)
+    {
+        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};
+            LPWSTR buf_url;
+            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++;
+    }
 }
 
 /***********************************************************************
@@ -1324,154 +2061,222 @@ static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin )
     return n;
 }
 
-/***********************************************************************
- *  HTTP_InsertAuthorization
- *
- *   Insert or delete the authorization field in the request header.
- */
-static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
+static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue )
 {
-    if (pAuthInfo)
+    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)]);
+}
+
+static BOOL HTTP_DoAuthorization( LPWININETHTTPREQW lpwhr, LPCWSTR pszAuthValue,
+                                  struct HttpAuthInfo **ppAuthInfo,
+                                  LPWSTR domain_and_username, LPWSTR password )
+{
+    SECURITY_STATUS sec_status;
+    struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
+    BOOL first = FALSE;
+
+    TRACE("%s\n", debugstr_w(pszAuthValue));
+
+    if (!pAuthInfo)
     {
-        static const WCHAR wszSpace[] = {' ',0};
-        static const WCHAR wszBasic[] = {'B','a','s','i','c',0};
-        unsigned int len;
-        WCHAR *authorization = NULL;
+        TimeStamp exp;
 
-        if (pAuthInfo->auth_data_len)
-        {
-            /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
-            len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3;
-            authorization = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
-            if (!authorization)
-                return FALSE;
+        first = TRUE;
+        pAuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*pAuthInfo));
+        if (!pAuthInfo)
+            return FALSE;
 
-            strcpyW(authorization, pAuthInfo->scheme);
-            strcatW(authorization, wszSpace);
-            HTTP_EncodeBase64(pAuthInfo->auth_data,
-                              pAuthInfo->auth_data_len,
-                              authorization+strlenW(authorization));
+        SecInvalidateHandle(&pAuthInfo->cred);
+        SecInvalidateHandle(&pAuthInfo->ctx);
+        memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp));
+        pAuthInfo->attr = 0;
+        pAuthInfo->auth_data = NULL;
+        pAuthInfo->auth_data_len = 0;
+        pAuthInfo->finished = FALSE;
 
-            /* clear the data as it isn't valid now that it has been sent to the
-             * server, unless it's Basic authentication which doesn't do
-             * connection tracking */
-            if (strcmpiW(pAuthInfo->scheme, wszBasic))
+        if (is_basic_auth_value(pszAuthValue))
+        {
+            static const WCHAR szBasic[] = {'B','a','s','i','c',0};
+            pAuthInfo->scheme = WININET_strdupW(szBasic);
+            if (!pAuthInfo->scheme)
             {
-                HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data);
-                pAuthInfo->auth_data = NULL;
-                pAuthInfo->auth_data_len = 0;
+                HeapFree(GetProcessHeap(), 0, pAuthInfo);
+                return FALSE;
             }
         }
+        else
+        {
+            PVOID pAuthData;
+            SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
 
-        TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
+            pAuthInfo->scheme = WININET_strdupW(pszAuthValue);
+            if (!pAuthInfo->scheme)
+            {
+                HeapFree(GetProcessHeap(), 0, pAuthInfo);
+                return FALSE;
+            }
 
-        HTTP_ProcessHeader(lpwhr, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
+            if (domain_and_username)
+            {
+                WCHAR *user = strchrW(domain_and_username, '\\');
+                WCHAR *domain = domain_and_username;
 
-        HeapFree(GetProcessHeap(), 0, authorization);
-    }
-    return TRUE;
-}
+                /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
 
-static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req)
-{
-    WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
-    DWORD size;
+                pAuthData = &nt_auth_identity;
 
-    size = sizeof(new_location);
-    if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL))
+                if (user) user++;
+                else
+                {
+                    user = domain_and_username;
+                    domain = NULL;
+                }
+
+                nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
+                nt_auth_identity.User = user;
+                nt_auth_identity.UserLength = strlenW(nt_auth_identity.User);
+                nt_auth_identity.Domain = domain;
+                nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
+                nt_auth_identity.Password = password;
+                nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password);
+            }
+            else
+                /* use default credentials */
+                pAuthData = NULL;
+
+            sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
+                                                   SECPKG_CRED_OUTBOUND, NULL,
+                                                   pAuthData, NULL,
+                                                   NULL, &pAuthInfo->cred,
+                                                   &exp);
+            if (sec_status == SEC_E_OK)
+            {
+                PSecPkgInfoW sec_pkg_info;
+                sec_status = QuerySecurityPackageInfoW(pAuthInfo->scheme, &sec_pkg_info);
+                if (sec_status == SEC_E_OK)
+                {
+                    pAuthInfo->max_token = sec_pkg_info->cbMaxToken;
+                    FreeContextBuffer(sec_pkg_info);
+                }
+            }
+            if (sec_status != SEC_E_OK)
+            {
+                WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
+                     debugstr_w(pAuthInfo->scheme), sec_status);
+                HeapFree(GetProcessHeap(), 0, pAuthInfo->scheme);
+                HeapFree(GetProcessHeap(), 0, pAuthInfo);
+                return FALSE;
+            }
+        }
+        *ppAuthInfo = pAuthInfo;
+    }
+    else if (pAuthInfo->finished)
+        return FALSE;
+
+    if ((strlenW(pszAuthValue) < strlenW(pAuthInfo->scheme)) ||
+        strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme)))
     {
-        if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL;
-        strcpyW( url, new_location );
+        ERR("authentication scheme changed from %s to %s\n",
+            debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue));
+        return FALSE;
     }
-    else
+
+    if (is_basic_auth_value(pszAuthValue))
     {
-        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 };
-        WININETHTTPSESSIONW *session = req->lpHttpSession;
+        int userlen;
+        int passlen;
+        char *auth_data;
 
-        size = 16; /* "https://" + sizeof(port#) + ":/\0" */
-        size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath );
+        TRACE("basic authentication\n");
 
-        if (!(url = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL;
+        /* 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 (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
-            sprintfW( url, formatSSL, session->lpszHostName, session->nHostPort );
-        else
-            sprintfW( url, format, session->lpszHostName, session->nHostPort );
-        if (req->lpszPath[0] != '/') strcatW( url, slash );
-        strcatW( url, req->lpszPath );
-    }
-    TRACE("url=%s\n", debugstr_w(url));
-    return url;
-}
+        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);
 
-/***********************************************************************
- *           HTTP_DealWithProxy
- */
-static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC,
-    LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr)
-{
-    WCHAR buf[MAXHOSTNAME];
-    WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
-    static WCHAR szNul[] = { 0 };
-    URL_COMPONENTSW UrlComponents;
-    static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
-    static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
+        /* length includes a nul terminator, which will be re-used for the ':' */
+        auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen);
+        if (!auth_data)
+            return FALSE;
 
-    memset( &UrlComponents, 0, sizeof UrlComponents );
-    UrlComponents.dwStructSize = sizeof UrlComponents;
-    UrlComponents.lpszHostName = buf;
-    UrlComponents.dwHostNameLength = MAXHOSTNAME;
+        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);
 
-    if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
-                                 hIC->lpszProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
-        sprintfW(proxy, szFormat, hIC->lpszProxy);
+        pAuthInfo->auth_data = auth_data;
+        pAuthInfo->auth_data_len = userlen + 1 + passlen;
+        pAuthInfo->finished = TRUE;
+
+        return TRUE;
+    }
     else
-	strcpyW(proxy, hIC->lpszProxy);
-    if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
-        return FALSE;
-    if( UrlComponents.dwHostNameLength == 0 )
-        return FALSE;
+    {
+        LPCWSTR pszAuthData;
+        SecBufferDesc out_desc, in_desc;
+        SecBuffer out, in;
+        unsigned char *buffer;
+        ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
+            ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
 
-    if( !lpwhr->lpszPath )
-        lpwhr->lpszPath = szNul;
+        in.BufferType = SECBUFFER_TOKEN;
+        in.cbBuffer = 0;
+        in.pvBuffer = NULL;
 
-    if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
-        UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
+        in_desc.ulVersion = 0;
+        in_desc.cBuffers = 1;
+        in_desc.pBuffers = &in;
 
-    HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
-    lpwhs->lpszServerName = WININET_strdupW(UrlComponents.lpszHostName);
-    lpwhs->nServerPort = UrlComponents.nPort;
+        pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme);
+        if (*pszAuthData == ' ')
+        {
+            pszAuthData++;
+            in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL);
+            in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer);
+            HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
+        }
 
-    TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort);
-    return TRUE;
-}
+        buffer = HeapAlloc(GetProcessHeap(), 0, pAuthInfo->max_token);
 
-static BOOL HTTP_ResolveName(LPWININETHTTPREQW lpwhr)
-{
-    char szaddr[32];
-    LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
+        out.BufferType = SECBUFFER_TOKEN;
+        out.cbBuffer = pAuthInfo->max_token;
+        out.pvBuffer = buffer;
 
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                          INTERNET_STATUS_RESOLVING_NAME,
-                          lpwhs->lpszServerName,
-                          strlenW(lpwhs->lpszServerName)+1);
+        out_desc.ulVersion = 0;
+        out_desc.cBuffers = 1;
+        out_desc.pBuffers = &out;
 
-    if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
-                    &lpwhs->socketAddress))
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
-        return FALSE;
+        sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL,
+                                                first ? NULL : &pAuthInfo->ctx,
+                                                first ? lpwhr->lpHttpSession->lpszServerName : NULL,
+                                                context_req, 0, SECURITY_NETWORK_DREP,
+                                                in.pvBuffer ? &in_desc : NULL,
+                                                0, &pAuthInfo->ctx, &out_desc,
+                                                &pAuthInfo->attr, &pAuthInfo->exp);
+        if (sec_status == SEC_E_OK)
+        {
+            pAuthInfo->finished = TRUE;
+            pAuthInfo->auth_data = out.pvBuffer;
+            pAuthInfo->auth_data_len = out.cbBuffer;
+            TRACE("sending last auth packet\n");
+        }
+        else if (sec_status == SEC_I_CONTINUE_NEEDED)
+        {
+            pAuthInfo->auth_data = out.pvBuffer;
+            pAuthInfo->auth_data_len = out.cbBuffer;
+            TRACE("sending next auth packet\n");
+        }
+        else
+        {
+            ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
+            pAuthInfo->finished = TRUE;
+            HeapFree(GetProcessHeap(), 0, out.pvBuffer);
+            return FALSE;
+        }
     }
 
-    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);
-
-    TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr);
     return TRUE;
 }
 
@@ -1798,78 +2603,6 @@ static DWORD HTTPREQ_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buf
     return ERROR_INTERNET_INVALID_OPTION;
 }
 
-/* read some more data into the read buffer (the read section must be held) */
-static BOOL read_more_data( WININETHTTPREQW *req, int maxlen )
-{
-    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;
-    }
-
-    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;
-}
-
-/* remove some amount of data from the read buffer (the read section must be held) */
-static void remove_data( WININETHTTPREQW *req, int count )
-{
-    if (!(req->read_size -= count)) req->read_pos = 0;
-    else req->read_pos += count;
-}
-
-static BOOL read_line( WININETHTTPREQW *req, LPSTR buffer, DWORD *len )
-{
-    int count, bytes_read, pos = 0;
-
-    EnterCriticalSection( &req->read_section );
-    for (;;)
-    {
-        BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
-
-        if (eol)
-        {
-            count = eol - (req->read_buf + req->read_pos);
-            bytes_read = count + 1;
-        }
-        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 (!read_more_data( req, -1 ) || !req->read_size)
-        {
-            *len = 0;
-            TRACE( "returning empty string\n" );
-            LeaveCriticalSection( &req->read_section );
-            return FALSE;
-        }
-    }
-    LeaveCriticalSection( &req->read_section );
-
-    if (pos < *len)
-    {
-        if (pos && buffer[pos - 1] == '\r') pos--;
-        *len = pos + 1;
-    }
-    buffer[*len - 1] = 0;
-    TRACE( "returning %s\n", debugstr_a(buffer));
-    return TRUE;
-}
-
 /* discard data contents until we reach end of line (the read section must be held) */
 static BOOL discard_eol( WININETHTTPREQW *req )
 {
@@ -2044,6 +2777,47 @@ static void HTTP_ReceiveRequestData(WININETHTTPREQW *req, BOOL first_notif)
                           sizeof(INTERNET_ASYNC_RESULT));
 }
 
+/***********************************************************************
+ *           HTTP_FinishedReading (internal)
+ *
+ * Called when all content from server has been read by client.
+ *
+ */
+static BOOL HTTP_FinishedReading(LPWININETHTTPREQW 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)
+    {
+        HTTPREQ_CloseConnection(&lpwhr->hdr);
+    }
+
+    /* FIXME: store data in the URL cache here */
+
+    return TRUE;
+}
+
 /* read data from the http connection (the read section must be held) */
 static DWORD HTTPREQ_Read(WININETHTTPREQW *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
 {
@@ -2351,949 +3125,6 @@ static const HANDLEHEADERVtbl HTTPREQVtbl = {
 };
 
 /***********************************************************************
- *           HTTP_HttpOpenRequestW (internal)
- *
- * Open a HTTP request handle
- *
- * RETURNS
- *    HINTERNET  a HTTP request handle on success
- *    NULL 	 on failure
- *
- */
-HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs,
-	LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
-	LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
-	DWORD dwFlags, DWORD_PTR dwContext)
-{
-    LPWININETAPPINFOW hIC = NULL;
-    LPWININETHTTPREQW lpwhr;
-    LPWSTR lpszHostName = NULL;
-    HINTERNET handle = NULL;
-    static const WCHAR szHostForm[] = {'%','s',':','%','u',0};
-    DWORD len;
-
-    TRACE("-->\n");
-
-    assert( lpwhs->hdr.htype == WH_HHTTPSESSION );
-    hIC = lpwhs->lpAppInfo;
-
-    lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW));
-    if (NULL == lpwhr)
-    {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-        goto lend;
-    }
-    lpwhr->hdr.htype = WH_HHTTPREQ;
-    lpwhr->hdr.vtbl = &HTTPREQVtbl;
-    lpwhr->hdr.dwFlags = dwFlags;
-    lpwhr->hdr.dwContext = dwContext;
-    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;
-    list_add_head( &lpwhs->hdr.children, &lpwhr->hdr.entry );
-
-    lpszHostName = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) *
-            (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */));
-    if (NULL == lpszHostName)
-    {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-        goto lend;
-    }
-
-    handle = WININET_AllocHandle( &lpwhr->hdr );
-    if (NULL == handle)
-    {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-        goto lend;
-    }
-
-    if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE))
-    {
-        InternetCloseHandle( handle );
-        handle = NULL;
-        goto lend;
-    }
-
-    if (lpszObjectName && *lpszObjectName) {
-        HRESULT rc;
-
-        len = 0;
-        rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
-        if (rc != E_POINTER)
-            len = strlenW(lpszObjectName)+1;
-        lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
-        rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len,
-                   URL_ESCAPE_SPACES_ONLY);
-        if (rc != S_OK)
-        {
-            ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
-            strcpyW(lpwhr->lpszPath,lpszObjectName);
-        }
-    }else {
-        static const WCHAR slashW[] = {'/',0};
-
-        lpwhr->lpszPath = WININET_strdupW(slashW);
-    }
-
-    if (lpszReferrer && *lpszReferrer)
-        HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
-
-    if (lpszAcceptTypes)
-    {
-        int i;
-        for (i = 0; lpszAcceptTypes[i]; i++)
-        {
-            if (!*lpszAcceptTypes[i]) continue;
-            HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i],
-                               HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA |
-                               HTTP_ADDHDR_FLAG_REQ |
-                               (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0));
-        }
-    }
-
-    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_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
-    }
-    else
-        HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName,
-                HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
-
-    if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER)
-        lpwhs->nServerPort = (dwFlags & INTERNET_FLAG_SECURE ?
-                        INTERNET_DEFAULT_HTTPS_PORT :
-                        INTERNET_DEFAULT_HTTP_PORT);
-
-    if (lpwhs->nHostPort == INTERNET_INVALID_PORT_NUMBER)
-        lpwhs->nHostPort = (dwFlags & INTERNET_FLAG_SECURE ?
-                        INTERNET_DEFAULT_HTTPS_PORT :
-                        INTERNET_DEFAULT_HTTP_PORT);
-
-    if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
-        HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
-
-    INTERNET_SendCallback(&lpwhs->hdr, dwContext,
-                          INTERNET_STATUS_HANDLE_CREATED, &handle,
-                          sizeof(handle));
-
-lend:
-    HeapFree(GetProcessHeap(), 0, lpszHostName);
-    if( lpwhr )
-        WININET_Release( &lpwhr->hdr );
-
-    TRACE("<-- %p (%p)\n", handle, lpwhr);
-    return handle;
-}
-
-/* read any content returned by the server so that the connection can be
- * reused */
-static void HTTP_DrainContent(WININETHTTPREQW *req)
-{
-    DWORD bytes_read;
-
-    if (!NETCON_connected(&req->netConnection)) return;
-
-    if (req->dwContentLength == -1)
-    {
-        NETCON_close(&req->netConnection);
-        return;
-    }
-
-    do
-    {
-        char buffer[2048];
-        if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS)
-            return;
-    } while (bytes_read);
-}
-
-static const LPCWSTR header_lookup[] = {
-    szMime_Version,		/* HTTP_QUERY_MIME_VERSION = 0 */
-    szContent_Type,		/* HTTP_QUERY_CONTENT_TYPE = 1 */
-    szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
-    szContent_ID,		/* HTTP_QUERY_CONTENT_ID = 3 */
-    NULL,			/* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
-    szContent_Length,		/* HTTP_QUERY_CONTENT_LENGTH =  5 */
-    szContent_Language,		/* HTTP_QUERY_CONTENT_LANGUAGE =  6 */
-    szAllow,			/* HTTP_QUERY_ALLOW = 7 */
-    szPublic,			/* HTTP_QUERY_PUBLIC = 8 */
-    szDate,			/* HTTP_QUERY_DATE = 9 */
-    szExpires,			/* HTTP_QUERY_EXPIRES = 10 */
-    szLast_Modified,		/* HTTP_QUERY_LAST_MODIFIED = 11 */
-    NULL,			/* HTTP_QUERY_MESSAGE_ID = 12 */
-    szURI,			/* HTTP_QUERY_URI = 13 */
-    szFrom,			/* HTTP_QUERY_DERIVED_FROM = 14 */
-    NULL,			/* HTTP_QUERY_COST = 15 */
-    NULL,			/* HTTP_QUERY_LINK = 16 */
-    szPragma,			/* HTTP_QUERY_PRAGMA = 17 */
-    NULL,			/* HTTP_QUERY_VERSION = 18 */
-    szStatus,			/* HTTP_QUERY_STATUS_CODE = 19 */
-    NULL,			/* HTTP_QUERY_STATUS_TEXT = 20 */
-    NULL,			/* HTTP_QUERY_RAW_HEADERS = 21 */
-    NULL,			/* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
-    szConnection,		/* HTTP_QUERY_CONNECTION = 23 */
-    szAccept,			/* HTTP_QUERY_ACCEPT = 24 */
-    szAccept_Charset,		/* HTTP_QUERY_ACCEPT_CHARSET = 25 */
-    szAccept_Encoding,		/* HTTP_QUERY_ACCEPT_ENCODING = 26 */
-    szAccept_Language,		/* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
-    szAuthorization,		/* HTTP_QUERY_AUTHORIZATION = 28 */
-    szContent_Encoding,		/* HTTP_QUERY_CONTENT_ENCODING = 29 */
-    NULL,			/* HTTP_QUERY_FORWARDED = 30 */
-    NULL,			/* HTTP_QUERY_FROM = 31 */
-    szIf_Modified_Since,	/* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
-    szLocation,			/* HTTP_QUERY_LOCATION = 33 */
-    NULL,			/* HTTP_QUERY_ORIG_URI = 34 */
-    szReferer,			/* HTTP_QUERY_REFERER = 35 */
-    szRetry_After,		/* HTTP_QUERY_RETRY_AFTER = 36 */
-    szServer,			/* HTTP_QUERY_SERVER = 37 */
-    NULL,			/* HTTP_TITLE = 38 */
-    szUser_Agent,		/* HTTP_QUERY_USER_AGENT = 39 */
-    szWWW_Authenticate,		/* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
-    szProxy_Authenticate,	/* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
-    szAccept_Ranges,		/* HTTP_QUERY_ACCEPT_RANGES = 42 */
-    szSet_Cookie,		/* HTTP_QUERY_SET_COOKIE = 43 */
-    szCookie,			/* HTTP_QUERY_COOKIE = 44 */
-    NULL,			/* HTTP_QUERY_REQUEST_METHOD = 45 */
-    NULL,			/* HTTP_QUERY_REFRESH = 46 */
-    NULL,			/* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
-    szAge,			/* HTTP_QUERY_AGE = 48 */
-    szCache_Control,		/* HTTP_QUERY_CACHE_CONTROL = 49 */
-    szContent_Base,		/* HTTP_QUERY_CONTENT_BASE = 50 */
-    szContent_Location,		/* HTTP_QUERY_CONTENT_LOCATION = 51 */
-    szContent_MD5,		/* HTTP_QUERY_CONTENT_MD5 = 52 */
-    szContent_Range,		/* HTTP_QUERY_CONTENT_RANGE = 53 */
-    szETag,			/* HTTP_QUERY_ETAG = 54 */
-    hostW,			/* 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 */
-    szIf_Unmodified_Since,	/* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
-    szMax_Forwards,		/* HTTP_QUERY_MAX_FORWARDS = 60 */
-    szProxy_Authorization,	/* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
-    szRange,			/* HTTP_QUERY_RANGE = 62 */
-    szTransfer_Encoding,	/* HTTP_QUERY_TRANSFER_ENCODING = 63 */
-    szUpgrade,			/* HTTP_QUERY_UPGRADE = 64 */
-    szVary,			/* HTTP_QUERY_VARY = 65 */
-    szVia,			/* HTTP_QUERY_VIA = 66 */
-    szWarning,			/* HTTP_QUERY_WARNING = 67 */
-    szExpect,			/* HTTP_QUERY_EXPECT = 68 */
-    szProxy_Connection,		/* HTTP_QUERY_PROXY_CONNECTION = 69 */
-    szUnless_Modified_Since,	/* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
-};
-
-#define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
-
-/***********************************************************************
- *           HTTP_HttpQueryInfoW (internal)
- */
-static BOOL 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 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_CONTENT_LENGTH:
-        if(lpwhr->gzip_stream) {
-            INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
-            return FALSE;
-        }
-
-        index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
-                                          requested_index,request_only);
-        break;
-
-    case HTTP_QUERY_RAW_HEADERS_CRLF:
-        {
-            LPWSTR headers;
-            DWORD len = 0;
-            BOOL ret = FALSE;
-
-            if (request_only)
-                headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
-            else
-                headers = lpwhr->lpszRawHeaders;
-
-            if (headers)
-                len = strlenW(headers) * sizeof(WCHAR);
-
-            if (len + sizeof(WCHAR) > *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));
-                }
-                TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
-                ret = TRUE;
-            }
-            *lpdwBufferLength = len;
-
-            if (request_only)
-                HeapFree(GetProcessHeap(), 0, headers);
-            return ret;
-        }
-    case HTTP_QUERY_RAW_HEADERS:
-        {
-            LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf);
-            DWORD i, size = 0;
-            LPWSTR pszString = lpBuffer;
-
-            for (i = 0; ppszRawHeaderLines[i]; i++)
-                size += strlenW(ppszRawHeaderLines[i]) + 1;
-
-            if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
-            {
-                HTTP_FreeTokens(ppszRawHeaderLines);
-                *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
-                INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
-                return FALSE;
-            }
-            if (pszString)
-            {
-                for (i = 0; ppszRawHeaderLines[i]; i++)
-                {
-                    DWORD len = strlenW(ppszRawHeaderLines[i]);
-                    memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
-                    pszString += len+1;
-                }
-                *pszString = '\0';
-                TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
-            }
-            *lpdwBufferLength = size * sizeof(WCHAR);
-            HTTP_FreeTokens(ppszRawHeaderLines);
-
-            return TRUE;
-        }
-    case HTTP_QUERY_STATUS_TEXT:
-        if (lpwhr->lpszStatusText)
-        {
-            DWORD len = strlenW(lpwhr->lpszStatusText);
-            if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
-            {
-                *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
-                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);
-            return TRUE;
-        }
-        break;
-    case HTTP_QUERY_VERSION:
-        if (lpwhr->lpszVersion)
-        {
-            DWORD len = strlenW(lpwhr->lpszVersion);
-            if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
-            {
-                *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
-                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);
-            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])
-            index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
-                                              requested_index,request_only);
-    }
-
-    if (index >= 0)
-        lphttpHdr = &lpwhr->pCustHeaders[index];
-
-    /* Ensure header satisfies requested attributes */
-    if (!lphttpHdr ||
-        ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
-         (~lphttpHdr->wFlags & HDR_ISREQUEST)))
-    {
-        INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
-        return bSuccess;
-    }
-
-    if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++;
-
-    /* coalesce value to requested type */
-    if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
-    {
-        *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
-        TRACE(" returning number: %d\n", *(int *)lpBuffer);
-        bSuccess = TRUE;
-    }
-    else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
-    {
-        time_t tmpTime;
-        struct tm tmpTM;
-        SYSTEMTIME *STHook;
-
-        tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
-
-        tmpTM = *gmtime(&tmpTime);
-        STHook = (SYSTEMTIME *)lpBuffer;
-        STHook->wDay = tmpTM.tm_mday;
-        STHook->wHour = tmpTM.tm_hour;
-        STHook->wMilliseconds = 0;
-        STHook->wMinute = tmpTM.tm_min;
-        STHook->wDayOfWeek = tmpTM.tm_wday;
-        STHook->wMonth = tmpTM.tm_mon + 1;
-        STHook->wSecond = tmpTM.tm_sec;
-        STHook->wYear = tmpTM.tm_year;
-        bSuccess = TRUE;
-	
-        TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
-              STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
-              STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
-    }
-    else if (lphttpHdr->lpszValue)
-    {
-        DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
-
-        if (len > *lpdwBufferLength)
-        {
-            *lpdwBufferLength = len;
-            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;
-    }
-    return bSuccess;
-}
-
-/***********************************************************************
- *           HttpQueryInfoW (WININET.@)
- *
- * Queries for information about an HTTP request
- *
- * RETURNS
- *    TRUE  on success
- *    FALSE on failure
- *
- */
-BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
-	LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
-{
-    BOOL bSuccess = FALSE;
-    LPWININETHTTPREQW lpwhr;
-
-    if (TRACE_ON(wininet)) {
-#define FE(x) { x, #x }
-	static const wininet_flag_info query_flags[] = {
-	    FE(HTTP_QUERY_MIME_VERSION),
-	    FE(HTTP_QUERY_CONTENT_TYPE),
-	    FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
-	    FE(HTTP_QUERY_CONTENT_ID),
-	    FE(HTTP_QUERY_CONTENT_DESCRIPTION),
-	    FE(HTTP_QUERY_CONTENT_LENGTH),
-	    FE(HTTP_QUERY_CONTENT_LANGUAGE),
-	    FE(HTTP_QUERY_ALLOW),
-	    FE(HTTP_QUERY_PUBLIC),
-	    FE(HTTP_QUERY_DATE),
-	    FE(HTTP_QUERY_EXPIRES),
-	    FE(HTTP_QUERY_LAST_MODIFIED),
-	    FE(HTTP_QUERY_MESSAGE_ID),
-	    FE(HTTP_QUERY_URI),
-	    FE(HTTP_QUERY_DERIVED_FROM),
-	    FE(HTTP_QUERY_COST),
-	    FE(HTTP_QUERY_LINK),
-	    FE(HTTP_QUERY_PRAGMA),
-	    FE(HTTP_QUERY_VERSION),
-	    FE(HTTP_QUERY_STATUS_CODE),
-	    FE(HTTP_QUERY_STATUS_TEXT),
-	    FE(HTTP_QUERY_RAW_HEADERS),
-	    FE(HTTP_QUERY_RAW_HEADERS_CRLF),
-	    FE(HTTP_QUERY_CONNECTION),
-	    FE(HTTP_QUERY_ACCEPT),
-	    FE(HTTP_QUERY_ACCEPT_CHARSET),
-	    FE(HTTP_QUERY_ACCEPT_ENCODING),
-	    FE(HTTP_QUERY_ACCEPT_LANGUAGE),
-	    FE(HTTP_QUERY_AUTHORIZATION),
-	    FE(HTTP_QUERY_CONTENT_ENCODING),
-	    FE(HTTP_QUERY_FORWARDED),
-	    FE(HTTP_QUERY_FROM),
-	    FE(HTTP_QUERY_IF_MODIFIED_SINCE),
-	    FE(HTTP_QUERY_LOCATION),
-	    FE(HTTP_QUERY_ORIG_URI),
-	    FE(HTTP_QUERY_REFERER),
-	    FE(HTTP_QUERY_RETRY_AFTER),
-	    FE(HTTP_QUERY_SERVER),
-	    FE(HTTP_QUERY_TITLE),
-	    FE(HTTP_QUERY_USER_AGENT),
-	    FE(HTTP_QUERY_WWW_AUTHENTICATE),
-	    FE(HTTP_QUERY_PROXY_AUTHENTICATE),
-	    FE(HTTP_QUERY_ACCEPT_RANGES),
-        FE(HTTP_QUERY_SET_COOKIE),
-        FE(HTTP_QUERY_COOKIE),
-	    FE(HTTP_QUERY_REQUEST_METHOD),
-	    FE(HTTP_QUERY_REFRESH),
-	    FE(HTTP_QUERY_CONTENT_DISPOSITION),
-	    FE(HTTP_QUERY_AGE),
-	    FE(HTTP_QUERY_CACHE_CONTROL),
-	    FE(HTTP_QUERY_CONTENT_BASE),
-	    FE(HTTP_QUERY_CONTENT_LOCATION),
-	    FE(HTTP_QUERY_CONTENT_MD5),
-	    FE(HTTP_QUERY_CONTENT_RANGE),
-	    FE(HTTP_QUERY_ETAG),
-	    FE(HTTP_QUERY_HOST),
-	    FE(HTTP_QUERY_IF_MATCH),
-	    FE(HTTP_QUERY_IF_NONE_MATCH),
-	    FE(HTTP_QUERY_IF_RANGE),
-	    FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
-	    FE(HTTP_QUERY_MAX_FORWARDS),
-	    FE(HTTP_QUERY_PROXY_AUTHORIZATION),
-	    FE(HTTP_QUERY_RANGE),
-	    FE(HTTP_QUERY_TRANSFER_ENCODING),
-	    FE(HTTP_QUERY_UPGRADE),
-	    FE(HTTP_QUERY_VARY),
-	    FE(HTTP_QUERY_VIA),
-	    FE(HTTP_QUERY_WARNING),
-	    FE(HTTP_QUERY_CUSTOM)
-	};
-	static const wininet_flag_info modifier_flags[] = {
-	    FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
-	    FE(HTTP_QUERY_FLAG_SYSTEMTIME),
-	    FE(HTTP_QUERY_FLAG_NUMBER),
-	    FE(HTTP_QUERY_FLAG_COALESCE)
-	};
-#undef FE
-	DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
-	DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
-	DWORD i;
-
-	TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
-	TRACE("  Attribute:");
-	for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
-	    if (query_flags[i].val == info) {
-		TRACE(" %s", query_flags[i].name);
-		break;
-	    }
-	}
-	if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
-	    TRACE(" Unknown (%08x)", info);
-	}
-
-	TRACE(" Modifier:");
-	for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
-	    if (modifier_flags[i].val & info_mod) {
-		TRACE(" %s", modifier_flags[i].name);
-		info_mod &= ~ modifier_flags[i].val;
-	    }
-	}
-	
-	if (info_mod) {
-	    TRACE(" Unknown (%08x)", info_mod);
-	}
-	TRACE("\n");
-    }
-    
-    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
-    if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-	goto lend;
-    }
-
-    if (lpBuffer == NULL)
-        *lpdwBufferLength = 0;
-    bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
-	                            lpBuffer, lpdwBufferLength, lpdwIndex);
-
-lend:
-    if( lpwhr )
-         WININET_Release( &lpwhr->hdr );
-
-    TRACE("%d <--\n", bSuccess);
-    return bSuccess;
-}
-
-/***********************************************************************
- *           HttpQueryInfoA (WININET.@)
- *
- * Queries for information about an HTTP request
- *
- * RETURNS
- *    TRUE  on success
- *    FALSE on failure
- *
- */
-BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
-	LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
-{
-    BOOL result;
-    DWORD len;
-    WCHAR* bufferW;
-
-    if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
-       (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
-    {
-        return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
-                               lpdwBufferLength, lpdwIndex );
-    }
-
-    if (lpBuffer)
-    {
-        DWORD alloclen;
-        len = (*lpdwBufferLength)*sizeof(WCHAR);
-        if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
-        {
-            alloclen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ) * sizeof(WCHAR);
-            if (alloclen < len)
-                alloclen = len;
-        }
-        else
-            alloclen = len;
-        bufferW = HeapAlloc( GetProcessHeap(), 0, alloclen );
-        /* buffer is in/out because of HTTP_QUERY_CUSTOM */
-        if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
-            MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, bufferW, alloclen / sizeof(WCHAR) );
-    } else
-    {
-        bufferW = NULL;
-        len = 0;
-    }
-
-    result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
-                           &len, lpdwIndex );
-    if( result )
-    {
-        len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1,
-                                     lpBuffer, *lpdwBufferLength, NULL, NULL );
-        *lpdwBufferLength = len - 1;
-
-        TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer));
-    }
-    else
-        /* since the strings being returned from HttpQueryInfoW should be
-         * only ASCII characters, it is reasonable to assume that all of
-         * the Unicode characters can be reduced to a single byte */
-        *lpdwBufferLength = len / sizeof(WCHAR);
-
-    HeapFree(GetProcessHeap(), 0, bufferW );
-
-    return result;
-}
-
-/***********************************************************************
- *           HttpSendRequestExA (WININET.@)
- *
- * Sends the specified request to the HTTP server and allows chunked
- * transfers.
- *
- * RETURNS
- *  Success: TRUE
- *  Failure: FALSE, call GetLastError() for more information.
- */
-BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
-			       LPINTERNET_BUFFERSA lpBuffersIn,
-			       LPINTERNET_BUFFERSA lpBuffersOut,
-			       DWORD dwFlags, DWORD_PTR dwContext)
-{
-    INTERNET_BUFFERSW BuffersInW;
-    BOOL rc = FALSE;
-    DWORD headerlen;
-    LPWSTR header = NULL;
-
-    TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
-	    lpBuffersOut, dwFlags, dwContext);
-
-    if (lpBuffersIn)
-    {
-        BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
-        if (lpBuffersIn->lpcszHeader)
-        {
-            headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
-                    lpBuffersIn->dwHeadersLength,0,0);
-            header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR));
-            if (!(BuffersInW.lpcszHeader = header))
-            {
-                INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-                return FALSE;
-            }
-            BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
-                    lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
-                    header, headerlen);
-        }
-        else
-            BuffersInW.lpcszHeader = NULL;
-        BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
-        BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
-        BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
-        BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
-        BuffersInW.Next = NULL;
-    }
-
-    rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
-
-    HeapFree(GetProcessHeap(),0,header);
-
-    return rc;
-}
-
-/***********************************************************************
- *           HttpSendRequestExW (WININET.@)
- *
- * Sends the specified request to the HTTP server and allows chunked
- * transfers
- *
- * RETURNS
- *  Success: TRUE
- *  Failure: FALSE, call GetLastError() for more information.
- */
-BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
-                   LPINTERNET_BUFFERSW lpBuffersIn,
-                   LPINTERNET_BUFFERSW lpBuffersOut,
-                   DWORD dwFlags, DWORD_PTR dwContext)
-{
-    BOOL ret = FALSE;
-    LPWININETHTTPREQW lpwhr;
-    LPWININETHTTPSESSIONW lpwhs;
-    LPWININETAPPINFOW hIC;
-
-    TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
-            lpBuffersOut, dwFlags, dwContext);
-
-    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
-
-    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-        goto lend;
-    }
-
-    lpwhs = lpwhr->lpHttpSession;
-    assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
-    hIC = lpwhs->lpAppInfo;
-    assert(hIC->hdr.htype == WH_HINIT);
-
-    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        WORKREQUEST workRequest;
-        struct WORKREQ_HTTPSENDREQUESTW *req;
-
-        workRequest.asyncproc = AsyncHttpSendRequestProc;
-        workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
-        req = &workRequest.u.HttpSendRequestW;
-        if (lpBuffersIn)
-        {
-            if (lpBuffersIn->lpcszHeader)
-                /* FIXME: this should use dwHeadersLength or may not be necessary at all */
-                req->lpszHeader = WININET_strdupW(lpBuffersIn->lpcszHeader);
-            else
-                req->lpszHeader = NULL;
-            req->dwHeaderLength = lpBuffersIn->dwHeadersLength;
-            req->lpOptional = lpBuffersIn->lpvBuffer;
-            req->dwOptionalLength = lpBuffersIn->dwBufferLength;
-            req->dwContentLength = lpBuffersIn->dwBufferTotal;
-        }
-        else
-        {
-            req->lpszHeader = NULL;
-            req->dwHeaderLength = 0;
-            req->lpOptional = NULL;
-            req->dwOptionalLength = 0;
-            req->dwContentLength = 0;
-        }
-
-        req->bEndRequest = FALSE;
-
-        INTERNET_AsyncCall(&workRequest);
-        /*
-         * This is from windows.
-         */
-        INTERNET_SetLastError(ERROR_IO_PENDING);
-    }
-    else
-    {
-        if (lpBuffersIn)
-            ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
-                                        lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
-                                        lpBuffersIn->dwBufferTotal, FALSE);
-        else
-            ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
-    }
-
-lend:
-    if ( lpwhr )
-        WININET_Release( &lpwhr->hdr );
-
-    TRACE("<---\n");
-    return ret;
-}
-
-/***********************************************************************
- *           HttpSendRequestW (WININET.@)
- *
- * Sends the specified request to the HTTP server
- *
- * RETURNS
- *    TRUE  on success
- *    FALSE on failure
- *
- */
-BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
-	DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
-{
-    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 = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
-    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-	r = FALSE;
-        goto lend;
-    }
-
-    lpwhs = lpwhr->lpHttpSession;
-    if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-	r = FALSE;
-        goto lend;
-    }
-
-    hIC = lpwhs->lpAppInfo;
-    if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT)
-    {
-        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
-	r = FALSE;
-        goto lend;
-    }
-
-    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
-    {
-        WORKREQUEST workRequest;
-        struct WORKREQ_HTTPSENDREQUESTW *req;
-
-        workRequest.asyncproc = AsyncHttpSendRequestProc;
-        workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
-        req = &workRequest.u.HttpSendRequestW;
-        if (lpszHeaders)
-        {
-            DWORD size;
-
-            if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
-            else size = dwHeaderLength * sizeof(WCHAR);
-
-            req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, size);
-            memcpy(req->lpszHeader, lpszHeaders, size);
-        }
-        else
-            req->lpszHeader = 0;
-        req->dwHeaderLength = dwHeaderLength;
-        req->lpOptional = lpOptional;
-        req->dwOptionalLength = dwOptionalLength;
-        req->dwContentLength = dwOptionalLength;
-        req->bEndRequest = TRUE;
-
-        INTERNET_AsyncCall(&workRequest);
-        /*
-         * This is from windows.
-         */
-        INTERNET_SetLastError(ERROR_IO_PENDING);
-        r = FALSE;
-    }
-    else
-    {
-	r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders,
-		dwHeaderLength, lpOptional, dwOptionalLength,
-		dwOptionalLength, TRUE);
-    }
-lend:
-    if( lpwhr )
-        WININET_Release( &lpwhr->hdr );
-    return r;
-}
-
-/***********************************************************************
- *           HttpSendRequestA (WININET.@)
- *
- * Sends the specified request to the HTTP server
- *
- * RETURNS
- *    TRUE  on success
- *    FALSE on failure
- *
- */
-BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
-	DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
-{
-    BOOL result;
-    LPWSTR szHeaders=NULL;
-    DWORD nLen=dwHeaderLength;
-    if(lpszHeaders!=NULL)
-    {
-        nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
-        szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR));
-        MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
-    }
-    result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
-    HeapFree(GetProcessHeap(),0,szHeaders);
-    return result;
-}
-
-/***********************************************************************
  *           HTTP_GetRedirectURL (internal)
  */
 static LPWSTR HTTP_GetRedirectURL(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
@@ -3354,7 +3185,6 @@ static LPWSTR HTTP_GetRedirectURL(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
     return combined_url;
 }
 
-
 /***********************************************************************
  *           HTTP_HandleRedirect (internal)
  */
@@ -3423,7 +3253,7 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
 
 #if 0
         /*
-         * This upsets redirects to binary files on sourceforge.net 
+         * This upsets redirects to binary files on sourceforge.net
          * and gives an html page instead of the target file
          * Examination of the HTTP request sent by native wininet.dll
          * reveals that it doesn't send a referrer in that case.
@@ -3437,7 +3267,7 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
                            HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
                            HTTP_ADDHDR_FLAG_ADD_IF_NEW);
 #endif
-        
+
         HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName);
         if (urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT &&
             urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT)
@@ -3510,98 +3340,278 @@ static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl)
 }
 
 /***********************************************************************
- *           HTTP_build_req (internal)
+ *  HTTP_InsertAuthorization
  *
- *  concatenate all the strings in the request together
+ *   Insert or delete the authorization field in the request header.
  */
-static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
+static BOOL HTTP_InsertAuthorization( LPWININETHTTPREQW lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
 {
-    LPCWSTR *t;
-    LPWSTR str;
+    if (pAuthInfo)
+    {
+        static const WCHAR wszSpace[] = {' ',0};
+        static const WCHAR wszBasic[] = {'B','a','s','i','c',0};
+        unsigned int len;
+        WCHAR *authorization = NULL;
 
-    for( t = list; *t ; t++  )
-        len += strlenW( *t );
-    len++;
+        if (pAuthInfo->auth_data_len)
+        {
+            /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
+            len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3;
+            authorization = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
+            if (!authorization)
+                return FALSE;
 
-    str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
-    *str = 0;
+            strcpyW(authorization, pAuthInfo->scheme);
+            strcatW(authorization, wszSpace);
+            HTTP_EncodeBase64(pAuthInfo->auth_data,
+                              pAuthInfo->auth_data_len,
+                              authorization+strlenW(authorization));
 
-    for( t = list; *t ; t++ )
-        strcatW( str, *t );
+            /* clear the data as it isn't valid now that it has been sent to the
+             * server, unless it's Basic authentication which doesn't do
+             * connection tracking */
+            if (strcmpiW(pAuthInfo->scheme, wszBasic))
+            {
+                HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data);
+                pAuthInfo->auth_data = NULL;
+                pAuthInfo->auth_data_len = 0;
+            }
+        }
 
-    return str;
+        TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
+
+        HTTP_ProcessHeader(lpwhr, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
+
+        HeapFree(GetProcessHeap(), 0, authorization);
+    }
+    return TRUE;
 }
 
-static BOOL HTTP_SecureProxyConnect(LPWININETHTTPREQW lpwhr)
+/***********************************************************************
+ *          IsHostInProxyBypassList (@)
+ *
+ * Undocumented
+ *
+ */
+BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
 {
-    LPWSTR lpszPath;
-    LPWSTR requestString;
-    INT len;
-    INT cnt;
-    INT responseLen;
-    char *ascii_req;
-    BOOL ret;
-    static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0};
-    static const WCHAR szFormat[] = {'%','s',':','%','d',0};
-    LPWININETHTTPSESSIONW lpwhs = lpwhr->lpHttpSession;
+   FIXME("STUB: flags=%d host=%s length=%d\n",flags,szHost,length);
+   return FALSE;
+}
 
-    TRACE("\n");
+static WCHAR *HTTP_BuildProxyRequestUrl(WININETHTTPREQW *req)
+{
+    WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
+    DWORD size;
 
-    lpszPath = HeapAlloc( GetProcessHeap(), 0, (lstrlenW( lpwhs->lpszHostName ) + 13)*sizeof(WCHAR) );
-    sprintfW( lpszPath, szFormat, lpwhs->lpszHostName, lpwhs->nHostPort );
-    requestString = HTTP_BuildHeaderRequestString( lpwhr, szConnect, lpszPath, g_szHttp1_1 );
-    HeapFree( GetProcessHeap(), 0, lpszPath );
+    size = sizeof(new_location);
+    if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL))
+    {
+        if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL;
+        strcpyW( url, new_location );
+    }
+    else
+    {
+        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 };
+        WININETHTTPSESSIONW *session = req->lpHttpSession;
 
-    len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
-                                NULL, 0, NULL, NULL );
-    len--; /* the nul terminator isn't needed */
-    ascii_req = HeapAlloc( GetProcessHeap(), 0, len );
-    WideCharToMultiByte( CP_ACP, 0, requestString, -1,
-                            ascii_req, len, NULL, NULL );
-    HeapFree( GetProcessHeap(), 0, requestString );
+        size = 16; /* "https://" + sizeof(port#) + ":/\0" */
+        size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath );
 
-    TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
+        if (!(url = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL;
 
-    ret = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt );
-    HeapFree( GetProcessHeap(), 0, ascii_req );
-    if (!ret || cnt < 0)
-        return FALSE;
+        if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
+            sprintfW( url, formatSSL, session->lpszHostName, session->nHostPort );
+        else
+            sprintfW( url, format, session->lpszHostName, session->nHostPort );
+        if (req->lpszPath[0] != '/') strcatW( url, slash );
+        strcatW( url, req->lpszPath );
+    }
+    TRACE("url=%s\n", debugstr_w(url));
+    return url;
+}
 
-    responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE );
-    if (!responseLen)
+/***********************************************************************
+ *           HTTP_DealWithProxy
+ */
+static BOOL HTTP_DealWithProxy( LPWININETAPPINFOW hIC,
+    LPWININETHTTPSESSIONW lpwhs, LPWININETHTTPREQW lpwhr)
+{
+    WCHAR buf[MAXHOSTNAME];
+    WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
+    static WCHAR szNul[] = { 0 };
+    URL_COMPONENTSW UrlComponents;
+    static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
+    static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
+
+    memset( &UrlComponents, 0, sizeof UrlComponents );
+    UrlComponents.dwStructSize = sizeof UrlComponents;
+    UrlComponents.lpszHostName = buf;
+    UrlComponents.dwHostNameLength = MAXHOSTNAME;
+
+    if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
+                                 hIC->lpszProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
+        sprintfW(proxy, szFormat, hIC->lpszProxy);
+    else
+	strcpyW(proxy, hIC->lpszProxy);
+    if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
+        return FALSE;
+    if( UrlComponents.dwHostNameLength == 0 )
         return FALSE;
 
+    if( !lpwhr->lpszPath )
+        lpwhr->lpszPath = szNul;
+
+    if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
+        UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
+
+    HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
+    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;
 }
 
-static void HTTP_InsertCookies(LPWININETHTTPREQW lpwhr)
+/* read any content returned by the server so that the connection can be
+ * reused */
+static void HTTP_DrainContent(WININETHTTPREQW *req)
 {
-    static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
-    LPWSTR lpszCookies, lpszUrl = NULL;
-    DWORD nCookieSize, size;
-    LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
+    DWORD bytes_read;
 
-    size = (strlenW(Host->lpszValue) + strlenW(szUrlForm) + strlenW(lpwhr->lpszPath)) * sizeof(WCHAR);
-    if (!(lpszUrl = HeapAlloc(GetProcessHeap(), 0, size))) return;
-    sprintfW( lpszUrl, szUrlForm, Host->lpszValue, lpwhr->lpszPath);
+    if (!NETCON_connected(&req->netConnection)) return;
 
-    if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize))
+    if (req->dwContentLength == -1)
     {
-        int cnt = 0;
-        static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0};
+        NETCON_close(&req->netConnection);
+        return;
+    }
 
-        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);
+    do
+    {
+        char buffer[2048];
+        if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS)
+            return;
+    } while (bytes_read);
+}
 
-            HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_REPLACE);
-            HeapFree(GetProcessHeap(), 0, lpszCookies);
+#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(WININETHTTPREQW *req)
+{
+    gzip_stream_t *gzip_stream;
+    int 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;
+}
+
+#else
+
+static void init_gzip_stream(WININETHTTPREQW *req)
+{
+    ERR("gzip stream not supported, missing zlib.\n");
+}
+
+#endif
+
+/* set the request content length based on the headers */
+static DWORD set_content_length( LPWININETHTTPREQW 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;
+}
+
+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 = WININET_strdupW(szSlash);
+    else /* remove \r and \n*/
+    {
+        int nLen = strlenW(lpwhr->lpszPath);
+        while ((nLen >0 ) && ((lpwhr->lpszPath[nLen-1] == '\r')||(lpwhr->lpszPath[nLen-1] == '\n')))
+        {
+            nLen--;
+            lpwhr->lpszPath[nLen]='\0';
+        }
+        /* Replace '\' with '/' */
+        while (nLen>0) {
+            nLen--;
+            if (lpwhr->lpszPath[nLen] == '\\') lpwhr->lpszPath[nLen]='/';
         }
     }
-    HeapFree(GetProcessHeap(), 0, lpszUrl);
+
+    if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
+                       lpwhr->lpszPath, strlenW(lpwhr->lpszPath), szHttp, strlenW(szHttp) )
+       && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
+    {
+        WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0,
+                             (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR));
+        *fixurl = '/';
+        strcpyW(fixurl + 1, lpwhr->lpszPath);
+        HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
+        lpwhr->lpszPath = fixurl;
+    }
 }
 
 /***********************************************************************
@@ -3713,7 +3723,7 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders,
         else
             requestString = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
 
- 
+
         TRACE("Request header -> %s\n", debugstr_w(requestString) );
 
         /* Send the request and store the results */
@@ -3753,14 +3763,14 @@ BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders,
 
             INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                                 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
-    
+
             if (cnt < 0)
                 goto lend;
-    
+
             responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
             if (responseLen)
                 bSuccess = TRUE;
-    
+
             INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
                                 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
                                 sizeof(DWORD));
@@ -3904,798 +3914,775 @@ lend:
     return bSuccess;
 }
 
-/***********************************************************************
- *           HTTPSESSION_Destroy (internal)
+/* **********************************************************************
  *
- * Deallocate session handle
+ * Helper functions for the HttpSendRequest(Ex) functions
  *
  */
-static void HTTPSESSION_Destroy(WININETHANDLEHEADER *hdr)
+static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
 {
-    LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr;
+    struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
+    LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) workRequest->hdr;
 
-    TRACE("%p\n", lpwhs);
+    TRACE("%p\n", lpwhr);
 
-    WININET_Release(&lpwhs->lpAppInfo->hdr);
+    HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
+            req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
+            req->dwContentLength, req->bEndRequest);
 
-    HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName);
-    HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
-    HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword);
-    HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
-    HeapFree(GetProcessHeap(), 0, lpwhs);
+    HeapFree(GetProcessHeap(), 0, req->lpszHeader);
 }
 
-static DWORD HTTPSESSION_QueryOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
+/***********************************************************************
+ *           HttpSendRequestExW (WININET.@)
+ *
+ * Sends the specified request to the HTTP server and allows chunked
+ * transfers
+ *
+ * RETURNS
+ *  Success: TRUE
+ *  Failure: FALSE, call GetLastError() for more information.
+ */
+BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
+                   LPINTERNET_BUFFERSW lpBuffersIn,
+                   LPINTERNET_BUFFERSW lpBuffersOut,
+                   DWORD dwFlags, DWORD_PTR dwContext)
 {
-    switch(option) {
-    case INTERNET_OPTION_HANDLE_TYPE:
-        TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
+    BOOL ret = FALSE;
+    LPWININETHTTPREQW lpwhr;
+    LPWININETHTTPSESSIONW lpwhs;
+    LPWININETAPPINFOW hIC;
 
-        if (*size < sizeof(ULONG))
-            return ERROR_INSUFFICIENT_BUFFER;
+    TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
+            lpBuffersOut, dwFlags, dwContext);
 
-        *size = sizeof(DWORD);
-        *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP;
-        return ERROR_SUCCESS;
-    }
+    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
 
-    return INET_QueryOption(option, buffer, size, unicode);
-}
+    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
+    {
+        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+        goto lend;
+    }
 
-static DWORD HTTPSESSION_SetOption(WININETHANDLEHEADER *hdr, DWORD option, void *buffer, DWORD size)
-{
-    WININETHTTPSESSIONW *ses = (WININETHTTPSESSIONW*)hdr;
+    lpwhs = lpwhr->lpHttpSession;
+    assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
+    hIC = lpwhs->lpAppInfo;
+    assert(hIC->hdr.htype == WH_HINIT);
 
-    switch(option) {
-    case INTERNET_OPTION_USERNAME:
+    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
     {
-        HeapFree(GetProcessHeap(), 0, ses->lpszUserName);
-        if (!(ses->lpszUserName = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY;
-        return ERROR_SUCCESS;
+        WORKREQUEST workRequest;
+        struct WORKREQ_HTTPSENDREQUESTW *req;
+
+        workRequest.asyncproc = AsyncHttpSendRequestProc;
+        workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
+        req = &workRequest.u.HttpSendRequestW;
+        if (lpBuffersIn)
+        {
+            if (lpBuffersIn->lpcszHeader)
+                /* FIXME: this should use dwHeadersLength or may not be necessary at all */
+                req->lpszHeader = WININET_strdupW(lpBuffersIn->lpcszHeader);
+            else
+                req->lpszHeader = NULL;
+            req->dwHeaderLength = lpBuffersIn->dwHeadersLength;
+            req->lpOptional = lpBuffersIn->lpvBuffer;
+            req->dwOptionalLength = lpBuffersIn->dwBufferLength;
+            req->dwContentLength = lpBuffersIn->dwBufferTotal;
+        }
+        else
+        {
+            req->lpszHeader = NULL;
+            req->dwHeaderLength = 0;
+            req->lpOptional = NULL;
+            req->dwOptionalLength = 0;
+            req->dwContentLength = 0;
+        }
+
+        req->bEndRequest = FALSE;
+
+        INTERNET_AsyncCall(&workRequest);
+        /*
+         * This is from windows.
+         */
+        INTERNET_SetLastError(ERROR_IO_PENDING);
     }
-    case INTERNET_OPTION_PASSWORD:
+    else
     {
-        HeapFree(GetProcessHeap(), 0, ses->lpszPassword);
-        if (!(ses->lpszPassword = WININET_strdupW(buffer))) return ERROR_OUTOFMEMORY;
-        return ERROR_SUCCESS;
-    }
-    default: break;
+        if (lpBuffersIn)
+            ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
+                                        lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
+                                        lpBuffersIn->dwBufferTotal, FALSE);
+        else
+            ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
     }
 
-    return ERROR_INTERNET_INVALID_OPTION;
-}
-
-static const HANDLEHEADERVtbl HTTPSESSIONVtbl = {
-    HTTPSESSION_Destroy,
-    NULL,
-    HTTPSESSION_QueryOption,
-    HTTPSESSION_SetOption,
-    NULL,
-    NULL,
-    NULL,
-    NULL,
-    NULL
-};
+lend:
+    if ( lpwhr )
+        WININET_Release( &lpwhr->hdr );
 
+    TRACE("<---\n");
+    return ret;
+}
 
 /***********************************************************************
- *           HTTP_Connect  (internal)
+ *           HttpSendRequestExA (WININET.@)
  *
- * Create http session handle
+ * Sends the specified request to the HTTP server and allows chunked
+ * transfers.
  *
  * RETURNS
- *   HINTERNET a session handle on success
- *   NULL on failure
- *
+ *  Success: TRUE
+ *  Failure: FALSE, call GetLastError() for more information.
  */
-HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
-	INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
-	LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
-	DWORD dwInternalFlags)
+BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
+			       LPINTERNET_BUFFERSA lpBuffersIn,
+			       LPINTERNET_BUFFERSA lpBuffersOut,
+			       DWORD dwFlags, DWORD_PTR dwContext)
 {
-    LPWININETHTTPSESSIONW lpwhs = NULL;
-    HINTERNET handle = NULL;
-
-    TRACE("-->\n");
-
-    if (!lpszServerName || !lpszServerName[0])
-    {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
-        goto lerror;
-    }
-
-    assert( hIC->hdr.htype == WH_HINIT );
-
-    lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW));
-    if (NULL == lpwhs)
-    {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-	goto lerror;
-    }
-
-   /*
-    * According to my tests. The name is not resolved until a request is sent
-    */
-
-    lpwhs->hdr.htype = WH_HHTTPSESSION;
-    lpwhs->hdr.vtbl = &HTTPSESSIONVtbl;
-    lpwhs->hdr.dwFlags = dwFlags;
-    lpwhs->hdr.dwContext = dwContext;
-    lpwhs->hdr.dwInternalFlags = dwInternalFlags | (hIC->hdr.dwInternalFlags & INET_CALLBACKW);
-    lpwhs->hdr.refs = 1;
-    lpwhs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
-
-    WININET_AddRef( &hIC->hdr );
-    lpwhs->lpAppInfo = hIC;
-    list_add_head( &hIC->hdr.children, &lpwhs->hdr.entry );
-
-    handle = WININET_AllocHandle( &lpwhs->hdr );
-    if (NULL == handle)
-    {
-        ERR("Failed to alloc handle\n");
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
-	goto lerror;
-    }
+    INTERNET_BUFFERSW BuffersInW;
+    BOOL rc = FALSE;
+    DWORD headerlen;
+    LPWSTR header = NULL;
 
-    if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
-        if(strchrW(hIC->lpszProxy, ' '))
-            FIXME("Several proxies not implemented.\n");
-        if(hIC->lpszProxyBypass)
-            FIXME("Proxy bypass is ignored.\n");
-    }
-    if (lpszServerName && lpszServerName[0])
-    {
-        lpwhs->lpszServerName = WININET_strdupW(lpszServerName);
-        lpwhs->lpszHostName = WININET_strdupW(lpszServerName);
-    }
-    if (lpszUserName && lpszUserName[0])
-        lpwhs->lpszUserName = WININET_strdupW(lpszUserName);
-    if (lpszPassword && lpszPassword[0])
-        lpwhs->lpszPassword = WININET_strdupW(lpszPassword);
-    lpwhs->nServerPort = nServerPort;
-    lpwhs->nHostPort = nServerPort;
+    TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
+	    lpBuffersOut, dwFlags, dwContext);
 
-    /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
-    if (!(lpwhs->hdr.dwInternalFlags & INET_OPENURL))
+    if (lpBuffersIn)
     {
-        INTERNET_SendCallback(&hIC->hdr, dwContext,
-                              INTERNET_STATUS_HANDLE_CREATED, &handle,
-                              sizeof(handle));
+        BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
+        if (lpBuffersIn->lpcszHeader)
+        {
+            headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
+                    lpBuffersIn->dwHeadersLength,0,0);
+            header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR));
+            if (!(BuffersInW.lpcszHeader = header))
+            {
+                INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+                return FALSE;
+            }
+            BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
+                    lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
+                    header, headerlen);
+        }
+        else
+            BuffersInW.lpcszHeader = NULL;
+        BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
+        BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
+        BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
+        BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
+        BuffersInW.Next = NULL;
     }
 
-lerror:
-    if( lpwhs )
-        WININET_Release( &lpwhs->hdr );
+    rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
 
-/*
- * an INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
- * windows
- */
+    HeapFree(GetProcessHeap(),0,header);
 
-    TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs);
-    return handle;
+    return rc;
 }
 
-
 /***********************************************************************
- *           HTTP_OpenConnection (internal)
+ *           HttpSendRequestW (WININET.@)
  *
- * Connect to a web server
+ * Sends the specified request to the HTTP server
  *
  * RETURNS
+ *    TRUE  on success
+ *    FALSE on failure
  *
- *   TRUE  on success
- *   FALSE on failure
  */
-static BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr)
+BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
+	DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
 {
-    BOOL bSuccess = FALSE;
-    LPWININETHTTPSESSIONW lpwhs;
+    LPWININETHTTPREQW lpwhr;
+    LPWININETHTTPSESSIONW lpwhs = NULL;
     LPWININETAPPINFOW hIC = NULL;
-    char szaddr[32];
-
-    TRACE("-->\n");
+    BOOL r;
 
+    TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
+            debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
 
-    if (lpwhr->hdr.htype != WH_HHTTPREQ)
+    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
+    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
     {
-        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+	r = FALSE;
         goto lend;
     }
 
-    if (NETCON_connected(&lpwhr->netConnection))
+    lpwhs = lpwhr->lpHttpSession;
+    if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
     {
-        bSuccess = TRUE;
+        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+	r = FALSE;
         goto lend;
     }
-    if (!HTTP_ResolveName(lpwhr)) goto lend;
-
-    lpwhs = lpwhr->lpHttpSession;
 
     hIC = lpwhs->lpAppInfo;
-    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.sin_family,
-                         SOCK_STREAM, 0))
+    if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT)
     {
-        WARN("Socket creation failed: %u\n", INTERNET_GetLastError());
+        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+	r = FALSE;
         goto lend;
     }
 
-    if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
-                      sizeof(lpwhs->socketAddress)))
-       goto lend;
-
-    if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)
+    if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
     {
-        /* Note: we differ from Microsoft's WinINet here. they seem to have
-         * a bug that causes no status callbacks to be sent when starting
-         * a tunnel to a proxy server using the CONNECT verb. i believe our
-         * behaviour to be more correct and to not cause any incompatibilities
-         * because using a secure connection through a proxy server is a rare
-         * case that would be hard for anyone to depend on */
-        if (hIC->lpszProxy && !HTTP_SecureProxyConnect(lpwhr))
-            goto lend;
+        WORKREQUEST workRequest;
+        struct WORKREQ_HTTPSENDREQUESTW *req;
 
-        if (!NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName))
+        workRequest.asyncproc = AsyncHttpSendRequestProc;
+        workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
+        req = &workRequest.u.HttpSendRequestW;
+        if (lpszHeaders)
         {
-            WARN("Couldn't connect securely to host\n");
-            goto lend;
-        }
-    }
-
-    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
-                          INTERNET_STATUS_CONNECTED_TO_SERVER,
-                          szaddr, strlen(szaddr)+1);
-
-    bSuccess = TRUE;
-
-lend:
-    lpwhr->read_pos = lpwhr->read_size = 0;
-    lpwhr->read_chunked = FALSE;
-
-    TRACE("%d <--\n", bSuccess);
-    return bSuccess;
-}
+            DWORD size;
 
+            if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
+            else size = dwHeaderLength * sizeof(WCHAR);
 
-/***********************************************************************
- *           HTTP_clear_response_headers (internal)
- *
- * clear out any old response headers
- */
-static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr )
-{
-    DWORD i;
+            req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, size);
+            memcpy(req->lpszHeader, lpszHeaders, size);
+        }
+        else
+            req->lpszHeader = 0;
+        req->dwHeaderLength = dwHeaderLength;
+        req->lpOptional = lpOptional;
+        req->dwOptionalLength = dwOptionalLength;
+        req->dwContentLength = dwOptionalLength;
+        req->bEndRequest = TRUE;
 
-    for( i=0; i<lpwhr->nCustHeaders; i++)
+        INTERNET_AsyncCall(&workRequest);
+        /*
+         * This is from windows.
+         */
+        INTERNET_SetLastError(ERROR_IO_PENDING);
+        r = FALSE;
+    }
+    else
     {
-        if( !lpwhr->pCustHeaders[i].lpszField )
-            continue;
-        if( !lpwhr->pCustHeaders[i].lpszValue )
-            continue;
-        if ( lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST )
-            continue;
-        HTTP_DeleteCustomHeader( lpwhr, i );
-        i--;
+	r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders,
+		dwHeaderLength, lpOptional, dwOptionalLength,
+		dwOptionalLength, TRUE);
     }
+lend:
+    if( lpwhr )
+        WININET_Release( &lpwhr->hdr );
+    return r;
 }
 
 /***********************************************************************
- *           HTTP_GetResponseHeaders (internal)
+ *           HttpSendRequestA (WININET.@)
  *
- * Read server response
+ * Sends the specified request to the HTTP server
  *
  * RETURNS
+ *    TRUE  on success
+ *    FALSE on failure
  *
- *   TRUE  on success
- *   FALSE on error
  */
-static INT HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr, BOOL clear)
+BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
+	DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
 {
-    INT cbreaks = 0;
-    WCHAR buffer[MAX_REPLY_LEN];
-    DWORD buflen = MAX_REPLY_LEN;
-    BOOL bSuccess = FALSE;
-    INT  rc = 0;
-    static const WCHAR szHundred[] = {'1','0','0',0};
-    char bufferA[MAX_REPLY_LEN];
-    LPWSTR status_code, status_text;
-    DWORD cchMaxRawHeaders = 1024;
-    LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR));
-    LPWSTR temp;
-    DWORD cchRawHeaders = 0;
-
-    TRACE("-->\n");
-
-    /* clear old response headers (eg. from a redirect response) */
-    if (clear) HTTP_clear_response_headers( lpwhr );
-
-    if (!NETCON_connected(&lpwhr->netConnection))
-        goto lend;
-
-    do {
-        /*
-         * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
-         */
-        buflen = MAX_REPLY_LEN;
-        if (!read_line(lpwhr, bufferA, &buflen))
-            goto lend;
-        rc += buflen;
-        MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
-
-        /* split the version from the status code */
-        status_code = strchrW( buffer, ' ' );
-        if( !status_code )
-            goto lend;
-        *status_code++=0;
-
-        /* split the status code from the status text */
-        status_text = strchrW( status_code, ' ' );
-        if( !status_text )
-            goto lend;
-        *status_text++=0;
-
-        TRACE("version [%s] status code [%s] status text [%s]\n",
-           debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
+    BOOL result;
+    LPWSTR szHeaders=NULL;
+    DWORD nLen=dwHeaderLength;
+    if(lpszHeaders!=NULL)
+    {
+        nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
+        szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR));
+        MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
+    }
+    result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
+    HeapFree(GetProcessHeap(),0,szHeaders);
+    return result;
+}
 
-    } while (!strcmpW(status_code, szHundred)); /* ignore "100 Continue" responses */
+static BOOL HTTP_HttpEndRequestW(LPWININETHTTPREQW lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
+{
+    BOOL rc = FALSE;
+    INT responseLen;
+    DWORD dwBufferSize;
+    INTERNET_ASYNC_RESULT iar;
 
-    /* Add status code */
-    HTTP_ProcessHeader(lpwhr, szStatus, status_code,
-            HTTP_ADDHDR_FLAG_REPLACE);
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                  INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
 
-    HeapFree(GetProcessHeap(),0,lpwhr->lpszVersion);
-    HeapFree(GetProcessHeap(),0,lpwhr->lpszStatusText);
+    responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
+    if (responseLen)
+        rc = TRUE;
 
-    lpwhr->lpszVersion= WININET_strdupW(buffer);
-    lpwhr->lpszStatusText = WININET_strdupW(status_text);
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                  INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
 
-    /* Restore the spaces */
-    *(status_code-1) = ' ';
-    *(status_text-1) = ' ';
+    /* process cookies here. Is this right? */
+    HTTP_ProcessCookies(lpwhr);
 
-    /* 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;
-    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';
+    if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
 
-    /* Parse each response line */
-    do
+    if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
     {
-	buflen = MAX_REPLY_LEN;
-        if (read_line(lpwhr, bufferA, &buflen))
+        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))
         {
-            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)
+            WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
+            dwBufferSize=sizeof(szNewLocation);
+            if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL))
             {
-                while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
-                    cchMaxRawHeaders *= 2;
-                temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
-                if (temp == NULL) goto lend;
-                lpszRawHeaders = temp;
-                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';
-
-                HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1],
-                                   HTTP_ADDREQ_FLAG_ADD );
-
-                HTTP_FreeTokens(pFieldAndValue);
+                /* redirects are always GETs */
+                HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
+                lpwhr->lpszVerb = WININET_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));
+                    rc = HTTP_HandleRedirect(lpwhr, new_url);
+                    if (rc)
+                        rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
+                    HeapFree( GetProcessHeap(), 0, new_url );
+                }
             }
         }
-	else
-	{
-	    cbreaks++;
-	    if (cbreaks >= 2)
-	       break;
-	}
-    }while(1);
-
-    HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
-    lpwhr->lpszRawHeaders = lpszRawHeaders;
-    TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
-    bSuccess = TRUE;
+    }
 
-lend:
+    iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
+    iar.dwError = rc ? 0 : INTERNET_GetLastError();
 
-    TRACE("<--\n");
-    if (bSuccess)
-        return rc;
-    else
-    {
-        HeapFree(GetProcessHeap(), 0, lpszRawHeaders);
-        return 0;
-    }
+    INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
+                          INTERNET_STATUS_REQUEST_COMPLETE, &iar,
+                          sizeof(INTERNET_ASYNC_RESULT));
+    return rc;
 }
 
-
-static void strip_spaces(LPWSTR start)
+static void AsyncHttpEndRequestProc(WORKREQUEST *work)
 {
-    LPWSTR str = start;
-    LPWSTR end;
-
-    while (*str == ' ' && *str != '\0')
-        str++;
+    struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
+    LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW)work->hdr;
 
-    if (str != start)
-        memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1));
+    TRACE("%p\n", lpwhr);
 
-    end = start + strlenW(start) - 1;
-    while (end >= start && *end == ' ')
-    {
-        *end = '\0';
-        end--;
-    }
+    HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext);
 }
 
-
 /***********************************************************************
- *           HTTP_InterpretHttpHeader (internal)
+ *           HttpEndRequestW (WININET.@)
  *
- * Parse server response
+ * Ends an HTTP request that was started by HttpSendRequestEx
  *
  * RETURNS
+ *    TRUE	if successful
+ *    FALSE	on failure
  *
- *   Pointer to array of field, value, NULL on success.
- *   NULL on error.
  */
-static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer)
+BOOL WINAPI HttpEndRequestW(HINTERNET hRequest,
+        LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
 {
-    LPWSTR * pTokenPair;
-    LPWSTR pszColon;
-    INT len;
+    BOOL rc = FALSE;
+    LPWININETHTTPREQW lpwhr;
 
-    pTokenPair = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTokenPair)*3);
+    TRACE("-->\n");
 
-    pszColon = strchrW(buffer, ':');
-    /* must have two tokens */
-    if (!pszColon)
+    if (lpBuffersOut)
     {
-        HTTP_FreeTokens(pTokenPair);
-        if (buffer[0])
-            TRACE("No ':' in line: %s\n", debugstr_w(buffer));
-        return NULL;
+        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
     }
 
-    pTokenPair[0] = HeapAlloc(GetProcessHeap(), 0, (pszColon - buffer + 1) * sizeof(WCHAR));
-    if (!pTokenPair[0])
+    lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hRequest );
+
+    if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
     {
-        HTTP_FreeTokens(pTokenPair);
-        return NULL;
+        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+        if (lpwhr)
+            WININET_Release( &lpwhr->hdr );
+        return FALSE;
     }
-    memcpy(pTokenPair[0], buffer, (pszColon - buffer) * sizeof(WCHAR));
-    pTokenPair[0][pszColon - buffer] = '\0';
+    lpwhr->hdr.dwFlags |= dwFlags;
 
-    /* skip colon */
-    pszColon++;
-    len = strlenW(pszColon);
-    pTokenPair[1] = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
-    if (!pTokenPair[1])
+    if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
     {
-        HTTP_FreeTokens(pTokenPair);
-        return NULL;
-    }
-    memcpy(pTokenPair[1], pszColon, (len + 1) * sizeof(WCHAR));
+        WORKREQUEST work;
+        struct WORKREQ_HTTPENDREQUESTW *request;
 
-    strip_spaces(pTokenPair[0]);
-    strip_spaces(pTokenPair[1]);
+        work.asyncproc = AsyncHttpEndRequestProc;
+        work.hdr = WININET_AddRef( &lpwhr->hdr );
 
-    TRACE("field(%s) Value(%s)\n", debugstr_w(pTokenPair[0]), debugstr_w(pTokenPair[1]));
-    return pTokenPair;
+        request = &work.u.HttpEndRequestW;
+        request->dwFlags = dwFlags;
+        request->dwContext = dwContext;
+
+        INTERNET_AsyncCall(&work);
+        INTERNET_SetLastError(ERROR_IO_PENDING);
+    }
+    else
+        rc = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
+
+    WININET_Release( &lpwhr->hdr );
+    TRACE("%i <--\n",rc);
+    return rc;
 }
 
 /***********************************************************************
- *           HTTP_ProcessHeader (internal)
+ *           HttpEndRequestA (WININET.@)
  *
- * Stuff header into header tables according to <dwModifier>
+ * Ends an HTTP request that was started by HttpSendRequestEx
+ *
+ * RETURNS
+ *    TRUE	if successful
+ *    FALSE	on failure
  *
  */
-
-#define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
-
-static BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
+BOOL WINAPI HttpEndRequestA(HINTERNET hRequest,
+        LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
 {
-    LPHTTPHEADERW lphttpHdr = NULL;
-    BOOL bSuccess = FALSE;
-    INT index = -1;
-    BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ;
-
-    TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier);
-
-    /* REPLACE wins out over ADD */
-    if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
-        dwModifier &= ~HTTP_ADDHDR_FLAG_ADD;
-    
-    if (dwModifier & HTTP_ADDHDR_FLAG_ADD)
-        index = -1;
-    else
-        index = HTTP_GetCustomHeaderIndex(lpwhr, field, 0, request_only);
+    TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
 
-    if (index >= 0)
+    if (lpBuffersOut)
     {
-        if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
-        {
-            return FALSE;
-        }
-        lphttpHdr = &lpwhr->pCustHeaders[index];
+        INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
     }
-    else if (value)
-    {
-        HTTPHEADERW hdr;
 
-        hdr.lpszField = (LPWSTR)field;
-        hdr.lpszValue = (LPWSTR)value;
-        hdr.wFlags = hdr.wCount = 0;
+    return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
+}
 
-        if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
-            hdr.wFlags |= HDR_ISREQUEST;
+/***********************************************************************
+ *           HTTP_HttpOpenRequestW (internal)
+ *
+ * Open a HTTP request handle
+ *
+ * RETURNS
+ *    HINTERNET  a HTTP request handle on success
+ *    NULL 	 on failure
+ *
+ */
+HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs,
+	LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
+	LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
+	DWORD dwFlags, DWORD_PTR dwContext)
+{
+    LPWININETAPPINFOW hIC = NULL;
+    LPWININETHTTPREQW lpwhr;
+    LPWSTR lpszHostName = NULL;
+    HINTERNET handle = NULL;
+    static const WCHAR szHostForm[] = {'%','s',':','%','u',0};
+    DWORD len;
 
-        return HTTP_InsertCustomHeader(lpwhr, &hdr);
-    }
-    /* no value to delete */
-    else return TRUE;
+    TRACE("-->\n");
 
-    if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
-	    lphttpHdr->wFlags |= HDR_ISREQUEST;
-    else
-        lphttpHdr->wFlags &= ~HDR_ISREQUEST;
+    assert( lpwhs->hdr.htype == WH_HHTTPSESSION );
+    hIC = lpwhs->lpAppInfo;
 
-    if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
+    lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQW));
+    if (NULL == lpwhr)
     {
-        HTTP_DeleteCustomHeader( lpwhr, index );
-
-        if (value)
-        {
-            HTTPHEADERW hdr;
-
-            hdr.lpszField = (LPWSTR)field;
-            hdr.lpszValue = (LPWSTR)value;
-            hdr.wFlags = hdr.wCount = 0;
+        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+        goto lend;
+    }
+    lpwhr->hdr.htype = WH_HHTTPREQ;
+    lpwhr->hdr.vtbl = &HTTPREQVtbl;
+    lpwhr->hdr.dwFlags = dwFlags;
+    lpwhr->hdr.dwContext = dwContext;
+    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 );
 
-            if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
-                hdr.wFlags |= HDR_ISREQUEST;
+    WININET_AddRef( &lpwhs->hdr );
+    lpwhr->lpHttpSession = lpwhs;
+    list_add_head( &lpwhs->hdr.children, &lpwhr->hdr.entry );
 
-            return HTTP_InsertCustomHeader(lpwhr, &hdr);
-        }
+    lpszHostName = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) *
+            (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */));
+    if (NULL == lpszHostName)
+    {
+        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+        goto lend;
+    }
 
-        return TRUE;
+    handle = WININET_AllocHandle( &lpwhr->hdr );
+    if (NULL == handle)
+    {
+        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+        goto lend;
     }
-    else if (dwModifier & COALESCEFLAGS)
+
+    if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE))
     {
-        LPWSTR lpsztmp;
-        WCHAR ch = 0;
-        INT len = 0;
-        INT origlen = strlenW(lphttpHdr->lpszValue);
-        INT valuelen = strlenW(value);
+        InternetCloseHandle( handle );
+        handle = NULL;
+        goto lend;
+    }
 
-        if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
-        {
-            ch = ',';
-            lphttpHdr->wFlags |= HDR_COMMADELIMITED;
-        }
-        else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
+    if (lpszObjectName && *lpszObjectName) {
+        HRESULT rc;
+
+        len = 0;
+        rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
+        if (rc != E_POINTER)
+            len = strlenW(lpszObjectName)+1;
+        lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
+        rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len,
+                   URL_ESCAPE_SPACES_ONLY);
+        if (rc != S_OK)
         {
-            ch = ';';
-            lphttpHdr->wFlags |= HDR_COMMADELIMITED;
+            ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
+            strcpyW(lpwhr->lpszPath,lpszObjectName);
         }
+    }else {
+        static const WCHAR slashW[] = {'/',0};
 
-        len = origlen + valuelen + ((ch > 0) ? 2 : 0);
+        lpwhr->lpszPath = WININET_strdupW(slashW);
+    }
 
-        lpsztmp = HeapReAlloc(GetProcessHeap(), 0, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
-        if (lpsztmp)
-        {
-            lphttpHdr->lpszValue = lpsztmp;
-    /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
-            if (ch > 0)
-            {
-                lphttpHdr->lpszValue[origlen] = ch;
-                origlen++;
-                lphttpHdr->lpszValue[origlen] = ' ';
-                origlen++;
-            }
+    if (lpszReferrer && *lpszReferrer)
+        HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
 
-            memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
-            lphttpHdr->lpszValue[len] = '\0';
-            bSuccess = TRUE;
-        }
-        else
+    if (lpszAcceptTypes)
+    {
+        int i;
+        for (i = 0; lpszAcceptTypes[i]; i++)
         {
-            WARN("HeapReAlloc (%d bytes) failed\n",len+1);
-            INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+            if (!*lpszAcceptTypes[i]) continue;
+            HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i],
+                               HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA |
+                               HTTP_ADDHDR_FLAG_REQ |
+                               (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0));
         }
     }
-    TRACE("<-- %d\n",bSuccess);
-    return bSuccess;
-}
-
 
-/***********************************************************************
- *           HTTP_FinishedReading (internal)
- *
- * Called when all content from server has been read by client.
- *
- */
-static BOOL HTTP_FinishedReading(LPWININETHTTPREQW lpwhr)
-{
-    WCHAR szVersion[10];
-    WCHAR szConnectionResponse[20];
-    DWORD dwBufferSize = sizeof(szVersion);
-    BOOL keepalive = FALSE;
+    lpwhr->lpszVerb = WININET_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
 
-    TRACE("\n");
+    if (lpszVersion)
+        lpwhr->lpszVersion = WININET_strdupW(lpszVersion);
+    else
+        lpwhr->lpszVersion = WININET_strdupW(g_szHttp1_1);
 
-    /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
-     * the connection is keep-alive by default */
-    if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion,
-                             &dwBufferSize, NULL) &&
-        !strcmpiW(szVersion, g_szHttp1_1))
+    if (lpwhs->nHostPort != INTERNET_INVALID_PORT_NUMBER &&
+        lpwhs->nHostPort != INTERNET_DEFAULT_HTTP_PORT &&
+        lpwhs->nHostPort != INTERNET_DEFAULT_HTTPS_PORT)
     {
-        keepalive = TRUE;
+        sprintfW(lpszHostName, szHostForm, lpwhs->lpszHostName, lpwhs->nHostPort);
+        HTTP_ProcessHeader(lpwhr, hostW, lpszHostName,
+                HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
     }
+    else
+        HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName,
+                HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
 
-    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 (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER)
+        lpwhs->nServerPort = (dwFlags & INTERNET_FLAG_SECURE ?
+                        INTERNET_DEFAULT_HTTPS_PORT :
+                        INTERNET_DEFAULT_HTTP_PORT);
 
-    if (!keepalive)
-    {
-        HTTPREQ_CloseConnection(&lpwhr->hdr);
-    }
+    if (lpwhs->nHostPort == INTERNET_INVALID_PORT_NUMBER)
+        lpwhs->nHostPort = (dwFlags & INTERNET_FLAG_SECURE ?
+                        INTERNET_DEFAULT_HTTPS_PORT :
+                        INTERNET_DEFAULT_HTTP_PORT);
 
-    /* FIXME: store data in the URL cache here */
+    if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
+        HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
 
-    return TRUE;
-}
+    INTERNET_SendCallback(&lpwhs->hdr, dwContext,
+                          INTERNET_STATUS_HANDLE_CREATED, &handle,
+                          sizeof(handle));
 
+lend:
+    HeapFree(GetProcessHeap(), 0, lpszHostName);
+    if( lpwhr )
+        WININET_Release( &lpwhr->hdr );
+
+    TRACE("<-- %p (%p)\n", handle, lpwhr);
+    return handle;
+}
 
 /***********************************************************************
- *           HTTP_GetCustomHeaderIndex (internal)
+ *           HttpOpenRequestW (WININET.@)
  *
- * Return index of custom header from header array
+ * Open a HTTP request handle
+ *
+ * RETURNS
+ *    HINTERNET  a HTTP request handle on success
+ *    NULL 	 on failure
  *
  */
-static INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField,
-                                     int requested_index, BOOL request_only)
+HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
+	LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
+	LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
+	DWORD dwFlags, DWORD_PTR dwContext)
 {
-    DWORD index;
-
-    TRACE("%s\n", debugstr_w(lpszField));
+    LPWININETHTTPSESSIONW lpwhs;
+    HINTERNET handle = NULL;
 
-    for (index = 0; index < lpwhr->nCustHeaders; index++)
+    TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
+          debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
+          debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
+          dwFlags, dwContext);
+    if(lpszAcceptTypes!=NULL)
     {
-        if (strcmpiW(lpwhr->pCustHeaders[index].lpszField, lpszField))
-            continue;
-
-        if (request_only && !(lpwhr->pCustHeaders[index].wFlags & HDR_ISREQUEST))
-            continue;
-
-        if (!request_only && (lpwhr->pCustHeaders[index].wFlags & HDR_ISREQUEST))
-            continue;
-
-        if (requested_index == 0)
-            break;
-        requested_index --;
+        int i;
+        for(i=0;lpszAcceptTypes[i]!=NULL;i++)
+            TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
     }
 
-    if (index >= lpwhr->nCustHeaders)
-	index = -1;
+    lpwhs = (LPWININETHTTPSESSIONW) WININET_GetObject( hHttpSession );
+    if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
+    {
+        INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
+	goto lend;
+    }
 
-    TRACE("Return: %d\n", index);
-    return index;
+    /*
+     * My tests seem to show that the windows version does not
+     * become asynchronous until after this point. And anyhow
+     * if this call was asynchronous then how would you get the
+     * necessary HINTERNET pointer returned by this function.
+     *
+     */
+    handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName,
+                                   lpszVersion, lpszReferrer, lpszAcceptTypes,
+                                   dwFlags, dwContext);
+lend:
+    if( lpwhs )
+        WININET_Release( &lpwhs->hdr );
+    TRACE("returning %p\n", handle);
+    return handle;
 }
 
 
 /***********************************************************************
- *           HTTP_InsertCustomHeader (internal)
+ *           HttpOpenRequestA (WININET.@)
  *
- * Insert header into array
+ * Open a HTTP request handle
+ *
+ * RETURNS
+ *    HINTERNET  a HTTP request handle on success
+ *    NULL 	 on failure
  *
  */
-static BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr)
+HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
+	LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
+	LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
+	DWORD dwFlags, DWORD_PTR dwContext)
 {
-    INT count;
-    LPHTTPHEADERW lph = NULL;
-    BOOL r = FALSE;
+    LPWSTR szVerb = NULL, szObjectName = NULL;
+    LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
+    INT len, acceptTypesCount;
+    HINTERNET rc = FALSE;
+    LPCSTR *types;
 
-    TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
-    count = lpwhr->nCustHeaders + 1;
-    if (count > 1)
-	lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERW) * count);
-    else
-	lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
+    TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
+          debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
+          debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
+          dwFlags, dwContext);
 
-    if (NULL != lph)
+    if (lpszVerb)
     {
-	lpwhr->pCustHeaders = lph;
-        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++;
-        r = TRUE;
+        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);
     }
-    else
+
+    if (lpszObjectName)
     {
-        INTERNET_SetLastError(ERROR_OUTOFMEMORY);
+        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 );
     }
 
-    return r;
-}
-
-
-/***********************************************************************
- *           HTTP_DeleteCustomHeader (internal)
- *
- * Delete header from array
- *  If this function is called, the indexs may change.
- */
-static BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, DWORD index)
-{
-    if( lpwhr->nCustHeaders <= 0 )
-        return FALSE;
-    if( index >= lpwhr->nCustHeaders )
-        return FALSE;
-    lpwhr->nCustHeaders--;
+    if (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 );
+    }
 
-    HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszField);
-    HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszValue);
+    if (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 );
+    }
 
-    memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
-             (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) );
-    memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) );
+    if (lpszAcceptTypes)
+    {
+        acceptTypesCount = 0;
+        types = lpszAcceptTypes;
+        while (*types)
+        {
+            __TRY
+            {
+                /* find out how many there are */
+                if (*types && **types)
+                {
+                    TRACE("accept type: %s\n", debugstr_a(*types));
+                    acceptTypesCount++;
+                }
+            }
+            __EXCEPT_PAGE_FAULT
+            {
+                WARN("invalid accept type pointer\n");
+            }
+            __ENDTRY;
+            types++;
+        }
+        szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
+        if (!szAcceptTypes) goto end;
 
-    return TRUE;
-}
+        acceptTypesCount = 0;
+        types = lpszAcceptTypes;
+        while (*types)
+        {
+            __TRY
+            {
+                if (*types && **types)
+                {
+                    len = MultiByteToWideChar(CP_ACP, 0, *types, -1, NULL, 0 );
+                    szAcceptTypes[acceptTypesCount] = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
 
+                    MultiByteToWideChar(CP_ACP, 0, *types, -1, szAcceptTypes[acceptTypesCount], len);
+                    acceptTypesCount++;
+                }
+            }
+            __EXCEPT_PAGE_FAULT
+            {
+                /* ignore invalid pointer */
+            }
+            __ENDTRY;
+            types++;
+        }
+        szAcceptTypes[acceptTypesCount] = NULL;
+    }
 
-/***********************************************************************
- *           HTTP_VerifyValidHeader (internal)
- *
- * Verify the given header is not invalid for the given http request
- *
- */
-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))
-        return FALSE;
+    rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
+                          szVersion, szReferrer,
+                          (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
 
-    return TRUE;
-}
+end:
+    if (szAcceptTypes)
+    {
+        acceptTypesCount = 0;
+        while (szAcceptTypes[acceptTypesCount])
+        {
+            HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
+            acceptTypesCount++;
+        }
+        HeapFree(GetProcessHeap(), 0, szAcceptTypes);
+    }
+    HeapFree(GetProcessHeap(), 0, szReferrer);
+    HeapFree(GetProcessHeap(), 0, szVersion);
+    HeapFree(GetProcessHeap(), 0, szObjectName);
+    HeapFree(GetProcessHeap(), 0, szVerb);
 
-/***********************************************************************
- *          IsHostInProxyBypassList (@)
- *
- * Undocumented
- *
- */
-BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
-{
-   FIXME("STUB: flags=%d host=%s length=%d\n",flags,szHost,length);
-   return FALSE;
+    return rc;
 }
diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h
index 1d49eaa..e944434 100644
--- a/dlls/wininet/internet.h
+++ b/dlls/wininet/internet.h
@@ -389,14 +389,6 @@ BOOL INTERNET_AsyncCall(LPWORKREQUEST lpWorkRequest);
 LPSTR INTERNET_GetResponseBuffer(void);
 LPSTR INTERNET_GetNextLine(INT nSocket, LPDWORD dwLen);
 
-BOOLAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders,
-	DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
-	DWORD dwContentLength, BOOL bEndRequest);
-INTERNETAPI HINTERNET WINAPI HTTP_HttpOpenRequestW(LPWININETHTTPSESSIONW lpwhs,
-	LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
-	LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
-	DWORD dwFlags, DWORD_PTR dwContext);
-
 VOID SendAsyncCallback(LPWININETHANDLEHEADER hdr, DWORD_PTR dwContext,
                        DWORD dwInternetStatus, LPVOID lpvStatusInfo,
                        DWORD dwStatusInfoLength);
-- 
1.6.3.1




More information about the wine-patches mailing list