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