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