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