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