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