wininet: Directly return error status from refill_buffer.
[wine] / dlls / wininet / http.c
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',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 typedef struct _authorizationData
181 {
182     struct list entry;
183
184     LPWSTR lpszwHost;
185     LPWSTR lpszwRealm;
186     LPSTR  lpszAuthorization;
187     UINT   AuthorizationLen;
188 } authorizationData;
189
190 static struct list basicAuthorizationCache = LIST_INIT(basicAuthorizationCache);
191
192 static CRITICAL_SECTION authcache_cs;
193 static CRITICAL_SECTION_DEBUG critsect_debug =
194 {
195     0, 0, &authcache_cs,
196     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
197       0, 0, { (DWORD_PTR)(__FILE__ ": authcache_cs") }
198 };
199 static CRITICAL_SECTION authcache_cs = { &critsect_debug, -1, 0, 0, 0, 0 };
200
201 static DWORD HTTP_OpenConnection(http_request_t *req);
202 static BOOL HTTP_GetResponseHeaders(http_request_t *req, BOOL clear);
203 static BOOL HTTP_ProcessHeader(http_request_t *req, LPCWSTR field, LPCWSTR value, DWORD dwModifier);
204 static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer);
205 static BOOL HTTP_InsertCustomHeader(http_request_t *req, LPHTTPHEADERW lpHdr);
206 static INT HTTP_GetCustomHeaderIndex(http_request_t *req, LPCWSTR lpszField, INT index, BOOL Request);
207 static BOOL HTTP_DeleteCustomHeader(http_request_t *req, DWORD index);
208 static LPWSTR HTTP_build_req( LPCWSTR *list, int len );
209 static BOOL HTTP_HttpQueryInfoW(http_request_t*, DWORD, LPVOID, LPDWORD, LPDWORD);
210 static LPWSTR HTTP_GetRedirectURL(http_request_t *req, LPCWSTR lpszUrl);
211 static BOOL HTTP_HandleRedirect(http_request_t *req, LPCWSTR lpszUrl);
212 static UINT HTTP_DecodeBase64(LPCWSTR base64, LPSTR bin);
213 static BOOL HTTP_VerifyValidHeader(http_request_t *req, LPCWSTR field);
214 static void HTTP_DrainContent(http_request_t *req);
215 static BOOL HTTP_FinishedReading(http_request_t *req);
216
217 static LPHTTPHEADERW HTTP_GetHeader(http_request_t *req, LPCWSTR head)
218 {
219     int HeaderIndex = 0;
220     HeaderIndex = HTTP_GetCustomHeaderIndex(req, head, 0, TRUE);
221     if (HeaderIndex == -1)
222         return NULL;
223     else
224         return &req->pCustHeaders[HeaderIndex];
225 }
226
227 #ifdef HAVE_ZLIB
228
229 static voidpf wininet_zalloc(voidpf opaque, uInt items, uInt size)
230 {
231     return HeapAlloc(GetProcessHeap(), 0, items*size);
232 }
233
234 static void wininet_zfree(voidpf opaque, voidpf address)
235 {
236     HeapFree(GetProcessHeap(), 0, address);
237 }
238
239 static void init_gzip_stream(http_request_t *req)
240 {
241     gzip_stream_t *gzip_stream;
242     int index, zres;
243
244     gzip_stream = HeapAlloc(GetProcessHeap(), 0, sizeof(gzip_stream_t));
245     gzip_stream->zstream.zalloc = wininet_zalloc;
246     gzip_stream->zstream.zfree = wininet_zfree;
247     gzip_stream->zstream.opaque = NULL;
248     gzip_stream->zstream.next_in = NULL;
249     gzip_stream->zstream.avail_in = 0;
250     gzip_stream->zstream.next_out = NULL;
251     gzip_stream->zstream.avail_out = 0;
252     gzip_stream->buf_pos = 0;
253     gzip_stream->buf_size = 0;
254     gzip_stream->end_of_data = FALSE;
255
256     zres = inflateInit2(&gzip_stream->zstream, 0x1f);
257     if(zres != Z_OK) {
258         ERR("inflateInit failed: %d\n", zres);
259         HeapFree(GetProcessHeap(), 0, gzip_stream);
260         return;
261     }
262
263     req->gzip_stream = gzip_stream;
264
265     index = HTTP_GetCustomHeaderIndex(req, szContent_Length, 0, FALSE);
266     if(index != -1)
267         HTTP_DeleteCustomHeader(req, index);
268 }
269
270 #else
271
272 static void init_gzip_stream(http_request_t *req)
273 {
274     ERR("gzip stream not supported, missing zlib.\n");
275 }
276
277 #endif
278
279 /* set the request content length based on the headers */
280 static DWORD set_content_length( http_request_t *lpwhr )
281 {
282     static const WCHAR szChunked[] = {'c','h','u','n','k','e','d',0};
283     WCHAR encoding[20];
284     DWORD size;
285
286     size = sizeof(lpwhr->dwContentLength);
287     if (!HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_CONTENT_LENGTH,
288                              &lpwhr->dwContentLength, &size, NULL))
289         lpwhr->dwContentLength = ~0u;
290
291     size = sizeof(encoding);
292     if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_TRANSFER_ENCODING, encoding, &size, NULL) &&
293         !strcmpiW(encoding, szChunked))
294     {
295         lpwhr->dwContentLength = ~0u;
296         lpwhr->read_chunked = TRUE;
297     }
298
299     if(lpwhr->decoding) {
300         int encoding_idx;
301
302         static const WCHAR gzipW[] = {'g','z','i','p',0};
303
304         encoding_idx = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Encoding, 0, FALSE);
305         if(encoding_idx != -1 && !strcmpiW(lpwhr->pCustHeaders[encoding_idx].lpszValue, gzipW))
306             init_gzip_stream(lpwhr);
307     }
308
309     return lpwhr->dwContentLength;
310 }
311
312 /***********************************************************************
313  *           HTTP_Tokenize (internal)
314  *
315  *  Tokenize a string, allocating memory for the tokens.
316  */
317 static LPWSTR * HTTP_Tokenize(LPCWSTR string, LPCWSTR token_string)
318 {
319     LPWSTR * token_array;
320     int tokens = 0;
321     int i;
322     LPCWSTR next_token;
323
324     if (string)
325     {
326         /* empty string has no tokens */
327         if (*string)
328             tokens++;
329         /* count tokens */
330         for (i = 0; string[i]; i++)
331         {
332             if (!strncmpW(string+i, token_string, strlenW(token_string)))
333             {
334                 DWORD j;
335                 tokens++;
336                 /* we want to skip over separators, but not the null terminator */
337                 for (j = 0; j < strlenW(token_string) - 1; j++)
338                     if (!string[i+j])
339                         break;
340                 i += j;
341             }
342         }
343     }
344
345     /* add 1 for terminating NULL */
346     token_array = HeapAlloc(GetProcessHeap(), 0, (tokens+1) * sizeof(*token_array));
347     token_array[tokens] = NULL;
348     if (!tokens)
349         return token_array;
350     for (i = 0; i < tokens; i++)
351     {
352         int len;
353         next_token = strstrW(string, token_string);
354         if (!next_token) next_token = string+strlenW(string);
355         len = next_token - string;
356         token_array[i] = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
357         memcpy(token_array[i], string, len*sizeof(WCHAR));
358         token_array[i][len] = '\0';
359         string = next_token+strlenW(token_string);
360     }
361     return token_array;
362 }
363
364 /***********************************************************************
365  *           HTTP_FreeTokens (internal)
366  *
367  *  Frees memory returned from HTTP_Tokenize.
368  */
369 static void HTTP_FreeTokens(LPWSTR * token_array)
370 {
371     int i;
372     for (i = 0; token_array[i]; i++)
373         HeapFree(GetProcessHeap(), 0, token_array[i]);
374     HeapFree(GetProcessHeap(), 0, token_array);
375 }
376
377 /* **********************************************************************
378  * 
379  * Helper functions for the HttpSendRequest(Ex) functions
380  * 
381  */
382 static void AsyncHttpSendRequestProc(WORKREQUEST *workRequest)
383 {
384     struct WORKREQ_HTTPSENDREQUESTW const *req = &workRequest->u.HttpSendRequestW;
385     http_request_t *lpwhr = (http_request_t*) workRequest->hdr;
386
387     TRACE("%p\n", lpwhr);
388
389     HTTP_HttpSendRequestW(lpwhr, req->lpszHeader,
390             req->dwHeaderLength, req->lpOptional, req->dwOptionalLength,
391             req->dwContentLength, req->bEndRequest);
392
393     HeapFree(GetProcessHeap(), 0, req->lpszHeader);
394 }
395
396 static void HTTP_FixURL(http_request_t *lpwhr)
397 {
398     static const WCHAR szSlash[] = { '/',0 };
399     static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
400
401     /* If we don't have a path we set it to root */
402     if (NULL == lpwhr->lpszPath)
403         lpwhr->lpszPath = heap_strdupW(szSlash);
404     else /* remove \r and \n*/
405     {
406         int nLen = strlenW(lpwhr->lpszPath);
407         while ((nLen >0 ) && ((lpwhr->lpszPath[nLen-1] == '\r')||(lpwhr->lpszPath[nLen-1] == '\n')))
408         {
409             nLen--;
410             lpwhr->lpszPath[nLen]='\0';
411         }
412         /* Replace '\' with '/' */
413         while (nLen>0) {
414             nLen--;
415             if (lpwhr->lpszPath[nLen] == '\\') lpwhr->lpszPath[nLen]='/';
416         }
417     }
418
419     if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
420                        lpwhr->lpszPath, strlenW(lpwhr->lpszPath), szHttp, strlenW(szHttp) )
421        && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
422     {
423         WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0, 
424                              (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR));
425         *fixurl = '/';
426         strcpyW(fixurl + 1, lpwhr->lpszPath);
427         HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
428         lpwhr->lpszPath = fixurl;
429     }
430 }
431
432 static LPWSTR HTTP_BuildHeaderRequestString( http_request_t *lpwhr, LPCWSTR verb, LPCWSTR path, LPCWSTR version )
433 {
434     LPWSTR requestString;
435     DWORD len, n;
436     LPCWSTR *req;
437     UINT i;
438     LPWSTR p;
439
440     static const WCHAR szSpace[] = { ' ',0 };
441     static const WCHAR szColon[] = { ':',' ',0 };
442     static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
443
444     /* allocate space for an array of all the string pointers to be added */
445     len = (lpwhr->nCustHeaders)*4 + 10;
446     req = HeapAlloc( GetProcessHeap(), 0, len*sizeof(LPCWSTR) );
447
448     /* add the verb, path and HTTP version string */
449     n = 0;
450     req[n++] = verb;
451     req[n++] = szSpace;
452     req[n++] = path;
453     req[n++] = szSpace;
454     req[n++] = version;
455
456     /* Append custom request headers */
457     for (i = 0; i < lpwhr->nCustHeaders; i++)
458     {
459         if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
460         {
461             req[n++] = szCrLf;
462             req[n++] = lpwhr->pCustHeaders[i].lpszField;
463             req[n++] = szColon;
464             req[n++] = lpwhr->pCustHeaders[i].lpszValue;
465
466             TRACE("Adding custom header %s (%s)\n",
467                    debugstr_w(lpwhr->pCustHeaders[i].lpszField),
468                    debugstr_w(lpwhr->pCustHeaders[i].lpszValue));
469         }
470     }
471
472     if( n >= len )
473         ERR("oops. buffer overrun\n");
474
475     req[n] = NULL;
476     requestString = HTTP_build_req( req, 4 );
477     HeapFree( GetProcessHeap(), 0, req );
478
479     /*
480      * Set (header) termination string for request
481      * Make sure there's exactly two new lines at the end of the request
482      */
483     p = &requestString[strlenW(requestString)-1];
484     while ( (*p == '\n') || (*p == '\r') )
485        p--;
486     strcpyW( p+1, sztwocrlf );
487     
488     return requestString;
489 }
490
491 static void HTTP_ProcessCookies( http_request_t *lpwhr )
492 {
493     int HeaderIndex;
494     int numCookies = 0;
495     LPHTTPHEADERW setCookieHeader;
496
497     while((HeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSet_Cookie, numCookies, FALSE)) != -1)
498     {
499         setCookieHeader = &lpwhr->pCustHeaders[HeaderIndex];
500
501         if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && setCookieHeader->lpszValue)
502         {
503             int len;
504             static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','%','s',0};
505             LPWSTR buf_url;
506             LPHTTPHEADERW Host;
507
508             Host = HTTP_GetHeader(lpwhr, hostW);
509             len = lstrlenW(Host->lpszValue) + 9 + lstrlenW(lpwhr->lpszPath);
510             buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
511             sprintfW(buf_url, szFmt, Host->lpszValue, lpwhr->lpszPath);
512             InternetSetCookieW(buf_url, NULL, setCookieHeader->lpszValue);
513
514             HeapFree(GetProcessHeap(), 0, buf_url);
515         }
516         numCookies++;
517     }
518 }
519
520 static void strip_spaces(LPWSTR start)
521 {
522     LPWSTR str = start;
523     LPWSTR end;
524
525     while (*str == ' ' && *str != '\0')
526         str++;
527
528     if (str != start)
529         memmove(start, str, sizeof(WCHAR) * (strlenW(str) + 1));
530
531     end = start + strlenW(start) - 1;
532     while (end >= start && *end == ' ')
533     {
534         *end = '\0';
535         end--;
536     }
537 }
538
539 static inline BOOL is_basic_auth_value( LPCWSTR pszAuthValue, LPWSTR *pszRealm )
540 {
541     static const WCHAR szBasic[] = {'B','a','s','i','c'}; /* Note: not nul-terminated */
542     static const WCHAR szRealm[] = {'r','e','a','l','m'}; /* Note: not nul-terminated */
543     BOOL is_basic;
544     is_basic = !strncmpiW(pszAuthValue, szBasic, ARRAYSIZE(szBasic)) &&
545         ((pszAuthValue[ARRAYSIZE(szBasic)] == ' ') || !pszAuthValue[ARRAYSIZE(szBasic)]);
546     if (is_basic && pszRealm)
547     {
548         LPCWSTR token;
549         LPCWSTR ptr = &pszAuthValue[ARRAYSIZE(szBasic)];
550         LPCWSTR realm;
551         ptr++;
552         *pszRealm=NULL;
553         token = strchrW(ptr,'=');
554         if (!token)
555             return TRUE;
556         realm = ptr;
557         while (*realm == ' ' && *realm != '\0')
558             realm++;
559         if(!strncmpiW(realm, szRealm, ARRAYSIZE(szRealm)) &&
560             (realm[ARRAYSIZE(szRealm)] == ' ' || realm[ARRAYSIZE(szRealm)] == '='))
561         {
562             token++;
563             while (*token == ' ' && *token != '\0')
564                 token++;
565             if (*token == '\0')
566                 return TRUE;
567             *pszRealm = heap_strdupW(token);
568             strip_spaces(*pszRealm);
569         }
570     }
571
572     return is_basic;
573 }
574
575 static void destroy_authinfo( struct HttpAuthInfo *authinfo )
576 {
577     if (!authinfo) return;
578
579     if (SecIsValidHandle(&authinfo->ctx))
580         DeleteSecurityContext(&authinfo->ctx);
581     if (SecIsValidHandle(&authinfo->cred))
582         FreeCredentialsHandle(&authinfo->cred);
583
584     HeapFree(GetProcessHeap(), 0, authinfo->auth_data);
585     HeapFree(GetProcessHeap(), 0, authinfo->scheme);
586     HeapFree(GetProcessHeap(), 0, authinfo);
587 }
588
589 static UINT retrieve_cached_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR *auth_data)
590 {
591     authorizationData *ad;
592     UINT rc = 0;
593
594     TRACE("Looking for authorization for %s:%s\n",debugstr_w(host),debugstr_w(realm));
595
596     EnterCriticalSection(&authcache_cs);
597     LIST_FOR_EACH_ENTRY(ad, &basicAuthorizationCache, authorizationData, entry)
598     {
599         if (!strcmpiW(host,ad->lpszwHost) && !strcmpW(realm,ad->lpszwRealm))
600         {
601             TRACE("Authorization found in cache\n");
602             *auth_data = HeapAlloc(GetProcessHeap(),0,ad->AuthorizationLen);
603             memcpy(*auth_data,ad->lpszAuthorization,ad->AuthorizationLen);
604             rc = ad->AuthorizationLen;
605             break;
606         }
607     }
608     LeaveCriticalSection(&authcache_cs);
609     return rc;
610 }
611
612 static void cache_basic_authorization(LPWSTR host, LPWSTR realm, LPSTR auth_data, UINT auth_data_len)
613 {
614     struct list *cursor;
615     authorizationData* ad = NULL;
616
617     TRACE("caching authorization for %s:%s = %s\n",debugstr_w(host),debugstr_w(realm),debugstr_an(auth_data,auth_data_len));
618
619     EnterCriticalSection(&authcache_cs);
620     LIST_FOR_EACH(cursor, &basicAuthorizationCache)
621     {
622         authorizationData *check = LIST_ENTRY(cursor,authorizationData,entry);
623         if (!strcmpiW(host,check->lpszwHost) && !strcmpW(realm,check->lpszwRealm))
624         {
625             ad = check;
626             break;
627         }
628     }
629
630     if (ad)
631     {
632         TRACE("Found match in cache, replacing\n");
633         HeapFree(GetProcessHeap(),0,ad->lpszAuthorization);
634         ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len);
635         memcpy(ad->lpszAuthorization, auth_data, auth_data_len);
636         ad->AuthorizationLen = auth_data_len;
637     }
638     else
639     {
640         ad = HeapAlloc(GetProcessHeap(),0,sizeof(authorizationData));
641         ad->lpszwHost = heap_strdupW(host);
642         ad->lpszwRealm = heap_strdupW(realm);
643         ad->lpszAuthorization = HeapAlloc(GetProcessHeap(),0,auth_data_len);
644         memcpy(ad->lpszAuthorization, auth_data, auth_data_len);
645         ad->AuthorizationLen = auth_data_len;
646         list_add_head(&basicAuthorizationCache,&ad->entry);
647         TRACE("authorization cached\n");
648     }
649     LeaveCriticalSection(&authcache_cs);
650 }
651
652 static BOOL HTTP_DoAuthorization( http_request_t *lpwhr, LPCWSTR pszAuthValue,
653                                   struct HttpAuthInfo **ppAuthInfo,
654                                   LPWSTR domain_and_username, LPWSTR password,
655                                   LPWSTR host )
656 {
657     SECURITY_STATUS sec_status;
658     struct HttpAuthInfo *pAuthInfo = *ppAuthInfo;
659     BOOL first = FALSE;
660     LPWSTR szRealm = NULL;
661
662     TRACE("%s\n", debugstr_w(pszAuthValue));
663
664     if (!pAuthInfo)
665     {
666         TimeStamp exp;
667
668         first = TRUE;
669         pAuthInfo = HeapAlloc(GetProcessHeap(), 0, sizeof(*pAuthInfo));
670         if (!pAuthInfo)
671             return FALSE;
672
673         SecInvalidateHandle(&pAuthInfo->cred);
674         SecInvalidateHandle(&pAuthInfo->ctx);
675         memset(&pAuthInfo->exp, 0, sizeof(pAuthInfo->exp));
676         pAuthInfo->attr = 0;
677         pAuthInfo->auth_data = NULL;
678         pAuthInfo->auth_data_len = 0;
679         pAuthInfo->finished = FALSE;
680
681         if (is_basic_auth_value(pszAuthValue,NULL))
682         {
683             static const WCHAR szBasic[] = {'B','a','s','i','c',0};
684             pAuthInfo->scheme = heap_strdupW(szBasic);
685             if (!pAuthInfo->scheme)
686             {
687                 HeapFree(GetProcessHeap(), 0, pAuthInfo);
688                 return FALSE;
689             }
690         }
691         else
692         {
693             PVOID pAuthData;
694             SEC_WINNT_AUTH_IDENTITY_W nt_auth_identity;
695
696             pAuthInfo->scheme = heap_strdupW(pszAuthValue);
697             if (!pAuthInfo->scheme)
698             {
699                 HeapFree(GetProcessHeap(), 0, pAuthInfo);
700                 return FALSE;
701             }
702
703             if (domain_and_username)
704             {
705                 WCHAR *user = strchrW(domain_and_username, '\\');
706                 WCHAR *domain = domain_and_username;
707
708                 /* FIXME: make sure scheme accepts SEC_WINNT_AUTH_IDENTITY before calling AcquireCredentialsHandle */
709
710                 pAuthData = &nt_auth_identity;
711
712                 if (user) user++;
713                 else
714                 {
715                     user = domain_and_username;
716                     domain = NULL;
717                 }
718
719                 nt_auth_identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
720                 nt_auth_identity.User = user;
721                 nt_auth_identity.UserLength = strlenW(nt_auth_identity.User);
722                 nt_auth_identity.Domain = domain;
723                 nt_auth_identity.DomainLength = domain ? user - domain - 1 : 0;
724                 nt_auth_identity.Password = password;
725                 nt_auth_identity.PasswordLength = strlenW(nt_auth_identity.Password);
726             }
727             else
728                 /* use default credentials */
729                 pAuthData = NULL;
730
731             sec_status = AcquireCredentialsHandleW(NULL, pAuthInfo->scheme,
732                                                    SECPKG_CRED_OUTBOUND, NULL,
733                                                    pAuthData, NULL,
734                                                    NULL, &pAuthInfo->cred,
735                                                    &exp);
736             if (sec_status == SEC_E_OK)
737             {
738                 PSecPkgInfoW sec_pkg_info;
739                 sec_status = QuerySecurityPackageInfoW(pAuthInfo->scheme, &sec_pkg_info);
740                 if (sec_status == SEC_E_OK)
741                 {
742                     pAuthInfo->max_token = sec_pkg_info->cbMaxToken;
743                     FreeContextBuffer(sec_pkg_info);
744                 }
745             }
746             if (sec_status != SEC_E_OK)
747             {
748                 WARN("AcquireCredentialsHandleW for scheme %s failed with error 0x%08x\n",
749                      debugstr_w(pAuthInfo->scheme), sec_status);
750                 HeapFree(GetProcessHeap(), 0, pAuthInfo->scheme);
751                 HeapFree(GetProcessHeap(), 0, pAuthInfo);
752                 return FALSE;
753             }
754         }
755         *ppAuthInfo = pAuthInfo;
756     }
757     else if (pAuthInfo->finished)
758         return FALSE;
759
760     if ((strlenW(pszAuthValue) < strlenW(pAuthInfo->scheme)) ||
761         strncmpiW(pszAuthValue, pAuthInfo->scheme, strlenW(pAuthInfo->scheme)))
762     {
763         ERR("authentication scheme changed from %s to %s\n",
764             debugstr_w(pAuthInfo->scheme), debugstr_w(pszAuthValue));
765         return FALSE;
766     }
767
768     if (is_basic_auth_value(pszAuthValue,&szRealm))
769     {
770         int userlen;
771         int passlen;
772         char *auth_data = NULL;
773         UINT auth_data_len = 0;
774
775         TRACE("basic authentication realm %s\n",debugstr_w(szRealm));
776
777         if (!domain_and_username)
778         {
779             if (host && szRealm)
780                 auth_data_len = retrieve_cached_basic_authorization(host, szRealm,&auth_data);
781             if (auth_data_len == 0)
782             {
783                 HeapFree(GetProcessHeap(),0,szRealm);
784                 return FALSE;
785             }
786         }
787         else
788         {
789             userlen = WideCharToMultiByte(CP_UTF8, 0, domain_and_username, lstrlenW(domain_and_username), NULL, 0, NULL, NULL);
790             passlen = WideCharToMultiByte(CP_UTF8, 0, password, lstrlenW(password), NULL, 0, NULL, NULL);
791
792             /* length includes a nul terminator, which will be re-used for the ':' */
793             auth_data = HeapAlloc(GetProcessHeap(), 0, userlen + 1 + passlen);
794             if (!auth_data)
795             {
796                 HeapFree(GetProcessHeap(),0,szRealm);
797                 return FALSE;
798             }
799
800             WideCharToMultiByte(CP_UTF8, 0, domain_and_username, -1, auth_data, userlen, NULL, NULL);
801             auth_data[userlen] = ':';
802             WideCharToMultiByte(CP_UTF8, 0, password, -1, &auth_data[userlen+1], passlen, NULL, NULL);
803             auth_data_len = userlen + 1 + passlen;
804             if (host && szRealm)
805                 cache_basic_authorization(host, szRealm, auth_data, auth_data_len);
806         }
807
808         pAuthInfo->auth_data = auth_data;
809         pAuthInfo->auth_data_len = auth_data_len;
810         pAuthInfo->finished = TRUE;
811         HeapFree(GetProcessHeap(),0,szRealm);
812
813         return TRUE;
814     }
815     else
816     {
817         LPCWSTR pszAuthData;
818         SecBufferDesc out_desc, in_desc;
819         SecBuffer out, in;
820         unsigned char *buffer;
821         ULONG context_req = ISC_REQ_CONNECTION | ISC_REQ_USE_DCE_STYLE |
822             ISC_REQ_MUTUAL_AUTH | ISC_REQ_DELEGATE;
823
824         in.BufferType = SECBUFFER_TOKEN;
825         in.cbBuffer = 0;
826         in.pvBuffer = NULL;
827
828         in_desc.ulVersion = 0;
829         in_desc.cBuffers = 1;
830         in_desc.pBuffers = &in;
831
832         pszAuthData = pszAuthValue + strlenW(pAuthInfo->scheme);
833         if (*pszAuthData == ' ')
834         {
835             pszAuthData++;
836             in.cbBuffer = HTTP_DecodeBase64(pszAuthData, NULL);
837             in.pvBuffer = HeapAlloc(GetProcessHeap(), 0, in.cbBuffer);
838             HTTP_DecodeBase64(pszAuthData, in.pvBuffer);
839         }
840
841         buffer = HeapAlloc(GetProcessHeap(), 0, pAuthInfo->max_token);
842
843         out.BufferType = SECBUFFER_TOKEN;
844         out.cbBuffer = pAuthInfo->max_token;
845         out.pvBuffer = buffer;
846
847         out_desc.ulVersion = 0;
848         out_desc.cBuffers = 1;
849         out_desc.pBuffers = &out;
850
851         sec_status = InitializeSecurityContextW(first ? &pAuthInfo->cred : NULL,
852                                                 first ? NULL : &pAuthInfo->ctx,
853                                                 first ? lpwhr->lpHttpSession->lpszServerName : NULL,
854                                                 context_req, 0, SECURITY_NETWORK_DREP,
855                                                 in.pvBuffer ? &in_desc : NULL,
856                                                 0, &pAuthInfo->ctx, &out_desc,
857                                                 &pAuthInfo->attr, &pAuthInfo->exp);
858         if (sec_status == SEC_E_OK)
859         {
860             pAuthInfo->finished = TRUE;
861             pAuthInfo->auth_data = out.pvBuffer;
862             pAuthInfo->auth_data_len = out.cbBuffer;
863             TRACE("sending last auth packet\n");
864         }
865         else if (sec_status == SEC_I_CONTINUE_NEEDED)
866         {
867             pAuthInfo->auth_data = out.pvBuffer;
868             pAuthInfo->auth_data_len = out.cbBuffer;
869             TRACE("sending next auth packet\n");
870         }
871         else
872         {
873             ERR("InitializeSecurityContextW returned error 0x%08x\n", sec_status);
874             HeapFree(GetProcessHeap(), 0, out.pvBuffer);
875             destroy_authinfo(pAuthInfo);
876             *ppAuthInfo = NULL;
877             return FALSE;
878         }
879     }
880
881     return TRUE;
882 }
883
884 /***********************************************************************
885  *           HTTP_HttpAddRequestHeadersW (internal)
886  */
887 static BOOL HTTP_HttpAddRequestHeadersW(http_request_t *lpwhr,
888         LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
889 {
890     LPWSTR lpszStart;
891     LPWSTR lpszEnd;
892     LPWSTR buffer;
893     BOOL bSuccess = FALSE;
894     DWORD len;
895
896     TRACE("copying header: %s\n", debugstr_wn(lpszHeader, dwHeaderLength));
897
898     if( dwHeaderLength == ~0U )
899         len = strlenW(lpszHeader);
900     else
901         len = dwHeaderLength;
902     buffer = HeapAlloc( GetProcessHeap(), 0, sizeof(WCHAR)*(len+1) );
903     lstrcpynW( buffer, lpszHeader, len + 1);
904
905     lpszStart = buffer;
906
907     do
908     {
909         LPWSTR * pFieldAndValue;
910
911         lpszEnd = lpszStart;
912
913         while (*lpszEnd != '\0')
914         {
915             if (*lpszEnd == '\r' || *lpszEnd == '\n')
916                  break;
917             lpszEnd++;
918         }
919
920         if (*lpszStart == '\0')
921             break;
922
923         if (*lpszEnd == '\r' || *lpszEnd == '\n')
924         {
925             *lpszEnd = '\0';
926             lpszEnd++; /* Jump over newline */
927         }
928         TRACE("interpreting header %s\n", debugstr_w(lpszStart));
929         if (*lpszStart == '\0')
930         {
931             /* Skip 0-length headers */
932             lpszStart = lpszEnd;
933             bSuccess = TRUE;
934             continue;
935         }
936         pFieldAndValue = HTTP_InterpretHttpHeader(lpszStart);
937         if (pFieldAndValue)
938         {
939             bSuccess = HTTP_VerifyValidHeader(lpwhr, pFieldAndValue[0]);
940             if (bSuccess)
941                 bSuccess = HTTP_ProcessHeader(lpwhr, pFieldAndValue[0],
942                     pFieldAndValue[1], dwModifier | HTTP_ADDHDR_FLAG_REQ);
943             HTTP_FreeTokens(pFieldAndValue);
944         }
945
946         lpszStart = lpszEnd;
947     } while (bSuccess);
948
949     HeapFree(GetProcessHeap(), 0, buffer);
950
951     return bSuccess;
952 }
953
954 /***********************************************************************
955  *           HttpAddRequestHeadersW (WININET.@)
956  *
957  * Adds one or more HTTP header to the request handler
958  *
959  * NOTE
960  * On Windows if dwHeaderLength includes the trailing '\0', then
961  * HttpAddRequestHeadersW() adds it too. However this results in an
962  * invalid Http header which is rejected by some servers so we probably
963  * don't need to match Windows on that point.
964  *
965  * RETURNS
966  *    TRUE  on success
967  *    FALSE on failure
968  *
969  */
970 BOOL WINAPI HttpAddRequestHeadersW(HINTERNET hHttpRequest,
971         LPCWSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
972 {
973     BOOL bSuccess = FALSE;
974     http_request_t *lpwhr;
975
976     TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_wn(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
977
978     if (!lpszHeader) 
979       return TRUE;
980
981     lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
982     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
983     {
984         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
985         goto lend;
986     }
987     bSuccess = HTTP_HttpAddRequestHeadersW( lpwhr, lpszHeader, dwHeaderLength, dwModifier );
988 lend:
989     if( lpwhr )
990         WININET_Release( &lpwhr->hdr );
991
992     return bSuccess;
993 }
994
995 /***********************************************************************
996  *           HttpAddRequestHeadersA (WININET.@)
997  *
998  * Adds one or more HTTP header to the request handler
999  *
1000  * RETURNS
1001  *    TRUE  on success
1002  *    FALSE on failure
1003  *
1004  */
1005 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
1006         LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
1007 {
1008     DWORD len;
1009     LPWSTR hdr;
1010     BOOL r;
1011
1012     TRACE("%p, %s, %i, %i\n", hHttpRequest, debugstr_an(lpszHeader, dwHeaderLength), dwHeaderLength, dwModifier);
1013
1014     len = MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, NULL, 0 );
1015     hdr = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1016     MultiByteToWideChar( CP_ACP, 0, lpszHeader, dwHeaderLength, hdr, len );
1017     if( dwHeaderLength != ~0U )
1018         dwHeaderLength = len;
1019
1020     r = HttpAddRequestHeadersW( hHttpRequest, hdr, dwHeaderLength, dwModifier );
1021
1022     HeapFree( GetProcessHeap(), 0, hdr );
1023
1024     return r;
1025 }
1026
1027 /***********************************************************************
1028  *           HttpEndRequestA (WININET.@)
1029  *
1030  * Ends an HTTP request that was started by HttpSendRequestEx
1031  *
1032  * RETURNS
1033  *    TRUE      if successful
1034  *    FALSE     on failure
1035  *
1036  */
1037 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, 
1038         LPINTERNET_BUFFERSA lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
1039 {
1040     TRACE("(%p, %p, %08x, %08lx)\n", hRequest, lpBuffersOut, dwFlags, dwContext);
1041
1042     if (lpBuffersOut)
1043     {
1044         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1045         return FALSE;
1046     }
1047
1048     return HttpEndRequestW(hRequest, NULL, dwFlags, dwContext);
1049 }
1050
1051 static BOOL HTTP_HttpEndRequestW(http_request_t *lpwhr, DWORD dwFlags, DWORD_PTR dwContext)
1052 {
1053     BOOL rc = FALSE;
1054     INT responseLen;
1055     DWORD dwBufferSize;
1056     INTERNET_ASYNC_RESULT iar;
1057
1058     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1059                   INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1060
1061     responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
1062     if (responseLen)
1063         rc = TRUE;
1064
1065     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1066                   INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen, sizeof(DWORD));
1067
1068     /* process cookies here. Is this right? */
1069     HTTP_ProcessCookies(lpwhr);
1070
1071     if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
1072
1073     if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT))
1074     {
1075         DWORD dwCode,dwCodeLength = sizeof(DWORD);
1076         if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE, &dwCode, &dwCodeLength, NULL) &&
1077             (dwCode == 302 || dwCode == 301 || dwCode == 303))
1078         {
1079             WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
1080             dwBufferSize=sizeof(szNewLocation);
1081             if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_LOCATION, szNewLocation, &dwBufferSize, NULL))
1082             {
1083                 if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD))
1084                 {
1085                     HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1086                     lpwhr->lpszVerb = heap_strdupW(szGET);
1087                 }
1088                 HTTP_DrainContent(lpwhr);
1089                 if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation )))
1090                 {
1091                     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT,
1092                                           new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
1093                     rc = HTTP_HandleRedirect(lpwhr, new_url);
1094                     if (rc)
1095                         rc = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, TRUE);
1096                     HeapFree( GetProcessHeap(), 0, new_url );
1097                 }
1098             }
1099         }
1100     }
1101
1102     iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
1103     iar.dwError = rc ? 0 : INTERNET_GetLastError();
1104
1105     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1106                           INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1107                           sizeof(INTERNET_ASYNC_RESULT));
1108     return rc;
1109 }
1110
1111 static void AsyncHttpEndRequestProc(WORKREQUEST *work)
1112 {
1113     struct WORKREQ_HTTPENDREQUESTW const *req = &work->u.HttpEndRequestW;
1114     http_request_t *lpwhr = (http_request_t*)work->hdr;
1115
1116     TRACE("%p\n", lpwhr);
1117
1118     HTTP_HttpEndRequestW(lpwhr, req->dwFlags, req->dwContext);
1119 }
1120
1121 /***********************************************************************
1122  *           HttpEndRequestW (WININET.@)
1123  *
1124  * Ends an HTTP request that was started by HttpSendRequestEx
1125  *
1126  * RETURNS
1127  *    TRUE      if successful
1128  *    FALSE     on failure
1129  *
1130  */
1131 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, 
1132         LPINTERNET_BUFFERSW lpBuffersOut, DWORD dwFlags, DWORD_PTR dwContext)
1133 {
1134     BOOL rc = FALSE;
1135     http_request_t *lpwhr;
1136
1137     TRACE("-->\n");
1138
1139     if (lpBuffersOut)
1140     {
1141         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1142         return FALSE;
1143     }
1144
1145     lpwhr = (http_request_t*) WININET_GetObject( hRequest );
1146
1147     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1148     {
1149         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1150         if (lpwhr)
1151             WININET_Release( &lpwhr->hdr );
1152         return FALSE;
1153     }
1154     lpwhr->hdr.dwFlags |= dwFlags;
1155
1156     if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1157     {
1158         WORKREQUEST work;
1159         struct WORKREQ_HTTPENDREQUESTW *request;
1160
1161         work.asyncproc = AsyncHttpEndRequestProc;
1162         work.hdr = WININET_AddRef( &lpwhr->hdr );
1163
1164         request = &work.u.HttpEndRequestW;
1165         request->dwFlags = dwFlags;
1166         request->dwContext = dwContext;
1167
1168         INTERNET_AsyncCall(&work);
1169         INTERNET_SetLastError(ERROR_IO_PENDING);
1170     }
1171     else
1172         rc = HTTP_HttpEndRequestW(lpwhr, dwFlags, dwContext);
1173
1174     WININET_Release( &lpwhr->hdr );
1175     TRACE("%i <--\n",rc);
1176     return rc;
1177 }
1178
1179 /***********************************************************************
1180  *           HttpOpenRequestW (WININET.@)
1181  *
1182  * Open a HTTP request handle
1183  *
1184  * RETURNS
1185  *    HINTERNET  a HTTP request handle on success
1186  *    NULL       on failure
1187  *
1188  */
1189 HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
1190         LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
1191         LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
1192         DWORD dwFlags, DWORD_PTR dwContext)
1193 {
1194     http_session_t *lpwhs;
1195     HINTERNET handle = NULL;
1196
1197     TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
1198           debugstr_w(lpszVerb), debugstr_w(lpszObjectName),
1199           debugstr_w(lpszVersion), debugstr_w(lpszReferrer), lpszAcceptTypes,
1200           dwFlags, dwContext);
1201     if(lpszAcceptTypes!=NULL)
1202     {
1203         int i;
1204         for(i=0;lpszAcceptTypes[i]!=NULL;i++)
1205             TRACE("\taccept type: %s\n",debugstr_w(lpszAcceptTypes[i]));
1206     }    
1207
1208     lpwhs = (http_session_t*) WININET_GetObject( hHttpSession );
1209     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
1210     {
1211         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1212         goto lend;
1213     }
1214
1215     /*
1216      * My tests seem to show that the windows version does not
1217      * become asynchronous until after this point. And anyhow
1218      * if this call was asynchronous then how would you get the
1219      * necessary HINTERNET pointer returned by this function.
1220      *
1221      */
1222     handle = HTTP_HttpOpenRequestW(lpwhs, lpszVerb, lpszObjectName,
1223                                    lpszVersion, lpszReferrer, lpszAcceptTypes,
1224                                    dwFlags, dwContext);
1225 lend:
1226     if( lpwhs )
1227         WININET_Release( &lpwhs->hdr );
1228     TRACE("returning %p\n", handle);
1229     return handle;
1230 }
1231
1232
1233 /***********************************************************************
1234  *           HttpOpenRequestA (WININET.@)
1235  *
1236  * Open a HTTP request handle
1237  *
1238  * RETURNS
1239  *    HINTERNET  a HTTP request handle on success
1240  *    NULL       on failure
1241  *
1242  */
1243 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
1244         LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
1245         LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
1246         DWORD dwFlags, DWORD_PTR dwContext)
1247 {
1248     LPWSTR szVerb = NULL, szObjectName = NULL;
1249     LPWSTR szVersion = NULL, szReferrer = NULL, *szAcceptTypes = NULL;
1250     INT acceptTypesCount;
1251     HINTERNET rc = FALSE;
1252     LPCSTR *types;
1253
1254     TRACE("(%p, %s, %s, %s, %s, %p, %08x, %08lx)\n", hHttpSession,
1255           debugstr_a(lpszVerb), debugstr_a(lpszObjectName),
1256           debugstr_a(lpszVersion), debugstr_a(lpszReferrer), lpszAcceptTypes,
1257           dwFlags, dwContext);
1258
1259     if (lpszVerb)
1260     {
1261         szVerb = heap_strdupAtoW(lpszVerb);
1262         if ( !szVerb )
1263             goto end;
1264     }
1265
1266     if (lpszObjectName)
1267     {
1268         szObjectName = heap_strdupAtoW(lpszObjectName);
1269         if ( !szObjectName )
1270             goto end;
1271     }
1272
1273     if (lpszVersion)
1274     {
1275         szVersion = heap_strdupAtoW(lpszVersion);
1276         if ( !szVersion )
1277             goto end;
1278     }
1279
1280     if (lpszReferrer)
1281     {
1282         szReferrer = heap_strdupAtoW(lpszReferrer);
1283         if ( !szReferrer )
1284             goto end;
1285     }
1286
1287     if (lpszAcceptTypes)
1288     {
1289         acceptTypesCount = 0;
1290         types = lpszAcceptTypes;
1291         while (*types)
1292         {
1293             __TRY
1294             {
1295                 /* find out how many there are */
1296                 if (*types && **types)
1297                 {
1298                     TRACE("accept type: %s\n", debugstr_a(*types));
1299                     acceptTypesCount++;
1300                 }
1301             }
1302             __EXCEPT_PAGE_FAULT
1303             {
1304                 WARN("invalid accept type pointer\n");
1305             }
1306             __ENDTRY;
1307             types++;
1308         }
1309         szAcceptTypes = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR *) * (acceptTypesCount+1));
1310         if (!szAcceptTypes) goto end;
1311
1312         acceptTypesCount = 0;
1313         types = lpszAcceptTypes;
1314         while (*types)
1315         {
1316             __TRY
1317             {
1318                 if (*types && **types)
1319                     szAcceptTypes[acceptTypesCount++] = heap_strdupAtoW(*types);
1320             }
1321             __EXCEPT_PAGE_FAULT
1322             {
1323                 /* ignore invalid pointer */
1324             }
1325             __ENDTRY;
1326             types++;
1327         }
1328         szAcceptTypes[acceptTypesCount] = NULL;
1329     }
1330
1331     rc = HttpOpenRequestW(hHttpSession, szVerb, szObjectName,
1332                           szVersion, szReferrer,
1333                           (LPCWSTR*)szAcceptTypes, dwFlags, dwContext);
1334
1335 end:
1336     if (szAcceptTypes)
1337     {
1338         acceptTypesCount = 0;
1339         while (szAcceptTypes[acceptTypesCount])
1340         {
1341             HeapFree(GetProcessHeap(), 0, szAcceptTypes[acceptTypesCount]);
1342             acceptTypesCount++;
1343         }
1344         HeapFree(GetProcessHeap(), 0, szAcceptTypes);
1345     }
1346     HeapFree(GetProcessHeap(), 0, szReferrer);
1347     HeapFree(GetProcessHeap(), 0, szVersion);
1348     HeapFree(GetProcessHeap(), 0, szObjectName);
1349     HeapFree(GetProcessHeap(), 0, szVerb);
1350
1351     return rc;
1352 }
1353
1354 /***********************************************************************
1355  *  HTTP_EncodeBase64
1356  */
1357 static UINT HTTP_EncodeBase64( LPCSTR bin, unsigned int len, LPWSTR base64 )
1358 {
1359     UINT n = 0, x;
1360     static const CHAR HTTP_Base64Enc[] =
1361         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1362
1363     while( len > 0 )
1364     {
1365         /* first 6 bits, all from bin[0] */
1366         base64[n++] = HTTP_Base64Enc[(bin[0] & 0xfc) >> 2];
1367         x = (bin[0] & 3) << 4;
1368
1369         /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
1370         if( len == 1 )
1371         {
1372             base64[n++] = HTTP_Base64Enc[x];
1373             base64[n++] = '=';
1374             base64[n++] = '=';
1375             break;
1376         }
1377         base64[n++] = HTTP_Base64Enc[ x | ( (bin[1]&0xf0) >> 4 ) ];
1378         x = ( bin[1] & 0x0f ) << 2;
1379
1380         /* next 6 bits 4 from bin[1] and 2 from bin[2] */
1381         if( len == 2 )
1382         {
1383             base64[n++] = HTTP_Base64Enc[x];
1384             base64[n++] = '=';
1385             break;
1386         }
1387         base64[n++] = HTTP_Base64Enc[ x | ( (bin[2]&0xc0 ) >> 6 ) ];
1388
1389         /* last 6 bits, all from bin [2] */
1390         base64[n++] = HTTP_Base64Enc[ bin[2] & 0x3f ];
1391         bin += 3;
1392         len -= 3;
1393     }
1394     base64[n] = 0;
1395     return n;
1396 }
1397
1398 #define CH(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' : \
1399                ((x) >= 'a' && (x) <= 'z') ? (x) - 'a' + 26 : \
1400                ((x) >= '0' && (x) <= '9') ? (x) - '0' + 52 : \
1401                ((x) == '+') ? 62 : ((x) == '/') ? 63 : -1)
1402 static const signed char HTTP_Base64Dec[256] =
1403 {
1404     CH( 0),CH( 1),CH( 2),CH( 3),CH( 4),CH( 5),CH( 6),CH( 7),CH( 8),CH( 9),
1405     CH(10),CH(11),CH(12),CH(13),CH(14),CH(15),CH(16),CH(17),CH(18),CH(19),
1406     CH(20),CH(21),CH(22),CH(23),CH(24),CH(25),CH(26),CH(27),CH(28),CH(29),
1407     CH(30),CH(31),CH(32),CH(33),CH(34),CH(35),CH(36),CH(37),CH(38),CH(39),
1408     CH(40),CH(41),CH(42),CH(43),CH(44),CH(45),CH(46),CH(47),CH(48),CH(49),
1409     CH(50),CH(51),CH(52),CH(53),CH(54),CH(55),CH(56),CH(57),CH(58),CH(59),
1410     CH(60),CH(61),CH(62),CH(63),CH(64),CH(65),CH(66),CH(67),CH(68),CH(69),
1411     CH(70),CH(71),CH(72),CH(73),CH(74),CH(75),CH(76),CH(77),CH(78),CH(79),
1412     CH(80),CH(81),CH(82),CH(83),CH(84),CH(85),CH(86),CH(87),CH(88),CH(89),
1413     CH(90),CH(91),CH(92),CH(93),CH(94),CH(95),CH(96),CH(97),CH(98),CH(99),
1414     CH(100),CH(101),CH(102),CH(103),CH(104),CH(105),CH(106),CH(107),CH(108),CH(109),
1415     CH(110),CH(111),CH(112),CH(113),CH(114),CH(115),CH(116),CH(117),CH(118),CH(119),
1416     CH(120),CH(121),CH(122),CH(123),CH(124),CH(125),CH(126),CH(127),CH(128),CH(129),
1417     CH(130),CH(131),CH(132),CH(133),CH(134),CH(135),CH(136),CH(137),CH(138),CH(139),
1418     CH(140),CH(141),CH(142),CH(143),CH(144),CH(145),CH(146),CH(147),CH(148),CH(149),
1419     CH(150),CH(151),CH(152),CH(153),CH(154),CH(155),CH(156),CH(157),CH(158),CH(159),
1420     CH(160),CH(161),CH(162),CH(163),CH(164),CH(165),CH(166),CH(167),CH(168),CH(169),
1421     CH(170),CH(171),CH(172),CH(173),CH(174),CH(175),CH(176),CH(177),CH(178),CH(179),
1422     CH(180),CH(181),CH(182),CH(183),CH(184),CH(185),CH(186),CH(187),CH(188),CH(189),
1423     CH(190),CH(191),CH(192),CH(193),CH(194),CH(195),CH(196),CH(197),CH(198),CH(199),
1424     CH(200),CH(201),CH(202),CH(203),CH(204),CH(205),CH(206),CH(207),CH(208),CH(209),
1425     CH(210),CH(211),CH(212),CH(213),CH(214),CH(215),CH(216),CH(217),CH(218),CH(219),
1426     CH(220),CH(221),CH(222),CH(223),CH(224),CH(225),CH(226),CH(227),CH(228),CH(229),
1427     CH(230),CH(231),CH(232),CH(233),CH(234),CH(235),CH(236),CH(237),CH(238),CH(239),
1428     CH(240),CH(241),CH(242),CH(243),CH(244),CH(245),CH(246),CH(247),CH(248), CH(249),
1429     CH(250),CH(251),CH(252),CH(253),CH(254),CH(255),
1430 };
1431 #undef CH
1432
1433 /***********************************************************************
1434  *  HTTP_DecodeBase64
1435  */
1436 static UINT HTTP_DecodeBase64( LPCWSTR base64, LPSTR bin )
1437 {
1438     unsigned int n = 0;
1439
1440     while(*base64)
1441     {
1442         signed char in[4];
1443
1444         if (base64[0] >= ARRAYSIZE(HTTP_Base64Dec) ||
1445             ((in[0] = HTTP_Base64Dec[base64[0]]) == -1) ||
1446             base64[1] >= ARRAYSIZE(HTTP_Base64Dec) ||
1447             ((in[1] = HTTP_Base64Dec[base64[1]]) == -1))
1448         {
1449             WARN("invalid base64: %s\n", debugstr_w(base64));
1450             return 0;
1451         }
1452         if (bin)
1453             bin[n] = (unsigned char) (in[0] << 2 | in[1] >> 4);
1454         n++;
1455
1456         if ((base64[2] == '=') && (base64[3] == '='))
1457             break;
1458         if (base64[2] > ARRAYSIZE(HTTP_Base64Dec) ||
1459             ((in[2] = HTTP_Base64Dec[base64[2]]) == -1))
1460         {
1461             WARN("invalid base64: %s\n", debugstr_w(&base64[2]));
1462             return 0;
1463         }
1464         if (bin)
1465             bin[n] = (unsigned char) (in[1] << 4 | in[2] >> 2);
1466         n++;
1467
1468         if (base64[3] == '=')
1469             break;
1470         if (base64[3] > ARRAYSIZE(HTTP_Base64Dec) ||
1471             ((in[3] = HTTP_Base64Dec[base64[3]]) == -1))
1472         {
1473             WARN("invalid base64: %s\n", debugstr_w(&base64[3]));
1474             return 0;
1475         }
1476         if (bin)
1477             bin[n] = (unsigned char) (((in[2] << 6) & 0xc0) | in[3]);
1478         n++;
1479
1480         base64 += 4;
1481     }
1482
1483     return n;
1484 }
1485
1486 /***********************************************************************
1487  *  HTTP_InsertAuthorization
1488  *
1489  *   Insert or delete the authorization field in the request header.
1490  */
1491 static BOOL HTTP_InsertAuthorization( http_request_t *lpwhr, struct HttpAuthInfo *pAuthInfo, LPCWSTR header )
1492 {
1493     if (pAuthInfo)
1494     {
1495         static const WCHAR wszSpace[] = {' ',0};
1496         static const WCHAR wszBasic[] = {'B','a','s','i','c',0};
1497         unsigned int len;
1498         WCHAR *authorization = NULL;
1499
1500         if (pAuthInfo->auth_data_len)
1501         {
1502             /* scheme + space + base64 encoded data (3/2/1 bytes data -> 4 bytes of characters) */
1503             len = strlenW(pAuthInfo->scheme)+1+((pAuthInfo->auth_data_len+2)*4)/3;
1504             authorization = HeapAlloc(GetProcessHeap(), 0, (len+1)*sizeof(WCHAR));
1505             if (!authorization)
1506                 return FALSE;
1507
1508             strcpyW(authorization, pAuthInfo->scheme);
1509             strcatW(authorization, wszSpace);
1510             HTTP_EncodeBase64(pAuthInfo->auth_data,
1511                               pAuthInfo->auth_data_len,
1512                               authorization+strlenW(authorization));
1513
1514             /* clear the data as it isn't valid now that it has been sent to the
1515              * server, unless it's Basic authentication which doesn't do
1516              * connection tracking */
1517             if (strcmpiW(pAuthInfo->scheme, wszBasic))
1518             {
1519                 HeapFree(GetProcessHeap(), 0, pAuthInfo->auth_data);
1520                 pAuthInfo->auth_data = NULL;
1521                 pAuthInfo->auth_data_len = 0;
1522             }
1523         }
1524
1525         TRACE("Inserting authorization: %s\n", debugstr_w(authorization));
1526
1527         HTTP_ProcessHeader(lpwhr, header, authorization, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
1528
1529         HeapFree(GetProcessHeap(), 0, authorization);
1530     }
1531     return TRUE;
1532 }
1533
1534 static WCHAR *HTTP_BuildProxyRequestUrl(http_request_t *req)
1535 {
1536     WCHAR new_location[INTERNET_MAX_URL_LENGTH], *url;
1537     DWORD size;
1538
1539     size = sizeof(new_location);
1540     if (HTTP_HttpQueryInfoW(req, HTTP_QUERY_LOCATION, new_location, &size, NULL))
1541     {
1542         if (!(url = HeapAlloc( GetProcessHeap(), 0, size + sizeof(WCHAR) ))) return NULL;
1543         strcpyW( url, new_location );
1544     }
1545     else
1546     {
1547         static const WCHAR slash[] = { '/',0 };
1548         static const WCHAR format[] = { 'h','t','t','p',':','/','/','%','s',':','%','d',0 };
1549         static const WCHAR formatSSL[] = { 'h','t','t','p','s',':','/','/','%','s',':','%','d',0 };
1550         http_session_t *session = req->lpHttpSession;
1551
1552         size = 16; /* "https://" + sizeof(port#) + ":/\0" */
1553         size += strlenW( session->lpszHostName ) + strlenW( req->lpszPath );
1554
1555         if (!(url = HeapAlloc( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL;
1556
1557         if (req->hdr.dwFlags & INTERNET_FLAG_SECURE)
1558             sprintfW( url, formatSSL, session->lpszHostName, session->nHostPort );
1559         else
1560             sprintfW( url, format, session->lpszHostName, session->nHostPort );
1561         if (req->lpszPath[0] != '/') strcatW( url, slash );
1562         strcatW( url, req->lpszPath );
1563     }
1564     TRACE("url=%s\n", debugstr_w(url));
1565     return url;
1566 }
1567
1568 /***********************************************************************
1569  *           HTTP_DealWithProxy
1570  */
1571 static BOOL HTTP_DealWithProxy(appinfo_t *hIC, http_session_t *lpwhs, http_request_t *lpwhr)
1572 {
1573     WCHAR buf[MAXHOSTNAME];
1574     WCHAR proxy[MAXHOSTNAME + 15]; /* 15 == "http://" + sizeof(port#) + ":/\0" */
1575     static WCHAR szNul[] = { 0 };
1576     URL_COMPONENTSW UrlComponents;
1577     static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/',0 };
1578     static const WCHAR szFormat[] = { 'h','t','t','p',':','/','/','%','s',0 };
1579
1580     memset( &UrlComponents, 0, sizeof UrlComponents );
1581     UrlComponents.dwStructSize = sizeof UrlComponents;
1582     UrlComponents.lpszHostName = buf;
1583     UrlComponents.dwHostNameLength = MAXHOSTNAME;
1584
1585     if( CSTR_EQUAL != CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
1586                                  hIC->lpszProxy,strlenW(szHttp),szHttp,strlenW(szHttp)) )
1587         sprintfW(proxy, szFormat, hIC->lpszProxy);
1588     else
1589         strcpyW(proxy, hIC->lpszProxy);
1590     if( !InternetCrackUrlW(proxy, 0, 0, &UrlComponents) )
1591         return FALSE;
1592     if( UrlComponents.dwHostNameLength == 0 )
1593         return FALSE;
1594
1595     if( !lpwhr->lpszPath )
1596         lpwhr->lpszPath = szNul;
1597
1598     if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1599         UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1600
1601     HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1602     lpwhs->lpszServerName = heap_strdupW(UrlComponents.lpszHostName);
1603     lpwhs->nServerPort = UrlComponents.nPort;
1604
1605     TRACE("proxy server=%s port=%d\n", debugstr_w(lpwhs->lpszServerName), lpwhs->nServerPort);
1606     return TRUE;
1607 }
1608
1609 #ifndef INET6_ADDRSTRLEN
1610 #define INET6_ADDRSTRLEN 46
1611 #endif
1612
1613 static DWORD HTTP_ResolveName(http_request_t *lpwhr)
1614 {
1615     char szaddr[INET6_ADDRSTRLEN];
1616     http_session_t *lpwhs = lpwhr->lpHttpSession;
1617     const void *addr;
1618
1619     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1620                           INTERNET_STATUS_RESOLVING_NAME,
1621                           lpwhs->lpszServerName,
1622                           strlenW(lpwhs->lpszServerName)+1);
1623
1624     lpwhs->sa_len = sizeof(lpwhs->socketAddress);
1625     if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
1626                     (struct sockaddr *)&lpwhs->socketAddress, &lpwhs->sa_len))
1627         return ERROR_INTERNET_NAME_NOT_RESOLVED;
1628
1629     switch (lpwhs->socketAddress.ss_family)
1630     {
1631     case AF_INET:
1632         addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr;
1633         break;
1634     case AF_INET6:
1635         addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr;
1636         break;
1637     default:
1638         WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family);
1639         return ERROR_INTERNET_NAME_NOT_RESOLVED;
1640     }
1641     inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr));
1642     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1643                           INTERNET_STATUS_NAME_RESOLVED,
1644                           szaddr, strlen(szaddr)+1);
1645
1646     TRACE("resolved %s to %s\n", debugstr_w(lpwhs->lpszServerName), szaddr);
1647     return ERROR_SUCCESS;
1648 }
1649
1650
1651 /***********************************************************************
1652  *           HTTPREQ_Destroy (internal)
1653  *
1654  * Deallocate request handle
1655  *
1656  */
1657 static void HTTPREQ_Destroy(object_header_t *hdr)
1658 {
1659     http_request_t *lpwhr = (http_request_t*) hdr;
1660     DWORD i;
1661
1662     TRACE("\n");
1663
1664     if(lpwhr->hCacheFile)
1665         CloseHandle(lpwhr->hCacheFile);
1666
1667     HeapFree(GetProcessHeap(), 0, lpwhr->lpszCacheFile);
1668
1669     DeleteCriticalSection( &lpwhr->read_section );
1670     WININET_Release(&lpwhr->lpHttpSession->hdr);
1671
1672     destroy_authinfo(lpwhr->pAuthInfo);
1673     destroy_authinfo(lpwhr->pProxyAuthInfo);
1674
1675     HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1676     HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1677     HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
1678     HeapFree(GetProcessHeap(), 0, lpwhr->lpszVersion);
1679     HeapFree(GetProcessHeap(), 0, lpwhr->lpszStatusText);
1680
1681     for (i = 0; i < lpwhr->nCustHeaders; i++)
1682     {
1683         HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
1684         HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
1685     }
1686
1687 #ifdef HAVE_ZLIB
1688     if(lpwhr->gzip_stream) {
1689         if(!lpwhr->gzip_stream->end_of_data)
1690             inflateEnd(&lpwhr->gzip_stream->zstream);
1691         HeapFree(GetProcessHeap(), 0, lpwhr->gzip_stream);
1692     }
1693 #endif
1694
1695     HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1696     HeapFree(GetProcessHeap(), 0, lpwhr);
1697 }
1698
1699 static void HTTPREQ_CloseConnection(object_header_t *hdr)
1700 {
1701     http_request_t *lpwhr = (http_request_t*) hdr;
1702
1703     TRACE("%p\n",lpwhr);
1704
1705     if (!NETCON_connected(&lpwhr->netConnection))
1706         return;
1707
1708     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1709                           INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
1710
1711     NETCON_close(&lpwhr->netConnection);
1712
1713     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
1714                           INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
1715 }
1716
1717 static BOOL HTTP_GetRequestURL(http_request_t *req, LPWSTR buf)
1718 {
1719     LPHTTPHEADERW host_header;
1720
1721     static const WCHAR formatW[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
1722
1723     host_header = HTTP_GetHeader(req, hostW);
1724     if(!host_header)
1725         return FALSE;
1726
1727     sprintfW(buf, formatW, host_header->lpszValue, req->lpszPath); /* FIXME */
1728     return TRUE;
1729 }
1730
1731 static BOOL HTTP_KeepAlive(http_request_t *lpwhr)
1732 {
1733     WCHAR szVersion[10];
1734     WCHAR szConnectionResponse[20];
1735     DWORD dwBufferSize = sizeof(szVersion);
1736     BOOL keepalive = FALSE;
1737
1738     /* as per RFC 2068, S8.1.2.1, if the client is HTTP/1.1 then assume that
1739      * the connection is keep-alive by default */
1740     if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_VERSION, szVersion,
1741                              &dwBufferSize, NULL) &&
1742         !strcmpiW(szVersion, g_szHttp1_1))
1743     {
1744         keepalive = TRUE;
1745     }
1746
1747     dwBufferSize = sizeof(szConnectionResponse);
1748     if (HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_PROXY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL) ||
1749         HTTP_HttpQueryInfoW(lpwhr, HTTP_QUERY_CONNECTION, szConnectionResponse, &dwBufferSize, NULL))
1750     {
1751         keepalive = !strcmpiW(szConnectionResponse, szKeepAlive);
1752     }
1753
1754     return keepalive;
1755 }
1756
1757 static DWORD HTTPREQ_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
1758 {
1759     http_request_t *req = (http_request_t*)hdr;
1760
1761     switch(option) {
1762     case INTERNET_OPTION_DIAGNOSTIC_SOCKET_INFO:
1763     {
1764         http_session_t *lpwhs = req->lpHttpSession;
1765         INTERNET_DIAGNOSTIC_SOCKET_INFO *info = buffer;
1766
1767         FIXME("INTERNET_DIAGNOSTIC_SOCKET_INFO stub\n");
1768
1769         if (*size < sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO))
1770             return ERROR_INSUFFICIENT_BUFFER;
1771         *size = sizeof(INTERNET_DIAGNOSTIC_SOCKET_INFO);
1772         /* FIXME: can't get a SOCKET from our connection since we don't use
1773          * winsock
1774          */
1775         info->Socket = 0;
1776         /* FIXME: get source port from req->netConnection */
1777         info->SourcePort = 0;
1778         info->DestPort = lpwhs->nHostPort;
1779         info->Flags = 0;
1780         if (HTTP_KeepAlive(req))
1781             info->Flags |= IDSI_FLAG_KEEP_ALIVE;
1782         if (lpwhs->lpAppInfo->lpszProxy && lpwhs->lpAppInfo->lpszProxy[0] != 0)
1783             info->Flags |= IDSI_FLAG_PROXY;
1784         if (req->netConnection.useSSL)
1785             info->Flags |= IDSI_FLAG_SECURE;
1786
1787         return ERROR_SUCCESS;
1788     }
1789
1790     case INTERNET_OPTION_SECURITY_FLAGS:
1791     {
1792         http_session_t *lpwhs;
1793         lpwhs = req->lpHttpSession;
1794
1795         if (*size < sizeof(ULONG))
1796             return ERROR_INSUFFICIENT_BUFFER;
1797
1798         *size = sizeof(DWORD);
1799         if (lpwhs->hdr.dwFlags & INTERNET_FLAG_SECURE)
1800             *(DWORD*)buffer = SECURITY_FLAG_SECURE;
1801         else
1802             *(DWORD*)buffer = 0;
1803         FIXME("Semi-STUB INTERNET_OPTION_SECURITY_FLAGS: %x\n",*(DWORD*)buffer);
1804         return ERROR_SUCCESS;
1805     }
1806
1807     case INTERNET_OPTION_HANDLE_TYPE:
1808         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
1809
1810         if (*size < sizeof(ULONG))
1811             return ERROR_INSUFFICIENT_BUFFER;
1812
1813         *size = sizeof(DWORD);
1814         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_HTTP_REQUEST;
1815         return ERROR_SUCCESS;
1816
1817     case INTERNET_OPTION_URL: {
1818         WCHAR url[INTERNET_MAX_URL_LENGTH];
1819         HTTPHEADERW *host;
1820         DWORD len;
1821         WCHAR *pch;
1822
1823         static const WCHAR httpW[] = {'h','t','t','p',':','/','/',0};
1824
1825         TRACE("INTERNET_OPTION_URL\n");
1826
1827         host = HTTP_GetHeader(req, hostW);
1828         strcpyW(url, httpW);
1829         strcatW(url, host->lpszValue);
1830         if (NULL != (pch = strchrW(url + strlenW(httpW), ':')))
1831             *pch = 0;
1832         strcatW(url, req->lpszPath);
1833
1834         TRACE("INTERNET_OPTION_URL: %s\n",debugstr_w(url));
1835
1836         if(unicode) {
1837             len = (strlenW(url)+1) * sizeof(WCHAR);
1838             if(*size < len)
1839                 return ERROR_INSUFFICIENT_BUFFER;
1840
1841             *size = len;
1842             strcpyW(buffer, url);
1843             return ERROR_SUCCESS;
1844         }else {
1845             len = WideCharToMultiByte(CP_ACP, 0, url, -1, buffer, *size, NULL, NULL);
1846             if(len > *size)
1847                 return ERROR_INSUFFICIENT_BUFFER;
1848
1849             *size = len;
1850             return ERROR_SUCCESS;
1851         }
1852     }
1853
1854     case INTERNET_OPTION_CACHE_TIMESTAMPS: {
1855         INTERNET_CACHE_ENTRY_INFOW *info;
1856         INTERNET_CACHE_TIMESTAMPS *ts = buffer;
1857         WCHAR url[INTERNET_MAX_URL_LENGTH];
1858         DWORD nbytes, error;
1859         BOOL ret;
1860
1861         TRACE("INTERNET_OPTION_CACHE_TIMESTAMPS\n");
1862
1863         if (*size < sizeof(*ts))
1864         {
1865             *size = sizeof(*ts);
1866             return ERROR_INSUFFICIENT_BUFFER;
1867         }
1868         nbytes = 0;
1869         HTTP_GetRequestURL(req, url);
1870         ret = GetUrlCacheEntryInfoW(url, NULL, &nbytes);
1871         error = GetLastError();
1872         if (!ret && error == ERROR_INSUFFICIENT_BUFFER)
1873         {
1874             if (!(info = HeapAlloc(GetProcessHeap(), 0, nbytes)))
1875                 return ERROR_OUTOFMEMORY;
1876
1877             GetUrlCacheEntryInfoW(url, info, &nbytes);
1878
1879             ts->ftExpires = info->ExpireTime;
1880             ts->ftLastModified = info->LastModifiedTime;
1881
1882             HeapFree(GetProcessHeap(), 0, info);
1883             *size = sizeof(*ts);
1884             return ERROR_SUCCESS;
1885         }
1886         return error;
1887     }
1888
1889     case INTERNET_OPTION_DATAFILE_NAME: {
1890         DWORD req_size;
1891
1892         TRACE("INTERNET_OPTION_DATAFILE_NAME\n");
1893
1894         if(!req->lpszCacheFile) {
1895             *size = 0;
1896             return ERROR_INTERNET_ITEM_NOT_FOUND;
1897         }
1898
1899         if(unicode) {
1900             req_size = (lstrlenW(req->lpszCacheFile)+1) * sizeof(WCHAR);
1901             if(*size < req_size)
1902                 return ERROR_INSUFFICIENT_BUFFER;
1903
1904             *size = req_size;
1905             memcpy(buffer, req->lpszCacheFile, *size);
1906             return ERROR_SUCCESS;
1907         }else {
1908             req_size = WideCharToMultiByte(CP_ACP, 0, req->lpszCacheFile, -1, NULL, 0, NULL, NULL);
1909             if (req_size > *size)
1910                 return ERROR_INSUFFICIENT_BUFFER;
1911
1912             *size = WideCharToMultiByte(CP_ACP, 0, req->lpszCacheFile,
1913                     -1, buffer, *size, NULL, NULL);
1914             return ERROR_SUCCESS;
1915         }
1916     }
1917
1918     case INTERNET_OPTION_SECURITY_CERTIFICATE_STRUCT: {
1919         PCCERT_CONTEXT context;
1920
1921         if(*size < sizeof(INTERNET_CERTIFICATE_INFOW)) {
1922             *size = sizeof(INTERNET_CERTIFICATE_INFOW);
1923             return ERROR_INSUFFICIENT_BUFFER;
1924         }
1925
1926         context = (PCCERT_CONTEXT)NETCON_GetCert(&(req->netConnection));
1927         if(context) {
1928             INTERNET_CERTIFICATE_INFOW *info = (INTERNET_CERTIFICATE_INFOW*)buffer;
1929             DWORD len;
1930
1931             memset(info, 0, sizeof(INTERNET_CERTIFICATE_INFOW));
1932             info->ftExpiry = context->pCertInfo->NotAfter;
1933             info->ftStart = context->pCertInfo->NotBefore;
1934             if(unicode) {
1935                 len = CertNameToStrW(context->dwCertEncodingType,
1936                         &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
1937                 info->lpszSubjectInfo = LocalAlloc(0, len*sizeof(WCHAR));
1938                 if(info->lpszSubjectInfo)
1939                     CertNameToStrW(context->dwCertEncodingType,
1940                              &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
1941                              info->lpszSubjectInfo, len);
1942                 len = CertNameToStrW(context->dwCertEncodingType,
1943                          &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
1944                 info->lpszIssuerInfo = LocalAlloc(0, len*sizeof(WCHAR));
1945                 if (info->lpszIssuerInfo)
1946                     CertNameToStrW(context->dwCertEncodingType,
1947                              &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
1948                              info->lpszIssuerInfo, len);
1949             }else {
1950                 INTERNET_CERTIFICATE_INFOA *infoA = (INTERNET_CERTIFICATE_INFOA*)info;
1951
1952                 len = CertNameToStrA(context->dwCertEncodingType,
1953                          &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR, NULL, 0);
1954                 infoA->lpszSubjectInfo = LocalAlloc(0, len);
1955                 if(infoA->lpszSubjectInfo)
1956                     CertNameToStrA(context->dwCertEncodingType,
1957                              &context->pCertInfo->Subject, CERT_SIMPLE_NAME_STR,
1958                              infoA->lpszSubjectInfo, len);
1959                 len = CertNameToStrA(context->dwCertEncodingType,
1960                          &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR, NULL, 0);
1961                 infoA->lpszIssuerInfo = LocalAlloc(0, len);
1962                 if(infoA->lpszIssuerInfo)
1963                     CertNameToStrA(context->dwCertEncodingType,
1964                              &context->pCertInfo->Issuer, CERT_SIMPLE_NAME_STR,
1965                              infoA->lpszIssuerInfo, len);
1966             }
1967
1968             /*
1969              * Contrary to MSDN, these do not appear to be set.
1970              * lpszProtocolName
1971              * lpszSignatureAlgName
1972              * lpszEncryptionAlgName
1973              * dwKeySize
1974              */
1975             CertFreeCertificateContext(context);
1976             return ERROR_SUCCESS;
1977         }
1978     }
1979     }
1980
1981     return INET_QueryOption(option, buffer, size, unicode);
1982 }
1983
1984 static DWORD HTTPREQ_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
1985 {
1986     http_request_t *req = (http_request_t*)hdr;
1987
1988     switch(option) {
1989     case INTERNET_OPTION_SEND_TIMEOUT:
1990     case INTERNET_OPTION_RECEIVE_TIMEOUT:
1991         TRACE("INTERNET_OPTION_SEND/RECEIVE_TIMEOUT\n");
1992
1993         if (size != sizeof(DWORD))
1994             return ERROR_INVALID_PARAMETER;
1995
1996         return NETCON_set_timeout(&req->netConnection, option == INTERNET_OPTION_SEND_TIMEOUT,
1997                     *(DWORD*)buffer);
1998
1999     case INTERNET_OPTION_USERNAME:
2000         HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszUserName);
2001         if (!(req->lpHttpSession->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
2002         return ERROR_SUCCESS;
2003
2004     case INTERNET_OPTION_PASSWORD:
2005         HeapFree(GetProcessHeap(), 0, req->lpHttpSession->lpszPassword);
2006         if (!(req->lpHttpSession->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
2007         return ERROR_SUCCESS;
2008     case INTERNET_OPTION_HTTP_DECODING:
2009         if(size != sizeof(BOOL))
2010             return ERROR_INVALID_PARAMETER;
2011         req->decoding = *(BOOL*)buffer;
2012         return ERROR_SUCCESS;
2013     }
2014
2015     return ERROR_INTERNET_INVALID_OPTION;
2016 }
2017
2018 /* read some more data into the read buffer (the read section must be held) */
2019 static DWORD read_more_data( http_request_t *req, int maxlen )
2020 {
2021     DWORD res;
2022     int len;
2023
2024     if (req->read_pos)
2025     {
2026         /* move existing data to the start of the buffer */
2027         if(req->read_size)
2028             memmove( req->read_buf, req->read_buf + req->read_pos, req->read_size );
2029         req->read_pos = 0;
2030     }
2031
2032     if (maxlen == -1) maxlen = sizeof(req->read_buf);
2033
2034     res = NETCON_recv( &req->netConnection, req->read_buf + req->read_size,
2035                        maxlen - req->read_size, 0, &len );
2036     if(res == ERROR_SUCCESS)
2037         req->read_size += len;
2038
2039     return res;
2040 }
2041
2042 /* remove some amount of data from the read buffer (the read section must be held) */
2043 static void remove_data( http_request_t *req, int count )
2044 {
2045     if (!(req->read_size -= count)) req->read_pos = 0;
2046     else req->read_pos += count;
2047 }
2048
2049 static BOOL read_line( http_request_t *req, LPSTR buffer, DWORD *len )
2050 {
2051     int count, bytes_read, pos = 0;
2052     DWORD res;
2053
2054     EnterCriticalSection( &req->read_section );
2055     for (;;)
2056     {
2057         BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
2058
2059         if (eol)
2060         {
2061             count = eol - (req->read_buf + req->read_pos);
2062             bytes_read = count + 1;
2063         }
2064         else count = bytes_read = req->read_size;
2065
2066         count = min( count, *len - pos );
2067         memcpy( buffer + pos, req->read_buf + req->read_pos, count );
2068         pos += count;
2069         remove_data( req, bytes_read );
2070         if (eol) break;
2071
2072         if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS || !req->read_size)
2073         {
2074             *len = 0;
2075             TRACE( "returning empty string\n" );
2076             LeaveCriticalSection( &req->read_section );
2077             INTERNET_SetLastError(res);
2078             return FALSE;
2079         }
2080     }
2081     LeaveCriticalSection( &req->read_section );
2082
2083     if (pos < *len)
2084     {
2085         if (pos && buffer[pos - 1] == '\r') pos--;
2086         *len = pos + 1;
2087     }
2088     buffer[*len - 1] = 0;
2089     TRACE( "returning %s\n", debugstr_a(buffer));
2090     return TRUE;
2091 }
2092
2093 /* discard data contents until we reach end of line (the read section must be held) */
2094 static DWORD discard_eol( http_request_t *req )
2095 {
2096     DWORD res;
2097
2098     do
2099     {
2100         BYTE *eol = memchr( req->read_buf + req->read_pos, '\n', req->read_size );
2101         if (eol)
2102         {
2103             remove_data( req, (eol + 1) - (req->read_buf + req->read_pos) );
2104             break;
2105         }
2106         req->read_pos = req->read_size = 0;  /* discard everything */
2107         if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res;
2108     } while (req->read_size);
2109     return ERROR_SUCCESS;
2110 }
2111
2112 /* read the size of the next chunk (the read section must be held) */
2113 static DWORD start_next_chunk( http_request_t *req )
2114 {
2115     DWORD chunk_size = 0, res;
2116
2117     if (!req->dwContentLength) return ERROR_SUCCESS;
2118     if (req->dwContentLength == req->dwContentRead)
2119     {
2120         /* read terminator for the previous chunk */
2121         if ((res = discard_eol( req )) != ERROR_SUCCESS) return res;
2122         req->dwContentLength = ~0u;
2123         req->dwContentRead = 0;
2124     }
2125     for (;;)
2126     {
2127         while (req->read_size)
2128         {
2129             char ch = req->read_buf[req->read_pos];
2130             if (ch >= '0' && ch <= '9') chunk_size = chunk_size * 16 + ch - '0';
2131             else if (ch >= 'a' && ch <= 'f') chunk_size = chunk_size * 16 + ch - 'a' + 10;
2132             else if (ch >= 'A' && ch <= 'F') chunk_size = chunk_size * 16 + ch - 'A' + 10;
2133             else if (ch == ';' || ch == '\r' || ch == '\n')
2134             {
2135                 TRACE( "reading %u byte chunk\n", chunk_size );
2136                 req->dwContentLength = chunk_size;
2137                 req->dwContentRead = 0;
2138                 return discard_eol( req );
2139             }
2140             remove_data( req, 1 );
2141         }
2142         if ((res = read_more_data( req, -1 )) != ERROR_SUCCESS) return res;
2143         if (!req->read_size)
2144         {
2145             req->dwContentLength = req->dwContentRead = 0;
2146             return ERROR_SUCCESS;
2147         }
2148     }
2149 }
2150
2151 /* check if we have reached the end of the data to read (the read section must be held) */
2152 static BOOL end_of_read_data( http_request_t *req )
2153 {
2154     if (req->gzip_stream) return req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
2155     if (req->read_chunked) return (req->dwContentLength == 0);
2156     if (req->dwContentLength == ~0u) return FALSE;
2157     return (req->dwContentLength == req->dwContentRead);
2158 }
2159
2160 /* fetch some more data into the read buffer (the read section must be held) */
2161 static DWORD refill_buffer( http_request_t *req )
2162 {
2163     int len = sizeof(req->read_buf);
2164     DWORD res;
2165
2166     if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
2167     {
2168         if ((res = start_next_chunk( req )) != ERROR_SUCCESS) return res;
2169     }
2170
2171     if (req->dwContentLength != ~0u) len = min( len, req->dwContentLength - req->dwContentRead );
2172     if (len <= req->read_size) return ERROR_SUCCESS;
2173
2174     if ((res = read_more_data( req, len )) != ERROR_SUCCESS) return res;
2175     if (!req->read_size) req->dwContentLength = req->dwContentRead = 0;
2176     return ERROR_SUCCESS;
2177 }
2178
2179 static DWORD read_gzip_data(http_request_t *req, BYTE *buf, int size, BOOL sync, int *read_ret)
2180 {
2181     DWORD ret = ERROR_SUCCESS;
2182     int read = 0;
2183
2184 #ifdef HAVE_ZLIB
2185     z_stream *zstream = &req->gzip_stream->zstream;
2186     int zres;
2187
2188     while(read < size && !req->gzip_stream->end_of_data) {
2189         if(!req->read_size) {
2190             if(!sync || refill_buffer(req) != ERROR_SUCCESS)
2191                 break;
2192         }
2193
2194         zstream->next_in = req->read_buf+req->read_pos;
2195         zstream->avail_in = req->read_size;
2196         zstream->next_out = buf+read;
2197         zstream->avail_out = size-read;
2198         zres = inflate(zstream, Z_FULL_FLUSH);
2199         read = size - zstream->avail_out;
2200         remove_data(req, req->read_size-zstream->avail_in);
2201         if(zres == Z_STREAM_END) {
2202             TRACE("end of data\n");
2203             req->gzip_stream->end_of_data = TRUE;
2204             inflateEnd(&req->gzip_stream->zstream);
2205         }else if(zres != Z_OK) {
2206             WARN("inflate failed %d\n", zres);
2207             if(!read)
2208                 ret = ERROR_INTERNET_DECODING_FAILED;
2209             break;
2210         }
2211     }
2212 #endif
2213
2214     *read_ret = read;
2215     return ret;
2216 }
2217
2218 static void refill_gzip_buffer(http_request_t *req)
2219 {
2220     DWORD res;
2221     int len;
2222
2223     if(!req->gzip_stream || !req->read_size || req->gzip_stream->buf_size == sizeof(req->gzip_stream->buf))
2224         return;
2225
2226     if(req->gzip_stream->buf_pos) {
2227         if(req->gzip_stream->buf_size)
2228             memmove(req->gzip_stream->buf, req->gzip_stream->buf + req->gzip_stream->buf_pos, req->gzip_stream->buf_size);
2229         req->gzip_stream->buf_pos = 0;
2230     }
2231
2232     res = read_gzip_data(req, req->gzip_stream->buf + req->gzip_stream->buf_size,
2233             sizeof(req->gzip_stream->buf) - req->gzip_stream->buf_size, FALSE, &len);
2234     if(res == ERROR_SUCCESS)
2235         req->gzip_stream->buf_size += len;
2236 }
2237
2238 /* return the size of data available to be read immediately (the read section must be held) */
2239 static DWORD get_avail_data( http_request_t *req )
2240 {
2241     if (req->gzip_stream) {
2242         refill_gzip_buffer(req);
2243         return req->gzip_stream->buf_size;
2244     }
2245     if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
2246         return 0;
2247     return min( req->read_size, req->dwContentLength - req->dwContentRead );
2248 }
2249
2250 static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif)
2251 {
2252     INTERNET_ASYNC_RESULT iar;
2253     DWORD res;
2254
2255     TRACE("%p\n", req);
2256
2257     EnterCriticalSection( &req->read_section );
2258     if ((res = refill_buffer( req )) == ERROR_SUCCESS) {
2259         iar.dwResult = (DWORD_PTR)req->hdr.hInternet;
2260         iar.dwError = first_notif ? 0 : get_avail_data(req);
2261     }else {
2262         iar.dwResult = 0;
2263         iar.dwError = res;
2264     }
2265     LeaveCriticalSection( &req->read_section );
2266
2267     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2268                           sizeof(INTERNET_ASYNC_RESULT));
2269 }
2270
2271 /* read data from the http connection (the read section must be held) */
2272 static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL sync)
2273 {
2274     BOOL finished_reading = FALSE;
2275     int len, bytes_read = 0;
2276     DWORD ret = ERROR_SUCCESS;
2277
2278     EnterCriticalSection( &req->read_section );
2279
2280     if (req->read_chunked && (req->dwContentLength == ~0u || req->dwContentLength == req->dwContentRead))
2281     {
2282         if (start_next_chunk( req ) != ERROR_SUCCESS) goto done;
2283     }
2284
2285     if(req->gzip_stream) {
2286         if(req->gzip_stream->buf_size) {
2287             bytes_read = min(req->gzip_stream->buf_size, size);
2288             memcpy(buffer, req->gzip_stream->buf + req->gzip_stream->buf_pos, bytes_read);
2289             req->gzip_stream->buf_pos += bytes_read;
2290             req->gzip_stream->buf_size -= bytes_read;
2291         }else if(!req->read_size && !req->gzip_stream->end_of_data) {
2292             refill_buffer(req);
2293         }
2294
2295         if(size > bytes_read) {
2296             ret = read_gzip_data(req, (BYTE*)buffer+bytes_read, size-bytes_read, sync, &len);
2297             if(ret == ERROR_SUCCESS)
2298                 bytes_read += len;
2299         }
2300
2301         finished_reading = req->gzip_stream->end_of_data && !req->gzip_stream->buf_size;
2302     }else {
2303         if (req->dwContentLength != ~0u) size = min( size, req->dwContentLength - req->dwContentRead );
2304
2305         if (req->read_size) {
2306             bytes_read = min( req->read_size, size );
2307             memcpy( buffer, req->read_buf + req->read_pos, bytes_read );
2308             remove_data( req, bytes_read );
2309         }
2310
2311         if (size > bytes_read && (!bytes_read || sync)) {
2312             if (NETCON_recv( &req->netConnection, (char *)buffer + bytes_read, size - bytes_read,
2313                              sync ? MSG_WAITALL : 0, &len) == ERROR_SUCCESS)
2314                 bytes_read += len;
2315             /* always return success, even if the network layer returns an error */
2316         }
2317
2318         finished_reading = !bytes_read && req->dwContentRead == req->dwContentLength;
2319     }
2320 done:
2321     req->dwContentRead += bytes_read;
2322     *read = bytes_read;
2323
2324     TRACE( "retrieved %u bytes (%u/%u)\n", bytes_read, req->dwContentRead, req->dwContentLength );
2325     LeaveCriticalSection( &req->read_section );
2326
2327     if(ret == ERROR_SUCCESS && req->lpszCacheFile) {
2328         BOOL res;
2329         DWORD dwBytesWritten;
2330
2331         res = WriteFile(req->hCacheFile, buffer, bytes_read, &dwBytesWritten, NULL);
2332         if(!res)
2333             WARN("WriteFile failed: %u\n", GetLastError());
2334     }
2335
2336     if(finished_reading)
2337         HTTP_FinishedReading(req);
2338
2339     return ret;
2340 }
2341
2342
2343 static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read)
2344 {
2345     http_request_t *req = (http_request_t*)hdr;
2346     return HTTPREQ_Read(req, buffer, size, read, TRUE);
2347 }
2348
2349 static void HTTPREQ_AsyncReadFileExAProc(WORKREQUEST *workRequest)
2350 {
2351     struct WORKREQ_INTERNETREADFILEEXA const *data = &workRequest->u.InternetReadFileExA;
2352     http_request_t *req = (http_request_t*)workRequest->hdr;
2353     INTERNET_ASYNC_RESULT iar;
2354     DWORD res;
2355
2356     TRACE("INTERNETREADFILEEXA %p\n", workRequest->hdr);
2357
2358     res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2359             data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2360
2361     iar.dwResult = res == ERROR_SUCCESS;
2362     iar.dwError = res;
2363
2364     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2365                           INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2366                           sizeof(INTERNET_ASYNC_RESULT));
2367 }
2368
2369 static DWORD HTTPREQ_ReadFileExA(object_header_t *hdr, INTERNET_BUFFERSA *buffers,
2370         DWORD flags, DWORD_PTR context)
2371 {
2372     http_request_t *req = (http_request_t*)hdr;
2373     DWORD res;
2374
2375     if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2376         FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2377
2378     if (buffers->dwStructSize != sizeof(*buffers))
2379         return ERROR_INVALID_PARAMETER;
2380
2381     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2382
2383     if ((hdr->dwFlags & INTERNET_FLAG_ASYNC) && !get_avail_data(req))
2384     {
2385         WORKREQUEST workRequest;
2386
2387         if (TryEnterCriticalSection( &req->read_section ))
2388         {
2389             if (get_avail_data(req))
2390             {
2391                 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2392                                    &buffers->dwBufferLength, FALSE);
2393                 LeaveCriticalSection( &req->read_section );
2394                 goto done;
2395             }
2396             LeaveCriticalSection( &req->read_section );
2397         }
2398
2399         workRequest.asyncproc = HTTPREQ_AsyncReadFileExAProc;
2400         workRequest.hdr = WININET_AddRef(&req->hdr);
2401         workRequest.u.InternetReadFileExA.lpBuffersOut = buffers;
2402
2403         INTERNET_AsyncCall(&workRequest);
2404
2405         return ERROR_IO_PENDING;
2406     }
2407
2408     res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
2409             !(flags & IRF_NO_WAIT));
2410
2411 done:
2412     if (res == ERROR_SUCCESS) {
2413         DWORD size = buffers->dwBufferLength;
2414         INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2415                 &size, sizeof(size));
2416     }
2417
2418     return res;
2419 }
2420
2421 static void HTTPREQ_AsyncReadFileExWProc(WORKREQUEST *workRequest)
2422 {
2423     struct WORKREQ_INTERNETREADFILEEXW const *data = &workRequest->u.InternetReadFileExW;
2424     http_request_t *req = (http_request_t*)workRequest->hdr;
2425     INTERNET_ASYNC_RESULT iar;
2426     DWORD res;
2427
2428     TRACE("INTERNETREADFILEEXW %p\n", workRequest->hdr);
2429
2430     res = HTTPREQ_Read(req, data->lpBuffersOut->lpvBuffer,
2431             data->lpBuffersOut->dwBufferLength, &data->lpBuffersOut->dwBufferLength, TRUE);
2432
2433     iar.dwResult = res == ERROR_SUCCESS;
2434     iar.dwError = res;
2435
2436     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext,
2437                           INTERNET_STATUS_REQUEST_COMPLETE, &iar,
2438                           sizeof(INTERNET_ASYNC_RESULT));
2439 }
2440
2441 static DWORD HTTPREQ_ReadFileExW(object_header_t *hdr, INTERNET_BUFFERSW *buffers,
2442         DWORD flags, DWORD_PTR context)
2443 {
2444
2445     http_request_t *req = (http_request_t*)hdr;
2446     DWORD res;
2447
2448     if (flags & ~(IRF_ASYNC|IRF_NO_WAIT))
2449         FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT));
2450
2451     if (buffers->dwStructSize != sizeof(*buffers))
2452         return ERROR_INVALID_PARAMETER;
2453
2454     INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
2455
2456     if (hdr->dwFlags & INTERNET_FLAG_ASYNC)
2457     {
2458         WORKREQUEST workRequest;
2459
2460         if (TryEnterCriticalSection( &req->read_section ))
2461         {
2462             if (get_avail_data(req))
2463             {
2464                 res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength,
2465                                    &buffers->dwBufferLength, FALSE);
2466                 LeaveCriticalSection( &req->read_section );
2467                 goto done;
2468             }
2469             LeaveCriticalSection( &req->read_section );
2470         }
2471
2472         workRequest.asyncproc = HTTPREQ_AsyncReadFileExWProc;
2473         workRequest.hdr = WININET_AddRef(&req->hdr);
2474         workRequest.u.InternetReadFileExW.lpBuffersOut = buffers;
2475
2476         INTERNET_AsyncCall(&workRequest);
2477
2478         return ERROR_IO_PENDING;
2479     }
2480
2481     res = HTTPREQ_Read(req, buffers->lpvBuffer, buffers->dwBufferLength, &buffers->dwBufferLength,
2482             !(flags & IRF_NO_WAIT));
2483
2484 done:
2485     if (res == ERROR_SUCCESS) {
2486         DWORD size = buffers->dwBufferLength;
2487         INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED,
2488                 &size, sizeof(size));
2489     }
2490
2491     return res;
2492 }
2493
2494 static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written)
2495 {
2496     DWORD res;
2497     http_request_t *lpwhr = (http_request_t*)hdr;
2498
2499     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
2500
2501     *written = 0;
2502     res = NETCON_send(&lpwhr->netConnection, buffer, size, 0, (LPINT)written);
2503     if (res == ERROR_SUCCESS)
2504         lpwhr->dwBytesWritten += *written;
2505
2506     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_SENT, written, sizeof(DWORD));
2507     return res;
2508 }
2509
2510 static void HTTPREQ_AsyncQueryDataAvailableProc(WORKREQUEST *workRequest)
2511 {
2512     http_request_t *req = (http_request_t*)workRequest->hdr;
2513
2514     HTTP_ReceiveRequestData(req, FALSE);
2515 }
2516
2517 static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx)
2518 {
2519     http_request_t *req = (http_request_t*)hdr;
2520
2521     TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
2522
2523     if (req->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
2524     {
2525         WORKREQUEST workRequest;
2526
2527         /* never wait, if we can't enter the section we queue an async request right away */
2528         if (TryEnterCriticalSection( &req->read_section ))
2529         {
2530             if ((*available = get_avail_data( req ))) goto done;
2531             if (end_of_read_data( req )) goto done;
2532             LeaveCriticalSection( &req->read_section );
2533         }
2534
2535         workRequest.asyncproc = HTTPREQ_AsyncQueryDataAvailableProc;
2536         workRequest.hdr = WININET_AddRef( &req->hdr );
2537
2538         INTERNET_AsyncCall(&workRequest);
2539
2540         return ERROR_IO_PENDING;
2541     }
2542
2543     EnterCriticalSection( &req->read_section );
2544
2545     if (!(*available = get_avail_data( req )) && !end_of_read_data( req ))
2546     {
2547         refill_buffer( req );
2548         *available = get_avail_data( req );
2549     }
2550
2551 done:
2552     if (*available == sizeof(req->read_buf) && !req->gzip_stream)  /* check if we have even more pending in the socket */
2553     {
2554         DWORD extra;
2555         if (NETCON_query_data_available(&req->netConnection, &extra))
2556             *available = min( *available + extra, req->dwContentLength - req->dwContentRead );
2557     }
2558     LeaveCriticalSection( &req->read_section );
2559
2560     TRACE( "returning %u\n", *available );
2561     return ERROR_SUCCESS;
2562 }
2563
2564 static const object_vtbl_t HTTPREQVtbl = {
2565     HTTPREQ_Destroy,
2566     HTTPREQ_CloseConnection,
2567     HTTPREQ_QueryOption,
2568     HTTPREQ_SetOption,
2569     HTTPREQ_ReadFile,
2570     HTTPREQ_ReadFileExA,
2571     HTTPREQ_ReadFileExW,
2572     HTTPREQ_WriteFile,
2573     HTTPREQ_QueryDataAvailable,
2574     NULL
2575 };
2576
2577 /***********************************************************************
2578  *           HTTP_HttpOpenRequestW (internal)
2579  *
2580  * Open a HTTP request handle
2581  *
2582  * RETURNS
2583  *    HINTERNET  a HTTP request handle on success
2584  *    NULL       on failure
2585  *
2586  */
2587 HINTERNET WINAPI HTTP_HttpOpenRequestW(http_session_t *lpwhs,
2588         LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
2589         LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
2590         DWORD dwFlags, DWORD_PTR dwContext)
2591 {
2592     appinfo_t *hIC = NULL;
2593     http_request_t *lpwhr;
2594     LPWSTR lpszHostName = NULL;
2595     HINTERNET handle = NULL;
2596     static const WCHAR szHostForm[] = {'%','s',':','%','u',0};
2597     DWORD len;
2598
2599     TRACE("-->\n");
2600
2601     assert( lpwhs->hdr.htype == WH_HHTTPSESSION );
2602     hIC = lpwhs->lpAppInfo;
2603
2604     lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_request_t));
2605     if (NULL == lpwhr)
2606     {
2607         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2608         goto lend;
2609     }
2610     lpwhr->hdr.htype = WH_HHTTPREQ;
2611     lpwhr->hdr.vtbl = &HTTPREQVtbl;
2612     lpwhr->hdr.dwFlags = dwFlags;
2613     lpwhr->hdr.dwContext = dwContext;
2614     lpwhr->hdr.refs = 1;
2615     lpwhr->hdr.lpfnStatusCB = lpwhs->hdr.lpfnStatusCB;
2616     lpwhr->hdr.dwInternalFlags = lpwhs->hdr.dwInternalFlags & INET_CALLBACKW;
2617     lpwhr->dwContentLength = ~0u;
2618     InitializeCriticalSection( &lpwhr->read_section );
2619
2620     WININET_AddRef( &lpwhs->hdr );
2621     lpwhr->lpHttpSession = lpwhs;
2622     list_add_head( &lpwhs->hdr.children, &lpwhr->hdr.entry );
2623
2624     lpszHostName = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) *
2625             (strlenW(lpwhs->lpszHostName) + 7 /* length of ":65535" + 1 */));
2626     if (NULL == lpszHostName)
2627     {
2628         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2629         goto lend;
2630     }
2631
2632     handle = WININET_AllocHandle( &lpwhr->hdr );
2633     if (NULL == handle)
2634     {
2635         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2636         goto lend;
2637     }
2638
2639     if (!NETCON_init(&lpwhr->netConnection, dwFlags & INTERNET_FLAG_SECURE))
2640     {
2641         InternetCloseHandle( handle );
2642         handle = NULL;
2643         goto lend;
2644     }
2645
2646     if (lpszObjectName && *lpszObjectName) {
2647         HRESULT rc;
2648
2649         len = 0;
2650         rc = UrlEscapeW(lpszObjectName, NULL, &len, URL_ESCAPE_SPACES_ONLY);
2651         if (rc != E_POINTER)
2652             len = strlenW(lpszObjectName)+1;
2653         lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
2654         rc = UrlEscapeW(lpszObjectName, lpwhr->lpszPath, &len,
2655                    URL_ESCAPE_SPACES_ONLY);
2656         if (rc != S_OK)
2657         {
2658             ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(lpszObjectName),rc);
2659             strcpyW(lpwhr->lpszPath,lpszObjectName);
2660         }
2661     }else {
2662         static const WCHAR slashW[] = {'/',0};
2663
2664         lpwhr->lpszPath = heap_strdupW(slashW);
2665     }
2666
2667     if (lpszReferrer && *lpszReferrer)
2668         HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
2669
2670     if (lpszAcceptTypes)
2671     {
2672         int i;
2673         for (i = 0; lpszAcceptTypes[i]; i++)
2674         {
2675             if (!*lpszAcceptTypes[i]) continue;
2676             HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i],
2677                                HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA |
2678                                HTTP_ADDHDR_FLAG_REQ |
2679                                (i == 0 ? HTTP_ADDHDR_FLAG_REPLACE : 0));
2680         }
2681     }
2682
2683     lpwhr->lpszVerb = heap_strdupW(lpszVerb && *lpszVerb ? lpszVerb : szGET);
2684     lpwhr->lpszVersion = heap_strdupW(lpszVersion ? lpszVersion : g_szHttp1_1);
2685
2686     if (lpwhs->nHostPort != INTERNET_INVALID_PORT_NUMBER &&
2687         lpwhs->nHostPort != INTERNET_DEFAULT_HTTP_PORT &&
2688         lpwhs->nHostPort != INTERNET_DEFAULT_HTTPS_PORT)
2689     {
2690         sprintfW(lpszHostName, szHostForm, lpwhs->lpszHostName, lpwhs->nHostPort);
2691         HTTP_ProcessHeader(lpwhr, hostW, lpszHostName,
2692                 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
2693     }
2694     else
2695         HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName,
2696                 HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REQ);
2697
2698     if (lpwhs->nServerPort == INTERNET_INVALID_PORT_NUMBER)
2699         lpwhs->nServerPort = (dwFlags & INTERNET_FLAG_SECURE ?
2700                         INTERNET_DEFAULT_HTTPS_PORT :
2701                         INTERNET_DEFAULT_HTTP_PORT);
2702
2703     if (lpwhs->nHostPort == INTERNET_INVALID_PORT_NUMBER)
2704         lpwhs->nHostPort = (dwFlags & INTERNET_FLAG_SECURE ?
2705                         INTERNET_DEFAULT_HTTPS_PORT :
2706                         INTERNET_DEFAULT_HTTP_PORT);
2707
2708     if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
2709         HTTP_DealWithProxy( hIC, lpwhs, lpwhr );
2710
2711     INTERNET_SendCallback(&lpwhs->hdr, dwContext,
2712                           INTERNET_STATUS_HANDLE_CREATED, &handle,
2713                           sizeof(handle));
2714
2715 lend:
2716     HeapFree(GetProcessHeap(), 0, lpszHostName);
2717     if( lpwhr )
2718         WININET_Release( &lpwhr->hdr );
2719
2720     TRACE("<-- %p (%p)\n", handle, lpwhr);
2721     return handle;
2722 }
2723
2724 /* read any content returned by the server so that the connection can be
2725  * reused */
2726 static void HTTP_DrainContent(http_request_t *req)
2727 {
2728     DWORD bytes_read;
2729
2730     if (!NETCON_connected(&req->netConnection)) return;
2731
2732     if (req->dwContentLength == -1)
2733     {
2734         NETCON_close(&req->netConnection);
2735         return;
2736     }
2737     if (!strcmpW(req->lpszVerb, szHEAD)) return;
2738
2739     do
2740     {
2741         char buffer[2048];
2742         if (HTTPREQ_Read(req, buffer, sizeof(buffer), &bytes_read, TRUE) != ERROR_SUCCESS)
2743             return;
2744     } while (bytes_read);
2745 }
2746
2747 static const LPCWSTR header_lookup[] = {
2748     szMime_Version,             /* HTTP_QUERY_MIME_VERSION = 0 */
2749     szContent_Type,             /* HTTP_QUERY_CONTENT_TYPE = 1 */
2750     szContent_Transfer_Encoding,/* HTTP_QUERY_CONTENT_TRANSFER_ENCODING = 2 */
2751     szContent_ID,               /* HTTP_QUERY_CONTENT_ID = 3 */
2752     NULL,                       /* HTTP_QUERY_CONTENT_DESCRIPTION = 4 */
2753     szContent_Length,           /* HTTP_QUERY_CONTENT_LENGTH =  5 */
2754     szContent_Language,         /* HTTP_QUERY_CONTENT_LANGUAGE =  6 */
2755     szAllow,                    /* HTTP_QUERY_ALLOW = 7 */
2756     szPublic,                   /* HTTP_QUERY_PUBLIC = 8 */
2757     szDate,                     /* HTTP_QUERY_DATE = 9 */
2758     szExpires,                  /* HTTP_QUERY_EXPIRES = 10 */
2759     szLast_Modified,            /* HTTP_QUERY_LAST_MODIFIED = 11 */
2760     NULL,                       /* HTTP_QUERY_MESSAGE_ID = 12 */
2761     szURI,                      /* HTTP_QUERY_URI = 13 */
2762     szFrom,                     /* HTTP_QUERY_DERIVED_FROM = 14 */
2763     NULL,                       /* HTTP_QUERY_COST = 15 */
2764     NULL,                       /* HTTP_QUERY_LINK = 16 */
2765     szPragma,                   /* HTTP_QUERY_PRAGMA = 17 */
2766     NULL,                       /* HTTP_QUERY_VERSION = 18 */
2767     szStatus,                   /* HTTP_QUERY_STATUS_CODE = 19 */
2768     NULL,                       /* HTTP_QUERY_STATUS_TEXT = 20 */
2769     NULL,                       /* HTTP_QUERY_RAW_HEADERS = 21 */
2770     NULL,                       /* HTTP_QUERY_RAW_HEADERS_CRLF = 22 */
2771     szConnection,               /* HTTP_QUERY_CONNECTION = 23 */
2772     szAccept,                   /* HTTP_QUERY_ACCEPT = 24 */
2773     szAccept_Charset,           /* HTTP_QUERY_ACCEPT_CHARSET = 25 */
2774     szAccept_Encoding,          /* HTTP_QUERY_ACCEPT_ENCODING = 26 */
2775     szAccept_Language,          /* HTTP_QUERY_ACCEPT_LANGUAGE = 27 */
2776     szAuthorization,            /* HTTP_QUERY_AUTHORIZATION = 28 */
2777     szContent_Encoding,         /* HTTP_QUERY_CONTENT_ENCODING = 29 */
2778     NULL,                       /* HTTP_QUERY_FORWARDED = 30 */
2779     NULL,                       /* HTTP_QUERY_FROM = 31 */
2780     szIf_Modified_Since,        /* HTTP_QUERY_IF_MODIFIED_SINCE = 32 */
2781     szLocation,                 /* HTTP_QUERY_LOCATION = 33 */
2782     NULL,                       /* HTTP_QUERY_ORIG_URI = 34 */
2783     szReferer,                  /* HTTP_QUERY_REFERER = 35 */
2784     szRetry_After,              /* HTTP_QUERY_RETRY_AFTER = 36 */
2785     szServer,                   /* HTTP_QUERY_SERVER = 37 */
2786     NULL,                       /* HTTP_TITLE = 38 */
2787     szUser_Agent,               /* HTTP_QUERY_USER_AGENT = 39 */
2788     szWWW_Authenticate,         /* HTTP_QUERY_WWW_AUTHENTICATE = 40 */
2789     szProxy_Authenticate,       /* HTTP_QUERY_PROXY_AUTHENTICATE = 41 */
2790     szAccept_Ranges,            /* HTTP_QUERY_ACCEPT_RANGES = 42 */
2791     szSet_Cookie,               /* HTTP_QUERY_SET_COOKIE = 43 */
2792     szCookie,                   /* HTTP_QUERY_COOKIE = 44 */
2793     NULL,                       /* HTTP_QUERY_REQUEST_METHOD = 45 */
2794     NULL,                       /* HTTP_QUERY_REFRESH = 46 */
2795     NULL,                       /* HTTP_QUERY_CONTENT_DISPOSITION = 47 */
2796     szAge,                      /* HTTP_QUERY_AGE = 48 */
2797     szCache_Control,            /* HTTP_QUERY_CACHE_CONTROL = 49 */
2798     szContent_Base,             /* HTTP_QUERY_CONTENT_BASE = 50 */
2799     szContent_Location,         /* HTTP_QUERY_CONTENT_LOCATION = 51 */
2800     szContent_MD5,              /* HTTP_QUERY_CONTENT_MD5 = 52 */
2801     szContent_Range,            /* HTTP_QUERY_CONTENT_RANGE = 53 */
2802     szETag,                     /* HTTP_QUERY_ETAG = 54 */
2803     hostW,                      /* HTTP_QUERY_HOST = 55 */
2804     szIf_Match,                 /* HTTP_QUERY_IF_MATCH = 56 */
2805     szIf_None_Match,            /* HTTP_QUERY_IF_NONE_MATCH = 57 */
2806     szIf_Range,                 /* HTTP_QUERY_IF_RANGE = 58 */
2807     szIf_Unmodified_Since,      /* HTTP_QUERY_IF_UNMODIFIED_SINCE = 59 */
2808     szMax_Forwards,             /* HTTP_QUERY_MAX_FORWARDS = 60 */
2809     szProxy_Authorization,      /* HTTP_QUERY_PROXY_AUTHORIZATION = 61 */
2810     szRange,                    /* HTTP_QUERY_RANGE = 62 */
2811     szTransfer_Encoding,        /* HTTP_QUERY_TRANSFER_ENCODING = 63 */
2812     szUpgrade,                  /* HTTP_QUERY_UPGRADE = 64 */
2813     szVary,                     /* HTTP_QUERY_VARY = 65 */
2814     szVia,                      /* HTTP_QUERY_VIA = 66 */
2815     szWarning,                  /* HTTP_QUERY_WARNING = 67 */
2816     szExpect,                   /* HTTP_QUERY_EXPECT = 68 */
2817     szProxy_Connection,         /* HTTP_QUERY_PROXY_CONNECTION = 69 */
2818     szUnless_Modified_Since,    /* HTTP_QUERY_UNLESS_MODIFIED_SINCE = 70 */
2819 };
2820
2821 #define LAST_TABLE_HEADER (sizeof(header_lookup)/sizeof(header_lookup[0]))
2822
2823 /***********************************************************************
2824  *           HTTP_HttpQueryInfoW (internal)
2825  */
2826 static BOOL HTTP_HttpQueryInfoW(http_request_t *lpwhr, DWORD dwInfoLevel,
2827         LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
2828 {
2829     LPHTTPHEADERW lphttpHdr = NULL;
2830     BOOL bSuccess = FALSE;
2831     BOOL request_only = dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS;
2832     INT requested_index = lpdwIndex ? *lpdwIndex : 0;
2833     DWORD level = (dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK);
2834     INT index = -1;
2835
2836     /* Find requested header structure */
2837     switch (level)
2838     {
2839     case HTTP_QUERY_CUSTOM:
2840         if (!lpBuffer) return FALSE;
2841         index = HTTP_GetCustomHeaderIndex(lpwhr, lpBuffer, requested_index, request_only);
2842         break;
2843     case HTTP_QUERY_RAW_HEADERS_CRLF:
2844         {
2845             LPWSTR headers;
2846             DWORD len = 0;
2847             BOOL ret = FALSE;
2848
2849             if (request_only)
2850                 headers = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
2851             else
2852                 headers = lpwhr->lpszRawHeaders;
2853
2854             if (headers)
2855                 len = strlenW(headers) * sizeof(WCHAR);
2856
2857             if (len + sizeof(WCHAR) > *lpdwBufferLength)
2858             {
2859                 len += sizeof(WCHAR);
2860                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2861                 ret = FALSE;
2862             }
2863             else if (lpBuffer)
2864             {
2865                 if (headers)
2866                     memcpy(lpBuffer, headers, len + sizeof(WCHAR));
2867                 else
2868                 {
2869                     len = strlenW(szCrLf) * sizeof(WCHAR);
2870                     memcpy(lpBuffer, szCrLf, sizeof(szCrLf));
2871                 }
2872                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len / sizeof(WCHAR)));
2873                 ret = TRUE;
2874             }
2875             *lpdwBufferLength = len;
2876
2877             if (request_only)
2878                 HeapFree(GetProcessHeap(), 0, headers);
2879             return ret;
2880         }
2881     case HTTP_QUERY_RAW_HEADERS:
2882         {
2883             LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf);
2884             DWORD i, size = 0;
2885             LPWSTR pszString = lpBuffer;
2886
2887             for (i = 0; ppszRawHeaderLines[i]; i++)
2888                 size += strlenW(ppszRawHeaderLines[i]) + 1;
2889
2890             if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
2891             {
2892                 HTTP_FreeTokens(ppszRawHeaderLines);
2893                 *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
2894                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2895                 return FALSE;
2896             }
2897             if (pszString)
2898             {
2899                 for (i = 0; ppszRawHeaderLines[i]; i++)
2900                 {
2901                     DWORD len = strlenW(ppszRawHeaderLines[i]);
2902                     memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
2903                     pszString += len+1;
2904                 }
2905                 *pszString = '\0';
2906                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, size));
2907             }
2908             *lpdwBufferLength = size * sizeof(WCHAR);
2909             HTTP_FreeTokens(ppszRawHeaderLines);
2910
2911             return TRUE;
2912         }
2913     case HTTP_QUERY_STATUS_TEXT:
2914         if (lpwhr->lpszStatusText)
2915         {
2916             DWORD len = strlenW(lpwhr->lpszStatusText);
2917             if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
2918             {
2919                 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
2920                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2921                 return FALSE;
2922             }
2923             if (lpBuffer)
2924             {
2925                 memcpy(lpBuffer, lpwhr->lpszStatusText, (len + 1) * sizeof(WCHAR));
2926                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
2927             }
2928             *lpdwBufferLength = len * sizeof(WCHAR);
2929             return TRUE;
2930         }
2931         break;
2932     case HTTP_QUERY_VERSION:
2933         if (lpwhr->lpszVersion)
2934         {
2935             DWORD len = strlenW(lpwhr->lpszVersion);
2936             if (len + 1 > *lpdwBufferLength/sizeof(WCHAR))
2937             {
2938                 *lpdwBufferLength = (len + 1) * sizeof(WCHAR);
2939                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
2940                 return FALSE;
2941             }
2942             if (lpBuffer)
2943             {
2944                 memcpy(lpBuffer, lpwhr->lpszVersion, (len + 1) * sizeof(WCHAR));
2945                 TRACE("returning data: %s\n", debugstr_wn(lpBuffer, len));
2946             }
2947             *lpdwBufferLength = len * sizeof(WCHAR);
2948             return TRUE;
2949         }
2950         break;
2951     case HTTP_QUERY_CONTENT_ENCODING:
2952         index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[lpwhr->gzip_stream ? HTTP_QUERY_CONTENT_TYPE : level],
2953                 requested_index,request_only);
2954         break;
2955     default:
2956         assert (LAST_TABLE_HEADER == (HTTP_QUERY_UNLESS_MODIFIED_SINCE + 1));
2957
2958         if (level < LAST_TABLE_HEADER && header_lookup[level])
2959             index = HTTP_GetCustomHeaderIndex(lpwhr, header_lookup[level],
2960                                               requested_index,request_only);
2961     }
2962
2963     if (index >= 0)
2964         lphttpHdr = &lpwhr->pCustHeaders[index];
2965
2966     /* Ensure header satisfies requested attributes */
2967     if (!lphttpHdr ||
2968         ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
2969          (~lphttpHdr->wFlags & HDR_ISREQUEST)))
2970     {
2971         INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
2972         return bSuccess;
2973     }
2974
2975     if (lpdwIndex && level != HTTP_QUERY_STATUS_CODE) (*lpdwIndex)++;
2976
2977     /* coalesce value to requested type */
2978     if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER && lpBuffer)
2979     {
2980         *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
2981         TRACE(" returning number: %d\n", *(int *)lpBuffer);
2982         bSuccess = TRUE;
2983     }
2984     else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME && lpBuffer)
2985     {
2986         time_t tmpTime;
2987         struct tm tmpTM;
2988         SYSTEMTIME *STHook;
2989
2990         tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
2991
2992         tmpTM = *gmtime(&tmpTime);
2993         STHook = (SYSTEMTIME *)lpBuffer;
2994         STHook->wDay = tmpTM.tm_mday;
2995         STHook->wHour = tmpTM.tm_hour;
2996         STHook->wMilliseconds = 0;
2997         STHook->wMinute = tmpTM.tm_min;
2998         STHook->wDayOfWeek = tmpTM.tm_wday;
2999         STHook->wMonth = tmpTM.tm_mon + 1;
3000         STHook->wSecond = tmpTM.tm_sec;
3001         STHook->wYear = tmpTM.tm_year;
3002         bSuccess = TRUE;
3003         
3004         TRACE(" returning time: %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n",
3005               STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
3006               STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
3007     }
3008     else if (lphttpHdr->lpszValue)
3009     {
3010         DWORD len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
3011
3012         if (len > *lpdwBufferLength)
3013         {
3014             *lpdwBufferLength = len;
3015             INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
3016             return bSuccess;
3017         }
3018         if (lpBuffer)
3019         {
3020             memcpy(lpBuffer, lphttpHdr->lpszValue, len);
3021             TRACE(" returning string: %s\n", debugstr_w(lpBuffer));
3022         }
3023         *lpdwBufferLength = len - sizeof(WCHAR);
3024         bSuccess = TRUE;
3025     }
3026     return bSuccess;
3027 }
3028
3029 /***********************************************************************
3030  *           HttpQueryInfoW (WININET.@)
3031  *
3032  * Queries for information about an HTTP request
3033  *
3034  * RETURNS
3035  *    TRUE  on success
3036  *    FALSE on failure
3037  *
3038  */
3039 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
3040         LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
3041 {
3042     BOOL bSuccess = FALSE;
3043     http_request_t *lpwhr;
3044
3045     if (TRACE_ON(wininet)) {
3046 #define FE(x) { x, #x }
3047         static const wininet_flag_info query_flags[] = {
3048             FE(HTTP_QUERY_MIME_VERSION),
3049             FE(HTTP_QUERY_CONTENT_TYPE),
3050             FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
3051             FE(HTTP_QUERY_CONTENT_ID),
3052             FE(HTTP_QUERY_CONTENT_DESCRIPTION),
3053             FE(HTTP_QUERY_CONTENT_LENGTH),
3054             FE(HTTP_QUERY_CONTENT_LANGUAGE),
3055             FE(HTTP_QUERY_ALLOW),
3056             FE(HTTP_QUERY_PUBLIC),
3057             FE(HTTP_QUERY_DATE),
3058             FE(HTTP_QUERY_EXPIRES),
3059             FE(HTTP_QUERY_LAST_MODIFIED),
3060             FE(HTTP_QUERY_MESSAGE_ID),
3061             FE(HTTP_QUERY_URI),
3062             FE(HTTP_QUERY_DERIVED_FROM),
3063             FE(HTTP_QUERY_COST),
3064             FE(HTTP_QUERY_LINK),
3065             FE(HTTP_QUERY_PRAGMA),
3066             FE(HTTP_QUERY_VERSION),
3067             FE(HTTP_QUERY_STATUS_CODE),
3068             FE(HTTP_QUERY_STATUS_TEXT),
3069             FE(HTTP_QUERY_RAW_HEADERS),
3070             FE(HTTP_QUERY_RAW_HEADERS_CRLF),
3071             FE(HTTP_QUERY_CONNECTION),
3072             FE(HTTP_QUERY_ACCEPT),
3073             FE(HTTP_QUERY_ACCEPT_CHARSET),
3074             FE(HTTP_QUERY_ACCEPT_ENCODING),
3075             FE(HTTP_QUERY_ACCEPT_LANGUAGE),
3076             FE(HTTP_QUERY_AUTHORIZATION),
3077             FE(HTTP_QUERY_CONTENT_ENCODING),
3078             FE(HTTP_QUERY_FORWARDED),
3079             FE(HTTP_QUERY_FROM),
3080             FE(HTTP_QUERY_IF_MODIFIED_SINCE),
3081             FE(HTTP_QUERY_LOCATION),
3082             FE(HTTP_QUERY_ORIG_URI),
3083             FE(HTTP_QUERY_REFERER),
3084             FE(HTTP_QUERY_RETRY_AFTER),
3085             FE(HTTP_QUERY_SERVER),
3086             FE(HTTP_QUERY_TITLE),
3087             FE(HTTP_QUERY_USER_AGENT),
3088             FE(HTTP_QUERY_WWW_AUTHENTICATE),
3089             FE(HTTP_QUERY_PROXY_AUTHENTICATE),
3090             FE(HTTP_QUERY_ACCEPT_RANGES),
3091         FE(HTTP_QUERY_SET_COOKIE),
3092         FE(HTTP_QUERY_COOKIE),
3093             FE(HTTP_QUERY_REQUEST_METHOD),
3094             FE(HTTP_QUERY_REFRESH),
3095             FE(HTTP_QUERY_CONTENT_DISPOSITION),
3096             FE(HTTP_QUERY_AGE),
3097             FE(HTTP_QUERY_CACHE_CONTROL),
3098             FE(HTTP_QUERY_CONTENT_BASE),
3099             FE(HTTP_QUERY_CONTENT_LOCATION),
3100             FE(HTTP_QUERY_CONTENT_MD5),
3101             FE(HTTP_QUERY_CONTENT_RANGE),
3102             FE(HTTP_QUERY_ETAG),
3103             FE(HTTP_QUERY_HOST),
3104             FE(HTTP_QUERY_IF_MATCH),
3105             FE(HTTP_QUERY_IF_NONE_MATCH),
3106             FE(HTTP_QUERY_IF_RANGE),
3107             FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
3108             FE(HTTP_QUERY_MAX_FORWARDS),
3109             FE(HTTP_QUERY_PROXY_AUTHORIZATION),
3110             FE(HTTP_QUERY_RANGE),
3111             FE(HTTP_QUERY_TRANSFER_ENCODING),
3112             FE(HTTP_QUERY_UPGRADE),
3113             FE(HTTP_QUERY_VARY),
3114             FE(HTTP_QUERY_VIA),
3115             FE(HTTP_QUERY_WARNING),
3116             FE(HTTP_QUERY_CUSTOM)
3117         };
3118         static const wininet_flag_info modifier_flags[] = {
3119             FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
3120             FE(HTTP_QUERY_FLAG_SYSTEMTIME),
3121             FE(HTTP_QUERY_FLAG_NUMBER),
3122             FE(HTTP_QUERY_FLAG_COALESCE)
3123         };
3124 #undef FE
3125         DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
3126         DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
3127         DWORD i;
3128
3129         TRACE("(%p, 0x%08x)--> %d\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
3130         TRACE("  Attribute:");
3131         for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
3132             if (query_flags[i].val == info) {
3133                 TRACE(" %s", query_flags[i].name);
3134                 break;
3135             }
3136         }
3137         if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
3138             TRACE(" Unknown (%08x)", info);
3139         }
3140
3141         TRACE(" Modifier:");
3142         for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
3143             if (modifier_flags[i].val & info_mod) {
3144                 TRACE(" %s", modifier_flags[i].name);
3145                 info_mod &= ~ modifier_flags[i].val;
3146             }
3147         }
3148         
3149         if (info_mod) {
3150             TRACE(" Unknown (%08x)", info_mod);
3151         }
3152         TRACE("\n");
3153     }
3154     
3155     lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
3156     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
3157     {
3158         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3159         goto lend;
3160     }
3161
3162     if (lpBuffer == NULL)
3163         *lpdwBufferLength = 0;
3164     bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
3165                                     lpBuffer, lpdwBufferLength, lpdwIndex);
3166
3167 lend:
3168     if( lpwhr )
3169          WININET_Release( &lpwhr->hdr );
3170
3171     TRACE("%d <--\n", bSuccess);
3172     return bSuccess;
3173 }
3174
3175 /***********************************************************************
3176  *           HttpQueryInfoA (WININET.@)
3177  *
3178  * Queries for information about an HTTP request
3179  *
3180  * RETURNS
3181  *    TRUE  on success
3182  *    FALSE on failure
3183  *
3184  */
3185 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
3186         LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
3187 {
3188     BOOL result;
3189     DWORD len;
3190     WCHAR* bufferW;
3191
3192     if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
3193        (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
3194     {
3195         return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
3196                                lpdwBufferLength, lpdwIndex );
3197     }
3198
3199     if (lpBuffer)
3200     {
3201         DWORD alloclen;
3202         len = (*lpdwBufferLength)*sizeof(WCHAR);
3203         if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
3204         {
3205             alloclen = MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, NULL, 0 ) * sizeof(WCHAR);
3206             if (alloclen < len)
3207                 alloclen = len;
3208         }
3209         else
3210             alloclen = len;
3211         bufferW = HeapAlloc( GetProcessHeap(), 0, alloclen );
3212         /* buffer is in/out because of HTTP_QUERY_CUSTOM */
3213         if ((dwInfoLevel & HTTP_QUERY_HEADER_MASK) == HTTP_QUERY_CUSTOM)
3214             MultiByteToWideChar( CP_ACP, 0, lpBuffer, -1, bufferW, alloclen / sizeof(WCHAR) );
3215     } else
3216     {
3217         bufferW = NULL;
3218         len = 0;
3219     }
3220
3221     result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
3222                            &len, lpdwIndex );
3223     if( result )
3224     {
3225         len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR) + 1,
3226                                      lpBuffer, *lpdwBufferLength, NULL, NULL );
3227         *lpdwBufferLength = len - 1;
3228
3229         TRACE("lpBuffer: %s\n", debugstr_a(lpBuffer));
3230     }
3231     else
3232         /* since the strings being returned from HttpQueryInfoW should be
3233          * only ASCII characters, it is reasonable to assume that all of
3234          * the Unicode characters can be reduced to a single byte */
3235         *lpdwBufferLength = len / sizeof(WCHAR);
3236
3237     HeapFree(GetProcessHeap(), 0, bufferW );
3238
3239     return result;
3240 }
3241
3242 /***********************************************************************
3243  *           HttpSendRequestExA (WININET.@)
3244  *
3245  * Sends the specified request to the HTTP server and allows chunked
3246  * transfers.
3247  *
3248  * RETURNS
3249  *  Success: TRUE
3250  *  Failure: FALSE, call GetLastError() for more information.
3251  */
3252 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
3253                                LPINTERNET_BUFFERSA lpBuffersIn,
3254                                LPINTERNET_BUFFERSA lpBuffersOut,
3255                                DWORD dwFlags, DWORD_PTR dwContext)
3256 {
3257     INTERNET_BUFFERSW BuffersInW;
3258     BOOL rc = FALSE;
3259     DWORD headerlen;
3260     LPWSTR header = NULL;
3261
3262     TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
3263             lpBuffersOut, dwFlags, dwContext);
3264
3265     if (lpBuffersIn)
3266     {
3267         BuffersInW.dwStructSize = sizeof(LPINTERNET_BUFFERSW);
3268         if (lpBuffersIn->lpcszHeader)
3269         {
3270             headerlen = MultiByteToWideChar(CP_ACP,0,lpBuffersIn->lpcszHeader,
3271                     lpBuffersIn->dwHeadersLength,0,0);
3272             header = HeapAlloc(GetProcessHeap(),0,headerlen*sizeof(WCHAR));
3273             if (!(BuffersInW.lpcszHeader = header))
3274             {
3275                 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
3276                 return FALSE;
3277             }
3278             BuffersInW.dwHeadersLength = MultiByteToWideChar(CP_ACP, 0,
3279                     lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
3280                     header, headerlen);
3281         }
3282         else
3283             BuffersInW.lpcszHeader = NULL;
3284         BuffersInW.dwHeadersTotal = lpBuffersIn->dwHeadersTotal;
3285         BuffersInW.lpvBuffer = lpBuffersIn->lpvBuffer;
3286         BuffersInW.dwBufferLength = lpBuffersIn->dwBufferLength;
3287         BuffersInW.dwBufferTotal = lpBuffersIn->dwBufferTotal;
3288         BuffersInW.Next = NULL;
3289     }
3290
3291     rc = HttpSendRequestExW(hRequest, lpBuffersIn ? &BuffersInW : NULL, NULL, dwFlags, dwContext);
3292
3293     HeapFree(GetProcessHeap(),0,header);
3294
3295     return rc;
3296 }
3297
3298 /***********************************************************************
3299  *           HttpSendRequestExW (WININET.@)
3300  *
3301  * Sends the specified request to the HTTP server and allows chunked
3302  * transfers
3303  *
3304  * RETURNS
3305  *  Success: TRUE
3306  *  Failure: FALSE, call GetLastError() for more information.
3307  */
3308 BOOL WINAPI HttpSendRequestExW(HINTERNET hRequest,
3309                    LPINTERNET_BUFFERSW lpBuffersIn,
3310                    LPINTERNET_BUFFERSW lpBuffersOut,
3311                    DWORD dwFlags, DWORD_PTR dwContext)
3312 {
3313     BOOL ret = FALSE;
3314     http_request_t *lpwhr;
3315     http_session_t *lpwhs;
3316     appinfo_t *hIC;
3317
3318     TRACE("(%p, %p, %p, %08x, %08lx)\n", hRequest, lpBuffersIn,
3319             lpBuffersOut, dwFlags, dwContext);
3320
3321     lpwhr = (http_request_t*) WININET_GetObject( hRequest );
3322
3323     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
3324     {
3325         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
3326         goto lend;
3327     }
3328
3329     lpwhs = lpwhr->lpHttpSession;
3330     assert(lpwhs->hdr.htype == WH_HHTTPSESSION);
3331     hIC = lpwhs->lpAppInfo;
3332     assert(hIC->hdr.htype == WH_HINIT);
3333
3334     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3335     {
3336         WORKREQUEST workRequest;
3337         struct WORKREQ_HTTPSENDREQUESTW *req;
3338
3339         workRequest.asyncproc = AsyncHttpSendRequestProc;
3340         workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
3341         req = &workRequest.u.HttpSendRequestW;
3342         if (lpBuffersIn)
3343         {
3344             DWORD size = 0;
3345
3346             if (lpBuffersIn->lpcszHeader)
3347             {
3348                 if (lpBuffersIn->dwHeadersLength == ~0u)
3349                     size = (strlenW( lpBuffersIn->lpcszHeader ) + 1) * sizeof(WCHAR);
3350                 else
3351                     size = lpBuffersIn->dwHeadersLength * sizeof(WCHAR);
3352
3353                 req->lpszHeader = HeapAlloc( GetProcessHeap(), 0, size );
3354                 memcpy( req->lpszHeader, lpBuffersIn->lpcszHeader, size );
3355             }
3356             else req->lpszHeader = NULL;
3357
3358             req->dwHeaderLength = size / sizeof(WCHAR);
3359             req->lpOptional = lpBuffersIn->lpvBuffer;
3360             req->dwOptionalLength = lpBuffersIn->dwBufferLength;
3361             req->dwContentLength = lpBuffersIn->dwBufferTotal;
3362         }
3363         else
3364         {
3365             req->lpszHeader = NULL;
3366             req->dwHeaderLength = 0;
3367             req->lpOptional = NULL;
3368             req->dwOptionalLength = 0;
3369             req->dwContentLength = 0;
3370         }
3371
3372         req->bEndRequest = FALSE;
3373
3374         INTERNET_AsyncCall(&workRequest);
3375         /*
3376          * This is from windows.
3377          */
3378         INTERNET_SetLastError(ERROR_IO_PENDING);
3379     }
3380     else
3381     {
3382         if (lpBuffersIn)
3383             ret = HTTP_HttpSendRequestW(lpwhr, lpBuffersIn->lpcszHeader, lpBuffersIn->dwHeadersLength,
3384                                         lpBuffersIn->lpvBuffer, lpBuffersIn->dwBufferLength,
3385                                         lpBuffersIn->dwBufferTotal, FALSE);
3386         else
3387             ret = HTTP_HttpSendRequestW(lpwhr, NULL, 0, NULL, 0, 0, FALSE);
3388     }
3389
3390 lend:
3391     if ( lpwhr )
3392         WININET_Release( &lpwhr->hdr );
3393
3394     TRACE("<---\n");
3395     return ret;
3396 }
3397
3398 /***********************************************************************
3399  *           HttpSendRequestW (WININET.@)
3400  *
3401  * Sends the specified request to the HTTP server
3402  *
3403  * RETURNS
3404  *    TRUE  on success
3405  *    FALSE on failure
3406  *
3407  */
3408 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
3409         DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
3410 {
3411     http_request_t *lpwhr;
3412     http_session_t *lpwhs = NULL;
3413     appinfo_t *hIC = NULL;
3414     DWORD res = ERROR_SUCCESS;
3415
3416     TRACE("%p, %s, %i, %p, %i)\n", hHttpRequest,
3417             debugstr_wn(lpszHeaders, dwHeaderLength), dwHeaderLength, lpOptional, dwOptionalLength);
3418
3419     lpwhr = (http_request_t*) WININET_GetObject( hHttpRequest );
3420     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
3421     {
3422         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3423         goto lend;
3424     }
3425
3426     lpwhs = lpwhr->lpHttpSession;
3427     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
3428     {
3429         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3430         goto lend;
3431     }
3432
3433     hIC = lpwhs->lpAppInfo;
3434     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT)
3435     {
3436         res = ERROR_INTERNET_INCORRECT_HANDLE_TYPE;
3437         goto lend;
3438     }
3439
3440     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
3441     {
3442         WORKREQUEST workRequest;
3443         struct WORKREQ_HTTPSENDREQUESTW *req;
3444
3445         workRequest.asyncproc = AsyncHttpSendRequestProc;
3446         workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
3447         req = &workRequest.u.HttpSendRequestW;
3448         if (lpszHeaders)
3449         {
3450             DWORD size;
3451
3452             if (dwHeaderLength == ~0u) size = (strlenW(lpszHeaders) + 1) * sizeof(WCHAR);
3453             else size = dwHeaderLength * sizeof(WCHAR);
3454
3455             req->lpszHeader = HeapAlloc(GetProcessHeap(), 0, size);
3456             memcpy(req->lpszHeader, lpszHeaders, size);
3457         }
3458         else
3459             req->lpszHeader = 0;
3460         req->dwHeaderLength = dwHeaderLength;
3461         req->lpOptional = lpOptional;
3462         req->dwOptionalLength = dwOptionalLength;
3463         req->dwContentLength = dwOptionalLength;
3464         req->bEndRequest = TRUE;
3465
3466         INTERNET_AsyncCall(&workRequest);
3467         /*
3468          * This is from windows.
3469          */
3470         res = ERROR_IO_PENDING;
3471     }
3472     else
3473     {
3474         BOOL r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders,
3475                 dwHeaderLength, lpOptional, dwOptionalLength,
3476                 dwOptionalLength, TRUE);
3477         if(!r)
3478             res = INTERNET_GetLastError();
3479     }
3480 lend:
3481     if( lpwhr )
3482         WININET_Release( &lpwhr->hdr );
3483
3484     if(res != ERROR_SUCCESS)
3485         SetLastError(res);
3486     return res == ERROR_SUCCESS;
3487 }
3488
3489 /***********************************************************************
3490  *           HttpSendRequestA (WININET.@)
3491  *
3492  * Sends the specified request to the HTTP server
3493  *
3494  * RETURNS
3495  *    TRUE  on success
3496  *    FALSE on failure
3497  *
3498  */
3499 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
3500         DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
3501 {
3502     BOOL result;
3503     LPWSTR szHeaders=NULL;
3504     DWORD nLen=dwHeaderLength;
3505     if(lpszHeaders!=NULL)
3506     {
3507         nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
3508         szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR));
3509         MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
3510     }
3511     result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
3512     HeapFree(GetProcessHeap(),0,szHeaders);
3513     return result;
3514 }
3515
3516 /***********************************************************************
3517  *           HTTP_GetRedirectURL (internal)
3518  */
3519 static LPWSTR HTTP_GetRedirectURL(http_request_t *lpwhr, LPCWSTR lpszUrl)
3520 {
3521     static WCHAR szHttp[] = {'h','t','t','p',0};
3522     static WCHAR szHttps[] = {'h','t','t','p','s',0};
3523     http_session_t *lpwhs = lpwhr->lpHttpSession;
3524     URL_COMPONENTSW urlComponents;
3525     DWORD url_length = 0;
3526     LPWSTR orig_url;
3527     LPWSTR combined_url;
3528
3529     urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
3530     urlComponents.lpszScheme = (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE) ? szHttps : szHttp;
3531     urlComponents.dwSchemeLength = 0;
3532     urlComponents.lpszHostName = lpwhs->lpszHostName;
3533     urlComponents.dwHostNameLength = 0;
3534     urlComponents.nPort = lpwhs->nHostPort;
3535     urlComponents.lpszUserName = lpwhs->lpszUserName;
3536     urlComponents.dwUserNameLength = 0;
3537     urlComponents.lpszPassword = NULL;
3538     urlComponents.dwPasswordLength = 0;
3539     urlComponents.lpszUrlPath = lpwhr->lpszPath;
3540     urlComponents.dwUrlPathLength = 0;
3541     urlComponents.lpszExtraInfo = NULL;
3542     urlComponents.dwExtraInfoLength = 0;
3543
3544     if (!InternetCreateUrlW(&urlComponents, 0, NULL, &url_length) &&
3545         (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
3546         return NULL;
3547
3548     orig_url = HeapAlloc(GetProcessHeap(), 0, url_length);
3549
3550     /* convert from bytes to characters */
3551     url_length = url_length / sizeof(WCHAR) - 1;
3552     if (!InternetCreateUrlW(&urlComponents, 0, orig_url, &url_length))
3553     {
3554         HeapFree(GetProcessHeap(), 0, orig_url);
3555         return NULL;
3556     }
3557
3558     url_length = 0;
3559     if (!InternetCombineUrlW(orig_url, lpszUrl, NULL, &url_length, ICU_ENCODE_SPACES_ONLY) &&
3560         (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
3561     {
3562         HeapFree(GetProcessHeap(), 0, orig_url);
3563         return NULL;
3564     }
3565     combined_url = HeapAlloc(GetProcessHeap(), 0, url_length * sizeof(WCHAR));
3566
3567     if (!InternetCombineUrlW(orig_url, lpszUrl, combined_url, &url_length, ICU_ENCODE_SPACES_ONLY))
3568     {
3569         HeapFree(GetProcessHeap(), 0, orig_url);
3570         HeapFree(GetProcessHeap(), 0, combined_url);
3571         return NULL;
3572     }
3573     HeapFree(GetProcessHeap(), 0, orig_url);
3574     return combined_url;
3575 }
3576
3577
3578 /***********************************************************************
3579  *           HTTP_HandleRedirect (internal)
3580  */
3581 static BOOL HTTP_HandleRedirect(http_request_t *lpwhr, LPCWSTR lpszUrl)
3582 {
3583     http_session_t *lpwhs = lpwhr->lpHttpSession;
3584     appinfo_t *hIC = lpwhs->lpAppInfo;
3585     BOOL using_proxy = hIC->lpszProxy && hIC->lpszProxy[0];
3586     WCHAR path[INTERNET_MAX_URL_LENGTH];
3587     int index;
3588
3589     if(lpszUrl[0]=='/')
3590     {
3591         /* if it's an absolute path, keep the same session info */
3592         lstrcpynW(path, lpszUrl, INTERNET_MAX_URL_LENGTH);
3593     }
3594     else
3595     {
3596         URL_COMPONENTSW urlComponents;
3597         WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
3598         static WCHAR szHttp[] = {'h','t','t','p',0};
3599         static WCHAR szHttps[] = {'h','t','t','p','s',0};
3600
3601         userName[0] = 0;
3602         hostName[0] = 0;
3603         protocol[0] = 0;
3604
3605         urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
3606         urlComponents.lpszScheme = protocol;
3607         urlComponents.dwSchemeLength = 32;
3608         urlComponents.lpszHostName = hostName;
3609         urlComponents.dwHostNameLength = MAXHOSTNAME;
3610         urlComponents.lpszUserName = userName;
3611         urlComponents.dwUserNameLength = 1024;
3612         urlComponents.lpszPassword = NULL;
3613         urlComponents.dwPasswordLength = 0;
3614         urlComponents.lpszUrlPath = path;
3615         urlComponents.dwUrlPathLength = 2048;
3616         urlComponents.lpszExtraInfo = NULL;
3617         urlComponents.dwExtraInfoLength = 0;
3618         if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
3619             return FALSE;
3620
3621         if (!strncmpW(szHttp, urlComponents.lpszScheme, strlenW(szHttp)) &&
3622             (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE))
3623         {
3624             TRACE("redirect from secure page to non-secure page\n");
3625             /* FIXME: warn about from secure redirect to non-secure page */
3626             lpwhr->hdr.dwFlags &= ~INTERNET_FLAG_SECURE;
3627         }
3628         if (!strncmpW(szHttps, urlComponents.lpszScheme, strlenW(szHttps)) &&
3629             !(lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE))
3630         {
3631             TRACE("redirect from non-secure page to secure page\n");
3632             /* FIXME: notify about redirect to secure page */
3633             lpwhr->hdr.dwFlags |= INTERNET_FLAG_SECURE;
3634         }
3635
3636         if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
3637         {
3638             if (lstrlenW(protocol)>4) /*https*/
3639                 urlComponents.nPort = INTERNET_DEFAULT_HTTPS_PORT;
3640             else /*http*/
3641                 urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
3642         }
3643
3644 #if 0
3645         /*
3646          * This upsets redirects to binary files on sourceforge.net 
3647          * and gives an html page instead of the target file
3648          * Examination of the HTTP request sent by native wininet.dll
3649          * reveals that it doesn't send a referrer in that case.
3650          * Maybe there's a flag that enables this, or maybe a referrer
3651          * shouldn't be added in case of a redirect.
3652          */
3653
3654         /* consider the current host as the referrer */
3655         if (lpwhs->lpszServerName && *lpwhs->lpszServerName)
3656             HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName,
3657                            HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
3658                            HTTP_ADDHDR_FLAG_ADD_IF_NEW);
3659 #endif
3660         
3661         HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName);
3662         if (urlComponents.nPort != INTERNET_DEFAULT_HTTP_PORT &&
3663             urlComponents.nPort != INTERNET_DEFAULT_HTTPS_PORT)
3664         {
3665             int len;
3666             static const WCHAR fmt[] = {'%','s',':','%','i',0};
3667             len = lstrlenW(hostName);
3668             len += 7; /* 5 for strlen("65535") + 1 for ":" + 1 for '\0' */
3669             lpwhs->lpszHostName = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
3670             sprintfW(lpwhs->lpszHostName, fmt, hostName, urlComponents.nPort);
3671         }
3672         else
3673             lpwhs->lpszHostName = heap_strdupW(hostName);
3674
3675         HTTP_ProcessHeader(lpwhr, hostW, lpwhs->lpszHostName, HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDHDR_FLAG_REQ);
3676
3677         HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
3678         lpwhs->lpszUserName = NULL;
3679         if (userName[0])
3680             lpwhs->lpszUserName = heap_strdupW(userName);
3681
3682         if (!using_proxy)
3683         {
3684             if (strcmpiW(lpwhs->lpszServerName, hostName) || lpwhs->nServerPort != urlComponents.nPort)
3685             {
3686                 DWORD res;
3687
3688                 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
3689                 lpwhs->lpszServerName = heap_strdupW(hostName);
3690                 lpwhs->nServerPort = urlComponents.nPort;
3691
3692                 NETCON_close(&lpwhr->netConnection);
3693                 if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS) {
3694                     INTERNET_SetLastError(res);
3695                     return FALSE;
3696                 }
3697                 if (!NETCON_init(&lpwhr->netConnection, lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)) return FALSE;
3698                 lpwhr->read_pos = lpwhr->read_size = 0;
3699                 lpwhr->read_chunked = FALSE;
3700             }
3701         }
3702         else
3703             TRACE("Redirect through proxy\n");
3704     }
3705
3706     HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
3707     lpwhr->lpszPath=NULL;
3708     if (*path)
3709     {
3710         DWORD needed = 0;
3711         HRESULT rc;
3712
3713         rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
3714         if (rc != E_POINTER)
3715             needed = strlenW(path)+1;
3716         lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR));
3717         rc = UrlEscapeW(path, lpwhr->lpszPath, &needed,
3718                         URL_ESCAPE_SPACES_ONLY);
3719         if (rc != S_OK)
3720         {
3721             ERR("Unable to escape string!(%s) (%d)\n",debugstr_w(path),rc);
3722             strcpyW(lpwhr->lpszPath,path);
3723         }
3724     }
3725
3726     /* Remove custom content-type/length headers on redirects.  */
3727     index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Type, 0, TRUE);
3728     if (0 <= index)
3729         HTTP_DeleteCustomHeader(lpwhr, index);
3730     index = HTTP_GetCustomHeaderIndex(lpwhr, szContent_Length, 0, TRUE);
3731     if (0 <= index)
3732         HTTP_DeleteCustomHeader(lpwhr, index);
3733
3734     return TRUE;
3735 }
3736
3737 /***********************************************************************
3738  *           HTTP_build_req (internal)
3739  *
3740  *  concatenate all the strings in the request together
3741  */
3742 static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
3743 {
3744     LPCWSTR *t;
3745     LPWSTR str;
3746
3747     for( t = list; *t ; t++  )
3748         len += strlenW( *t );
3749     len++;
3750
3751     str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
3752     *str = 0;
3753
3754     for( t = list; *t ; t++ )
3755         strcatW( str, *t );
3756
3757     return str;
3758 }
3759
3760 static DWORD HTTP_SecureProxyConnect(http_request_t *lpwhr)
3761 {
3762     LPWSTR lpszPath;
3763     LPWSTR requestString;
3764     INT len;
3765     INT cnt;
3766     INT responseLen;
3767     char *ascii_req;
3768     DWORD res;
3769     static const WCHAR szConnect[] = {'C','O','N','N','E','C','T',0};
3770     static const WCHAR szFormat[] = {'%','s',':','%','d',0};
3771     http_session_t *lpwhs = lpwhr->lpHttpSession;
3772
3773     TRACE("\n");
3774
3775     lpszPath = HeapAlloc( GetProcessHeap(), 0, (lstrlenW( lpwhs->lpszHostName ) + 13)*sizeof(WCHAR) );
3776     sprintfW( lpszPath, szFormat, lpwhs->lpszHostName, lpwhs->nHostPort );
3777     requestString = HTTP_BuildHeaderRequestString( lpwhr, szConnect, lpszPath, g_szHttp1_1 );
3778     HeapFree( GetProcessHeap(), 0, lpszPath );
3779
3780     len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
3781                                 NULL, 0, NULL, NULL );
3782     len--; /* the nul terminator isn't needed */
3783     ascii_req = HeapAlloc( GetProcessHeap(), 0, len );
3784     WideCharToMultiByte( CP_ACP, 0, requestString, -1,
3785                             ascii_req, len, NULL, NULL );
3786     HeapFree( GetProcessHeap(), 0, requestString );
3787
3788     TRACE("full request -> %s\n", debugstr_an( ascii_req, len ) );
3789
3790     res = NETCON_send( &lpwhr->netConnection, ascii_req, len, 0, &cnt );
3791     HeapFree( GetProcessHeap(), 0, ascii_req );
3792     if (res != ERROR_SUCCESS)
3793         return res;
3794
3795     responseLen = HTTP_GetResponseHeaders( lpwhr, TRUE );
3796     if (!responseLen)
3797         return ERROR_HTTP_INVALID_HEADER;
3798
3799     return ERROR_SUCCESS;
3800 }
3801
3802 static void HTTP_InsertCookies(http_request_t *lpwhr)
3803 {
3804     static const WCHAR szUrlForm[] = {'h','t','t','p',':','/','/','%','s','%','s',0};
3805     LPWSTR lpszCookies, lpszUrl = NULL;
3806     DWORD nCookieSize, size;
3807     LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
3808
3809     size = (strlenW(Host->lpszValue) + strlenW(szUrlForm) + strlenW(lpwhr->lpszPath)) * sizeof(WCHAR);
3810     if (!(lpszUrl = HeapAlloc(GetProcessHeap(), 0, size))) return;
3811     sprintfW( lpszUrl, szUrlForm, Host->lpszValue, lpwhr->lpszPath);
3812
3813     if (InternetGetCookieW(lpszUrl, NULL, NULL, &nCookieSize))
3814     {
3815         int cnt = 0;
3816         static const WCHAR szCookie[] = {'C','o','o','k','i','e',':',' ',0};
3817
3818         size = sizeof(szCookie) + nCookieSize * sizeof(WCHAR) + sizeof(szCrLf);
3819         if ((lpszCookies = HeapAlloc(GetProcessHeap(), 0, size)))
3820         {
3821             cnt += sprintfW(lpszCookies, szCookie);
3822             InternetGetCookieW(lpszUrl, NULL, lpszCookies + cnt, &nCookieSize);
3823             strcatW(lpszCookies, szCrLf);
3824
3825             HTTP_HttpAddRequestHeadersW(lpwhr, lpszCookies, strlenW(lpszCookies), HTTP_ADDREQ_FLAG_REPLACE);
3826             HeapFree(GetProcessHeap(), 0, lpszCookies);
3827         }
3828     }
3829     HeapFree(GetProcessHeap(), 0, lpszUrl);
3830 }
3831
3832 /***********************************************************************
3833  *           HTTP_HttpSendRequestW (internal)
3834  *
3835  * Sends the specified request to the HTTP server
3836  *
3837  * RETURNS
3838  *    TRUE  on success
3839  *    FALSE on failure
3840  *
3841  */
3842 BOOL WINAPI HTTP_HttpSendRequestW(http_request_t *lpwhr, LPCWSTR lpszHeaders,
3843         DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength,
3844         DWORD dwContentLength, BOOL bEndRequest)
3845 {
3846     INT cnt;
3847     BOOL bSuccess = FALSE, redirected = FALSE;
3848     LPWSTR requestString = NULL;
3849     INT responseLen;
3850     BOOL loop_next;
3851     INTERNET_ASYNC_RESULT iar;
3852     static const WCHAR szPost[] = { 'P','O','S','T',0 };
3853     static const WCHAR szContentLength[] =
3854         { 'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0 };
3855     WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \r\n */ + 20 /* int */ ];
3856     DWORD res;
3857
3858     TRACE("--> %p\n", lpwhr);
3859
3860     assert(lpwhr->hdr.htype == WH_HHTTPREQ);
3861
3862     /* if the verb is NULL default to GET */
3863     if (!lpwhr->lpszVerb)
3864         lpwhr->lpszVerb = heap_strdupW(szGET);
3865
3866     if (dwContentLength || strcmpW(lpwhr->lpszVerb, szGET))
3867     {
3868         sprintfW(contentLengthStr, szContentLength, dwContentLength);
3869         HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_REPLACE);
3870         lpwhr->dwBytesToWrite = dwContentLength;
3871     }
3872     if (lpwhr->lpHttpSession->lpAppInfo->lpszAgent)
3873     {
3874         WCHAR *agent_header;
3875         static const WCHAR user_agent[] = {'U','s','e','r','-','A','g','e','n','t',':',' ','%','s','\r','\n',0};
3876         int len;
3877
3878         len = strlenW(lpwhr->lpHttpSession->lpAppInfo->lpszAgent) + strlenW(user_agent);
3879         agent_header = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3880         sprintfW(agent_header, user_agent, lpwhr->lpHttpSession->lpAppInfo->lpszAgent);
3881
3882         HTTP_HttpAddRequestHeadersW(lpwhr, agent_header, strlenW(agent_header), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
3883         HeapFree(GetProcessHeap(), 0, agent_header);
3884     }
3885     if (lpwhr->hdr.dwFlags & INTERNET_FLAG_PRAGMA_NOCACHE)
3886     {
3887         static const WCHAR pragma_nocache[] = {'P','r','a','g','m','a',':',' ','n','o','-','c','a','c','h','e','\r','\n',0};
3888         HTTP_HttpAddRequestHeadersW(lpwhr, pragma_nocache, strlenW(pragma_nocache), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
3889     }
3890     if ((lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_CACHE_WRITE) && !strcmpW(lpwhr->lpszVerb, szPost))
3891     {
3892         static const WCHAR cache_control[] = {'C','a','c','h','e','-','C','o','n','t','r','o','l',':',
3893                                               ' ','n','o','-','c','a','c','h','e','\r','\n',0};
3894         HTTP_HttpAddRequestHeadersW(lpwhr, cache_control, strlenW(cache_control), HTTP_ADDREQ_FLAG_ADD_IF_NEW);
3895     }
3896
3897     do
3898     {
3899         DWORD len;
3900         char *ascii_req;
3901
3902         loop_next = FALSE;
3903
3904         /* like native, just in case the caller forgot to call InternetReadFile
3905          * for all the data */
3906         HTTP_DrainContent(lpwhr);
3907         lpwhr->dwContentRead = 0;
3908
3909         if (TRACE_ON(wininet))
3910         {
3911             LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
3912             TRACE("Going to url %s %s\n", debugstr_w(Host->lpszValue), debugstr_w(lpwhr->lpszPath));
3913         }
3914
3915         HTTP_FixURL(lpwhr);
3916         if (lpwhr->hdr.dwFlags & INTERNET_FLAG_KEEP_CONNECTION)
3917         {
3918             HTTP_ProcessHeader(lpwhr, szConnection, szKeepAlive, HTTP_ADDHDR_FLAG_REQ | HTTP_ADDHDR_FLAG_REPLACE);
3919         }
3920         HTTP_InsertAuthorization(lpwhr, lpwhr->pAuthInfo, szAuthorization);
3921         HTTP_InsertAuthorization(lpwhr, lpwhr->pProxyAuthInfo, szProxy_Authorization);
3922
3923         if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES))
3924             HTTP_InsertCookies(lpwhr);
3925
3926         /* add the headers the caller supplied */
3927         if( lpszHeaders && dwHeaderLength )
3928         {
3929             HTTP_HttpAddRequestHeadersW(lpwhr, lpszHeaders, dwHeaderLength,
3930                         HTTP_ADDREQ_FLAG_ADD | HTTP_ADDHDR_FLAG_REPLACE);
3931         }
3932
3933         if (lpwhr->lpHttpSession->lpAppInfo->lpszProxy && lpwhr->lpHttpSession->lpAppInfo->lpszProxy[0])
3934         {
3935             WCHAR *url = HTTP_BuildProxyRequestUrl(lpwhr);
3936             requestString = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, url, lpwhr->lpszVersion);
3937             HeapFree(GetProcessHeap(), 0, url);
3938         }
3939         else
3940             requestString = HTTP_BuildHeaderRequestString(lpwhr, lpwhr->lpszVerb, lpwhr->lpszPath, lpwhr->lpszVersion);
3941
3942  
3943         TRACE("Request header -> %s\n", debugstr_w(requestString) );
3944
3945         /* Send the request and store the results */
3946         if ((res = HTTP_OpenConnection(lpwhr)) != ERROR_SUCCESS) {
3947             INTERNET_SetLastError(res);
3948             goto lend;
3949         }
3950
3951         /* send the request as ASCII, tack on the optional data */
3952         if (!lpOptional || redirected)
3953             dwOptionalLength = 0;
3954         len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
3955                                    NULL, 0, NULL, NULL );
3956         ascii_req = HeapAlloc( GetProcessHeap(), 0, len + dwOptionalLength );
3957         WideCharToMultiByte( CP_ACP, 0, requestString, -1,
3958                              ascii_req, len, NULL, NULL );
3959         if( lpOptional )
3960             memcpy( &ascii_req[len-1], lpOptional, dwOptionalLength );
3961         len = (len + dwOptionalLength - 1);
3962         ascii_req[len] = 0;
3963         TRACE("full request -> %s\n", debugstr_a(ascii_req) );
3964
3965         INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
3966                               INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
3967
3968         NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt);
3969         HeapFree( GetProcessHeap(), 0, ascii_req );
3970
3971         lpwhr->dwBytesWritten = dwOptionalLength;
3972
3973         INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
3974                               INTERNET_STATUS_REQUEST_SENT,
3975                               &len, sizeof(DWORD));
3976
3977         if (bEndRequest)
3978         {
3979             DWORD dwBufferSize;
3980             DWORD dwStatusCode;
3981
3982             INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
3983                                 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
3984     
3985             if (cnt < 0)
3986                 goto lend;
3987     
3988             responseLen = HTTP_GetResponseHeaders(lpwhr, TRUE);
3989             if (responseLen)
3990                 bSuccess = TRUE;
3991     
3992             INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
3993                                 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
3994                                 sizeof(DWORD));
3995
3996             HTTP_ProcessCookies(lpwhr);
3997
3998             if (!set_content_length( lpwhr )) HTTP_FinishedReading(lpwhr);
3999
4000             dwBufferSize = sizeof(dwStatusCode);
4001             if (!HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,
4002                                      &dwStatusCode,&dwBufferSize,NULL))
4003                 dwStatusCode = 0;
4004
4005             if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
4006             {
4007                 WCHAR *new_url, szNewLocation[INTERNET_MAX_URL_LENGTH];
4008                 dwBufferSize=sizeof(szNewLocation);
4009                 if ((dwStatusCode==HTTP_STATUS_REDIRECT || dwStatusCode==HTTP_STATUS_MOVED) &&
4010                     HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,NULL))
4011                 {
4012                     if (strcmpW(lpwhr->lpszVerb, szGET) && strcmpW(lpwhr->lpszVerb, szHEAD))
4013                     {
4014                         HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
4015                         lpwhr->lpszVerb = heap_strdupW(szGET);
4016                     }
4017                     HTTP_DrainContent(lpwhr);
4018                     if ((new_url = HTTP_GetRedirectURL( lpwhr, szNewLocation )))
4019                     {
4020                         INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext, INTERNET_STATUS_REDIRECT,
4021                                               new_url, (strlenW(new_url) + 1) * sizeof(WCHAR));
4022                         bSuccess = HTTP_HandleRedirect(lpwhr, new_url);
4023                         if (bSuccess)
4024                         {
4025                             HeapFree(GetProcessHeap(), 0, requestString);
4026                             loop_next = TRUE;
4027                         }
4028                         HeapFree( GetProcessHeap(), 0, new_url );
4029                     }
4030                     redirected = TRUE;
4031                 }
4032             }
4033             if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_AUTH) && bSuccess)
4034             {
4035                 WCHAR szAuthValue[2048];
4036                 dwBufferSize=2048;
4037                 if (dwStatusCode == HTTP_STATUS_DENIED)
4038                 {
4039                     LPHTTPHEADERW Host = HTTP_GetHeader(lpwhr, hostW);
4040                     DWORD dwIndex = 0;
4041                     while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_WWW_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex))
4042                     {
4043                         if (HTTP_DoAuthorization(lpwhr, szAuthValue,
4044                                                  &lpwhr->pAuthInfo,
4045                                                  lpwhr->lpHttpSession->lpszUserName,
4046                                                  lpwhr->lpHttpSession->lpszPassword,
4047                                                  Host->lpszValue))
4048                         {
4049                             loop_next = TRUE;
4050                             break;
4051                         }
4052                     }
4053                 }
4054                 if (dwStatusCode == HTTP_STATUS_PROXY_AUTH_REQ)
4055                 {
4056                     DWORD dwIndex = 0;
4057                     while (HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_PROXY_AUTHENTICATE,szAuthValue,&dwBufferSize,&dwIndex))
4058                     {
4059                         if (HTTP_DoAuthorization(lpwhr, szAuthValue,
4060                                                  &lpwhr->pProxyAuthInfo,
4061                                                  lpwhr->lpHttpSession->lpAppInfo->lpszProxyUsername,
4062                                                  lpwhr->lpHttpSession->lpAppInfo->lpszProxyPassword,
4063                                                  NULL))
4064                         {
4065                             loop_next = TRUE;
4066                             break;
4067                         }
4068                     }
4069                 }
4070             }
4071         }
4072         else
4073             bSuccess = TRUE;
4074     }
4075     while (loop_next);
4076
4077     if(bSuccess) {
4078         WCHAR url[INTERNET_MAX_URL_LENGTH];
4079         WCHAR cacheFileName[MAX_PATH+1];
4080         BOOL b;
4081
4082         b = HTTP_GetRequestURL(lpwhr, url);
4083         if(!b) {
4084             WARN("Could not get URL\n");
4085             goto lend;
4086         }
4087
4088         b = CreateUrlCacheEntryW(url, lpwhr->dwContentLength > 0 ? lpwhr->dwContentLength : 0, NULL, cacheFileName, 0);
4089         if(b) {
4090             lpwhr->lpszCacheFile = heap_strdupW(cacheFileName);
4091             lpwhr->hCacheFile = CreateFileW(lpwhr->lpszCacheFile, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
4092                       NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
4093             if(lpwhr->hCacheFile == INVALID_HANDLE_VALUE) {
4094                 WARN("Could not create file: %u\n", GetLastError());
4095                 lpwhr->hCacheFile = NULL;
4096             }
4097         }else {
4098             WARN("Could not create cache entry: %08x\n", GetLastError());
4099         }
4100     }
4101
4102 lend:
4103
4104     HeapFree(GetProcessHeap(), 0, requestString);
4105
4106     /* TODO: send notification for P3P header */
4107
4108     if (lpwhr->lpHttpSession->lpAppInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC)
4109     {
4110         if (bSuccess)
4111         {
4112             if (lpwhr->dwBytesWritten == lpwhr->dwBytesToWrite) HTTP_ReceiveRequestData(lpwhr, TRUE);
4113             else
4114             {
4115                 iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
4116                 iar.dwError = 0;
4117
4118                 INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
4119                                   INTERNET_STATUS_REQUEST_COMPLETE, &iar,
4120                                   sizeof(INTERNET_ASYNC_RESULT));
4121             }
4122         }
4123         else
4124         {
4125             iar.dwResult = (DWORD_PTR)lpwhr->hdr.hInternet;
4126             iar.dwError = INTERNET_GetLastError();
4127
4128             INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
4129                                   INTERNET_STATUS_REQUEST_COMPLETE, &iar,
4130                                   sizeof(INTERNET_ASYNC_RESULT));
4131         }
4132     }
4133
4134     TRACE("<--\n");
4135     if (bSuccess) INTERNET_SetLastError(ERROR_SUCCESS);
4136     return bSuccess;
4137 }
4138
4139 /***********************************************************************
4140  *           HTTPSESSION_Destroy (internal)
4141  *
4142  * Deallocate session handle
4143  *
4144  */
4145 static void HTTPSESSION_Destroy(object_header_t *hdr)
4146 {
4147     http_session_t *lpwhs = (http_session_t*) hdr;
4148
4149     TRACE("%p\n", lpwhs);
4150
4151     WININET_Release(&lpwhs->lpAppInfo->hdr);
4152
4153     HeapFree(GetProcessHeap(), 0, lpwhs->lpszHostName);
4154     HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
4155     HeapFree(GetProcessHeap(), 0, lpwhs->lpszPassword);
4156     HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
4157     HeapFree(GetProcessHeap(), 0, lpwhs);
4158 }
4159
4160 static DWORD HTTPSESSION_QueryOption(object_header_t *hdr, DWORD option, void *buffer, DWORD *size, BOOL unicode)
4161 {
4162     switch(option) {
4163     case INTERNET_OPTION_HANDLE_TYPE:
4164         TRACE("INTERNET_OPTION_HANDLE_TYPE\n");
4165
4166         if (*size < sizeof(ULONG))
4167             return ERROR_INSUFFICIENT_BUFFER;
4168
4169         *size = sizeof(DWORD);
4170         *(DWORD*)buffer = INTERNET_HANDLE_TYPE_CONNECT_HTTP;
4171         return ERROR_SUCCESS;
4172     }
4173
4174     return INET_QueryOption(option, buffer, size, unicode);
4175 }
4176
4177 static DWORD HTTPSESSION_SetOption(object_header_t *hdr, DWORD option, void *buffer, DWORD size)
4178 {
4179     http_session_t *ses = (http_session_t*)hdr;
4180
4181     switch(option) {
4182     case INTERNET_OPTION_USERNAME:
4183     {
4184         HeapFree(GetProcessHeap(), 0, ses->lpszUserName);
4185         if (!(ses->lpszUserName = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
4186         return ERROR_SUCCESS;
4187     }
4188     case INTERNET_OPTION_PASSWORD:
4189     {
4190         HeapFree(GetProcessHeap(), 0, ses->lpszPassword);
4191         if (!(ses->lpszPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY;
4192         return ERROR_SUCCESS;
4193     }
4194     default: break;
4195     }
4196
4197     return ERROR_INTERNET_INVALID_OPTION;
4198 }
4199
4200 static const object_vtbl_t HTTPSESSIONVtbl = {
4201     HTTPSESSION_Destroy,
4202     NULL,
4203     HTTPSESSION_QueryOption,
4204     HTTPSESSION_SetOption,
4205     NULL,
4206     NULL,
4207     NULL,
4208     NULL,
4209     NULL
4210 };
4211
4212
4213 /***********************************************************************
4214  *           HTTP_Connect  (internal)
4215  *
4216  * Create http session handle
4217  *
4218  * RETURNS
4219  *   HINTERNET a session handle on success
4220  *   NULL on failure
4221  *
4222  */
4223 HINTERNET HTTP_Connect(appinfo_t *hIC, LPCWSTR lpszServerName,
4224         INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
4225         LPCWSTR lpszPassword, DWORD dwFlags, DWORD_PTR dwContext,
4226         DWORD dwInternalFlags)
4227 {
4228     http_session_t *lpwhs = NULL;
4229     HINTERNET handle = NULL;
4230
4231     TRACE("-->\n");
4232
4233     if (!lpszServerName || !lpszServerName[0])
4234     {
4235         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
4236         goto lerror;
4237     }
4238
4239     assert( hIC->hdr.htype == WH_HINIT );
4240
4241     lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(http_session_t));
4242     if (NULL == lpwhs)
4243     {
4244         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
4245         goto lerror;
4246     }
4247
4248    /*
4249     * According to my tests. The name is not resolved until a request is sent
4250     */
4251
4252     lpwhs->hdr.htype = WH_HHTTPSESSION;
4253     lpwhs->hdr.vtbl = &HTTPSESSIONVtbl;
4254     lpwhs->hdr.dwFlags = dwFlags;
4255     lpwhs->hdr.dwContext = dwContext;
4256     lpwhs->hdr.dwInternalFlags = dwInternalFlags | (hIC->hdr.dwInternalFlags & INET_CALLBACKW);
4257     lpwhs->hdr.refs = 1;
4258     lpwhs->hdr.lpfnStatusCB = hIC->hdr.lpfnStatusCB;
4259
4260     WININET_AddRef( &hIC->hdr );
4261     lpwhs->lpAppInfo = hIC;
4262     list_add_head( &hIC->hdr.children, &lpwhs->hdr.entry );
4263
4264     handle = WININET_AllocHandle( &lpwhs->hdr );
4265     if (NULL == handle)
4266     {
4267         ERR("Failed to alloc handle\n");
4268         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
4269         goto lerror;
4270     }
4271
4272     if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
4273         if(strchrW(hIC->lpszProxy, ' '))
4274             FIXME("Several proxies not implemented.\n");
4275         if(hIC->lpszProxyBypass)
4276             FIXME("Proxy bypass is ignored.\n");
4277     }
4278     if (lpszServerName && lpszServerName[0])
4279     {
4280         lpwhs->lpszServerName = heap_strdupW(lpszServerName);
4281         lpwhs->lpszHostName = heap_strdupW(lpszServerName);
4282     }
4283     if (lpszUserName && lpszUserName[0])
4284         lpwhs->lpszUserName = heap_strdupW(lpszUserName);
4285     if (lpszPassword && lpszPassword[0])
4286         lpwhs->lpszPassword = heap_strdupW(lpszPassword);
4287     lpwhs->nServerPort = nServerPort;
4288     lpwhs->nHostPort = nServerPort;
4289
4290     /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
4291     if (!(lpwhs->hdr.dwInternalFlags & INET_OPENURL))
4292     {
4293         INTERNET_SendCallback(&hIC->hdr, dwContext,
4294                               INTERNET_STATUS_HANDLE_CREATED, &handle,
4295                               sizeof(handle));
4296     }
4297
4298 lerror:
4299     if( lpwhs )
4300         WININET_Release( &lpwhs->hdr );
4301
4302 /*
4303  * an INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
4304  * windows
4305  */
4306
4307     TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs);
4308     return handle;
4309 }
4310
4311
4312 /***********************************************************************
4313  *           HTTP_OpenConnection (internal)
4314  *
4315  * Connect to a web server
4316  *
4317  * RETURNS
4318  *
4319  *   TRUE  on success
4320  *   FALSE on failure
4321  */
4322 static DWORD HTTP_OpenConnection(http_request_t *lpwhr)
4323 {
4324     http_session_t *lpwhs;
4325     appinfo_t *hIC = NULL;
4326     char szaddr[INET6_ADDRSTRLEN];
4327     const void *addr;
4328     DWORD res = ERROR_SUCCESS;
4329
4330     TRACE("-->\n");
4331
4332
4333     if (lpwhr->hdr.htype != WH_HHTTPREQ)
4334     {
4335         res = ERROR_INVALID_PARAMETER;
4336         goto lend;
4337     }
4338
4339     if (NETCON_connected(&lpwhr->netConnection))
4340         goto lend;
4341     if ((res = HTTP_ResolveName(lpwhr)) != ERROR_SUCCESS) goto lend;
4342
4343     lpwhs = lpwhr->lpHttpSession;
4344
4345     hIC = lpwhs->lpAppInfo;
4346     switch (lpwhs->socketAddress.ss_family)
4347     {
4348     case AF_INET:
4349         addr = &((struct sockaddr_in *)&lpwhs->socketAddress)->sin_addr;
4350         break;
4351     case AF_INET6:
4352         addr = &((struct sockaddr_in6 *)&lpwhs->socketAddress)->sin6_addr;
4353         break;
4354     default:
4355         WARN("unsupported family %d\n", lpwhs->socketAddress.ss_family);
4356         return ERROR_INTERNET_NAME_NOT_RESOLVED;
4357     }
4358     inet_ntop(lpwhs->socketAddress.ss_family, addr, szaddr, sizeof(szaddr));
4359     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
4360                           INTERNET_STATUS_CONNECTING_TO_SERVER,
4361                           szaddr,
4362                           strlen(szaddr)+1);
4363
4364     res = NETCON_create(&lpwhr->netConnection, lpwhs->socketAddress.ss_family, SOCK_STREAM, 0);
4365     if (res != ERROR_SUCCESS)
4366     {
4367         WARN("Socket creation failed: %u\n", res);
4368         goto lend;
4369     }
4370
4371     res = NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
4372                          lpwhs->sa_len);
4373     if(res != ERROR_SUCCESS)
4374        goto lend;
4375
4376     if (lpwhr->hdr.dwFlags & INTERNET_FLAG_SECURE)
4377     {
4378         /* Note: we differ from Microsoft's WinINet here. they seem to have
4379          * a bug that causes no status callbacks to be sent when starting
4380          * a tunnel to a proxy server using the CONNECT verb. i believe our
4381          * behaviour to be more correct and to not cause any incompatibilities
4382          * because using a secure connection through a proxy server is a rare
4383          * case that would be hard for anyone to depend on */
4384         if (hIC->lpszProxy && (res = HTTP_SecureProxyConnect(lpwhr)) != ERROR_SUCCESS)
4385             goto lend;
4386
4387         res = NETCON_secure_connect(&lpwhr->netConnection, lpwhs->lpszHostName);
4388         if(res != ERROR_SUCCESS)
4389         {
4390             WARN("Couldn't connect securely to host\n");
4391             goto lend;
4392         }
4393     }
4394
4395     INTERNET_SendCallback(&lpwhr->hdr, lpwhr->hdr.dwContext,
4396                           INTERNET_STATUS_CONNECTED_TO_SERVER,
4397                           szaddr, strlen(szaddr)+1);
4398
4399 lend:
4400     lpwhr->read_pos = lpwhr->read_size = 0;
4401     lpwhr->read_chunked = FALSE;
4402
4403     TRACE("%d <--\n", res);
4404     return res;
4405 }
4406
4407
4408 /***********************************************************************
4409  *           HTTP_clear_response_headers (internal)
4410  *
4411  * clear out any old response headers
4412  */
4413 static void HTTP_clear_response_headers( http_request_t *lpwhr )
4414 {
4415     DWORD i;
4416
4417     for( i=0; i<lpwhr->nCustHeaders; i++)
4418     {
4419         if( !lpwhr->pCustHeaders[i].lpszField )
4420             continue;
4421         if( !lpwhr->pCustHeaders[i].lpszValue )
4422             continue;
4423         if ( lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST )
4424             continue;
4425         HTTP_DeleteCustomHeader( lpwhr, i );
4426         i--;
4427     }
4428 }
4429
4430 /***********************************************************************
4431  *           HTTP_GetResponseHeaders (internal)
4432  *
4433  * Read server response
4434  *
4435  * RETURNS
4436  *
4437  *   TRUE  on success
4438  *   FALSE on error
4439  */
4440 static INT HTTP_GetResponseHeaders(http_request_t *lpwhr, BOOL clear)
4441 {
4442     INT cbreaks = 0;
4443     WCHAR buffer[MAX_REPLY_LEN];
4444     DWORD buflen = MAX_REPLY_LEN;
4445     BOOL bSuccess = FALSE;
4446     INT  rc = 0;
4447     char bufferA[MAX_REPLY_LEN];
4448     LPWSTR status_code = NULL, status_text = NULL;
4449     DWORD cchMaxRawHeaders = 1024;
4450     LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR));
4451     LPWSTR temp;
4452     DWORD cchRawHeaders = 0;
4453     BOOL codeHundred = FALSE;
4454
4455     TRACE("-->\n");
4456
4457     /* clear old response headers (eg. from a redirect response) */
4458     if (clear) HTTP_clear_response_headers( lpwhr );
4459
4460     if (!NETCON_connected(&lpwhr->netConnection))
4461         goto lend;
4462
4463     do {
4464         static const WCHAR szHundred[] = {'1','0','0',0};
4465         /*
4466          * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
4467          */
4468         buflen = MAX_REPLY_LEN;
4469         if (!read_line(lpwhr, bufferA, &buflen))
4470             goto lend;
4471         rc += buflen;
4472         MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
4473         /* check is this a status code line? */
4474         if (!strncmpW(buffer, g_szHttp1_0, 4))
4475         {
4476             /* split the version from the status code */
4477             status_code = strchrW( buffer, ' ' );
4478             if( !status_code )
4479                 goto lend;
4480             *status_code++=0;
4481
4482             /* split the status code from the status text */
4483             status_text = strchrW( status_code, ' ' );
4484             if( !status_text )
4485                 goto lend;
4486             *status_text++=0;
4487
4488             TRACE("version [%s] status code [%s] status text [%s]\n",
4489                debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
4490
4491             codeHundred = (!strcmpW(status_code, szHundred));
4492         }
4493         else if (!codeHundred)
4494         {
4495             FIXME("Non status line at head of response (%s)\n",debugstr_w(buffer));
4496             goto lend;
4497         }
4498     } while (codeHundred);
4499
4500     /* Add status code */
4501     HTTP_ProcessHeader(lpwhr, szStatus, status_code,
4502             HTTP_ADDHDR_FLAG_REPLACE);
4503
4504     HeapFree(GetProcessHeap(),0,lpwhr->lpszVersion);
4505     HeapFree(GetProcessHeap(),0,lpwhr->lpszStatusText);
4506
4507     lpwhr->lpszVersion = heap_strdupW(buffer);
4508     lpwhr->lpszStatusText = heap_strdupW(status_text);
4509
4510     /* Restore the spaces */
4511     *(status_code-1) = ' ';
4512     *(status_text-1) = ' ';
4513
4514     /* regenerate raw headers */
4515     while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
4516         cchMaxRawHeaders *= 2;
4517     temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
4518     if (temp == NULL) goto lend;
4519     lpszRawHeaders = temp;
4520     memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
4521     cchRawHeaders += (buflen-1);
4522     memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
4523     cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
4524     lpszRawHeaders[cchRawHeaders] = '\0';
4525
4526     /* Parse each response line */
4527     do
4528     {
4529         buflen = MAX_REPLY_LEN;
4530         if (read_line(lpwhr, bufferA, &buflen))
4531         {
4532             LPWSTR * pFieldAndValue;
4533
4534             TRACE("got line %s, now interpreting\n", debugstr_a(bufferA));
4535
4536             if (!bufferA[0]) break;
4537             MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
4538
4539             pFieldAndValue = HTTP_InterpretHttpHeader(buffer);
4540             if (pFieldAndValue)
4541             {
4542                 while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
4543                     cchMaxRawHeaders *= 2;
4544                 temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
4545                 if (temp == NULL) goto lend;
4546                 lpszRawHeaders = temp;
4547                 memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
4548                 cchRawHeaders += (buflen-1);
4549                 memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
4550                 cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
4551                 lpszRawHeaders[cchRawHeaders] = '\0';
4552
4553                 HTTP_ProcessHeader(lpwhr, pFieldAndValue[0], pFieldAndValue[1],
4554                                    HTTP_ADDREQ_FLAG_ADD );
4555
4556                 HTTP_FreeTokens(pFieldAndValue);
4557             }
4558         }
4559         else
4560         {
4561             cbreaks++;
4562             if (cbreaks >= 2)
4563                break;
4564         }
4565     }while(1);
4566
4567     /* make sure the response header is terminated with an empty line.  Some apps really
4568        truly care about that empty line being there for some reason.  Just add it to the
4569        header. */
4570     if (cchRawHeaders + strlenW(szCrLf) > cchMaxRawHeaders)
4571     {
4572         cchMaxRawHeaders = cchRawHeaders + strlenW(szCrLf);
4573         temp = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders + 1) * sizeof(WCHAR));
4574         if (temp == NULL) goto lend;
4575         lpszRawHeaders = temp;
4576     }
4577
4578     memcpy(&lpszRawHeaders[cchRawHeaders], szCrLf, sizeof(szCrLf));
4579
4580     HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
4581     lpwhr->lpszRawHeaders = lpszRawHeaders;
4582     TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
4583     bSuccess = TRUE;
4584
4585 lend:
4586
4587     TRACE("<--\n");
4588     if (bSuccess)
4589         return rc;
4590     else
4591     {
4592         HeapFree(GetProcessHeap(), 0, lpszRawHeaders);
4593         return 0;
4594     }
4595 }
4596
4597 /***********************************************************************
4598  *           HTTP_InterpretHttpHeader (internal)
4599  *
4600  * Parse server response
4601  *
4602  * RETURNS
4603  *
4604  *   Pointer to array of field, value, NULL on success.
4605  *   NULL on error.
4606  */
4607 static LPWSTR * HTTP_InterpretHttpHeader(LPCWSTR buffer)
4608 {
4609     LPWSTR * pTokenPair;
4610     LPWSTR pszColon;
4611     INT len;
4612
4613     pTokenPair = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pTokenPair)*3);
4614
4615     pszColon = strchrW(buffer, ':');
4616     /* must have two tokens */
4617     if (!pszColon)
4618     {
4619         HTTP_FreeTokens(pTokenPair);
4620         if (buffer[0])
4621             TRACE("No ':' in line: %s\n", debugstr_w(buffer));
4622         return NULL;
4623     }
4624
4625     pTokenPair[0] = HeapAlloc(GetProcessHeap(), 0, (pszColon - buffer + 1) * sizeof(WCHAR));
4626     if (!pTokenPair[0])
4627     {
4628         HTTP_FreeTokens(pTokenPair);
4629         return NULL;
4630     }
4631     memcpy(pTokenPair[0], buffer, (pszColon - buffer) * sizeof(WCHAR));
4632     pTokenPair[0][pszColon - buffer] = '\0';
4633
4634     /* skip colon */
4635     pszColon++;
4636     len = strlenW(pszColon);
4637     pTokenPair[1] = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
4638     if (!pTokenPair[1])
4639     {
4640         HTTP_FreeTokens(pTokenPair);
4641         return NULL;
4642     }
4643     memcpy(pTokenPair[1], pszColon, (len + 1) * sizeof(WCHAR));
4644
4645     strip_spaces(pTokenPair[0]);
4646     strip_spaces(pTokenPair[1]);
4647
4648     TRACE("field(%s) Value(%s)\n", debugstr_w(pTokenPair[0]), debugstr_w(pTokenPair[1]));
4649     return pTokenPair;
4650 }
4651
4652 /***********************************************************************
4653  *           HTTP_ProcessHeader (internal)
4654  *
4655  * Stuff header into header tables according to <dwModifier>
4656  *
4657  */
4658
4659 #define COALESCEFLAGS (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
4660
4661 static BOOL HTTP_ProcessHeader(http_request_t *lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
4662 {
4663     LPHTTPHEADERW lphttpHdr = NULL;
4664     BOOL bSuccess = FALSE;
4665     INT index = -1;
4666     BOOL request_only = dwModifier & HTTP_ADDHDR_FLAG_REQ;
4667
4668     TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), dwModifier);
4669
4670     /* REPLACE wins out over ADD */
4671     if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
4672         dwModifier &= ~HTTP_ADDHDR_FLAG_ADD;
4673     
4674     if (dwModifier & HTTP_ADDHDR_FLAG_ADD)
4675         index = -1;
4676     else
4677         index = HTTP_GetCustomHeaderIndex(lpwhr, field, 0, request_only);
4678
4679     if (index >= 0)
4680     {
4681         if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
4682         {
4683             return FALSE;
4684         }
4685         lphttpHdr = &lpwhr->pCustHeaders[index];
4686     }
4687     else if (value)
4688     {
4689         HTTPHEADERW hdr;
4690
4691         hdr.lpszField = (LPWSTR)field;
4692         hdr.lpszValue = (LPWSTR)value;
4693         hdr.wFlags = hdr.wCount = 0;
4694
4695         if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
4696             hdr.wFlags |= HDR_ISREQUEST;
4697
4698         return HTTP_InsertCustomHeader(lpwhr, &hdr);
4699     }
4700     /* no value to delete */
4701     else return TRUE;
4702
4703     if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
4704             lphttpHdr->wFlags |= HDR_ISREQUEST;
4705     else
4706         lphttpHdr->wFlags &= ~HDR_ISREQUEST;
4707
4708     if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
4709     {
4710         HTTP_DeleteCustomHeader( lpwhr, index );
4711
4712         if (value)
4713         {
4714             HTTPHEADERW hdr;
4715
4716             hdr.lpszField = (LPWSTR)field;
4717             hdr.lpszValue = (LPWSTR)value;
4718             hdr.wFlags = hdr.wCount = 0;
4719
4720             if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
4721                 hdr.wFlags |= HDR_ISREQUEST;
4722
4723             return HTTP_InsertCustomHeader(lpwhr, &hdr);
4724         }
4725
4726         return TRUE;
4727     }
4728     else if (dwModifier & COALESCEFLAGS)
4729     {
4730         LPWSTR lpsztmp;
4731         WCHAR ch = 0;
4732         INT len = 0;
4733         INT origlen = strlenW(lphttpHdr->lpszValue);
4734         INT valuelen = strlenW(value);
4735
4736         if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
4737         {
4738             ch = ',';
4739             lphttpHdr->wFlags |= HDR_COMMADELIMITED;
4740         }
4741         else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
4742         {
4743             ch = ';';
4744             lphttpHdr->wFlags |= HDR_COMMADELIMITED;
4745         }
4746
4747         len = origlen + valuelen + ((ch > 0) ? 2 : 0);
4748
4749         lpsztmp = HeapReAlloc(GetProcessHeap(), 0, lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
4750         if (lpsztmp)
4751         {
4752             lphttpHdr->lpszValue = lpsztmp;
4753     /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
4754             if (ch > 0)
4755             {
4756                 lphttpHdr->lpszValue[origlen] = ch;
4757                 origlen++;
4758                 lphttpHdr->lpszValue[origlen] = ' ';
4759                 origlen++;
4760             }
4761
4762             memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
4763             lphttpHdr->lpszValue[len] = '\0';
4764             bSuccess = TRUE;
4765         }
4766         else
4767         {
4768             WARN("HeapReAlloc (%d bytes) failed\n",len+1);
4769             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
4770         }
4771     }
4772     TRACE("<-- %d\n",bSuccess);
4773     return bSuccess;
4774 }
4775
4776
4777 /***********************************************************************
4778  *           HTTP_FinishedReading (internal)
4779  *
4780  * Called when all content from server has been read by client.
4781  *
4782  */
4783 static BOOL HTTP_FinishedReading(http_request_t *lpwhr)
4784 {
4785     BOOL keepalive = HTTP_KeepAlive(lpwhr);
4786
4787     TRACE("\n");
4788
4789
4790     if (!keepalive)
4791     {
4792         HTTPREQ_CloseConnection(&lpwhr->hdr);
4793     }
4794
4795     /* FIXME: store data in the URL cache here */
4796
4797     return TRUE;
4798 }
4799
4800
4801 /***********************************************************************
4802  *           HTTP_GetCustomHeaderIndex (internal)
4803  *
4804  * Return index of custom header from header array
4805  *
4806  */
4807 static INT HTTP_GetCustomHeaderIndex(http_request_t *lpwhr, LPCWSTR lpszField,
4808                                      int requested_index, BOOL request_only)
4809 {
4810     DWORD index;
4811
4812     TRACE("%s\n", debugstr_w(lpszField));
4813
4814     for (index = 0; index < lpwhr->nCustHeaders; index++)
4815     {
4816         if (strcmpiW(lpwhr->pCustHeaders[index].lpszField, lpszField))
4817             continue;
4818
4819         if (request_only && !(lpwhr->pCustHeaders[index].wFlags & HDR_ISREQUEST))
4820             continue;
4821
4822         if (!request_only && (lpwhr->pCustHeaders[index].wFlags & HDR_ISREQUEST))
4823             continue;
4824
4825         if (requested_index == 0)
4826             break;
4827         requested_index --;
4828     }
4829
4830     if (index >= lpwhr->nCustHeaders)
4831         index = -1;
4832
4833     TRACE("Return: %d\n", index);
4834     return index;
4835 }
4836
4837
4838 /***********************************************************************
4839  *           HTTP_InsertCustomHeader (internal)
4840  *
4841  * Insert header into array
4842  *
4843  */
4844 static BOOL HTTP_InsertCustomHeader(http_request_t *lpwhr, LPHTTPHEADERW lpHdr)
4845 {
4846     INT count;
4847     LPHTTPHEADERW lph = NULL;
4848     BOOL r = FALSE;
4849
4850     TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
4851     count = lpwhr->nCustHeaders + 1;
4852     if (count > 1)
4853         lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERW) * count);
4854     else
4855         lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
4856
4857     if (NULL != lph)
4858     {
4859         lpwhr->pCustHeaders = lph;
4860         lpwhr->pCustHeaders[count-1].lpszField = heap_strdupW(lpHdr->lpszField);
4861         lpwhr->pCustHeaders[count-1].lpszValue = heap_strdupW(lpHdr->lpszValue);
4862         lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
4863         lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
4864         lpwhr->nCustHeaders++;
4865         r = TRUE;
4866     }
4867     else
4868     {
4869         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
4870     }
4871
4872     return r;
4873 }
4874
4875
4876 /***********************************************************************
4877  *           HTTP_DeleteCustomHeader (internal)
4878  *
4879  * Delete header from array
4880  *  If this function is called, the indexs may change.
4881  */
4882 static BOOL HTTP_DeleteCustomHeader(http_request_t *lpwhr, DWORD index)
4883 {
4884     if( lpwhr->nCustHeaders <= 0 )
4885         return FALSE;
4886     if( index >= lpwhr->nCustHeaders )
4887         return FALSE;
4888     lpwhr->nCustHeaders--;
4889
4890     HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszField);
4891     HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[index].lpszValue);
4892
4893     memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
4894              (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) );
4895     memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) );
4896
4897     return TRUE;
4898 }
4899
4900
4901 /***********************************************************************
4902  *           HTTP_VerifyValidHeader (internal)
4903  *
4904  * Verify the given header is not invalid for the given http request
4905  *
4906  */
4907 static BOOL HTTP_VerifyValidHeader(http_request_t *lpwhr, LPCWSTR field)
4908 {
4909     /* Accept-Encoding is stripped from HTTP/1.0 requests. It is invalid */
4910     if (!strcmpW(lpwhr->lpszVersion, g_szHttp1_0) && !strcmpiW(field, szAccept_Encoding))
4911         return FALSE;
4912
4913     return TRUE;
4914 }
4915
4916 /***********************************************************************
4917  *          IsHostInProxyBypassList (@)
4918  *
4919  * Undocumented
4920  *
4921  */
4922 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
4923 {
4924    FIXME("STUB: flags=%d host=%s length=%d\n",flags,szHost,length);
4925    return FALSE;
4926 }