~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/wininet/http.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * Wininet - Http Implementation
  3  *
  4  * Copyright 1999 Corel Corporation
  5  * Copyright 2002 CodeWeavers Inc.
  6  * Copyright 2002 TransGaming Technologies Inc.
  7  * Copyright 2004 Mike McCormack for CodeWeavers
  8  * Copyright 2005 Aric Stewart for CodeWeavers
  9  * Copyright 2006 Robert Shearman for CodeWeavers
 10  *
 11  * Ulrich Czekalla
 12  * David Hammerton
 13  *
 14  * This library is free software; you can redistribute it and/or
 15  * modify it under the terms of the GNU Lesser General Public
 16  * License as published by the Free Software Foundation; either
 17  * version 2.1 of the License, or (at your option) any later version.
 18  *
 19  * This library is distributed in the hope that it will be useful,
 20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 22  * Lesser General Public License for more details.
 23  *
 24  * You should have received a copy of the GNU Lesser General Public
 25  * License along with this library; if not, write to the Free Software
 26  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 27  */
 28 
 29 #include "config.h"
 30 #include "wine/port.h"
 31 
 32 #if defined(__MINGW32__) || defined (_MSC_VER)
 33 #include <ws2tcpip.h>
 34 #endif
 35 
 36 #include <sys/types.h>
 37 #ifdef HAVE_SYS_SOCKET_H
 38 # include <sys/socket.h>
 39 #endif
 40 #ifdef HAVE_ARPA_INET_H
 41 # include <arpa/inet.h>
 42 #endif
 43 #include <stdarg.h>
 44 #include <stdio.h>
 45 #include <stdlib.h>
 46 #ifdef HAVE_UNISTD_H
 47 # include <unistd.h>
 48 #endif
 49 #include <time.h>
 50 #include <assert.h>
 51 #ifdef HAVE_ZLIB
 52 #  include <zlib.h>
 53 #endif
 54 
 55 #include "windef.h"
 56 #include "winbase.h"
 57 #include "wininet.h"
 58 #include "winerror.h"
 59 #define NO_SHLWAPI_STREAM
 60 #define NO_SHLWAPI_REG
 61 #define NO_SHLWAPI_STRFCNS
 62 #define NO_SHLWAPI_GDI
 63 #include "shlwapi.h"
 64 #include "sspi.h"
 65 #include "wincrypt.h"
 66 
 67 #include "internet.h"
 68 #include "wine/debug.h"
 69 #include "wine/exception.h"
 70 #include "wine/unicode.h"
 71 
 72 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
 73 
 74 static const WCHAR g_szHttp1_0[] = {'H','T','T','P','/','1','.','',0};
 75 static const WCHAR g_szHttp1_1[] = {'H','T','T','P','/','1','.','1',0};
 76 static const WCHAR hostW[] = { 'H','o','s','t',0 };
 77 static const WCHAR szAuthorization[] = { 'A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
 78 static const WCHAR szProxy_Authorization[] = { 'P','r','o','x','y','-','A','u','t','h','o','r','i','z','a','t','i','o','n',0 };
 79 static const WCHAR szStatus[] = { 'S','t','a','t','u','s',0 };
 80 static const WCHAR szKeepAlive[] = {'K','e','e','p','-','A','l','i','v','e',0};
 81 static const WCHAR szGET[] = { 'G','E','T', 0 };
 82 static const WCHAR szHEAD[] = { 'H','E','A','D', 0 };
 83 static const WCHAR szCrLf[] = {'\r','\n', 0};
 84 
 85 static const WCHAR szAccept[] = { 'A','c','c','e','p','t',0 };
 86 static const WCHAR szAccept_Charset[] = { 'A','c','c','e','p','t','-','C','h','a','r','s','e','t', 0 };
 87 static const WCHAR szAccept_Encoding[] = { 'A','c','c','e','p','t','-','E','n','c','o','d','i','n','g',0 };
 88 static const WCHAR szAccept_Language[] = { 'A','c','c','e','p','t','-','L','a','n','g','u','a','g','e',0 };
 89 static const WCHAR szAccept_Ranges[] = { 'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
 90 static const WCHAR szAge[] = { 'A','g','e',0 };
 91 static const WCHAR szAllow[] = { 'A','l','l','o','w',0 };
 92 static const WCHAR szCache_Control[] = { 'C','a','c','h','e','-','C','o','n','t','r','o','l',0 };
 93 static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0 };
 94 static const WCHAR szContent_Base[] = { 'C','o','n','t','e','n','t','-','B','a','s','e',0 };
 95 static const WCHAR szContent_Encoding[] = { 'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0 };
 96 static const WCHAR szContent_ID[] = { 'C','o','n','t','e','n','t','-','I','D',0 };
 97 static const WCHAR szContent_Language[] = { 'C','o','n','t','e','n','t','-','L','a','n','g','u','a','g','e',0 };
 98 static const WCHAR szContent_Length[] = { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0 };
 99 static const WCHAR szContent_Location[] = { 'C','o','n','t','e','n','t','-','L','o','c','a','t','i','o','n',0 };
100 static const WCHAR szContent_MD5[] = { 'C','o','n','t','e','n','t','-','M','D','5',0 };
101 static const WCHAR szContent_Range[] = { 'C','o','n','t','e','n','t','-','R','a','n','g','e',0 };
102 static const WCHAR szContent_Transfer_Encoding[] = { 'C','o','n','t','e','n','t','-','T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
103 static const WCHAR szContent_Type[] = { 'C','o','n','t','e','n','t','-','T','y','p','e',0 };
104 static const WCHAR szCookie[] = { 'C','o','o','k','i','e',0 };
105 static const WCHAR szDate[] = { 'D','a','t','e',0 };
106 static const WCHAR szFrom[] = { 'F','r','o','m',0 };
107 static const WCHAR szETag[] = { 'E','T','a','g',0 };
108 static const WCHAR szExpect[] = { 'E','x','p','e','c','t',0 };
109 static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
110 static const WCHAR szIf_Match[] = { 'I','f','-','M','a','t','c','h',0 };
111 static const WCHAR szIf_Modified_Since[] = { 'I','f','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
112 static const WCHAR szIf_None_Match[] = { 'I','f','-','N','o','n','e','-','M','a','t','c','h',0 };
113 static const WCHAR szIf_Range[] = { 'I','f','-','R','a','n','g','e',0 };
114 static const WCHAR szIf_Unmodified_Since[] = { 'I','f','-','U','n','m','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
115 static const WCHAR szLast_Modified[] = { 'L','a','s','t','-','M','o','d','i','f','i','e','d',0 };
116 static const WCHAR szLocation[] = { 'L','o','c','a','t','i','o','n',0 };
117 static const WCHAR szMax_Forwards[] = { 'M','a','x','-','F','o','r','w','a','r','d','s',0 };
118 static const WCHAR szMime_Version[] = { 'M','i','m','e','-','V','e','r','s','i','o','n',0 };
119 static const WCHAR szPragma[] = { 'P','r','a','g','m','a',0 };
120 static const WCHAR szProxy_Authenticate[] = { 'P','r','o','x','y','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
121 static const WCHAR szProxy_Connection[] = { 'P','r','o','x','y','-','C','o','n','n','e','c','t','i','o','n',0 };
122 static const WCHAR szPublic[] = { 'P','u','b','l','i','c',0 };
123 static const WCHAR szRange[] = { 'R','a','n','g','e',0 };
124 static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0 };
125 static const WCHAR szRetry_After[] = { 'R','e','t','r','y','-','A','f','t','e','r',0 };
126 static const WCHAR szServer[] = { 'S','e','r','v','e','r',0 };
127 static const WCHAR szSet_Cookie[] = { 'S','e','t','-','C','o','o','k','i','e',0 };
128 static const WCHAR szTransfer_Encoding[] = { 'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0 };
129 static const WCHAR szUnless_Modified_Since[] = { 'U','n','l','e','s','s','-','M','o','d','i','f','i','e','d','-','S','i','n','c','e',0 };
130 static const WCHAR szUpgrade[] = { 'U','p','g','r','a','d','e',0 };
131 static const WCHAR szURI[] = { 'U','R','I',0 };
132 static const WCHAR szUser_Agent[] = { 'U','s','e','r','-','A','g','e','n','t',0 };
133 static const WCHAR szVary[] = { 'V','a','r','y',0 };
134 static const WCHAR szVia[] = { 'V','i','a',0 };
135 static const WCHAR szWarning[] = { 'W','a','r','n','i','n','g',0 };
136 static const WCHAR szWWW_Authenticate[] = { 'W','W','W','-','A','u','t','h','e','n','t','i','c','a','t','e',0 };
137 
138 #define MAXHOSTNAME 100
139 #define MAX_FIELD_VALUE_LEN 256
140 #define MAX_FIELD_LEN 256
141 
142 #define HTTP_REFERER    szReferer
143 #define HTTP_ACCEPT     szAccept
144 #define HTTP_USERAGENT  szUser_Agent
145 
146 #define HTTP_ADDHDR_FLAG_ADD                            0x20000000
147 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW                     0x10000000
148 #define HTTP_ADDHDR_FLAG_COALESCE                       0x40000000
149 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA            0x40000000
150 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON        0x01000000
151 #define HTTP_ADDHDR_FLAG_REPLACE                        0x80000000
152 #define HTTP_ADDHDR_FLAG_REQ                            0x02000000
153 
154 #define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
155 
156 struct HttpAuthInfo
157 {
158     LPWSTR scheme;
159     CredHandle cred;
160     CtxtHandle ctx;
161     TimeStamp exp;
162     ULONG attr;
163     ULONG max_token;
164     void *auth_data;
165     unsigned int auth_data_len;
166     BOOL finished; /* finished authenticating */
167 };
168 
169 
170 struct gzip_stream_t {
171 #ifdef HAVE_ZLIB
172     z_stream zstream;
173 #endif
174     BYTE buf[8192];
175     DWORD buf_size;
176     DWORD buf_pos;
177     BOOL end_of_data;
178 };
179 
180 static BOOL HTTP_OpenConnection(http_request_t *req);
181 static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear);
182 static BOOL HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
183 static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
184 static BOOL HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr);
185 static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request);
186 static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index);
187 static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
188 static BOOL HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD);
189 static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl);
190 static BOOL HTTP_HandleRedirect(http_request_t *req, LPCWSTR lpszUrl);
191 static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
192 static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field);
193 static void HTTP_DrainContent(http_request_t *req);
194 static BOOL HTTP_FinishedReading(http_request_t *req);
195 
196 static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head)
197 {
198     int HeaderIndex = 0;
199     HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
200     if (HeaderIndex == -1)
201         return NULL;
202     else
203         return &req->pCustHeaders[HeaderIndex];
204 }
205 
206 #ifdef HAVE_ZLIB
207 
208 static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size)
209 {
210     return HeapAlloc(GetProcessHeap(), 0, items*size);
211 }
212 
213 static void wininet_zfree(voidpf opaque, voidpf address)
214 {
215     HeapFree(GetProcessHeap(), 0, address);
216 }
217 
218 static void init_gzip_stream(http_request_t *req)
219 {
220     gzip_stream_t *gzip_stream;
221     int index, zres;
222 
223     gzip_stream = HeapAlloc(GetProcessHeap(), 0, sizeof(gzip_stream_t));
224     gzip_stream->zstream.zalloc = wininet_zalloc;
225     gzip_stream->zstream.zfree = wininet_zfree;
226     gzip_stream->zstream.opaque = NULL;
227     gzip_stream->zstream.next_in = NULL;
228     gzip_stream->zstream.avail_in = 0;
229     gzip_stream->zstream.next_out = NULL;
230     gzip_stream->zstream.avail_out = 0;
231     gzip_stream->buf_pos = 0;
232     gzip_stream->buf_size = 0;
233     gzip_stream->end_of_data = FALSE;
234 
235     zres = inflateInit2(&gzip_stream->zstream, 0x1f);
236     if(zres != Z_OK) {
237         ERR("inflateInit failed: %d\n", zres);
238         HeapFree(GetProcessHeap(), 0, gzip_stream);
239         return;
240     }
241 
242     req->gzip_stream = gzip_stream;
243 
244     index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE);
245     if(index != -1)
246         HTTP_DeleteCustomHeader(req, index);
247 }
248 
249 #else
250 
251 static void init_gzip_stream(http_request_t *req)
252 {
253     ERR("gzip stream not supported, missing zlib.\n");
254 }
255 
256 #endif
257 
258 /* set the request content length based on the headers */
259 static DWORD set_content_length( http_request_t *lpwhr )
260 {
261     static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
262     WCHAR encoding[20];
263     DWORD size;
264 
265     size = sizeof(lpwhr->dwContentLength);
266     if (!HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
267                              &lpwhr->dwContentLength, &size, NULL))
268         lpwhr->dwContentLength = ~0u;
269 
270     size = sizeof(encoding);
271     if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) &&
272         !strcmpiW(encoding, szChunked))
273     {
274         lpwhr->dwContentLength = ~0u;
275         lpwhr->read_chunked = TRUE;
276     }
277 
278     if(lpwhr->decoding) {
279         int encoding_idx;
280 
281         static const WCHAR gzipW[] = {'g','z','i','p',0};
282 
283         encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE);
284         if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW))
285             init_gzip_stream(lpwhr);
286     }
287 
288     return lpwhr->dwContentLength;
289 }
290 
291 /***********************************************************************
292  *           HTTP_Tokenize (internal)
293  *
294  *  Tokenize a string, allocating memory for the tokens.
295  */
296 static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string)
297 {
298     LPWSTR * token_array;
299     int tokens = 0;
300     int i;
301     LPCWSTR next_token;
302 
303     if (string)
304     {
305         /* empty string has no tokens */
306         if (*string)
307             tokens++;
308         /* count tokens */
309         for (i = 0; string[i]; i++)
310         {
311             if (!strncmpW(string+i, token_string, strlenW(token_string)))
312             {
313                 DWORD j;
314                 tokens++;
315                 /* we want to skip over separators, but not the null terminator */
316                 for (j = 0; j < strlenW(token_string) - 1; j++)
317                     if (!string[i+j])
318                         break;
319                 i += j;
320             }
321         }
322     }
323 
324     /* add 1 for terminating NULL */
325     token_array = HeapAlloc(GetProcessHeap(), 0, (tokens+1) * sizeof(*token_array));
326     token_array[tokens] = NULL;
327     if (!tokens)
328         return token_array;
329     for (i = 0; i < tokens; i++)
330     {
331         int len;
332         next_token = strstrW(string, token_string);
333         if (!next_token) next_token = string+strlenW(string);
334         len = next_token - string;
335         token_array[i] = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
336         memcpy(token_array[i], string, len*sizeof(WCHAR));
337         token_array[i][len] = '\0';
338         string = next_token+strlenW(token_string);
339     }
340     return token_array;
341 }
342 
343 /***********************************************************************
344  *           HTTP_FreeTokens (internal)
345  *
346  *  Frees memory returned from HTTP_Tokenize.
347  */
348 static void HTTP_FreeTokens(LPWSTR * token_array)
349 {
350     int i;
351     for (i = 0; token_array[i]; i++)
352         HeapFree(GetProcessHeap(), 0, token_array[i]);
353     HeapFree(GetProcessHeap(), 0, token_array);
354 }
355 
356 /* **********************************************************************
357  * 
358  * Helper functions for the HttpSendRequest(Ex) functions
359  * 
360  */
361 static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
362 {
363     struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
364     http_request_t *lpwhr = (http_request_t*) workRequest->hdr;
365 
366     TRACE("%p\n", lpwhr);
367 
368     HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
369             req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
370             req->dwContentLength, req->bEndRequest);
371 
372     HeapFree(GetProcessHeap(), 0, req->lpszHeader);
373 }
374 
375 static void HTTP_FixURL(http_request_t *lpwhr)
376 {
377     static const WCHAR szSlash[] = { '/',0 };
378     static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
379 
380     /* If we don't have a path we set it to root */
381     if (NULL == lpwhr->lpszPath)
382         lpwhr->lpszPath = heap_strdupW(szSlash);
383     else /* remove \r and \n*/
384     {
385         int nLen = strlenW(lpwhr->lpszPath);
386         while ((nLen >0 ) && ((lpwhr->lpszPath[nLen-1] == '\r')||(lpwhr->lpszPath[nLen-1] == '\n')))
387         {
388             nLen--;
389             lpwhr->lpszPath[nLen]='\0';
390         }
391         /* Replace '\' with '/' */
392         while (nLen>0) {
393             nLen--;
394             if (lpwhr->lpszPath[nLen] == '\\') lpwhr->lpszPath[nLen]='/';
395         }
396     }
397 
398     if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
399                        lpwhr->lpszPath, strlenW(lpwhr->lpszPath), szHttp, strlenW(szHttp) )
400        && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
401     {
402         WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0, 
403                              (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR));
404         *fixurl = '/';
405         strcpyW(fixurl + 1, lpwhr->lpszPath);
406         HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
407         lpwhr->lpszPath = fixurl;
408     }
409 }
410 
411 static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
412 {
413     LPWSTR requestString;
414     DWORD len, n;
415     LPCWSTR *req;
416     UINT i;
417     LPWSTR p;
418 
419     static const WCHAR szSpace[] = { ' ',0 };
420     static const WCHAR szColon[] = { ':',' ',0 };
421     static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
422 
423     /* allocate space for an array of all the string pointers to be added */
424     len = (lpwhr->nCustHeaders)*4 + 10;
425     req = HeapAlloc( GetProcessHeap(), 0, len*sizeof(LPCWSTR) );
426 
427     /* add the verb, path and HTTP version string */
428     n = 0;
429     req[n++] = verb;
430     req[n++] = szSpace;
431     req[n++] = path;
432     req[n++] = szSpace;
433     req[n++] = version;
434 
435     /* Append custom request headers */
436     for (i = 0; i < lpwhr->nCustHeaders; i++)
437     {
438         if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
439         {
440             req[n++] = szCrLf;
441             req[n++] = lpwhr->pCustHeaders[i].lpszField;
442             req[n++] = szColon;
443             req[n++] = lpwhr->pCustHeaders[i].lpszValue;
444 
445             TRACE("Adding custom header %s (%s)\n",
446                    debugstr_w(lpwhr->pCustHeaders[i].lpszField),
447                    debugstr_w(lpwhr->pCustHeaders[i].lpszValue));
448         }
449     }
450 
451     if( n >= len )
452         ERR("oops. buffer overrun\n");
453 
454     req[n] = NULL;
455     requestString = HTTP_build_req( req, 4 );
456     HeapFree( GetProcessHeap(), 0, req );
457 
458     /*
459      * Set (header) termination string for request
460      * Make sure there's exactly two new lines at the end of the request
461      */
462     p = &requestString[strlenW(requestString)-1];
463     while ( (*p == '\n') || (*p == '\r') )
464        p--;
465     strcpyW( p+1, sztwocrlf );
466     
467     return requestString;
468 }
469 
470 static void HTTP_ProcessCookies( http_request_t *lpwhr )
471 {
472     int HeaderIndex;
473     int numCookies = 0;
474     LPHTTPHEADERW setCookieHeader;
475 
476     while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1)
477     {
478         setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex];
479 
480         if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue)
481         {
482             int len;
483             static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0};
484             LPWSTR buf_url;
485             LPHTTPHEADERW Host;
486 
487             Host = HTTP_GetHeader(lpwhr, hostW);
488             len = lstrlenW(Host->lpszValue) + 9 + lstrlenW(lpwhr->lpszPath);
489             buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
490             sprintfW(buf_url, szFmt, Host->lpszValue, lpwhr->lpszPath);
491             InternetSetCookieW(buf_url, NULL, setCookieHeader->lpszValue);
492 
493             HeapFree(GetProcessHeap(), 0, buf_url);
494         }
495         numCookies++;
496     }
497 }
498 
499 static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue )
500 {
501     static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
502     return !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) &&
503         ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]);
504 }
505 
506 static void destroy_authinfo( struct HttpAuthInfo *authinfo )
507 {
508     if (!authinfo) return;
509 
510     if (SecIsValidHandle(&authinfo->ctx))
511         DeleteSecurityContext(&authinfo->ctx);
512     if (SecIsValidHandle(&authinfo->cred))
513         FreeCredentialsHandle(&authinfo->cred);
514 
515     HeapFree(GetProcessHeap(), 0, authinfo->auth_data);
516     HeapFree(GetProcessHeap(), 0, authinfo->scheme);
517     HeapFree(GetProcessHeap(), 0, authinfo);
518 }
519 
520 static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
521                                   struct HttpAuthInfo **ppAuthInfo,
522                                   LPWSTR domain_and_username, LPWSTR password )
523 {
524     SECURITY_STATUS sec_status;
525     struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
526     BOOL first = FALSE;
527 
528     TRACE("%s\n", debugstr_w(pszAuthValue));
529 
530     if (!pAuthInfo)
531     {
532         TimeStamp exp;
533 
534         first = TRUE;
535         pAuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*pAuthInfo));
536         if (!pAuthInfo)
537             return FALSE;
538 
539         SecInvalidateHandle(&pAuthInfo->cred);
540         SecInvalidateHandle(&pAuthInfo->ctx);
541         memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp));
542         pAuthInfo->attr = 0;
543         pAuthInfo->auth_data = NULL;
544         pAuthInfo->auth_data_len = 0;
545         pAuthInfo->finished = FALSE;
546 
547         if (is_basic_auth_value(pszAuthValue))
548         {
549             static const WCHAR szBasic[] = {'B','a','s','i','c',0};
550             pAuthInfo->scheme = heap_strdupW(szBasic);
551             if (!pAuthInfo->scheme)
552             {
553                 HeapFree(GetProcessHeap(), 0, pAuthInfo);
554                 return FALSE;
555             }
556         }
557         else
558         {
559             PVOID pAuthData;
560             SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
561 
562             pAuthInfo->scheme = heap_strdupW(pszAuthValue);
563             if (!pAuthInfo->scheme)
564             {
565                 HeapFree(GetProcessHeap(), 0, pAuthInfo);
566                 return FALSE;
567             }
568 
569             if (domain_and_username)
570             {
571                 WCHAR *user = strchrW(domain_and_username, '\\');
572                 WCHAR *domain = domain_and_username;
573 
574                 /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
575 
576                 pAuthData = &nt_auth_identity;
577 
578                 if (user) user++;
579                 else
580                 {
581                     user = domain_and_username;
582                     domain = NULL;
583                 }
584 
585                 nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
586                 nt_auth_identity.User = user;
587                 nt_auth_identity.UserLength = strlenW(nt_auth_identity.User);
588                 nt_auth_identity.Domain = domain;
589                 nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
590                 nt_auth_identity.Password = password;
591                 nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password);
592             }
593             else
594                 /* use default credentials */
595                 pAuthData = NULL;
596 
597             sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
598                                                    SECPKG_CRED_OUTBOUND, NULL,
599                                                    pAuthData, NULL,
600                                                    NULL, &pAuthInfo->cred,
601                                                    &exp);
602             if (sec_status == SEC_E_OK)
603             {
604                 PSecPkgInfoW sec_pkg_info;
605                 sec_status = QuerySecurityPackageInfoW(pAuthInfo->scheme, &sec_pkg_info);
606                 if (sec_status == SEC_E_OK)
607                 {
608                     pAuthInfo->max_token = sec_pkg_info->cbMaxToken;
609                     FreeContextBuffer(sec_pkg_info);
610                 }
611             }
612             if (sec_status != SEC_E_OK)
613             {
614                 WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
615                      debugstr_w(pAuthInfo->scheme), sec_status);
616                 HeapFree(GetProcessHeap(), 0, pAuthInfo->scheme);
617                 HeapFree(GetProcessHeap(), 0, pAuthInfo);
618                 return FALSE;
619             }
620         }
621         *ppAuthInfo = pAuthInfo;
622     }
623     else if (pAuthInfo->finished)
624         return FALSE;
625 
626     if ((strlenW(pszAuthValue) < strlenW(pAuthInfo->scheme)) ||
627         strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme)))
628     {
629         ERR("authentication scheme changed from %s to %s\n",
630             debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue));
631         return FALSE;
632     }
633 
634     if (is_basic_auth_value(pszAuthValue))
635     {
636         int userlen;
637         int passlen;
638         char *auth_data;
639 
640         TRACE("basic authentication\n");
641 
642         /* we don't cache credentials for basic authentication, so we can't
643          * retrieve them if the application didn't pass us any credentials */
644         if (!domain_and_username) return FALSE;
645 
646         userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
647         passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL);
648 
649         /* length includes a nul terminator, which will be re-used for the ':' */
650         auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen);
651         if (!auth_data)
652             return FALSE;
653 
654         WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL);
655         auth_data[userlen] = ':';
656         WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL);
657 
658         pAuthInfo->auth_data = auth_data;
659         pAuthInfo->auth_data_len = userlen + 1 + passlen;
660         pAuthInfo->finished = TRUE;
661 
662         return TRUE;
663     }
664     else
665     {
666         LPCWSTR pszAuthData;
667         SecBufferDesc out_desc, in_desc;
668         SecBuffer out, in;
669         unsigned char *buffer;
670         ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
671             ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
672 
673         in.BufferType = SECBUFFER_TOKEN;
674         in.cbBuffer = 0;
675         in.pvBuffer = NULL;
676 
677         in_desc.ulVersion = 0;
678         in_desc.cBuffers = 1;
679         in_desc.pBuffers = &in;
680 
681         pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme);
682         if (*pszAuthData == ' ')
683         {
684             pszAuthData++;
685             in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL);
686             in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer);
687             HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
688         }
689 
690         buffer = HeapAlloc(GetProcessHeap(), 0, pAuthInfo->max_token);
691 
692         out.BufferType = SECBUFFER_TOKEN;
693         out.cbBuffer = pAuthInfo->max_token;
694         out.pvBuffer = buffer;
695 
696         out_desc.ulVersion = 0;
697         out_desc.cBuffers = 1;
698         out_desc.pBuffers = &out;
699 
700         sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL,
701                                                 first ? NULL : &pAuthInfo->ctx,
702                                                 first ? lpwhr->lpHttpSession->lpszServerName : NULL,
703                                                 context_req, 0, SECURITY_NETWORK_DREP,
704                                                 in.pvBuffer ? &in_desc : NULL,
705                                                 0, &pAuthInfo->ctx, &out_desc,
706                                                 &pAuthInfo->attr, &pAuthInfo->exp);
707         if (sec_status == SEC_E_OK)
708         {
709             pAuthInfo->finished = TRUE;
710             pAuthInfo->auth_data = out.pvBuffer;
711             pAuthInfo->auth_data_len = out.cbBuffer;
712             TRACE("sending last auth packet\n");
713         }
714         else if (sec_status == SEC_I_CONTINUE_NEEDED)
715         {
716             pAuthInfo->auth_data = out.pvBuffer;
717             pAuthInfo->auth_data_len = out.cbBuffer;
718             TRACE("sending next auth packet\n");
719         }
720         else
721         {
722             ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
723             HeapFree(GetProcessHeap(), 0, out.pvBuffer);
724             destroy_authinfo(pAuthInfo);
725             *ppAuthInfo = NULL;
726             return FALSE;
727         }
728     }
729 
730     return TRUE;
731 }
732 
733 /***********************************************************************
734  *           HTTP_HttpAddRequestHeadersW (internal)
735  */
736 static BOOL HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
737         LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
738 {
739     LPWSTR lpszStart;
740     LPWSTR lpszEnd;
741     LPWSTR buffer;
742     BOOL bSuccess = FALSE;
743     DWORD len;
744 
745     TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength));
746 
747     if( dwHeaderLength == ~0U )
748         len = strlenW(lpszHeader);
749     else
750         len = dwHeaderLength;
751     buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR)*(len+1) );
752     lstrcpynW( buffer, lpszHeader, len + 1);
753 
754     lpszStart = buffer;
755 
756     do
757     {
758         LPWSTR * pFieldAndValue;
759 
760         lpszEnd = lpszStart;
761 
762         while (*lpszEnd != '\0')
763         {
764             if (*lpszEnd == '\r' || *lpszEnd == '\n')
765                  break;
766             lpszEnd++;
767         }
768 
769         if (*lpszStart == '\0')
770             break;
771 
772         if (*lpszEnd == '\r' || *lpszEnd == '\n')
773         {
774             *lpszEnd = '\0';
775             lpszEnd++; /* Jump over newline */
776         }
777         TRACE("interpreting header %s\n", debugstr_w(lpszStart));
778         if (*lpszStart == '\0')
779         {
780             /* Skip 0-length headers */
781             lpszStart = lpszEnd;
782             bSuccess = TRUE;
783             continue;
784         }
785         pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart);
786         if (pFieldAndValue)
787         {
788             bSuccess = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]);
789             if (bSuccess)
790                 bSuccess = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0],
791                     pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ);
792             HTTP_FreeTokens(pFieldAndValue);
793         }
794 
795         lpszStart = lpszEnd;
796     } while (bSuccess);
797 
798     HeapFree(GetProcessHeap(), 0, buffer);
799 
800     return bSuccess;
801 }
802 
803 /***********************************************************************
804  *           HttpAddRequestHeadersW (WININET.@)
805  *
806  * Adds one or more HTTP header to the request handler
807  *
808  * NOTE
809  * On Windows if dwHeaderLength includes the trailing '\0', then
810  * HttpAddRequestHeadersW() adds it too. However this results in an
811  * invalid Http header which is rejected by some servers so we probably
812  * don't need to match Windows on that point.
813  *
814  * RETURNS
815  *    TRUE  on success
816  *    FALSE on failure
817  *
818  */
819 BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
820         LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
821 {
822     BOOL bSuccess = FALSE;
823     http_request_t *lpwhr;
824 
825     TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
826 
827     if (!lpszHeader) 
828       return TRUE;
829 
830     lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
831     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
832     {
833         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
834         goto lend;
835     }
836     bSuccess = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier );
837 lend:
838     if( lpwhr )
839         WININET_Release( &lpwhr->hdr );
840 
841     return bSuccess;
842 }
843 
844 /***********************************************************************
845  *           HttpAddRequestHeadersA (WININET.@)
846  *
847  * Adds one or more HTTP header to the request handler
848  *
849  * RETURNS
850  *    TRUE  on success
851  *    FALSE on failure
852  *
853  */
854 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
855         LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
856 {
857     DWORD len;
858     LPWSTR hdr;
859     BOOL r;
860 
861     TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_an(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
862 
863     len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 );
864     hdr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
865     MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, hdr, len );
866     if( dwHeaderLength != ~0U )
867         dwHeaderLength = len;
868 
869     r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier );
870 
871     HeapFree( GetProcessHeap(), 0, hdr );
872 
873     return r;
874 }
875 
876 /***********************************************************************
877  *           HttpEndRequestA (WININET.@)
878  *
879  * Ends an HTTP request that was started by HttpSendRequestEx
880  *
881  * RETURNS
882  *    TRUE      if successful
883  *    FALSE     on failure
884  *
885  */
886 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, 
887         LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
888 {
889     TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
890 
891     if (lpBuffersOut)
892     {
893         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
894         return FALSE;
895     }
896 
897     return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
898 }
899 
900 static BOOL HTTP_HttpEndRequestW(http_request_t *lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
901 {
902     BOOL rc = FALSE;
903     INT responseLen;
904     DWORD dwBufferSize;
905     INTERNET_ASYNC_RESULT iar;
906 
907     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
908                   INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
909 
910     responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
911     if (responseLen)
912         rc = TRUE;
913 
914     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
915                   INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
916 
917     /* process cookies here. Is this right? */
918     HTTP_ProcessCookies(lpwhr);
919 
920     if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
921 
922     if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
923     {
924         DWORD dwCode,dwCodeLength = sizeof(DWORD);
925         if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) &&
926             (dwCode == 302 || dwCode == 301 || dwCode == 303))
927         {
928             WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
929             dwBufferSize=sizeof(szNewLocation);
930             if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL))
931             {
932                 if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD))
933                 {
934                     HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
935                     lpwhr->lpszVerb = heap_strdupW(szGET);
936                 }
937                 HTTP_DrainContent(lpwhr);
938                 if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation )))
939                 {
940                     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT,
941                                           new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
942                     rc = HTTP_HandleRedirect(lpwhr, new_url);
943                     if (rc)
944                         rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
945                     HeapFree( GetProcessHeap(), 0, new_url );
946                 }
947             }
948         }
949     }
950 
951     iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
952     iar.dwError = rc ? 0 : INTERNET_GetLastError();
953 
954     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
955                           INTERNET_STATUS_REQUEST_COMPLETE, &iar,
956                           sizeof(INTERNET_ASYNC_RESULT));
957     return rc;
958 }
959 
960 static void AsyncHttpEndRequestProc(WORKREQUEST *work)
961 {
962     struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
963     http_request_t *lpwhr = (http_request_t*)work->hdr;
964 
965     TRACE("%p\n", lpwhr);
966 
967     HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext);
968 }
969 
970 /***********************************************************************
971  *           HttpEndRequestW (WININET.@)
972  *
973  * Ends an HTTP request that was started by HttpSendRequestEx
974  *
975  * RETURNS
976  *    TRUE      if successful
977  *    FALSE     on failure
978  *
979  */
980 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, 
981         LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
982 {
983     BOOL rc = FALSE;
984     http_request_t *lpwhr;
985 
986     TRACE("-->\n");
987 
988     if (lpBuffersOut)
989     {
990         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
991         return FALSE;
992     }
993 
994     lpwhr = (http_request_t*) WININET_GetObject( hRequest );
995 
996     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
997     {
998         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
999         if (lpwhr)
1000             WININET_Release( &lpwhr->hdr );
1001         return FALSE;
1002     }
1003     lpwhr->hdr.dwFlags |= dwFlags;
1004 
1005     if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1006     {
1007         WORKREQUEST work;
1008         struct WORKREQ_HTTPENDREQUESTW *request;
1009 
1010         work.asyncproc = AsyncHttpEndRequestProc;
1011         work.hdr = WININET_AddRef( &lpwhr->hdr );
1012 
1013         request = &work.u.HttpEndRequestW;
1014         request->dwFlags = dwFlags;
1015         request->dwContext = dwContext;
1016 
1017         INTERNET_AsyncCall(&work);
1018         INTERNET_SetLastError(ERROR_IO_PENDING);
1019     }
1020     else
1021         rc = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
1022 
1023     WININET_Release( &lpwhr->hdr );
1024     TRACE("%i <--\n",rc);
1025     return rc;
1026 }
1027 
1028 /***********************************************************************
1029  *           HttpOpenRequestW (WININET.@)
1030  *
1031  * Open a HTTP request handle
1032  *
1033  * RETURNS
1034  *    HINTERNET  a HTTP request handle on success
1035  *    NULL       on failure
1036  *
1037  */
1038 HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
1039         LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
1040         LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
1041         DWORD dwFlags, DWORD_PTR dwContext)
1042 {
1043     http_session_t *lpwhs;
1044     HINTERNET handle = NULL;
1045 
1046     TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
1047           debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
1048           debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
1049           dwFlags, dwContext);
1050     if(lpszAcceptTypes!=NULL)
1051     {
1052         int i;
1053         for(i=0;lpszAcceptTypes[i]!=NULL;i++)
1054             TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
1055     }    
1056 
1057     lpwhs = (http_session_t*) WININET_GetObject( hHttpSession );
1058     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
1059     {
1060         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1061         goto lend;
1062     }
1063 
1064     /*
1065      * My tests seem to show that the windows version does not
1066      * become asynchronous until after this point. And anyhow
1067      * if this call was asynchronous then how would you get the
1068      * necessary HINTERNET pointer returned by this function.
1069      *
1070      */
1071     handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName,
1072                                    lpszVersion, lpszReferrer, lpszAcceptTypes,
1073                                    dwFlags, dwContext);
1074 lend:
1075     if( lpwhs )
1076         WININET_Release( &lpwhs->hdr );
1077     TRACE("returning %p\n", handle);
1078     return handle;
1079 }
1080 
1081 
1082 /***********************************************************************
1083  *           HttpOpenRequestA (WININET.@)
1084  *
1085  * Open a HTTP request handle
1086  *
1087  * RETURNS
1088  *    HINTERNET  a HTTP request handle on success
1089  *    NULL       on failure
1090  *
1091  */
1092 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
1093         LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
1094         LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
1095         DWORD dwFlags, DWORD_PTR dwContext)
1096 {
1097     LPWSTR szVerb = NULL, szObjectName = NULL;
1098     LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
1099     INT acceptTypesCount;
1100     HINTERNET rc = FALSE;
1101     LPCSTR *types;
1102 
1103     TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
1104           debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
1105           debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
1106           dwFlags, dwContext);
1107 
1108     if (lpszVerb)
1109     {
1110         szVerb = heap_strdupAtoW(lpszVerb);
1111         if ( !szVerb )
1112             goto end;
1113     }
1114 
1115     if (lpszObjectName)
1116     {
1117         szObjectName = heap_strdupAtoW(lpszObjectName);
1118         if ( !szObjectName )
1119             goto end;
1120     }
1121 
1122     if (lpszVersion)
1123     {
1124         szVersion = heap_strdupAtoW(lpszVersion);
1125         if ( !szVersion )
1126             goto end;
1127     }
1128 
1129     if (lpszReferrer)
1130     {
1131         szReferrer = heap_strdupAtoW(lpszReferrer);
1132         if ( !szReferrer )
1133             goto end;
1134     }
1135 
1136     if (lpszAcceptTypes)
1137     {
1138         acceptTypesCount = 0;
1139         types = lpszAcceptTypes;
1140         while (*types)
1141         {
1142             __TRY
1143             {
1144                 /* find out how many there are */
1145                 if (*types && **types)
1146                 {
1147                     TRACE("accept type: %s\n", debugstr_a(*types));
1148                     acceptTypesCount++;
1149                 }
1150             }
1151             __EXCEPT_PAGE_FAULT
1152             {
1153                 WARN("invalid accept type pointer\n");
1154             }
1155             __ENDTRY;
1156             types++;
1157         }
1158         szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
1159         if (!szAcceptTypes) goto end;
1160 
1161         acceptTypesCount = 0;
1162         types = lpszAcceptTypes;
1163         while (*types)
1164         {
1165             __TRY
1166             {
1167                 if (*types && **types)
1168                     szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types);
1169             }
1170             __EXCEPT_PAGE_FAULT
1171             {
1172                 /* ignore invalid pointer */
1173             }
1174             __ENDTRY;
1175             types++;
1176         }
1177         szAcceptTypes[acceptTypesCount] = NULL;
1178     }
1179 
1180     rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
1181                           szVersion, szReferrer,
1182                           (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
1183 
1184 end:
1185     if (szAcceptTypes)
1186     {
1187         acceptTypesCount = 0;
1188         while (szAcceptTypes[acceptTypesCount])
1189         {
1190             HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
1191             acceptTypesCount++;
1192         }
1193         HeapFree(GetProcessHeap(), 0, szAcceptTypes);
1194     }
1195     HeapFree(GetProcessHeap(), 0, szReferrer);
1196     HeapFree(GetProcessHeap(), 0, szVersion);
1197     HeapFree(GetProcessHeap(), 0, szObjectName);
1198     HeapFree(GetProcessHeap(), 0, szVerb);
1199 
1200     return rc;
1201 }
1202 
1203 /***********************************************************************
1204  *  HTTP_EncodeBase64
1205  */
1206 static UINT HTTP_EncodeBase64( LPCSTR bin, unsigned int len, LPWSTR base64 )
1207 {
1208     UINT n = 0, x;
1209     static const CHAR HTTP_Base64Enc[] =
1210         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1211 
1212     while( len > 0 )
1213     {
1214         /* first 6 bits, all from bin[0] */
1215         base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2];
1216         x = (bin[0] & 3) << 4;
1217 
1218         /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
1219         if( len == 1 )
1220         {
1221             base64[n++] = HTTP_Base64Enc[x];
1222             base64[n++] = '=';
1223             base64[n++] = '=';
1224             break;
1225         }
1226         base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ];
1227         x = ( bin[1] & 0x0f ) << 2;
1228 
1229         /* next 6 bits 4 from bin[1] and 2 from bin[2] */
1230         if( len == 2 )
1231         {
1232             base64[n++] = HTTP_Base64Enc[x];
1233             base64[n++] = '=';
1234             break;
1235         }
1236         base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ];
1237 
1238         /* last 6 bits, all from bin [2] */
1239         base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ];
1240         bin += 3;
1241         len -= 3;
1242     }
1243     base64[n] = 0;
1244     return n;
1245 }
1246 
1247 #define CH(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' : \
1248                ((x) >= 'a' && (x) <= 'z') ? (x) - 'a' + 26 : \
1249                ((x) >= '' && (x) <= '9') ? (x) - '' + 52 : \
1250                ((x) == '+') ? 62 : ((x) == '/') ? 63 : -1)
1251 static const signed char HTTP_Base64Dec[256] =
1252 {
1253     CH( 0),CH( 1),CH( 2),CH( 3),CH( 4),CH( 5),CH( 6),CH( 7),CH( 8),CH( 9),
1254     CH(10),CH(11),CH(12),CH(13),CH(14),CH(15),CH(16),CH(17),CH(18),CH(19),
1255     CH(20),CH(21),CH(22),CH(23),CH(24),CH(25),CH(26),CH(27),CH(28),CH(29),
1256     CH(30),CH(31),CH(32),CH(33),CH(34),CH(35),CH(36),CH(37),CH(38),CH(39),
1257     CH(40),CH(41),CH(42),CH(43),CH(44),CH(45),CH(46),CH(47),CH(48),CH(49),
1258     CH(50),CH(51),CH(52),CH(53),CH(54),CH(55),CH(56),CH(57),CH(58),CH(59),
1259     CH(60),CH(61),CH(62),CH(63),CH(64),CH(65),CH(66),CH(67),CH(68),CH(69),
1260     CH(70),CH(71),CH(72),CH(73),CH(74),CH(75),CH(76),CH(77),CH(78),CH(79),
1261     CH(80),CH(81),CH(82),CH(83),CH(84),CH(85),CH(86),CH(87),CH(88),CH(89),
1262     CH(90),CH(91),CH(92),CH(93),CH(94),CH(95),CH(96),CH(97),CH(98),CH(99),
1263     CH(100),CH(101),CH(102),CH(103),CH(104),CH(105),CH(106),CH(107),CH(108),CH(109),
1264     CH(110),CH(111),CH(112),CH(113),CH(114),CH(115),CH(116),CH(117),CH(118),CH(119),
1265     CH(120),CH(121),CH(122),CH(123),CH(124),CH(125),CH(126),CH(127),CH(128),CH(129),
1266     CH(130),CH(131),CH(132),CH(133),CH(134),CH(135),CH(136),CH(137),CH(138),CH(139),
1267     CH(140),CH(141),CH(142),CH(143),CH(144),CH(145),CH(146),CH(147),CH(148),CH(149),
1268     CH(150),CH(151),CH(152),CH(153),CH(154),CH(155),CH(156),CH(157),CH(158),CH(159),
1269     CH(160),CH(161),CH(162),CH(163),CH(164),CH(165),CH(166),CH(167),CH(168),CH(169),
1270     CH(170),CH(171),CH(172),CH(173),CH(174),CH(175),CH(176),CH(177),CH(178),CH(179),
1271     CH(180),CH(181),CH(182),CH(183),CH(184),CH(185),CH(186),CH(187),CH(188),CH(189),
1272     CH(190),CH(191),CH(192),CH(193),CH(194),CH(195),CH(196),CH(197),CH(198),CH(199),
1273     CH(200),CH(201),CH(202),CH(203),CH(204),CH(205),CH(206),CH(207),CH(208),CH(209),
1274     CH(210),CH(211),CH(212),CH(213),CH(214),CH(215),CH(216),CH(217),CH(218),CH(219),
1275     CH(220),CH(221),CH(222),CH(223),CH(224),CH(225),CH(226),CH(227),CH(228),CH(229),
1276     CH(230),CH(231),CH(232),CH(233),CH(234),CH(235),CH(236),CH(237),CH(238),CH(239),
1277     CH(240),CH(241),CH(242),CH(243),CH(244),CH(245),CH(246),CH(247),CH(248), CH(249),
1278     CH(250),CH(251),CH(252),CH(253),CH(254),CH(255),
1279 };
1280 #undef CH
1281 
1282 /***********************************************************************
1283  *  HTTP_DecodeBase64
1284  */
1285 static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin )
1286 {
1287     unsigned int n = 0;
1288 
1289     while(*base64)
1290     {
1291         signed char in[4];
1292 
1293         if (base64[0] >= ARRAYSIZE(HTTP_Base64Dec) ||
1294             ((in[0] = HTTP_Base64Dec[base64[0]]) == -1) ||
1295             base64[1] >= ARRAYSIZE(HTTP_Base64Dec) ||
1296             ((in[1] = HTTP_Base64Dec[base64[1]]) == -1))
1297         {
1298             WARN("invalid base64: %s\n", debugstr_w(base64));
1299             return 0;
1300         }
1301         if (bin)
1302             bin[n] = (unsigned char) (in[0] << 2 | in[1] >> 4);
1303         n++;
1304 
1305         if ((base64[2] == '=') && (base64[3] == '='))
1306             break;
1307         if (base64[2] > ARRAYSIZE(HTTP_Base64Dec) ||
1308             ((in[2] = HTTP_Base64Dec[base64[2]]) == -1))
1309         {
1310             WARN("invalid base64: %s\n", debugstr_w(&base64[2]));
1311             return 0;
1312         }
1313         if (bin)
1314             bin[n] = (unsigned char) (in[1] << 4 | in[2] >> 2);
1315         n++;
1316 
1317         if (base64[3] == '=')
1318             break;
1319         if (base64[3] > ARRAYSIZE(HTTP_Base64Dec) ||
1320             ((in[3] = HTTP_Base64Dec[base64[3]]) == -1))
1321         {
1322             WARN("invalid base64: %s\n", debugstr_w(&base64[3]));
1323             return 0;
1324         }
1325         if (bin)
1326             bin[n] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]);
1327         n++;
1328 
1329         base64 += 4;
1330     }
1331 
1332     return n;
1333 }
1334 
1335 /***********************************************************************
1336  *  HTTP_InsertAuthorization
1337  *
1338  *   Insert or delete the authorization field in the request header.
1339  */
1340 static BOOL HTTP_InsertAuthorization( http_request_t *lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
1341 {
1342     if (pAuthInfo)
1343     {
1344         static const WCHAR wszSpace[] = {' ',0};
1345         static const WCHAR wszBasic[] = {'B','a','s','i','c',0};
1346         unsigned int len;
1347         WCHAR *authorization = NULL;
1348 
1349         if (pAuthInfo->auth_data_len)
1350         {
1351             /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
1352             len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3;
1353             authorization = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
1354             if (!authorization)
1355                 return FALSE;
1356 
1357             strcpyW(authorization, pAuthInfo->scheme);
1358             strcatW(authorization, wszSpace);
1359             HTTP_EncodeBase64(pAuthInfo->auth_data,
1360                               pAuthInfo->auth_data_len,
1361                               authorization+strlenW(authorization));
1362 
1363             /* clear the data as it isn't valid now that it has been sent to the
1364              * server, unless it's Basic authentication which doesn't do
1365              * connection tracking */
1366             if (strcmpiW(pAuthInfo->scheme, wszBasic))
1367             {
1368                 HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data);
1369                 pAuthInfo->auth_data = NULL;
1370                 pAuthInfo->auth_data_len = 0;
1371             }
1372         }
1373 
1374         TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
1375 
1376         HTTP_ProcessHeader(lpwhr, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
1377 
1378         HeapFree(GetProcessHeap(), 0, authorization);
1379     }
1380     return TRUE;
1381 }
1382 
1383 static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
1384 {
1385     WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
1386     DWORD size;
1387 
1388     size = sizeof(new_location);
1389     if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL))
1390     {
1391         if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL;
1392         strcpyW( url, new_location );
1393     }
1394     else
1395     {
1396         static const WCHAR slash[] = { '/',0 };
1397         static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
1398         static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','d',0 };
1399         http_session_t *session = req->lpHttpSession;
1400 
1401         size = 16; /* "https://" + sizeof(port#) + ":/\0" */
1402         size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath );
1403 
1404         if (!(url = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL;
1405 
1406         if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
1407             sprintfW( url, formatSSL, session->lpszHostName, session->nHostPort );
1408         else
1409             sprintfW( url, format, session->lpszHostName, session->nHostPort );
1410         if (req->lpszPath[0] != '/') strcatW( url, slash );
1411         strcatW( url, req->lpszPath );
1412     }
1413     TRACE("url=%s\n", debugstr_w(url));
1414     return url;
1415 }
1416 
1417 /***********************************************************************
1418  *           HTTP_DealWithProxy
1419  */
1420 static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_request_t *lpwhr)
1421 {
1422     WCHAR buf[MAXHOSTNAME];
1423     WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
1424     static WCHAR szNul[] = { 0 };
1425     URL_COMPONENTSW UrlComponents;
1426     static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
1427     static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
1428 
1429     memset( &UrlComponents, 0, sizeof UrlComponents );
1430     UrlComponents.dwStructSize = sizeof UrlComponents;
1431     UrlComponents.lpszHostName = buf;
1432     UrlComponents.dwHostNameLength = MAXHOSTNAME;
1433 
1434     if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
1435                                  hIC->lpszProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
1436         sprintfW(proxy, szFormat, hIC->lpszProxy);
1437     else
1438         strcpyW(proxy, hIC->lpszProxy);
1439     if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
1440         return FALSE;
1441     if( UrlComponents.dwHostNameLength == 0 )
1442         return FALSE;
1443 
1444     if( !lpwhr->lpszPath )
1445         lpwhr->lpszPath = szNul;
1446 
1447     if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1448         UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1449 
1450     HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1451     lpwhs->lpszServerName = heap_strdupW(UrlComponents.lpszHostName);
1452     lpwhs->nServerPort = UrlComponents.nPort;
1453 
1454     TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort);
1455     return TRUE;
1456 }
1457 
1458 #ifndef INET6_ADDRSTRLEN
1459 #define INET6_ADDRSTRLEN 46
1460 #endif
1461 
1462 static BOOL HTTP_ResolveName(http_request_t *lpwhr)
1463 {
1464     char szaddr[INET6_ADDRSTRLEN];
1465     http_session_t *lpwhs = lpwhr->lpHttpSession;
1466     const void *addr;
1467 
1468     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1469                           INTERNET_STATUS_RESOLVING_NAME,
1470                           lpwhs->lpszServerName,
1471                           strlenW(lpwhs->lpszServerName)+1);
1472 
1473     lpwhs->sa_len = sizeof(lpwhs->socketAddress);
1474     if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
1475                     (struct sockaddr *)&lpwhs->socketAddress, &lpwhs->sa_len))
1476     {
1477         INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1478         return FALSE;
1479     }
1480 
1481     switch (lpwhs->socketAddress.ss_family)
1482     {
1483     case AF_INET:
1484         addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr;
1485         break;
1486     case AF_INET6:
1487         addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr;
1488         break;
1489     default:
1490         WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family);
1491         INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1492         return FALSE;
1493     }
1494     inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr));
1495     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1496                           INTERNET_STATUS_NAME_RESOLVED,
1497                           szaddr, strlen(szaddr)+1);
1498 
1499     TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr);
1500     return TRUE;
1501 }
1502 
1503 
1504 /***********************************************************************
1505  *           HTTPREQ_Destroy (internal)
1506  *
1507  * Deallocate request handle
1508  *
1509  */
1510 static void HTTPREQ_Destroy(object_header_t *hdr)
1511 {
1512     http_request_t *lpwhr = (http_request_t*) hdr;
1513     DWORD i;
1514 
1515     TRACE("\n");
1516 
1517     if(lpwhr->hCacheFile)
1518         CloseHandle(lpwhr->hCacheFile);
1519 
1520     HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile);
1521 
1522     DeleteCriticalSection( &lpwhr->read_section );
1523     WININET_Release(&lpwhr->lpHttpSession->hdr);
1524 
1525     destroy_authinfo(lpwhr->pAuthInfo);
1526     destroy_authinfo(lpwhr->pProxyAuthInfo);
1527 
1528     HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1529     HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1530     HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
1531     HeapFree(GetProcessHeap(), 0, lpwhr->lpszVersion);
1532     HeapFree(GetProcessHeap(), 0, lpwhr->lpszStatusText);
1533 
1534     for (i = 0; i < lpwhr->nCustHeaders; i++)
1535     {
1536         HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
1537         HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
1538     }
1539 
1540 #ifdef HAVE_ZLIB
1541     if(lpwhr->gzip_stream) {
1542         if(!lpwhr->gzip_stream->end_of_data)
1543             inflateEnd(&lpwhr->gzip_stream->zstream);
1544         HeapFree(GetProcessHeap(), 0, lpwhr->gzip_stream);
1545     }
1546 #endif
1547 
1548     HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1549     HeapFree(GetProcessHeap(), 0, lpwhr);
1550 }
1551 
1552 static void HTTPREQ_CloseConnection(object_header_t *hdr)
1553 {
1554     http_request_t *lpwhr = (http_request_t*) hdr;
1555 
1556     TRACE("%p\n",lpwhr);
1557 
1558     if (!NETCON_connected(&lpwhr->netConnection))
1559         return;
1560 
1561     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1562                           INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
1563 
1564     NETCON_close(&lpwhr->netConnection);
1565 
1566     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1567                           INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
1568 }
1569 
1570 static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
1571 {
1572     LPHTTPHEADERW host_header;
1573 
1574     static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1575 
1576     host_header = HTTP_GetHeader(req, hostW);
1577     if(!host_header)
1578         return FALSE;
1579 
1580     sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */
1581     return TRUE;
1582 }
1583 
1584 static BOOL HTTP_KeepAlive(http_request_t *lpwhr)
1585 {
1586     WCHAR szVersion[10];
1587     WCHAR szConnectionResponse[20];
1588     DWORD dwBufferSize = sizeof(szVersion);
1589     BOOL keepalive = FALSE;
1590 
1591     /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
1592      * the connection is keep-alive by default */
1593     if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion,
1594                              &dwBufferSize, NULL) &&
1595         !strcmpiW(szVersion, g_szHttp1_1))
1596     {
1597         keepalive = TRUE;
1598     }
1599 
1600     dwBufferSize = sizeof(szConnectionResponse);
1601     if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) ||
1602         HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL))
1603     {
1604         keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
1605     }
1606 
1607     return keepalive;
1608 }
1609 
1610 static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
1611 {
1612     http_request_t *req = (http_request_t*)hdr;
1613 
1614     switch(option) {
1615     case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO:
1616     {
1617         http_session_t *lpwhs = req->lpHttpSession;
1618         INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer;
1619 
1620         FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n");
1621 
1622         if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO))
1623             return ERROR_INSUFFICIENT_BUFFER;
1624         *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO);
1625         /* FIXME: can't get a SOCKET from our connection since we don't use
1626          * winsock
1627          */
1628         info->Socket = 0;
1629         /* FIXME: get source port from req->netConnection */
1630         info->SourcePort = 0;
1631         info->DestPort = lpwhs->nHostPort;
1632         info->Flags = 0;
1633         if (HTTP_KeepAlive(req))
1634             info->Flags |= IDSI_FLAG_KEEP_ALIVE;
1635         if (lpwhs->lpAppInfo->lpszProxy && lpwhs->lpAppInfo->lpszProxy[0] != 0)
1636             info->Flags |= IDSI_FLAG_PROXY;
1637         if (req->netConnection.useSSL)
1638             info->Flags |= IDSI_FLAG_SECURE;
1639 
1640         return ERROR_SUCCESS;
1641     }
1642 
1643     case INTERNET_OPTION_SECURITY_FLAGS:
1644     {
1645         http_session_t *lpwhs;
1646         lpwhs = req->lpHttpSession;
1647 
1648         if (*size < sizeof(ULONG))
1649             return ERROR_INSUFFICIENT_BUFFER;
1650 
1651         *size = sizeof(DWORD);
1652         if (lpwhs->hdr.dwFlags & INTERNET_FLAG_SECURE)
1653             *(DWORD*)buffer = SECURITY_FLAG_SECURE;
1654         else
1655             *(DWORD*)buffer = 0;
1656         FIXME("Semi-STUB INTERNET_OPTION_SECURITY_FLAGS: %x\n",*(DWORD*)buffer);
1657         return ERROR_SUCCESS;
1658     }
1659 
1660     case INTERNET_OPTION_HANDLE_TYPE:
1661         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
1662 
1663         if (*size < sizeof(ULONG))
1664             return ERROR_INSUFFICIENT_BUFFER;
1665 
1666         *size = sizeof(DWORD);
1667         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_HTTP_REQUEST;
1668         return ERROR_SUCCESS;
1669 
1670     case INTERNET_OPTION_URL: {
1671         WCHAR url[INTERNET_MAX_URL_LENGTH];
1672         HTTPHEADERW *host;
1673         DWORD len;
1674         WCHAR *pch;
1675 
1676         static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
1677 
1678         TRACE("INTERNET_OPTION_URL\n");
1679 
1680         host = HTTP_GetHeader(req, hostW);
1681         strcpyW(url, httpW);
1682         strcatW(url, host->lpszValue);
1683         if (NULL != (pch = strchrW(url + strlenW(httpW), ':')))
1684             *pch = 0;
1685         strcatW(url, req->lpszPath);
1686 
1687         TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
1688 
1689         if(unicode) {
1690             len = (strlenW(url)+1) * sizeof(WCHAR);
1691             if(*size < len)
1692                 return ERROR_INSUFFICIENT_BUFFER;
1693 
1694             *size = len;
1695             strcpyW(buffer, url);
1696             return ERROR_SUCCESS;
1697         }else {
1698             len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL);
1699             if(len > *size)
1700                 return ERROR_INSUFFICIENT_BUFFER;
1701 
1702             *size = len;
1703             return ERROR_SUCCESS;
1704         }
1705     }
1706 
1707     case INTERNET_OPTION_CACHE_TIMESTAMPS: {
1708         INTERNET_CACHE_ENTRY_INFOW *info;
1709         INTERNET_CACHE_TIMESTAMPS *ts = buffer;
1710         WCHAR url[INTERNET_MAX_URL_LENGTH];
1711         DWORD nbytes, error;
1712         BOOL ret;
1713 
1714         TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
1715 
1716         if (*size < sizeof(*ts))
1717         {
1718             *size = sizeof(*ts);
1719             return ERROR_INSUFFICIENT_BUFFER;
1720         }
1721         nbytes = 0;
1722         HTTP_GetRequestURL(req, url);
1723         ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes);
1724         error = GetLastError();
1725         if (!ret && error == ERROR_INSUFFICIENT_BUFFER)
1726         {
1727             if (!(info = HeapAlloc(GetProcessHeap(), 0, nbytes)))
1728                 return ERROR_OUTOFMEMORY;
1729 
1730             GetUrlCacheEntryInfoW(url, info, &nbytes);
1731 
1732             ts->ftExpires = info->ExpireTime;
1733             ts->ftLastModified = info->LastModifiedTime;
1734 
1735             HeapFree(GetProcessHeap(), 0, info);
1736             *size = sizeof(*ts);
1737             return ERROR_SUCCESS;
1738         }
1739         return error;
1740     }
1741 
1742     case INTERNET_OPTION_DATAFILE_NAME: {
1743         DWORD req_size;
1744 
1745         TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
1746 
1747         if(!req->lpszCacheFile) {
1748             *size = 0;
1749             return ERROR_INTERNET_ITEM_NOT_FOUND;
1750         }
1751 
1752         if(unicode) {
1753             req_size = (lstrlenW(req->lpszCacheFile)+1) * sizeof(WCHAR);
1754             if(*size < req_size)
1755                 return ERROR_INSUFFICIENT_BUFFER;
1756 
1757             *size = req_size;
1758             memcpy(buffer, req->lpszCacheFile, *size);
1759             return ERROR_SUCCESS;
1760         }else {
1761             req_size = WideCharToMultiByte(CP_ACP, 0, req->lpszCacheFile, -1, NULL, 0, NULL, NULL);
1762             if (req_size > *size)
1763                 return ERROR_INSUFFICIENT_BUFFER;
1764 
1765             *size = WideCharToMultiByte(CP_ACP, 0, req->lpszCacheFile,
1766                     -1, buffer, *size, NULL, NULL);
1767             return ERROR_SUCCESS;
1768         }
1769     }
1770 
1771     case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: {
1772         PCCERT_CONTEXT context;
1773 
1774         if(*size < sizeof(INTERNET_CERTIFICATE_INFOW)) {
1775             *size = sizeof(INTERNET_CERTIFICATE_INFOW);
1776             return ERROR_INSUFFICIENT_BUFFER;
1777         }
1778 
1779         context = (PCCERT_CONTEXT)NETCON_GetCert(&(req->netConnection));
1780         if(context) {
1781             INTERNET_CERTIFICATE_INFOW *info = (INTERNET_CERTIFICATE_INFOW*)buffer;
1782             DWORD len;
1783 
1784             memset(info, 0, sizeof(INTERNET_CERTIFICATE_INFOW));
1785             info->ftExpiry = context->pCertInfo->NotAfter;
1786             info->ftStart = context->pCertInfo->NotBefore;
1787             if(unicode) {
1788                 len = CertNameToStrW(context->dwCertEncodingType,
1789                         &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
1790                 info->lpszSubjectInfo = LocalAlloc(0, len*sizeof(WCHAR));
1791                 if(info->lpszSubjectInfo)
1792                     CertNameToStrW(context->dwCertEncodingType,
1793                              &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
1794                              info->lpszSubjectInfo, len);
1795                 len = CertNameToStrW(context->dwCertEncodingType,
1796                          &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
1797                 info->lpszIssuerInfo = LocalAlloc(0, len*sizeof(WCHAR));
1798                 if (info->lpszIssuerInfo)
1799                     CertNameToStrW(context->dwCertEncodingType,
1800                              &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
1801                              info->lpszIssuerInfo, len);
1802             }else {
1803                 INTERNET_CERTIFICATE_INFOA *infoA = (INTERNET_CERTIFICATE_INFOA*)info;
1804 
1805                 len = CertNameToStrA(context->dwCertEncodingType,
1806                          &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
1807                 infoA->lpszSubjectInfo = LocalAlloc(0, len);
1808                 if(infoA->lpszSubjectInfo)
1809                     CertNameToStrA(context->dwCertEncodingType,
1810                              &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
1811                              infoA->lpszSubjectInfo, len);
1812                 len = CertNameToStrA(context->dwCertEncodingType,
1813                          &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
1814                 infoA->lpszIssuerInfo = LocalAlloc(0, len);
1815                 if(infoA->lpszIssuerInfo)
1816                     CertNameToStrA(context->dwCertEncodingType,
1817                              &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
1818                              infoA->lpszIssuerInfo, len);
1819             }
1820 
1821             /*
1822              * Contrary to MSDN, these do not appear to be set.
1823              * lpszProtocolName
1824              * lpszSignatureAlgName
1825              * lpszEncryptionAlgName
1826              * dwKeySize
1827              */
1828             CertFreeCertificateContext(context);
1829             return ERROR_SUCCESS;
1830         }
1831     }
1832     }
1833 
1834     return INET_QueryOption(option, buffer, size, unicode);
1835 }
1836 
1837 static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
1838 {
1839     http_request_t *req = (http_request_t*)hdr;
1840 
1841     switch(option) {
1842     case INTERNET_OPTION_SEND_TIMEOUT:
1843     case INTERNET_OPTION_RECEIVE_TIMEOUT:
1844         TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
1845 
1846         if (size != sizeof(DWORD))
1847             return ERROR_INVALID_PARAMETER;
1848 
1849         return NETCON_set_timeout(&req->netConnection, option == INTERNET_OPTION_SEND_TIMEOUT,
1850                     *(DWORD*)buffer);
1851 
1852     case INTERNET_OPTION_USERNAME:
1853         HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszUserName);
1854         if (!(req->lpHttpSession->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
1855         return ERROR_SUCCESS;
1856 
1857     case INTERNET_OPTION_PASSWORD:
1858         HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszPassword);
1859         if (!(req->lpHttpSession->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
1860         return ERROR_SUCCESS;
1861     case INTERNET_OPTION_HTTP_DECODING:
1862         if(size != sizeof(BOOL))
1863             return ERROR_INVALID_PARAMETER;
1864         req->decoding = *(BOOL*)buffer;
1865         return ERROR_SUCCESS;
1866     }
1867 
1868     return ERROR_INTERNET_INVALID_OPTION;
1869 }
1870 
1871 /* read some more data into the read buffer (the read section must be held) */
1872 static BOOL read_more_data( http_request_t *req, int maxlen )
1873 {
1874     int len;
1875 
1876     if (req->read_pos)
1877     {
1878         /* move existing data to the start of the buffer */
1879         if(req->read_size)
1880             memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
1881         req->read_pos = 0;
1882     }
1883 
1884     if (maxlen == -1) maxlen = sizeof(req->read_buf);
1885 
1886     if(!NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
1887                      maxlen - req->read_size, 0, &len ))
1888         return FALSE;
1889 
1890     req->read_size += len;
1891     return TRUE;
1892 }
1893 
1894 /* remove some amount of data from the read buffer (the read section must be held) */
1895 static void remove_data( http_request_t *req, int count )
1896 {
1897     if (!(req->read_size -= count)) req->read_pos = 0;
1898     else req->read_pos += count;
1899 }
1900 
1901 static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
1902 {
1903     int count, bytes_read, pos = 0;
1904 
1905     EnterCriticalSection( &req->read_section );
1906     for (;;)
1907     {
1908         BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
1909 
1910         if (eol)
1911         {
1912             count = eol - (req->read_buf + req->read_pos);
1913             bytes_read = count + 1;
1914         }
1915         else count = bytes_read = req->read_size;
1916 
1917         count = min( count, *len - pos );
1918         memcpy( buffer + pos, req->read_buf + req->read_pos, count );
1919         pos += count;
1920         remove_data( req, bytes_read );
1921         if (eol) break;
1922 
1923         if (!read_more_data( req, -1 ) || !req->read_size)
1924         {
1925             *len = 0;
1926             TRACE( "returning empty string\n" );
1927             LeaveCriticalSection( &req->read_section );
1928             return FALSE;
1929         }
1930     }
1931     LeaveCriticalSection( &req->read_section );
1932 
1933     if (pos < *len)
1934     {
1935         if (pos && buffer[pos - 1] == '\r') pos--;
1936         *len = pos + 1;
1937     }
1938     buffer[*len - 1] = 0;
1939     TRACE( "returning %s\n", debugstr_a(buffer));
1940     return TRUE;
1941 }
1942 
1943 /* discard data contents until we reach end of line (the read section must be held) */
1944 static BOOL discard_eol( http_request_t *req )
1945 {
1946     do
1947     {
1948         BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
1949         if (eol)
1950         {
1951             remove_data( req, (eol + 1) - (req->read_buf + req->read_pos) );
1952             break;
1953         }
1954         req->read_pos = req->read_size = 0;  /* discard everything */
1955         if (!read_more_data( req, -1 )) return FALSE;
1956     } while (req->read_size);
1957     return TRUE;
1958 }
1959 
1960 /* read the size of the next chunk (the read section must be held) */
1961 static BOOL start_next_chunk( http_request_t *req )
1962 {
1963     DWORD chunk_size = 0;
1964 
1965     if (!req->dwContentLength) return TRUE;
1966     if (req->dwContentLength == req->dwContentRead)
1967     {
1968         /* read terminator for the previous chunk */
1969         if (!discard_eol( req )) return FALSE;
1970         req->dwContentLength = ~0u;
1971         req->dwContentRead = 0;
1972     }
1973     for (;;)
1974     {
1975         while (req->read_size)
1976         {
1977             char ch = req->read_buf[req->read_pos];
1978             if (ch >= '' && ch <= '9') chunk_size = chunk_size * 16 + ch - '';
1979             else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10;
1980             else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10;
1981             else if (ch == ';' || ch == '\r' || ch == '\n')
1982             {
1983                 TRACE( "reading %u byte chunk\n", chunk_size );
1984                 req->dwContentLength = chunk_size;
1985                 req->dwContentRead = 0;
1986                 if (!discard_eol( req )) return FALSE;
1987                 return TRUE;
1988             }
1989             remove_data( req, 1 );
1990         }
1991         if (!read_more_data( req, -1 )) return FALSE;
1992         if (!req->read_size)
1993         {
1994             req->dwContentLength = req->dwContentRead = 0;
1995             return TRUE;
1996         }
1997     }
1998 }
1999 
2000 /* check if we have reached the end of the data to read (the read section must be held) */
2001 static BOOL end_of_read_data( http_request_t *req )
2002 {
2003     if (req->gzip_stream) return req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
2004     if (req->read_chunked) return (req->dwContentLength == 0);
2005     if (req->dwContentLength == ~0u) return FALSE;
2006     return (req->dwContentLength == req->dwContentRead);
2007 }
2008 
2009 /* fetch some more data into the read buffer (the read section must be held) */
2010 static BOOL refill_buffer( http_request_t *req )
2011 {
2012     int len = sizeof(req->read_buf);
2013 
2014     if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
2015     {
2016         if (!start_next_chunk( req )) return FALSE;
2017     }
2018 
2019     if (req->dwContentLength != ~0u) len = min( len, req->dwContentLength - req->dwContentRead );
2020     if (len <= req->read_size) return TRUE;
2021 
2022     if (!read_more_data( req, len )) return FALSE;
2023     if (!req->read_size) req->dwContentLength = req->dwContentRead = 0;
2024     return TRUE;
2025 }
2026 
2027 static DWORD read_gzip_data(http_request_t *req, BYTE *buf, int size, BOOL sync, int *read_ret)
2028 {
2029     DWORD ret = ERROR_SUCCESS;
2030     int read = 0;
2031 
2032 #ifdef HAVE_ZLIB
2033     z_stream *zstream = &req->gzip_stream->zstream;
2034     int zres;
2035 
2036     while(read < size && !req->gzip_stream->end_of_data) {
2037         if(!req->read_size) {
2038             if(!sync || !refill_buffer(req))
2039                 break;
2040         }
2041 
2042         zstream->next_in = req->read_buf+req->read_pos;
2043         zstream->avail_in = req->read_size;
2044         zstream->next_out = buf+read;
2045         zstream->avail_out = size-read;
2046         zres = inflate(zstream, Z_FULL_FLUSH);
2047         read = size - zstream->avail_out;
2048         remove_data(req, req->read_size-zstream->avail_in);
2049         if(zres == Z_STREAM_END) {
2050             TRACE("end of data\n");
2051             req->gzip_stream->end_of_data = TRUE;
2052             inflateEnd(&req->gzip_stream->zstream);
2053         }else if(zres != Z_OK) {
2054             WARN("inflate failed %d\n", zres);
2055             if(!read)
2056                 ret = ERROR_INTERNET_DECODING_FAILED;
2057             break;
2058         }
2059     }
2060 #endif
2061 
2062     *read_ret = read;
2063     return ret;
2064 }
2065 
2066 static void refill_gzip_buffer(http_request_t *req)
2067 {
2068     DWORD res;
2069     int len;
2070 
2071     if(!req->gzip_stream || !req->read_size || req->gzip_stream->buf_size == sizeof(req->gzip_stream->buf))
2072         return;
2073 
2074     if(req->gzip_stream->buf_pos) {
2075         if(req->gzip_stream->buf_size)
2076             memmove(req->gzip_stream->buf, req->gzip_stream->buf + req->gzip_stream->buf_pos, req->gzip_stream->buf_size);
2077         req->gzip_stream->buf_pos = 0;
2078     }
2079 
2080     res = read_gzip_data(req, req->gzip_stream->buf + req->gzip_stream->buf_size,
2081             sizeof(req->gzip_stream->buf) - req->gzip_stream->buf_size, FALSE, &len);
2082     if(res == ERROR_SUCCESS)
2083         req->gzip_stream->buf_size += len;
2084 }
2085 
2086 /* return the size of data available to be read immediately (the read section must be held) */
2087 static DWORD get_avail_data( http_request_t *req )
2088 {
2089     if (req->gzip_stream) {
2090         refill_gzip_buffer(req);
2091         return req->gzip_stream->buf_size;
2092     }
2093     if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
2094         return 0;
2095     return min( req->read_size, req->dwContentLength - req->dwContentRead );
2096 }
2097 
2098 static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif)
2099 {
2100     INTERNET_ASYNC_RESULT iar;
2101 
2102     TRACE("%p\n", req);
2103 
2104     EnterCriticalSection( &req->read_section );
2105     if (refill_buffer( req )) {
2106         iar.dwResult = (DWORD_PTR)req->hdr.hInternet;
2107         iar.dwError = first_notif ? 0 : get_avail_data(req);
2108     }else {
2109         iar.dwResult = 0;
2110         iar.dwError = INTERNET_GetLastError();
2111     }
2112     LeaveCriticalSection( &req->read_section );
2113 
2114     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2115                           sizeof(INTERNET_ASYNC_RESULT));
2116 }
2117 
2118 /* read data from the http connection (the read section must be held) */
2119 static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
2120 {
2121     BOOL finished_reading = FALSE;
2122     int len, bytes_read = 0;
2123     DWORD ret = ERROR_SUCCESS;
2124 
2125     EnterCriticalSection( &req->read_section );
2126 
2127     if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
2128     {
2129         if (!start_next_chunk( req )) goto done;
2130     }
2131 
2132     if(req->gzip_stream) {
2133         if(req->gzip_stream->buf_size) {
2134             bytes_read = min(req->gzip_stream->buf_size, size);
2135             memcpy(buffer, req->gzip_stream->buf + req->gzip_stream->buf_pos, bytes_read);
2136             req->gzip_stream->buf_pos += bytes_read;
2137             req->gzip_stream->buf_size -= bytes_read;
2138         }else if(!req->read_size && !req->gzip_stream->end_of_data) {
2139             refill_buffer(req);
2140         }
2141 
2142         if(size > bytes_read) {
2143             ret = read_gzip_data(req, (BYTE*)buffer+bytes_read, size-bytes_read, sync, &len);
2144             if(ret == ERROR_SUCCESS)
2145                 bytes_read += len;
2146         }
2147 
2148         finished_reading = req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
2149     }else {
2150         if (req->dwContentLength != ~0u) size = min( size, req->dwContentLength - req->dwContentRead );
2151 
2152         if (req->read_size) {
2153             bytes_read = min( req->read_size, size );
2154             memcpy( buffer, req->read_buf + req->read_pos, bytes_read );
2155             remove_data( req, bytes_read );
2156         }
2157 
2158         if (size > bytes_read && (!bytes_read || sync)) {
2159             if (NETCON_recv( &req->netConnection, (char *)buffer + bytes_read, size - bytes_read,
2160                              sync ? MSG_WAITALL : 0, &len))
2161                 bytes_read += len;
2162             /* always return success, even if the network layer returns an error */
2163         }
2164 
2165         finished_reading = !bytes_read && req->dwContentRead == req->dwContentLength;
2166     }
2167 done:
2168     req->dwContentRead += bytes_read;
2169     *read = bytes_read;
2170 
2171     TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength );
2172     LeaveCriticalSection( &req->read_section );
2173 
2174     if(ret == ERROR_SUCCESS && req->lpszCacheFile) {
2175         BOOL res;
2176         DWORD dwBytesWritten;
2177 
2178         res = WriteFile(req->hCacheFile, buffer, bytes_read, &dwBytesWritten, NULL);
2179         if(!res)
2180             WARN("WriteFile failed: %u\n", GetLastError());
2181     }
2182 
2183     if(finished_reading)
2184         HTTP_FinishedReading(req);
2185 
2186     return ret;
2187 }
2188 
2189 
2190 static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
2191 {
2192     http_request_t *req = (http_request_t*)hdr;
2193     return HTTPREQ_Read(req, buffer, size, read, TRUE);
2194 }
2195 
2196 static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest)
2197 {
2198     struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA;
2199     http_request_t *req = (http_request_t*)workRequest->hdr;
2200     INTERNET_ASYNC_RESULT iar;
2201     DWORD res;
2202 
2203     TRACE("INTERNETREADFILEEXA %p\n", workRequest->hdr);
2204 
2205     res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2206             data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2207 
2208     iar.dwResult = res == ERROR_SUCCESS;
2209     iar.dwError = res;
2210 
2211     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2212                           INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2213                           sizeof(INTERNET_ASYNC_RESULT));
2214 }
2215 
2216 static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers,
2217         DWORD flags, DWORD_PTR context)
2218 {
2219     http_request_t *req = (http_request_t*)hdr;
2220     DWORD res;
2221 
2222     if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2223         FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2224 
2225     if (buffers->dwStructSize != sizeof(*buffers))
2226         return ERROR_INVALID_PARAMETER;
2227 
2228     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2229 
2230     if ((hdr->dwFlags & INTERNET_FLAG_ASYNC) && !get_avail_data(req))
2231     {
2232         WORKREQUEST workRequest;
2233 
2234         if (TryEnterCriticalSection( &req->read_section ))
2235         {
2236             if (get_avail_data(req))
2237             {
2238                 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2239                                    &buffers->dwBufferLength, FALSE);
2240                 LeaveCriticalSection( &req->read_section );
2241                 goto done;
2242             }
2243             LeaveCriticalSection( &req->read_section );
2244         }
2245 
2246         workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc;
2247         workRequest.hdr = WININET_AddRef(&req->hdr);
2248         workRequest.u.InternetReadFileExA.lpBuffersOut = buffers;
2249 
2250         INTERNET_AsyncCall(&workRequest);
2251 
2252         return ERROR_IO_PENDING;
2253     }
2254 
2255     res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
2256             !(flags & IRF_NO_WAIT));
2257 
2258 done:
2259     if (res == ERROR_SUCCESS) {
2260         DWORD size = buffers->dwBufferLength;
2261         INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2262                 &size, sizeof(size));
2263     }
2264 
2265     return res;
2266 }
2267 
2268 static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest)
2269 {
2270     struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW;
2271     http_request_t *req = (http_request_t*)workRequest->hdr;
2272     INTERNET_ASYNC_RESULT iar;
2273     DWORD res;
2274 
2275     TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr);
2276 
2277     res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2278             data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2279 
2280     iar.dwResult = res == ERROR_SUCCESS;
2281     iar.dwError = res;
2282 
2283     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2284                           INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2285                           sizeof(INTERNET_ASYNC_RESULT));
2286 }
2287 
2288 static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers,
2289         DWORD flags, DWORD_PTR context)
2290 {
2291 
2292     http_request_t *req = (http_request_t*)hdr;
2293     DWORD res;
2294 
2295     if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2296         FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2297 
2298     if (buffers->dwStructSize != sizeof(*buffers))
2299         return ERROR_INVALID_PARAMETER;
2300 
2301     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2302 
2303     if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
2304     {
2305         WORKREQUEST workRequest;
2306 
2307         if (TryEnterCriticalSection( &req->read_section ))
2308         {
2309             if (get_avail_data(req))
2310             {
2311                 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2312                                    &buffers->dwBufferLength, FALSE);
2313                 LeaveCriticalSection( &req->read_section );
2314                 goto done;
2315             }
2316             LeaveCriticalSection( &req->read_section );
2317         }
2318 
2319         workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc;
2320         workRequest.hdr = WININET_AddRef(&req->hdr);
2321         workRequest.u.InternetReadFileExW.lpBuffersOut = buffers;
2322 
2323         INTERNET_AsyncCall(&workRequest);
2324 
2325         return ERROR_IO_PENDING;
2326     }
2327 
2328     res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
2329             !(flags & IRF_NO_WAIT));
2330 
2331 done:
2332     if (res == ERROR_SUCCESS) {
2333         DWORD size = buffers->dwBufferLength;
2334         INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2335                 &size, sizeof(size));
2336     }
2337 
2338     return res;
2339 }
2340 
2341 static BOOL HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
2342 {
2343     BOOL ret;
2344     http_request_t *lpwhr = (http_request_t*)hdr;
2345 
2346     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2347 
2348     *written = 0;
2349     if ((ret = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written)))
2350         lpwhr->dwBytesWritten += *written;
2351 
2352     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD));
2353     return ret;
2354 }
2355 
2356 static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
2357 {
2358     http_request_t *req = (http_request_t*)workRequest->hdr;
2359 
2360     HTTP_ReceiveRequestData(req, FALSE);
2361 }
2362 
2363 static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
2364 {
2365     http_request_t *req = (http_request_t*)hdr;
2366 
2367     TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
2368 
2369     if (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2370     {
2371         WORKREQUEST workRequest;
2372 
2373         /* never wait, if we can't enter the section we queue an async request right away */
2374         if (TryEnterCriticalSection( &req->read_section ))
2375         {
2376             if ((*available = get_avail_data( req ))) goto done;
2377             if (end_of_read_data( req )) goto done;
2378             LeaveCriticalSection( &req->read_section );
2379         }
2380 
2381         workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc;
2382         workRequest.hdr = WININET_AddRef( &req->hdr );
2383 
2384         INTERNET_AsyncCall(&workRequest);
2385 
2386         return ERROR_IO_PENDING;
2387     }
2388 
2389     EnterCriticalSection( &req->read_section );
2390 
2391     if (!(*available = get_avail_data( req )) && !end_of_read_data( req ))
2392     {
2393         refill_buffer( req );
2394         *available = get_avail_data( req );
2395     }
2396 
2397 done:
2398     if (*available == sizeof(req->read_buf) && !req->gzip_stream)  /* check if we have even more pending in the socket */
2399     {
2400         DWORD extra;
2401         if (NETCON_query_data_available(&req->netConnection, &extra))
2402             *available = min( *available + extra, req->dwContentLength - req->dwContentRead );
2403     }
2404     LeaveCriticalSection( &req->read_section );
2405 
2406     TRACE( "returning %u\n", *available );
2407     return ERROR_SUCCESS;
2408 }
2409 
2410 static const object_vtbl_t HTTPREQVtbl = {
2411     HTTPREQ_Destroy,
2412     HTTPREQ_CloseConnection,
2413     HTTPREQ_QueryOption,
2414     HTTPREQ_SetOption,
2415     HTTPREQ_ReadFile,
2416     HTTPREQ_ReadFileExA,
2417     HTTPREQ_ReadFileExW,
2418     HTTPREQ_WriteFile,
2419     HTTPREQ_QueryDataAvailable,
2420     NULL
2421 };
2422 
2423 /***********************************************************************
2424  *           HTTP_HttpOpenRequestW (internal)
2425  *
2426  * Open a HTTP request handle
2427  *
2428  * RETURNS
2429  *    HINTERNET  a HTTP request handle on success
2430  *    NULL       on failure
2431  *
2432  */
2433 HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
2434         LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
2435         LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
2436         DWORD dwFlags, DWORD_PTR dwContext)
2437 {
2438     appinfo_t *hIC = NULL;
2439     http_request_t *lpwhr;
2440     LPWSTR lpszHostName = NULL;
2441     HINTERNET handle = NULL;
2442     static const WCHAR szHostForm[] = {'%','s',':','%','u',0};
2443     DWORD len;
2444 
2445     TRACE("-->\n");
2446 
2447     assert( lpwhs->hdr.htype == WH_HHTTPSESSION );
2448     hIC = lpwhs->lpAppInfo;
2449 
2450     lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_request_t));
2451     if (NULL == lpwhr)
2452     {
2453         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2454         goto lend;
2455     }
2456     lpwhr->hdr.htype = WH_HHTTPREQ;
2457     lpwhr->hdr.vtbl = &HTTPREQVtbl;
2458     lpwhr->hdr.dwFlags = dwFlags;
2459     lpwhr->hdr.dwContext = dwContext;
2460     lpwhr->hdr.refs = 1;
2461     lpwhr->hdr.lpfnStatusCB = lpwhs->hdr.lpfnStatusCB;
2462     lpwhr->hdr.dwInternalFlags = lpwhs->hdr.dwInternalFlags & INET_CALLBACKW;
2463     lpwhr->dwContentLength = ~0u;
2464     InitializeCriticalSection( &lpwhr->read_section );
2465 
2466     WININET_AddRef( &lpwhs->hdr );
2467     lpwhr->lpHttpSession = lpwhs;
2468     list_add_head( &lpwhs->hdr.children, &lpwhr->hdr.entry );
2469 
2470     lpszHostName = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) *
2471             (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */));
2472     if (NULL == lpszHostName)
2473     {
2474         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2475         goto lend;
2476     }
2477 
2478     handle = WININET_AllocHandle( &lpwhr->hdr );
2479     if (NULL == handle)
2480     {
2481         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2482         goto lend;
2483     }
2484 
2485     if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE))
2486     {
2487         InternetCloseHandle( handle );
2488         handle = NULL;
2489         goto lend;
2490     }
2491 
2492     if (lpszObjectName && *lpszObjectName) {
2493         HRESULT rc;
2494 
2495         len = 0;
2496         rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
2497         if (rc != E_POINTER)
2498             len = strlenW(lpszObjectName)+1;
2499         lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
2500         rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len,
2501                    URL_ESCAPE_SPACES_ONLY);
2502         if (rc != S_OK)
2503         {
2504             ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
2505             strcpyW(lpwhr->lpszPath,lpszObjectName);
2506         }
2507     }else {
2508         static const WCHAR slashW[] = {'/',0};
2509 
2510         lpwhr->lpszPath = heap_strdupW(slashW);
2511     }
2512 
2513     if (lpszReferrer && *lpszReferrer)
2514         HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
2515 
2516     if (lpszAcceptTypes)
2517     {
2518         int i;
2519         for (i = 0; lpszAcceptTypes[i]; i++)
2520         {
2521             if (!*lpszAcceptTypes[i]) continue;
2522             HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i],
2523                                HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA |
2524                                HTTP_ADDHDR_FLAG_REQ |
2525                                (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0));
2526         }
2527     }
2528 
2529     lpwhr->lpszVerb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
2530     lpwhr->lpszVersion = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1);
2531 
2532     if (lpwhs->nHostPort != INTERNET_INVALID_PORT_NUMBER &&
2533         lpwhs->nHostPort != INTERNET_DEFAULT_HTTP_PORT &&
2534         lpwhs->nHostPort != INTERNET_DEFAULT_HTTPS_PORT)
2535     {
2536         sprintfW(lpszHostName, szHostForm, lpwhs->lpszHostName, lpwhs->nHostPort);
2537         HTTP_ProcessHeader(lpwhr, hostW, lpszHostName,
2538                 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
2539     }
2540     else
2541         HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName,
2542                 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
2543 
2544     if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER)
2545         lpwhs->nServerPort = (dwFlags & INTERNET_FLAG_SECURE ?
2546                         INTERNET_DEFAULT_HTTPS_PORT :
2547                         INTERNET_DEFAULT_HTTP_PORT);
2548 
2549     if (lpwhs->nHostPort == INTERNET_INVALID_PORT_NUMBER)
2550         lpwhs->nHostPort = (dwFlags & INTERNET_FLAG_SECURE ?
2551                         INTERNET_DEFAULT_HTTPS_PORT :
2552                         INTERNET_DEFAULT_HTTP_PORT);
2553 
2554     if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
2555         HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
2556 
2557     INTERNET_SendCallback(&lpwhs->hdr, dwContext,
2558                           INTERNET_STATUS_HANDLE_CREATED, &handle,
2559                           sizeof(handle));
2560 
2561 lend:
2562     HeapFree(GetProcessHeap(), 0, lpszHostName);
2563     if( lpwhr )
2564         WININET_Release( &lpwhr->hdr );
2565 
2566     TRACE("<-- %p (%p)\n", handle, lpwhr);
2567     return handle;
2568 }
2569 
2570 /* read any content returned by the server so that the connection can be
2571  * reused */
2572 static void HTTP_DrainContent(http_request_t *req)
2573 {
2574     DWORD bytes_read;
2575 
2576     if (!NETCON_connected(&req->netConnection)) return;
2577 
2578     if (req->dwContentLength == -1)
2579     {
2580         NETCON_close(&req->netConnection);
2581         return;
2582     }
2583     if (!strcmpW(req->lpszVerb, szHEAD)) return;
2584 
2585     do
2586     {
2587         char buffer[2048];
2588         if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS)
2589             return;
2590     } while (bytes_read);
2591 }
2592 
2593 static const LPCWSTR header_lookup[] = {
2594     szMime_Version,             /* HTTP_QUERY_MIME_VERSION = 0 */
2595     szContent_Type,             /* HTTP_QUERY_CONTENT_TYPE = 1 */
2596     szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
2597     szContent_ID,               /* HTTP_QUERY_CONTENT_ID = 3 */
2598     NULL,                       /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
2599     szContent_Length,           /* HTTP_QUERY_CONTENT_LENGTH =  5 */
2600     szContent_Language,         /* HTTP_QUERY_CONTENT_LANGUAGE =  6 */
2601     szAllow,                    /* HTTP_QUERY_ALLOW = 7 */
2602     szPublic,                   /* HTTP_QUERY_PUBLIC = 8 */
2603     szDate,                     /* HTTP_QUERY_DATE = 9 */
2604     szExpires,                  /* HTTP_QUERY_EXPIRES = 10 */
2605     szLast_Modified,            /* HTTP_QUERY_LAST_MODIFIED = 11 */
2606     NULL,                       /* HTTP_QUERY_MESSAGE_ID = 12 */
2607     szURI,                      /* HTTP_QUERY_URI = 13 */
2608     szFrom,                     /* HTTP_QUERY_DERIVED_FROM = 14 */
2609     NULL,                       /* HTTP_QUERY_COST = 15 */
2610     NULL,                       /* HTTP_QUERY_LINK = 16 */
2611     szPragma,                   /* HTTP_QUERY_PRAGMA = 17 */
2612     NULL,                       /* HTTP_QUERY_VERSION = 18 */
2613     szStatus,                   /* HTTP_QUERY_STATUS_CODE = 19 */
2614     NULL,                       /* HTTP_QUERY_STATUS_TEXT = 20 */
2615     NULL,                       /* HTTP_QUERY_RAW_HEADERS = 21 */
2616     NULL,                       /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
2617     szConnection,               /* HTTP_QUERY_CONNECTION = 23 */
2618     szAccept,                   /* HTTP_QUERY_ACCEPT = 24 */
2619     szAccept_Charset,           /* HTTP_QUERY_ACCEPT_CHARSET = 25 */
2620     szAccept_Encoding,          /* HTTP_QUERY_ACCEPT_ENCODING = 26 */
2621     szAccept_Language,          /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
2622     szAuthorization,            /* HTTP_QUERY_AUTHORIZATION = 28 */
2623     szContent_Encoding,         /* HTTP_QUERY_CONTENT_ENCODING = 29 */
2624     NULL,                       /* HTTP_QUERY_FORWARDED = 30 */
2625     NULL,                       /* HTTP_QUERY_FROM = 31 */
2626     szIf_Modified_Since,        /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
2627     szLocation,                 /* HTTP_QUERY_LOCATION = 33 */
2628     NULL,                       /* HTTP_QUERY_ORIG_URI = 34 */
2629     szReferer,                  /* HTTP_QUERY_REFERER = 35 */
2630     szRetry_After,              /* HTTP_QUERY_RETRY_AFTER = 36 */
2631     szServer,                   /* HTTP_QUERY_SERVER = 37 */
2632     NULL,                       /* HTTP_TITLE = 38 */
2633     szUser_Agent,               /* HTTP_QUERY_USER_AGENT = 39 */
2634     szWWW_Authenticate,         /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
2635     szProxy_Authenticate,       /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
2636     szAccept_Ranges,            /* HTTP_QUERY_ACCEPT_RANGES = 42 */
2637     szSet_Cookie,               /* HTTP_QUERY_SET_COOKIE = 43 */
2638     szCookie,                   /* HTTP_QUERY_COOKIE = 44 */
2639     NULL,                       /* HTTP_QUERY_REQUEST_METHOD = 45 */
2640     NULL,                       /* HTTP_QUERY_REFRESH = 46 */
2641     NULL,                       /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
2642     szAge,                      /* HTTP_QUERY_AGE = 48 */
2643     szCache_Control,            /* HTTP_QUERY_CACHE_CONTROL = 49 */
2644     szContent_Base,             /* HTTP_QUERY_CONTENT_BASE = 50 */
2645     szContent_Location,         /* HTTP_QUERY_CONTENT_LOCATION = 51 */
2646     szContent_MD5,              /* HTTP_QUERY_CONTENT_MD5 = 52 */
2647     szContent_Range,            /* HTTP_QUERY_CONTENT_RANGE = 53 */
2648     szETag,                     /* HTTP_QUERY_ETAG = 54 */
2649     hostW,                      /* HTTP_QUERY_HOST = 55 */
2650     szIf_Match,                 /* HTTP_QUERY_IF_MATCH = 56 */
2651     szIf_None_Match,            /* HTTP_QUERY_IF_NONE_MATCH = 57 */
2652     szIf_Range,                 /* HTTP_QUERY_IF_RANGE = 58 */
2653     szIf_Unmodified_Since,      /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
2654     szMax_Forwards,             /* HTTP_QUERY_MAX_FORWARDS = 60 */
2655     szProxy_Authorization,      /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
2656     szRange,                    /* HTTP_QUERY_RANGE = 62 */
2657     szTransfer_Encoding,        /* HTTP_QUERY_TRANSFER_ENCODING = 63 */
2658     szUpgrade,                  /* HTTP_QUERY_UPGRADE = 64 */
2659     szVary,                     /* HTTP_QUERY_VARY = 65 */
2660     szVia,                      /* HTTP_QUERY_VIA = 66 */
2661     szWarning,                  /* HTTP_QUERY_WARNING = 67 */
2662     szExpect,                   /* HTTP_QUERY_EXPECT = 68 */
2663     szProxy_Connection,         /* HTTP_QUERY_PROXY_CONNECTION = 69 */
2664     szUnless_Modified_Since,    /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
2665 };
2666 
2667 #define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
2668 
2669 /***********************************************************************
2670  *           HTTP_HttpQueryInfoW (internal)
2671  */
2672 static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
2673         LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
2674 {
2675     LPHTTPHEADERW lphttpHdr = NULL;
2676     BOOL bSuccess = FALSE;
2677     BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS;
2678     INT requested_index = lpdwIndex ? *lpdwIndex : 0;
2679     DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
2680     INT index = -1;
2681 
2682     /* Find requested header structure */
2683     switch (level)
2684     {
2685     case HTTP_QUERY_CUSTOM:
2686         if (!lpBuffer) return FALSE;
2687         index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
2688         break;
2689     case HTTP_QUERY_RAW_HEADERS_CRLF:
2690         {
2691             LPWSTR headers;
2692             DWORD len = 0;
2693             BOOL ret = FALSE;
2694 
2695             if (request_only)
2696                 headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
2697             else
2698                 headers = lpwhr->lpszRawHeaders;
2699 
2700             if (headers)
2701                 len = strlenW(headers) * sizeof(WCHAR);
2702 
2703             if (len + sizeof(WCHAR) > *lpdwBufferLength)
2704             {
2705                 len += sizeof(WCHAR);
2706                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2707                 ret = FALSE;
2708             }
2709             else if (lpBuffer)
2710             {
2711                 if (headers)
2712                     memcpy(lpBuffer, headers, len + sizeof(WCHAR));
2713                 else
2714                 {
2715                     len = strlenW(szCrLf) * sizeof(WCHAR);
2716                     memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
2717                 }
2718                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
2719                 ret = TRUE;
2720             }
2721             *lpdwBufferLength = len;
2722 
2723             if (request_only)
2724                 HeapFree(GetProcessHeap(), 0, headers);
2725             return ret;
2726         }
2727     case HTTP_QUERY_RAW_HEADERS:
2728         {
2729             LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf);
2730             DWORD i, size = 0;
2731             LPWSTR pszString = lpBuffer;
2732 
2733             for (i = 0; ppszRawHeaderLines[i]; i++)
2734                 size += strlenW(ppszRawHeaderLines[i]) + 1;
2735 
2736             if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
2737             {
2738                 HTTP_FreeTokens(ppszRawHeaderLines);
2739                 *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
2740                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2741                 return FALSE;
2742             }
2743             if (pszString)
2744             {
2745                 for (i = 0; ppszRawHeaderLines[i]; i++)
2746                 {
2747                     DWORD len = strlenW(ppszRawHeaderLines[i]);
2748                     memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
2749                     pszString += len+1;
2750                 }
2751                 *pszString = '\0';
2752                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
2753             }
2754             *lpdwBufferLength = size * sizeof(WCHAR);
2755             HTTP_FreeTokens(ppszRawHeaderLines);
2756 
2757             return TRUE;
2758         }
2759     case HTTP_QUERY_STATUS_TEXT:
2760         if (lpwhr->lpszStatusText)
2761         {
2762             DWORD len = strlenW(lpwhr->lpszStatusText);
2763             if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
2764             {
2765                 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
2766                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2767                 return FALSE;
2768             }
2769             if (lpBuffer)
2770             {
2771                 memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR));
2772                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
2773             }
2774             *lpdwBufferLength = len * sizeof(WCHAR);
2775             return TRUE;
2776         }
2777         break;
2778     case HTTP_QUERY_VERSION:
2779         if (lpwhr->lpszVersion)
2780         {
2781             DWORD len = strlenW(lpwhr->lpszVersion);
2782             if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
2783             {
2784                 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
2785                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2786                 return FALSE;
2787             }
2788             if (lpBuffer)
2789             {
2790                 memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR));
2791                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
2792             }
2793             *lpdwBufferLength = len * sizeof(WCHAR);
2794             return TRUE;
2795         }
2796         break;
2797     case HTTP_QUERY_CONTENT_ENCODING:
2798         index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[lpwhr->gzip_stream ? HTTP_QUERY_CONTENT_TYPE : level],
2799                 requested_index,request_only);
2800         break;
2801     default:
2802         assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1));
2803 
2804         if (level < LAST_TABLE_HEADER && header_lookup[level])
2805             index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
2806                                               requested_index,request_only);
2807     }
2808 
2809     if (index >= 0)
2810         lphttpHdr = &lpwhr->pCustHeaders[index];
2811 
2812     /* Ensure header satisfies requested attributes */
2813     if (!lphttpHdr ||
2814         ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
2815          (~lphttpHdr->wFlags & HDR_ISREQUEST)))
2816     {
2817         INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
2818         return bSuccess;
2819     }
2820 
2821     if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++;
2822 
2823     /* coalesce value to requested type */
2824     if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
2825     {
2826         *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
2827         TRACE(" returning number: %d\n", *(int *)lpBuffer);
2828         bSuccess = TRUE;
2829     }
2830     else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
2831     {
2832         time_t tmpTime;
2833         struct tm tmpTM;
2834         SYSTEMTIME *STHook;
2835 
2836         tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
2837 
2838         tmpTM = *gmtime(&tmpTime);
2839         STHook = (SYSTEMTIME *)lpBuffer;
2840         STHook->wDay = tmpTM.tm_mday;
2841         STHook->wHour = tmpTM.tm_hour;
2842         STHook->wMilliseconds = 0;
2843         STHook->wMinute = tmpTM.tm_min;
2844         STHook->wDayOfWeek = tmpTM.tm_wday;
2845         STHook->wMonth = tmpTM.tm_mon + 1;
2846         STHook->wSecond = tmpTM.tm_sec;
2847         STHook->wYear = tmpTM.tm_year;
2848         bSuccess = TRUE;
2849         
2850         TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
2851               STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
2852               STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
2853     }
2854     else if (lphttpHdr->lpszValue)
2855     {
2856         DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
2857 
2858         if (len > *lpdwBufferLength)
2859         {
2860             *lpdwBufferLength = len;
2861             INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2862             return bSuccess;
2863         }
2864         if (lpBuffer)
2865         {
2866             memcpy(lpBuffer, lphttpHdr->lpszValue, len);
2867             TRACE(" returning string: %s\n", debugstr_w(lpBuffer));
2868         }
2869         *lpdwBufferLength = len - sizeof(WCHAR);
2870         bSuccess = TRUE;
2871     }
2872     return bSuccess;
2873 }
2874 
2875 /***********************************************************************
2876  *           HttpQueryInfoW (WININET.@)
2877  *
2878  * Queries for information about an HTTP request
2879  *
2880  * RETURNS
2881  *    TRUE  on success
2882  *    FALSE on failure
2883  *
2884  */
2885 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
2886         LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
2887 {
2888     BOOL bSuccess = FALSE;
2889     http_request_t *lpwhr;
2890 
2891     if (TRACE_ON(wininet)) {
2892 #define FE(x) { x, #x }
2893         static const wininet_flag_info query_flags[] = {
2894             FE(HTTP_QUERY_MIME_VERSION),
2895             FE(HTTP_QUERY_CONTENT_TYPE),
2896             FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
2897             FE(HTTP_QUERY_CONTENT_ID),
2898             FE(HTTP_QUERY_CONTENT_DESCRIPTION),
2899             FE(HTTP_QUERY_CONTENT_LENGTH),
2900             FE(HTTP_QUERY_CONTENT_LANGUAGE),
2901             FE(HTTP_QUERY_ALLOW),
2902             FE(HTTP_QUERY_PUBLIC),
2903             FE(HTTP_QUERY_DATE),
2904             FE(HTTP_QUERY_EXPIRES),
2905             FE(HTTP_QUERY_LAST_MODIFIED),
2906             FE(HTTP_QUERY_MESSAGE_ID),
2907             FE(HTTP_QUERY_URI),
2908             FE(HTTP_QUERY_DERIVED_FROM),
2909             FE(HTTP_QUERY_COST),
2910             FE(HTTP_QUERY_LINK),
2911             FE(HTTP_QUERY_PRAGMA),
2912             FE(HTTP_QUERY_VERSION),
2913             FE(HTTP_QUERY_STATUS_CODE),
2914             FE(HTTP_QUERY_STATUS_TEXT),
2915             FE(HTTP_QUERY_RAW_HEADERS),
2916             FE(HTTP_QUERY_RAW_HEADERS_CRLF),
2917             FE(HTTP_QUERY_CONNECTION),
2918             FE(HTTP_QUERY_ACCEPT),
2919             FE(HTTP_QUERY_ACCEPT_CHARSET),
2920             FE(HTTP_QUERY_ACCEPT_ENCODING),
2921             FE(HTTP_QUERY_ACCEPT_LANGUAGE),
2922             FE(HTTP_QUERY_AUTHORIZATION),
2923             FE(HTTP_QUERY_CONTENT_ENCODING),
2924             FE(HTTP_QUERY_FORWARDED),
2925             FE(HTTP_QUERY_FROM),
2926             FE(HTTP_QUERY_IF_MODIFIED_SINCE),
2927             FE(HTTP_QUERY_LOCATION),
2928             FE(HTTP_QUERY_ORIG_URI),
2929             FE(HTTP_QUERY_REFERER),
2930             FE(HTTP_QUERY_RETRY_AFTER),
2931             FE(HTTP_QUERY_SERVER),
2932             FE(HTTP_QUERY_TITLE),
2933             FE(HTTP_QUERY_USER_AGENT),
2934             FE(HTTP_QUERY_WWW_AUTHENTICATE),
2935             FE(HTTP_QUERY_PROXY_AUTHENTICATE),
2936             FE(HTTP_QUERY_ACCEPT_RANGES),
2937         FE(HTTP_QUERY_SET_COOKIE),
2938         FE(HTTP_QUERY_COOKIE),
2939             FE(HTTP_QUERY_REQUEST_METHOD),
2940             FE(HTTP_QUERY_REFRESH),
2941             FE(HTTP_QUERY_CONTENT_DISPOSITION),
2942             FE(HTTP_QUERY_AGE),
2943             FE(HTTP_QUERY_CACHE_CONTROL),
2944             FE(HTTP_QUERY_CONTENT_BASE),
2945             FE(HTTP_QUERY_CONTENT_LOCATION),
2946             FE(HTTP_QUERY_CONTENT_MD5),
2947             FE(HTTP_QUERY_CONTENT_RANGE),
2948             FE(HTTP_QUERY_ETAG),
2949             FE(HTTP_QUERY_HOST),
2950             FE(HTTP_QUERY_IF_MATCH),
2951             FE(HTTP_QUERY_IF_NONE_MATCH),
2952             FE(HTTP_QUERY_IF_RANGE),
2953             FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
2954             FE(HTTP_QUERY_MAX_FORWARDS),
2955             FE(HTTP_QUERY_PROXY_AUTHORIZATION),
2956             FE(HTTP_QUERY_RANGE),
2957             FE(HTTP_QUERY_TRANSFER_ENCODING),
2958             FE(HTTP_QUERY_UPGRADE),
2959             FE(HTTP_QUERY_VARY),
2960             FE(HTTP_QUERY_VIA),
2961             FE(HTTP_QUERY_WARNING),
2962             FE(HTTP_QUERY_CUSTOM)
2963         };
2964         static const wininet_flag_info modifier_flags[] = {
2965             FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
2966             FE(HTTP_QUERY_FLAG_SYSTEMTIME),
2967             FE(HTTP_QUERY_FLAG_NUMBER),
2968             FE(HTTP_QUERY_FLAG_COALESCE)
2969         };
2970 #undef FE
2971         DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
2972         DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
2973         DWORD i;
2974 
2975         TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
2976         TRACE("  Attribute:");
2977         for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
2978             if (query_flags[i].val == info) {
2979                 TRACE(" %s", query_flags[i].name);
2980                 break;
2981             }
2982         }
2983         if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
2984             TRACE(" Unknown (%08x)", info);
2985         }
2986 
2987         TRACE(" Modifier:");
2988         for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
2989             if (modifier_flags[i].val & info_mod) {
2990                 TRACE(" %s", modifier_flags[i].name);
2991                 info_mod &= ~ modifier_flags[i].val;
2992             }
2993         }
2994         
2995         if (info_mod) {
2996             TRACE(" Unknown (%08x)", info_mod);
2997         }
2998         TRACE("\n");
2999     }
3000     
3001     lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
3002     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
3003     {
3004         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3005         goto lend;
3006     }
3007 
3008     if (lpBuffer == NULL)
3009         *lpdwBufferLength = 0;
3010     bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
3011                                     lpBuffer, lpdwBufferLength, lpdwIndex);
3012 
3013 lend:
3014     if( lpwhr )
3015          WININET_Release( &lpwhr->hdr );
3016 
3017     TRACE("%d <--\n", bSuccess);
3018     return bSuccess;
3019 }
3020 
3021 /***********************************************************************
3022  *           HttpQueryInfoA (WININET.@)
3023  *
3024  * Queries for information about an HTTP request
3025  *
3026  * RETURNS
3027  *    TRUE  on success
3028  *    FALSE on failure
3029  *
3030  */
3031 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
3032         LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
3033 {
3034     BOOL result;
3035     DWORD len;
3036     WCHAR* bufferW;
3037 
3038     if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
3039        (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
3040     {
3041         return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
3042                                lpdwBufferLength, lpdwIndex );
3043     }
3044 
3045     if (lpBuffer)
3046     {
3047         DWORD alloclen;
3048         len = (*lpdwBufferLength)*sizeof(WCHAR);
3049         if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
3050         {
3051             alloclen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ) * sizeof(WCHAR);
3052             if (alloclen < len)
3053                 alloclen = len;
3054         }
3055         else
3056             alloclen = len;
3057         bufferW = HeapAlloc( GetProcessHeap(), 0, alloclen );
3058         /* buffer is in/out because of HTTP_QUERY_CUSTOM */
3059         if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
3060             MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, bufferW, alloclen / sizeof(WCHAR) );
3061     } else
3062     {
3063         bufferW = NULL;
3064         len = 0;
3065     }
3066 
3067     result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
3068                            &len, lpdwIndex );
3069     if( result )
3070     {
3071         len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1,
3072                                      lpBuffer, *lpdwBufferLength, NULL, NULL );
3073         *lpdwBufferLength = len - 1;
3074 
3075         TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer));
3076     }
3077     else
3078         /* since the strings being returned from HttpQueryInfoW should be
3079          * only ASCII characters, it is reasonable to assume that all of
3080          * the Unicode characters can be reduced to a single byte */
3081         *lpdwBufferLength = len / sizeof(WCHAR);
3082 
3083     HeapFree(GetProcessHeap(), 0, bufferW );
3084 
3085     return result;
3086 }
3087 
3088 /***********************************************************************
3089  *           HttpSendRequestExA (WININET.@)
3090  *
3091  * Sends the specified request to the HTTP server and allows chunked
3092  * transfers.
3093  *
3094  * RETURNS
3095  *  Success: TRUE
3096  *  Failure: FALSE, call GetLastError() for more information.
3097  */
3098 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
3099                                LPINTERNET_BUFFERSA lpBuffersIn,
3100                                LPINTERNET_BUFFERSA lpBuffersOut,
3101                                DWORD dwFlags, DWORD_PTR dwContext)
3102 {
3103     INTERNET_BUFFERSW BuffersInW;
3104     BOOL rc = FALSE;
3105     DWORD headerlen;
3106     LPWSTR header = NULL;
3107 
3108     TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
3109             lpBuffersOut, dwFlags, dwContext);
3110 
3111     if (lpBuffersIn)
3112     {
3113         BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
3114         if (lpBuffersIn->lpcszHeader)
3115         {
3116             headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
3117                     lpBuffersIn->dwHeadersLength,0,0);
3118             header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR));
3119             if (!(BuffersInW.lpcszHeader = header))
3120             {
3121                 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
3122                 return FALSE;
3123             }
3124             BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
3125                     lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
3126                     header, headerlen);
3127         }
3128         else
3129             BuffersInW.lpcszHeader = NULL;
3130         BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
3131         BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
3132         BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
3133         BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
3134         BuffersInW.Next = NULL;
3135     }
3136 
3137     rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
3138 
3139     HeapFree(GetProcessHeap(),0,header);
3140 
3141     return rc;
3142 }
3143 
3144 /***********************************************************************
3145  *           HttpSendRequestExW (WININET.@)
3146  *
3147  * Sends the specified request to the HTTP server and allows chunked
3148  * transfers
3149  *
3150  * RETURNS
3151  *  Success: TRUE
3152  *  Failure: FALSE, call GetLastError() for more information.
3153  */
3154 BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
3155                    LPINTERNET_BUFFERSW lpBuffersIn,
3156                    LPINTERNET_BUFFERSW lpBuffersOut,
3157                    DWORD dwFlags, DWORD_PTR dwContext)
3158 {
3159     BOOL ret = FALSE;
3160     http_request_t *lpwhr;
3161     http_session_t *lpwhs;
3162     appinfo_t *hIC;
3163 
3164     TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
3165             lpBuffersOut, dwFlags, dwContext);
3166 
3167     lpwhr = (http_request_t*) WININET_GetObject( hRequest );
3168 
3169     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
3170     {
3171         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3172         goto lend;
3173     }
3174 
3175     lpwhs = lpwhr->lpHttpSession;
3176     assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
3177     hIC = lpwhs->lpAppInfo;
3178     assert(hIC->hdr.htype == WH_HINIT);
3179 
3180     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3181     {
3182         WORKREQUEST workRequest;
3183         struct WORKREQ_HTTPSENDREQUESTW *req;
3184 
3185         workRequest.asyncproc = AsyncHttpSendRequestProc;
3186         workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
3187         req = &workRequest.u.HttpSendRequestW;
3188         if (lpBuffersIn)
3189         {
3190             /* FIXME: this should use dwHeadersLength or may not be necessary at all */
3191             req->lpszHeader = heap_strdupW(lpBuffersIn->lpcszHeader);
3192             req->dwHeaderLength = lpBuffersIn->dwHeadersLength;
3193             req->lpOptional = lpBuffersIn->lpvBuffer;
3194             req->dwOptionalLength = lpBuffersIn->dwBufferLength;
3195             req->dwContentLength = lpBuffersIn->dwBufferTotal;
3196         }
3197         else
3198         {
3199             req->lpszHeader = NULL;
3200             req->dwHeaderLength = 0;
3201             req->lpOptional = NULL;
3202             req->dwOptionalLength = 0;
3203             req->dwContentLength = 0;
3204         }
3205 
3206         req->bEndRequest = FALSE;
3207 
3208         INTERNET_AsyncCall(&workRequest);
3209         /*
3210          * This is from windows.
3211          */
3212         INTERNET_SetLastError(ERROR_IO_PENDING);
3213     }
3214     else
3215     {
3216         if (lpBuffersIn)
3217             ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
3218                                         lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
3219                                         lpBuffersIn->dwBufferTotal, FALSE);
3220         else
3221             ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
3222     }
3223 
3224 lend:
3225     if ( lpwhr )
3226         WININET_Release( &lpwhr->hdr );
3227 
3228     TRACE("<---\n");
3229     return ret;
3230 }
3231 
3232 /***********************************************************************
3233  *           HttpSendRequestW (WININET.@)
3234  *
3235  * Sends the specified request to the HTTP server
3236  *
3237  * RETURNS
3238  *    TRUE  on success
3239  *    FALSE on failure
3240  *
3241  */
3242 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
3243         DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
3244 {
3245     http_request_t *lpwhr;
3246     http_session_t *lpwhs = NULL;
3247     appinfo_t *hIC = NULL;
3248     BOOL r;
3249 
3250     TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
3251             debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
3252 
3253     lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
3254     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
3255     {
3256         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3257         r = FALSE;
3258         goto lend;
3259     }
3260 
3261     lpwhs = lpwhr->lpHttpSession;
3262     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
3263     {
3264         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3265         r = FALSE;
3266         goto lend;
3267     }
3268 
3269     hIC = lpwhs->lpAppInfo;
3270     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT)
3271     {
3272         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3273         r = FALSE;
3274         goto lend;
3275     }
3276 
3277     if (hIC->hdr.dwFlags &