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