Use pointers internally and refcount all objects.
[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 + 1) * sizeof(WCHAR);
866             return TRUE;
867         }
868         else if (index == HTTP_QUERY_RAW_HEADERS)
869         {
870             static const WCHAR szCrLf[] = {'\r','\n',0};
871             LPWSTR * ppszRawHeaderLines = HTTP_Tokenize(lpwhr->lpszRawHeaders, szCrLf);
872             int size = 0;
873             int i;
874             LPWSTR pszString = (WCHAR*)lpBuffer;
875
876             for (i = 0; ppszRawHeaderLines[i]; i++)
877                 size += strlenW(ppszRawHeaderLines[i]) + 1;
878
879             if (size + 1 > *lpdwBufferLength/sizeof(WCHAR))
880             {
881                 HTTP_FreeTokens(ppszRawHeaderLines);
882                 *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
883                 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
884                 return FALSE;
885             }
886
887             for (i = 0; ppszRawHeaderLines[i]; i++)
888             {
889                 int len = strlenW(ppszRawHeaderLines[i]);
890                 memcpy(pszString, ppszRawHeaderLines[i], (len+1)*sizeof(WCHAR));
891                 pszString += len+1;
892             }
893             *pszString = '\0';
894
895             TRACE("returning data: %s\n", debugstr_wn((WCHAR*)lpBuffer, size));
896
897             *lpdwBufferLength = (size + 1) * sizeof(WCHAR);
898             HTTP_FreeTokens(ppszRawHeaderLines);
899
900             return TRUE;
901         }
902         else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
903         {
904             lphttpHdr = &lpwhr->StdHeaders[index];
905         }
906         else
907         {
908             SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
909             return bSuccess;
910         }
911     }
912
913     /* Ensure header satisifies requested attributes */
914     if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
915             (~lphttpHdr->wFlags & HDR_ISREQUEST))
916     {
917         SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
918         return bSuccess;
919     }
920
921     /* coalesce value to reuqested type */
922     if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
923     {
924         *(int *)lpBuffer = atoiW(lphttpHdr->lpszValue);
925         bSuccess = TRUE;
926
927         TRACE(" returning number : %d\n", *(int *)lpBuffer);
928     }
929     else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
930     {
931         time_t tmpTime;
932         struct tm tmpTM;
933         SYSTEMTIME *STHook;
934
935         tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
936
937         tmpTM = *gmtime(&tmpTime);
938         STHook = (SYSTEMTIME *) lpBuffer;
939         if(STHook==NULL)
940             return bSuccess;
941
942         STHook->wDay = tmpTM.tm_mday;
943         STHook->wHour = tmpTM.tm_hour;
944         STHook->wMilliseconds = 0;
945         STHook->wMinute = tmpTM.tm_min;
946         STHook->wDayOfWeek = tmpTM.tm_wday;
947         STHook->wMonth = tmpTM.tm_mon + 1;
948         STHook->wSecond = tmpTM.tm_sec;
949         STHook->wYear = tmpTM.tm_year;
950         
951         bSuccess = TRUE;
952         
953         TRACE(" returning time : %04d/%02d/%02d - %d - %02d:%02d:%02d.%02d\n", 
954               STHook->wYear, STHook->wMonth, STHook->wDay, STHook->wDayOfWeek,
955               STHook->wHour, STHook->wMinute, STHook->wSecond, STHook->wMilliseconds);
956     }
957     else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
958     {
959             if (*lpdwIndex >= lphttpHdr->wCount)
960                 {
961                 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
962                 }
963             else
964             {
965             /* Copy strncpyW(lpBuffer, lphttpHdr[*lpdwIndex], len); */
966             (*lpdwIndex)++;
967             }
968     }
969     else
970     {
971         INT len = (strlenW(lphttpHdr->lpszValue) + 1) * sizeof(WCHAR);
972
973         if (len > *lpdwBufferLength)
974         {
975             *lpdwBufferLength = len;
976             INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
977             return bSuccess;
978         }
979
980         memcpy(lpBuffer, lphttpHdr->lpszValue, len);
981         *lpdwBufferLength = len - sizeof(WCHAR);
982         bSuccess = TRUE;
983
984         TRACE(" returning string : '%s'\n", debugstr_w(lpBuffer));
985     }
986     return bSuccess;
987 }
988
989 /***********************************************************************
990  *           HttpQueryInfoW (WININET.@)
991  *
992  * Queries for information about an HTTP request
993  *
994  * RETURNS
995  *    TRUE  on success
996  *    FALSE on failure
997  *
998  */
999 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
1000         LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
1001 {
1002     BOOL bSuccess = FALSE;
1003     LPWININETHTTPREQW lpwhr;
1004
1005     if (TRACE_ON(wininet)) {
1006 #define FE(x) { x, #x }
1007         static const wininet_flag_info query_flags[] = {
1008             FE(HTTP_QUERY_MIME_VERSION),
1009             FE(HTTP_QUERY_CONTENT_TYPE),
1010             FE(HTTP_QUERY_CONTENT_TRANSFER_ENCODING),
1011             FE(HTTP_QUERY_CONTENT_ID),
1012             FE(HTTP_QUERY_CONTENT_DESCRIPTION),
1013             FE(HTTP_QUERY_CONTENT_LENGTH),
1014             FE(HTTP_QUERY_CONTENT_LANGUAGE),
1015             FE(HTTP_QUERY_ALLOW),
1016             FE(HTTP_QUERY_PUBLIC),
1017             FE(HTTP_QUERY_DATE),
1018             FE(HTTP_QUERY_EXPIRES),
1019             FE(HTTP_QUERY_LAST_MODIFIED),
1020             FE(HTTP_QUERY_MESSAGE_ID),
1021             FE(HTTP_QUERY_URI),
1022             FE(HTTP_QUERY_DERIVED_FROM),
1023             FE(HTTP_QUERY_COST),
1024             FE(HTTP_QUERY_LINK),
1025             FE(HTTP_QUERY_PRAGMA),
1026             FE(HTTP_QUERY_VERSION),
1027             FE(HTTP_QUERY_STATUS_CODE),
1028             FE(HTTP_QUERY_STATUS_TEXT),
1029             FE(HTTP_QUERY_RAW_HEADERS),
1030             FE(HTTP_QUERY_RAW_HEADERS_CRLF),
1031             FE(HTTP_QUERY_CONNECTION),
1032             FE(HTTP_QUERY_ACCEPT),
1033             FE(HTTP_QUERY_ACCEPT_CHARSET),
1034             FE(HTTP_QUERY_ACCEPT_ENCODING),
1035             FE(HTTP_QUERY_ACCEPT_LANGUAGE),
1036             FE(HTTP_QUERY_AUTHORIZATION),
1037             FE(HTTP_QUERY_CONTENT_ENCODING),
1038             FE(HTTP_QUERY_FORWARDED),
1039             FE(HTTP_QUERY_FROM),
1040             FE(HTTP_QUERY_IF_MODIFIED_SINCE),
1041             FE(HTTP_QUERY_LOCATION),
1042             FE(HTTP_QUERY_ORIG_URI),
1043             FE(HTTP_QUERY_REFERER),
1044             FE(HTTP_QUERY_RETRY_AFTER),
1045             FE(HTTP_QUERY_SERVER),
1046             FE(HTTP_QUERY_TITLE),
1047             FE(HTTP_QUERY_USER_AGENT),
1048             FE(HTTP_QUERY_WWW_AUTHENTICATE),
1049             FE(HTTP_QUERY_PROXY_AUTHENTICATE),
1050             FE(HTTP_QUERY_ACCEPT_RANGES),
1051             FE(HTTP_QUERY_SET_COOKIE),
1052             FE(HTTP_QUERY_COOKIE),
1053             FE(HTTP_QUERY_REQUEST_METHOD),
1054             FE(HTTP_QUERY_REFRESH),
1055             FE(HTTP_QUERY_CONTENT_DISPOSITION),
1056             FE(HTTP_QUERY_AGE),
1057             FE(HTTP_QUERY_CACHE_CONTROL),
1058             FE(HTTP_QUERY_CONTENT_BASE),
1059             FE(HTTP_QUERY_CONTENT_LOCATION),
1060             FE(HTTP_QUERY_CONTENT_MD5),
1061             FE(HTTP_QUERY_CONTENT_RANGE),
1062             FE(HTTP_QUERY_ETAG),
1063             FE(HTTP_QUERY_HOST),
1064             FE(HTTP_QUERY_IF_MATCH),
1065             FE(HTTP_QUERY_IF_NONE_MATCH),
1066             FE(HTTP_QUERY_IF_RANGE),
1067             FE(HTTP_QUERY_IF_UNMODIFIED_SINCE),
1068             FE(HTTP_QUERY_MAX_FORWARDS),
1069             FE(HTTP_QUERY_PROXY_AUTHORIZATION),
1070             FE(HTTP_QUERY_RANGE),
1071             FE(HTTP_QUERY_TRANSFER_ENCODING),
1072             FE(HTTP_QUERY_UPGRADE),
1073             FE(HTTP_QUERY_VARY),
1074             FE(HTTP_QUERY_VIA),
1075             FE(HTTP_QUERY_WARNING),
1076             FE(HTTP_QUERY_CUSTOM)
1077         };
1078         static const wininet_flag_info modifier_flags[] = {
1079             FE(HTTP_QUERY_FLAG_REQUEST_HEADERS),
1080             FE(HTTP_QUERY_FLAG_SYSTEMTIME),
1081             FE(HTTP_QUERY_FLAG_NUMBER),
1082             FE(HTTP_QUERY_FLAG_COALESCE)
1083         };
1084 #undef FE
1085         DWORD info_mod = dwInfoLevel & HTTP_QUERY_MODIFIER_FLAGS_MASK;
1086         DWORD info = dwInfoLevel & HTTP_QUERY_HEADER_MASK;
1087         int i;
1088
1089         TRACE("(%p, 0x%08lx)--> %ld\n", hHttpRequest, dwInfoLevel, dwInfoLevel);
1090         TRACE("  Attribute:");
1091         for (i = 0; i < (sizeof(query_flags) / sizeof(query_flags[0])); i++) {
1092             if (query_flags[i].val == info) {
1093                 DPRINTF(" %s", query_flags[i].name);
1094                 break;
1095             }
1096         }
1097         if (i == (sizeof(query_flags) / sizeof(query_flags[0]))) {
1098             DPRINTF(" Unknown (%08lx)", info);
1099         }
1100
1101         DPRINTF(" Modifier:");
1102         for (i = 0; i < (sizeof(modifier_flags) / sizeof(modifier_flags[0])); i++) {
1103             if (modifier_flags[i].val & info_mod) {
1104                 DPRINTF(" %s", modifier_flags[i].name);
1105                 info_mod &= ~ modifier_flags[i].val;
1106             }
1107         }
1108         
1109         if (info_mod) {
1110             DPRINTF(" Unknown (%08lx)", info_mod);
1111         }
1112         DPRINTF("\n");
1113     }
1114     
1115     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
1116     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
1117     {
1118         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1119         goto lend;
1120     }
1121
1122     bSuccess = HTTP_HttpQueryInfoW( lpwhr, dwInfoLevel,
1123                                     lpBuffer, lpdwBufferLength, lpdwIndex);
1124
1125 lend:
1126     if( lpwhr )
1127          WININET_Release( &lpwhr->hdr );
1128
1129     TRACE("%d <--\n", bSuccess);
1130     return bSuccess;
1131 }
1132
1133 /***********************************************************************
1134  *           HttpQueryInfoA (WININET.@)
1135  *
1136  * Queries for information about an HTTP request
1137  *
1138  * RETURNS
1139  *    TRUE  on success
1140  *    FALSE on failure
1141  *
1142  */
1143 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
1144         LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
1145 {
1146     BOOL result;
1147     DWORD len;
1148     WCHAR* bufferW;
1149
1150     if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
1151        (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
1152     {
1153         return HttpQueryInfoW( hHttpRequest, dwInfoLevel, lpBuffer,
1154                                lpdwBufferLength, lpdwIndex );
1155     }
1156
1157     len = (*lpdwBufferLength)*sizeof(WCHAR);
1158     bufferW = HeapAlloc( GetProcessHeap(), 0, len );
1159     result = HttpQueryInfoW( hHttpRequest, dwInfoLevel, bufferW,
1160                            &len, lpdwIndex );
1161     if( result )
1162     {
1163         len = WideCharToMultiByte( CP_ACP,0, bufferW, len / sizeof(WCHAR),
1164                                      lpBuffer, *lpdwBufferLength, NULL, NULL );
1165         *lpdwBufferLength = len * sizeof(WCHAR);
1166     }
1167     HeapFree(GetProcessHeap(), 0, bufferW );
1168
1169     return result;
1170 }
1171
1172 /***********************************************************************
1173  *           HttpSendRequestExA (WININET.@)
1174  *
1175  * Sends the specified request to the HTTP server and allows chunked
1176  * transfers
1177  */
1178 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
1179                                LPINTERNET_BUFFERSA lpBuffersIn,
1180                                LPINTERNET_BUFFERSA lpBuffersOut,
1181                                DWORD dwFlags, DWORD dwContext)
1182 {
1183   FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
1184         lpBuffersOut, dwFlags, dwContext);
1185   return FALSE;
1186 }
1187
1188 /***********************************************************************
1189  *           HttpSendRequestW (WININET.@)
1190  *
1191  * Sends the specified request to the HTTP server
1192  *
1193  * RETURNS
1194  *    TRUE  on success
1195  *    FALSE on failure
1196  *
1197  */
1198 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
1199         DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1200 {
1201     LPWININETHTTPREQW lpwhr;
1202     LPWININETHTTPSESSIONW lpwhs = NULL;
1203     LPWININETAPPINFOW hIC = NULL;
1204     BOOL r;
1205
1206     TRACE("%p, %p (%s), %li, %p, %li)\n", hHttpRequest,
1207             lpszHeaders, debugstr_w(lpszHeaders), dwHeaderLength, lpOptional, dwOptionalLength);
1208
1209     lpwhr = (LPWININETHTTPREQW) WININET_GetObject( hHttpRequest );
1210     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
1211     {
1212         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1213         r = FALSE;
1214         goto lend;
1215     }
1216
1217     lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
1218     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
1219     {
1220         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1221         r = FALSE;
1222         goto lend;
1223     }
1224
1225     hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1226     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT)
1227     {
1228         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1229         r = FALSE;
1230         goto lend;
1231     }
1232
1233     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
1234     {
1235         WORKREQUEST workRequest;
1236         struct WORKREQ_HTTPSENDREQUESTW *req;
1237
1238         workRequest.asyncall = HTTPSENDREQUESTW;
1239         workRequest.hdr = WININET_AddRef( &lpwhr->hdr );
1240         req = &workRequest.u.HttpSendRequestW;
1241         if (lpszHeaders)
1242             req->lpszHeader = WININET_strdupW(lpszHeaders);
1243         else
1244             req->lpszHeader = 0;
1245         req->dwHeaderLength = dwHeaderLength;
1246         req->lpOptional = lpOptional;
1247         req->dwOptionalLength = dwOptionalLength;
1248
1249         INTERNET_AsyncCall(&workRequest);
1250         /*
1251          * This is from windows.
1252          */
1253         SetLastError(ERROR_IO_PENDING);
1254         r = FALSE;
1255     }
1256     else
1257     {
1258         r = HTTP_HttpSendRequestW(lpwhr, lpszHeaders,
1259                 dwHeaderLength, lpOptional, dwOptionalLength);
1260     }
1261 lend:
1262     if( lpwhr )
1263         WININET_Release( &lpwhr->hdr );
1264     return r;
1265 }
1266
1267 /***********************************************************************
1268  *           HttpSendRequestA (WININET.@)
1269  *
1270  * Sends the specified request to the HTTP server
1271  *
1272  * RETURNS
1273  *    TRUE  on success
1274  *    FALSE on failure
1275  *
1276  */
1277 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
1278         DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1279 {
1280     BOOL result;
1281     LPWSTR szHeaders=NULL;
1282     DWORD nLen=dwHeaderLength;
1283     if(lpszHeaders!=NULL)
1284     {
1285         nLen=MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,NULL,0);
1286         szHeaders=HeapAlloc(GetProcessHeap(),0,nLen*sizeof(WCHAR));
1287         MultiByteToWideChar(CP_ACP,0,lpszHeaders,dwHeaderLength,szHeaders,nLen);
1288     }
1289     result=HttpSendRequestW(hHttpRequest, szHeaders, nLen, lpOptional, dwOptionalLength);
1290     if(szHeaders!=NULL)
1291         HeapFree(GetProcessHeap(),0,szHeaders);
1292     return result;
1293 }
1294
1295 /***********************************************************************
1296  *           HTTP_HandleRedirect (internal)
1297  */
1298 static BOOL HTTP_HandleRedirect(LPWININETHTTPREQW lpwhr, LPCWSTR lpszUrl, LPCWSTR lpszHeaders,
1299                                 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength)
1300 {
1301     LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
1302     LPWININETAPPINFOW hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1303     WCHAR path[2048];
1304
1305     if(lpszUrl[0]=='/')
1306     {
1307         /* if it's an absolute path, keep the same session info */
1308         strcpyW(path,lpszUrl);
1309     }
1310     else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0)
1311     {
1312         TRACE("Redirect through proxy\n");
1313         strcpyW(path,lpszUrl);
1314     }
1315     else
1316     {
1317         URL_COMPONENTSW urlComponents;
1318         WCHAR protocol[32], hostName[MAXHOSTNAME], userName[1024];
1319         WCHAR password[1024], extra[1024];
1320         urlComponents.dwStructSize = sizeof(URL_COMPONENTSW);
1321         urlComponents.lpszScheme = protocol;
1322         urlComponents.dwSchemeLength = 32;
1323         urlComponents.lpszHostName = hostName;
1324         urlComponents.dwHostNameLength = MAXHOSTNAME;
1325         urlComponents.lpszUserName = userName;
1326         urlComponents.dwUserNameLength = 1024;
1327         urlComponents.lpszPassword = password;
1328         urlComponents.dwPasswordLength = 1024;
1329         urlComponents.lpszUrlPath = path;
1330         urlComponents.dwUrlPathLength = 2048;
1331         urlComponents.lpszExtraInfo = extra;
1332         urlComponents.dwExtraInfoLength = 1024;
1333         if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents))
1334             return FALSE;
1335         
1336         if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
1337             urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
1338
1339 #if 0
1340         /*
1341          * This upsets redirects to binary files on sourceforge.net 
1342          * and gives an html page instead of the target file
1343          * Examination of the HTTP request sent by native wininet.dll
1344          * reveals that it doesn't send a referrer in that case.
1345          * Maybe there's a flag that enables this, or maybe a referrer
1346          * shouldn't be added in case of a redirect.
1347          */
1348
1349         /* consider the current host as the referrer */
1350         if (NULL != lpwhs->lpszServerName && strlenW(lpwhs->lpszServerName))
1351             HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName,
1352                            HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|
1353                            HTTP_ADDHDR_FLAG_ADD_IF_NEW);
1354 #endif
1355         
1356         if (NULL != lpwhs->lpszServerName)
1357             HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1358         lpwhs->lpszServerName = WININET_strdupW(hostName);
1359         if (NULL != lpwhs->lpszUserName)
1360             HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1361         lpwhs->lpszUserName = WININET_strdupW(userName);
1362         lpwhs->nServerPort = urlComponents.nPort;
1363
1364         if (NULL != lpwhr->lpszHostName)
1365             HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1366         lpwhr->lpszHostName=WININET_strdupW(hostName);
1367
1368         SendAsyncCallback(hIC, &lpwhs->hdr, lpwhr->hdr.dwContext,
1369                       INTERNET_STATUS_RESOLVING_NAME,
1370                       lpwhs->lpszServerName,
1371                       strlenW(lpwhs->lpszServerName)+1);
1372
1373         if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
1374                     &lpwhs->phostent, &lpwhs->socketAddress))
1375         {
1376             INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
1377             return FALSE;
1378         }
1379
1380         SendAsyncCallback(hIC, &lpwhs->hdr, lpwhr->hdr.dwContext,
1381                       INTERNET_STATUS_NAME_RESOLVED,
1382                       &(lpwhs->socketAddress),
1383                       sizeof(struct sockaddr_in));
1384
1385     }
1386
1387     if(lpwhr->lpszPath)
1388         HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1389     lpwhr->lpszPath=NULL;
1390     if (strlenW(path))
1391     {
1392         DWORD needed = 0;
1393         HRESULT rc;
1394
1395         rc = UrlEscapeW(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
1396         if (rc != E_POINTER)
1397             needed = strlenW(path)+1;
1398         lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed*sizeof(WCHAR));
1399         rc = UrlEscapeW(path, lpwhr->lpszPath, &needed,
1400                         URL_ESCAPE_SPACES_ONLY);
1401         if (rc)
1402         {
1403             ERR("Unable to escape string!(%s) (%ld)\n",debugstr_w(path),rc);
1404             strcpyW(lpwhr->lpszPath,path);
1405         }
1406     }
1407
1408     return HTTP_HttpSendRequestW(lpwhr, lpszHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
1409 }
1410
1411 /***********************************************************************
1412  *           HTTP_build_req (internal)
1413  *
1414  *  concatenate all the strings in the request together
1415  */
1416 static LPWSTR HTTP_build_req( LPCWSTR *list, int len )
1417 {
1418     LPCWSTR *t;
1419     LPWSTR str;
1420
1421     for( t = list; *t ; t++  )
1422         len += strlenW( *t );
1423     len++;
1424
1425     str = HeapAlloc( GetProcessHeap(), 0, len*sizeof(WCHAR) );
1426     *str = 0;
1427
1428     for( t = list; *t ; t++ )
1429         strcatW( str, *t );
1430
1431     return str;
1432 }
1433
1434 /***********************************************************************
1435  *           HTTP_HttpSendRequestW (internal)
1436  *
1437  * Sends the specified request to the HTTP server
1438  *
1439  * RETURNS
1440  *    TRUE  on success
1441  *    FALSE on failure
1442  *
1443  */
1444 BOOL WINAPI HTTP_HttpSendRequestW(LPWININETHTTPREQW lpwhr, LPCWSTR lpszHeaders,
1445         DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
1446 {
1447     INT cnt;
1448     INT i;
1449     BOOL bSuccess = FALSE;
1450     LPWSTR requestString = NULL;
1451     INT responseLen;
1452     LPWININETHTTPSESSIONW lpwhs = NULL;
1453     LPWININETAPPINFOW hIC = NULL;
1454     BOOL loop_next = FALSE;
1455     int CustHeaderIndex;
1456
1457     TRACE("--> %p\n", lpwhr);
1458
1459     assert(lpwhr->hdr.htype == WH_HHTTPREQ);
1460
1461     lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
1462     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
1463     {
1464         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1465         return FALSE;
1466     }
1467
1468     hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1469     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT)
1470     {
1471         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
1472         return FALSE;
1473     }
1474
1475     /* Clear any error information */
1476     INTERNET_SetLastError(0);
1477
1478
1479     /* We must have a verb */
1480     if (NULL == lpwhr->lpszVerb)
1481     {
1482             goto lend;
1483     }
1484
1485     /* if we are using optional stuff, we must add the fixed header of that option length */
1486     if (lpOptional && dwOptionalLength)
1487     {
1488         static const WCHAR szContentLength[] = {
1489             'C','o','n','t','e','n','t','-','L','e','n','g','t','h',':',' ','%','l','i','\r','\n',0};
1490         WCHAR contentLengthStr[sizeof szContentLength/2 /* includes \n\r */ + 20 /* int */ ];
1491         sprintfW(contentLengthStr, szContentLength, dwOptionalLength);
1492         HTTP_HttpAddRequestHeadersW(lpwhr, contentLengthStr, -1L, HTTP_ADDREQ_FLAG_ADD);
1493     }
1494
1495     do
1496     {
1497         static const WCHAR szSlash[] = { '/',0 };
1498         static const WCHAR szSpace[] = { ' ',0 };
1499         static const WCHAR szHttp[] = { 'h','t','t','p',':','/','/', 0 };
1500         static const WCHAR szcrlf[] = {'\r','\n', 0};
1501         static const WCHAR sztwocrlf[] = {'\r','\n','\r','\n', 0};
1502         static const WCHAR szSetCookie[] = {'S','e','t','-','C','o','o','k','i','e',0 };
1503         static const WCHAR szColon[] = { ':',' ',0 };
1504         LPCWSTR *req;
1505         LPWSTR p;
1506         int len, n;
1507         char *ascii_req;
1508
1509
1510         TRACE("Going to url %s %s\n", debugstr_w(lpwhr->lpszHostName), debugstr_w(lpwhr->lpszPath));
1511         loop_next = FALSE;
1512
1513         /* If we don't have a path we set it to root */
1514         if (NULL == lpwhr->lpszPath)
1515             lpwhr->lpszPath = WININET_strdupW(szSlash);
1516
1517         if(CSTR_EQUAL != CompareStringW( LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
1518                            lpwhr->lpszPath, strlenW(szHttp), szHttp, strlenW(szHttp) )
1519            && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
1520         {
1521             WCHAR *fixurl = HeapAlloc(GetProcessHeap(), 0, 
1522                                  (strlenW(lpwhr->lpszPath) + 2)*sizeof(WCHAR));
1523             *fixurl = '/';
1524             strcpyW(fixurl + 1, lpwhr->lpszPath);
1525             HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
1526             lpwhr->lpszPath = fixurl;
1527         }
1528
1529         /* allocate space for an array of all the string pointers to be added */
1530         len = (2 + HTTP_QUERY_MAX + lpwhr->nCustHeaders)*4 + 3;
1531         req = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(LPCWSTR) );
1532
1533         /* add the verb, path and HTTP/1.0 */
1534         n = 0;
1535         req[n++] = lpwhr->lpszVerb;
1536         req[n++] = szSpace;
1537         req[n++] = lpwhr->lpszPath;
1538         req[n++] = HTTPHEADER;
1539
1540         /* Append standard request headers */
1541         for (i = 0; i <= HTTP_QUERY_MAX; i++)
1542         {
1543             if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1544             {
1545                 req[n++] = szcrlf;
1546                 req[n++] = lpwhr->StdHeaders[i].lpszField;
1547                 req[n++] = szColon;
1548                 req[n++] = lpwhr->StdHeaders[i].lpszValue;
1549
1550                 TRACE("Adding header %s (%s)\n",
1551                        debugstr_w(lpwhr->StdHeaders[i].lpszField),
1552                        debugstr_w(lpwhr->StdHeaders[i].lpszValue));
1553             }
1554         }
1555
1556         /* Append custom request heades */
1557         for (i = 0; i < lpwhr->nCustHeaders; i++)
1558         {
1559             if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1560             {
1561                 req[n++] = szcrlf;
1562                 req[n++] = lpwhr->pCustHeaders[i].lpszField;
1563                 req[n++] = szColon;
1564                 req[n++] = lpwhr->pCustHeaders[i].lpszValue;
1565
1566                 TRACE("Adding custom header %s (%s)\n",
1567                        debugstr_w(lpwhr->pCustHeaders[i].lpszField),
1568                        debugstr_w(lpwhr->pCustHeaders[i].lpszValue));
1569             }
1570         }
1571
1572         if (lpwhr->lpszHostName)
1573         {
1574             req[n++] = HTTPHOSTHEADER;
1575             req[n++] = lpwhr->lpszHostName;
1576         }
1577
1578         if( n > len )
1579             ERR("oops. buffer overrun\n");
1580
1581         requestString = HTTP_build_req( req, 4 );
1582         HeapFree( GetProcessHeap(), 0, req );
1583  
1584         /*
1585          * Set (header) termination string for request
1586          * Make sure there's exactly two new lines at the end of the request
1587          */
1588         p = &requestString[strlenW(requestString)-1];
1589         while ( (*p == '\n') || (*p == '\r') )
1590            p--;
1591         strcpyW( p+1, sztwocrlf );
1592  
1593         TRACE("Request header -> %s\n", debugstr_w(requestString) );
1594
1595         /* Send the request and store the results */
1596         if (!HTTP_OpenConnection(lpwhr))
1597             goto lend;
1598
1599         SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext,
1600                           INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1601
1602         /* send the request as ASCII, tack on the optional data */
1603         if( !lpOptional )
1604             dwOptionalLength = 0;
1605         len = WideCharToMultiByte( CP_ACP, 0, requestString, -1,
1606                                    NULL, 0, NULL, NULL );
1607         ascii_req = HeapAlloc( GetProcessHeap(), 0, len + dwOptionalLength );
1608         WideCharToMultiByte( CP_ACP, 0, requestString, -1,
1609                              ascii_req, len, NULL, NULL );
1610         if( lpOptional )
1611             memcpy( &ascii_req[len], lpOptional, dwOptionalLength );
1612         len += dwOptionalLength;
1613         NETCON_send(&lpwhr->netConnection, ascii_req, len, 0, &cnt);
1614         HeapFree( GetProcessHeap(), 0, ascii_req );
1615
1616         SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext,
1617                           INTERNET_STATUS_REQUEST_SENT,
1618                           &len,sizeof(DWORD));
1619
1620         SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext,
1621                           INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1622
1623         if (cnt < 0)
1624             goto lend;
1625
1626         responseLen = HTTP_GetResponseHeaders(lpwhr);
1627         if (responseLen)
1628             bSuccess = TRUE;
1629
1630         SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext,
1631                           INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
1632                           sizeof(DWORD));
1633
1634         /* process headers here. Is this right? */
1635         CustHeaderIndex = HTTP_GetCustomHeaderIndex(lpwhr, szSetCookie);
1636         if (!(lpwhr->hdr.dwFlags & INTERNET_FLAG_NO_COOKIES) && (CustHeaderIndex >= 0))
1637         {
1638             LPHTTPHEADERW setCookieHeader;
1639             int nPosStart = 0, nPosEnd = 0, len;
1640             static const WCHAR szFmt[] = { 'h','t','t','p',':','/','/','%','s','/',0};
1641
1642             setCookieHeader = &lpwhr->pCustHeaders[CustHeaderIndex];
1643
1644             while (setCookieHeader->lpszValue[nPosEnd] != '\0')
1645             {
1646                 LPWSTR buf_cookie, cookie_name, cookie_data;
1647                 LPWSTR buf_url;
1648                 LPWSTR domain = NULL;
1649                 int nEqualPos = 0;
1650                 while (setCookieHeader->lpszValue[nPosEnd] != ';' && setCookieHeader->lpszValue[nPosEnd] != ',' &&
1651                        setCookieHeader->lpszValue[nPosEnd] != '\0')
1652                 {
1653                     nPosEnd++;
1654                 }
1655                 if (setCookieHeader->lpszValue[nPosEnd] == ';')
1656                 {
1657                     /* fixme: not case sensitive, strcasestr is gnu only */
1658                     int nDomainPosEnd = 0;
1659                     int nDomainPosStart = 0, nDomainLength = 0;
1660                     static const WCHAR szDomain[] = {'d','o','m','a','i','n','=',0};
1661                     LPWSTR lpszDomain = strstrW(&setCookieHeader->lpszValue[nPosEnd], szDomain);
1662                     if (lpszDomain)
1663                     { /* they have specified their own domain, lets use it */
1664                         while (lpszDomain[nDomainPosEnd] != ';' && lpszDomain[nDomainPosEnd] != ',' &&
1665                                lpszDomain[nDomainPosEnd] != '\0')
1666                         {
1667                             nDomainPosEnd++;
1668                         }
1669                         nDomainPosStart = strlenW(szDomain);
1670                         nDomainLength = (nDomainPosEnd - nDomainPosStart) + 1;
1671                         domain = HeapAlloc(GetProcessHeap(), 0, (nDomainLength + 1)*sizeof(WCHAR));
1672                         strncpyW(domain, &lpszDomain[nDomainPosStart], nDomainLength);
1673                         domain[nDomainLength] = '\0';
1674                     }
1675                 }
1676                 if (setCookieHeader->lpszValue[nPosEnd] == '\0') break;
1677                 buf_cookie = HeapAlloc(GetProcessHeap(), 0, ((nPosEnd - nPosStart) + 1)*sizeof(WCHAR));
1678                 strncpyW(buf_cookie, &setCookieHeader->lpszValue[nPosStart], (nPosEnd - nPosStart));
1679                 buf_cookie[(nPosEnd - nPosStart)] = '\0';
1680                 TRACE("%s\n", debugstr_w(buf_cookie));
1681                 while (buf_cookie[nEqualPos] != '=' && buf_cookie[nEqualPos] != '\0')
1682                 {
1683                     nEqualPos++;
1684                 }
1685                 if (buf_cookie[nEqualPos] == '\0' || buf_cookie[nEqualPos + 1] == '\0')
1686                 {
1687                     HeapFree(GetProcessHeap(), 0, buf_cookie);
1688                     break;
1689                 }
1690
1691                 cookie_name = HeapAlloc(GetProcessHeap(), 0, (nEqualPos + 1)*sizeof(WCHAR));
1692                 strncpyW(cookie_name, buf_cookie, nEqualPos);
1693                 cookie_name[nEqualPos] = '\0';
1694                 cookie_data = &buf_cookie[nEqualPos + 1];
1695
1696
1697                 len = strlenW((domain ? domain : lpwhr->lpszHostName)) + strlenW(lpwhr->lpszPath) + 9;
1698                 buf_url = HeapAlloc(GetProcessHeap(), 0, len*sizeof(WCHAR));
1699                 sprintfW(buf_url, szFmt, (domain ? domain : lpwhr->lpszHostName)); /* FIXME PATH!!! */
1700                 InternetSetCookieW(buf_url, cookie_name, cookie_data);
1701
1702                 HeapFree(GetProcessHeap(), 0, buf_url);
1703                 HeapFree(GetProcessHeap(), 0, buf_cookie);
1704                 HeapFree(GetProcessHeap(), 0, cookie_name);
1705                 if (domain) HeapFree(GetProcessHeap(), 0, domain);
1706                 nPosStart = nPosEnd;
1707             }
1708         }
1709     }
1710     while (loop_next);
1711
1712 lend:
1713
1714     if (requestString)
1715         HeapFree(GetProcessHeap(), 0, requestString);
1716
1717     /* TODO: send notification for P3P header */
1718     
1719     if(!(hIC->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
1720     {
1721         DWORD dwCode,dwCodeLength=sizeof(DWORD),dwIndex=0;
1722         if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,&dwIndex) &&
1723             (dwCode==302 || dwCode==301))
1724         {
1725             WCHAR szNewLocation[2048];
1726             DWORD dwBufferSize=2048;
1727             dwIndex=0;
1728             if(HTTP_HttpQueryInfoW(lpwhr,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,&dwIndex))
1729             {
1730                 SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext,
1731                       INTERNET_STATUS_REDIRECT, szNewLocation,
1732                       dwBufferSize);
1733                 return HTTP_HandleRedirect(lpwhr, szNewLocation, lpszHeaders,
1734                                            dwHeaderLength, lpOptional, dwOptionalLength);
1735             }
1736         }
1737     }
1738
1739     if (hIC->lpfnStatusCB)
1740     {
1741         INTERNET_ASYNC_RESULT iar;
1742
1743         iar.dwResult = (DWORD)bSuccess;
1744         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1745
1746         SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext,
1747                       INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1748                       sizeof(INTERNET_ASYNC_RESULT));
1749     }
1750
1751     TRACE("<--\n");
1752     return bSuccess;
1753 }
1754
1755
1756 /***********************************************************************
1757  *           HTTP_Connect  (internal)
1758  *
1759  * Create http session handle
1760  *
1761  * RETURNS
1762  *   HINTERNET a session handle on success
1763  *   NULL on failure
1764  *
1765  */
1766 HINTERNET HTTP_Connect(LPWININETAPPINFOW hIC, LPCWSTR lpszServerName,
1767         INTERNET_PORT nServerPort, LPCWSTR lpszUserName,
1768         LPCWSTR lpszPassword, DWORD dwFlags, DWORD dwContext,
1769         DWORD dwInternalFlags)
1770 {
1771     BOOL bSuccess = FALSE;
1772     LPWININETHTTPSESSIONW lpwhs = NULL;
1773     HINTERNET handle = NULL;
1774
1775     TRACE("-->\n");
1776
1777     assert( hIC->hdr.htype == WH_HINIT );
1778
1779     hIC->hdr.dwContext = dwContext;
1780     
1781     lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONW));
1782     if (NULL == lpwhs)
1783     {
1784         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1785         goto lerror;
1786     }
1787
1788    /*
1789     * According to my tests. The name is not resolved until a request is sent
1790     */
1791
1792     if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1793         nServerPort = INTERNET_DEFAULT_HTTP_PORT;
1794
1795     lpwhs->hdr.htype = WH_HHTTPSESSION;
1796     lpwhs->hdr.lpwhparent = WININET_AddRef( &hIC->hdr );
1797     lpwhs->hdr.dwFlags = dwFlags;
1798     lpwhs->hdr.dwContext = dwContext;
1799     lpwhs->hdr.dwInternalFlags = dwInternalFlags;
1800     lpwhs->hdr.dwRefCount = 1;
1801     lpwhs->hdr.destroy = HTTP_CloseHTTPSessionHandle;
1802
1803     handle = WININET_AllocHandle( &lpwhs->hdr );
1804     if (NULL == handle)
1805     {
1806         ERR("Failed to alloc handle\n");
1807         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1808         goto lerror;
1809     }
1810
1811     if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1812         if(strchrW(hIC->lpszProxy, ' '))
1813             FIXME("Several proxies not implemented.\n");
1814         if(hIC->lpszProxyBypass)
1815             FIXME("Proxy bypass is ignored.\n");
1816     }
1817     if (NULL != lpszServerName)
1818         lpwhs->lpszServerName = WININET_strdupW(lpszServerName);
1819     if (NULL != lpszUserName)
1820         lpwhs->lpszUserName = WININET_strdupW(lpszUserName);
1821     lpwhs->nServerPort = nServerPort;
1822
1823     /* Don't send a handle created callback if this handle was created with InternetOpenUrl */
1824     if (hIC->lpfnStatusCB && !(lpwhs->hdr.dwInternalFlags & INET_OPENURL))
1825     {
1826         INTERNET_ASYNC_RESULT iar;
1827
1828         iar.dwResult = (DWORD)handle;
1829         iar.dwError = ERROR_SUCCESS;
1830
1831         SendAsyncCallback(hIC, &hIC->hdr, dwContext,
1832                       INTERNET_STATUS_HANDLE_CREATED, &iar,
1833                       sizeof(INTERNET_ASYNC_RESULT));
1834     }
1835
1836     bSuccess = TRUE;
1837
1838 lerror:
1839     if( lpwhs )
1840         WININET_Release( &lpwhs->hdr );
1841
1842 /*
1843  * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1844  * windows
1845  */
1846
1847     TRACE("%p --> %p (%p)\n", hIC, handle, lpwhs);
1848     return handle;
1849 }
1850
1851
1852 /***********************************************************************
1853  *           HTTP_OpenConnection (internal)
1854  *
1855  * Connect to a web server
1856  *
1857  * RETURNS
1858  *
1859  *   TRUE  on success
1860  *   FALSE on failure
1861  */
1862 BOOL HTTP_OpenConnection(LPWININETHTTPREQW lpwhr)
1863 {
1864     BOOL bSuccess = FALSE;
1865     LPWININETHTTPSESSIONW lpwhs;
1866     LPWININETAPPINFOW hIC = NULL;
1867
1868     TRACE("-->\n");
1869
1870
1871     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
1872     {
1873         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1874         goto lend;
1875     }
1876
1877     lpwhs = (LPWININETHTTPSESSIONW)lpwhr->hdr.lpwhparent;
1878
1879     hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
1880     SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext,
1881                       INTERNET_STATUS_CONNECTING_TO_SERVER,
1882                       &(lpwhs->socketAddress),
1883                        sizeof(struct sockaddr_in));
1884
1885     if (!NETCON_create(&lpwhr->netConnection, lpwhs->phostent->h_addrtype,
1886                          SOCK_STREAM, 0))
1887     {
1888         WARN("Socket creation failed\n");
1889         goto lend;
1890     }
1891
1892     if (!NETCON_connect(&lpwhr->netConnection, (struct sockaddr *)&lpwhs->socketAddress,
1893                       sizeof(lpwhs->socketAddress)))
1894     {
1895        WARN("Unable to connect to host (%s)\n", strerror(errno));
1896        goto lend;
1897     }
1898
1899     SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext,
1900                       INTERNET_STATUS_CONNECTED_TO_SERVER,
1901                       &(lpwhs->socketAddress),
1902                        sizeof(struct sockaddr_in));
1903
1904     bSuccess = TRUE;
1905
1906 lend:
1907     TRACE("%d <--\n", bSuccess);
1908     return bSuccess;
1909 }
1910
1911
1912 /***********************************************************************
1913  *           HTTP_clear_response_headers (internal)
1914  *
1915  * clear out any old response headers
1916  */
1917 static void HTTP_clear_response_headers( LPWININETHTTPREQW lpwhr )
1918 {
1919     DWORD i;
1920
1921     for( i=0; i<=HTTP_QUERY_MAX; i++ )
1922     {
1923         if( !lpwhr->StdHeaders[i].lpszField )
1924             continue;
1925         if( !lpwhr->StdHeaders[i].lpszValue )
1926             continue;
1927         if ( lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST )
1928             continue;
1929         HTTP_ReplaceHeaderValue( &lpwhr->StdHeaders[i], NULL );
1930     }
1931     for( i=0; i<lpwhr->nCustHeaders; i++)
1932     {
1933         if( !lpwhr->pCustHeaders[i].lpszField )
1934             continue;
1935         if( !lpwhr->pCustHeaders[i].lpszValue )
1936             continue;
1937         if ( lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST )
1938             continue;
1939         HTTP_ReplaceHeaderValue( &lpwhr->pCustHeaders[i], NULL );
1940     }
1941 }
1942
1943 /***********************************************************************
1944  *           HTTP_GetResponseHeaders (internal)
1945  *
1946  * Read server response
1947  *
1948  * RETURNS
1949  *
1950  *   TRUE  on success
1951  *   FALSE on error
1952  */
1953 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQW lpwhr)
1954 {
1955     INT cbreaks = 0;
1956     WCHAR buffer[MAX_REPLY_LEN];
1957     DWORD buflen = MAX_REPLY_LEN;
1958     BOOL bSuccess = FALSE;
1959     INT  rc = 0;
1960     WCHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1961     static const WCHAR szHttp[] = { 'H','T','T','P',0 };
1962     static const WCHAR szCrLf[] = {'\r','\n',0};
1963     char bufferA[MAX_REPLY_LEN];
1964     LPWSTR status_code, status_text;
1965     int cchMaxRawHeaders = 1024;
1966     LPWSTR lpszRawHeaders = HeapAlloc(GetProcessHeap(), 0, (cchMaxRawHeaders+1)*sizeof(WCHAR));
1967     int cchRawHeaders = 0;
1968
1969     TRACE("-->\n");
1970
1971     /* clear old response headers (eg. from a redirect response) */
1972     HTTP_clear_response_headers( lpwhr );
1973
1974     if (!NETCON_connected(&lpwhr->netConnection))
1975         goto lend;
1976
1977     /*
1978      * HACK peek at the buffer
1979      */
1980     NETCON_recv(&lpwhr->netConnection, buffer, buflen, MSG_PEEK, &rc);
1981
1982     /*
1983      * We should first receive 'HTTP/1.x nnn OK' where nnn is the status code.
1984      */
1985     buflen = MAX_REPLY_LEN;
1986     memset(buffer, 0, MAX_REPLY_LEN);
1987     if (!NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
1988         goto lend;
1989     MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
1990
1991     if (strncmpW(buffer, szHttp, 4) != 0)
1992         goto lend;
1993
1994     /* regenerate raw headers */
1995     while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
1996     {
1997         cchMaxRawHeaders *= 2;
1998         lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
1999     }
2000     memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
2001     cchRawHeaders += (buflen-1);
2002     memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
2003     cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
2004     lpszRawHeaders[cchRawHeaders] = '\0';
2005
2006     /* split the version from the status code */
2007     status_code = strchrW( buffer, ' ' );
2008     if( !status_code )
2009         goto lend;
2010     *status_code++=0;
2011
2012     /* split the status code from the status text */
2013     status_text = strchrW( status_code, ' ' );
2014     if( !status_text )
2015         goto lend;
2016     *status_text++=0;
2017
2018     TRACE("version [%s] status code [%s] status text [%s]\n",
2019          debugstr_w(buffer), debugstr_w(status_code), debugstr_w(status_text) );
2020     HTTP_ReplaceHeaderValue( &lpwhr->StdHeaders[HTTP_QUERY_VERSION], buffer );
2021     HTTP_ReplaceHeaderValue( &lpwhr->StdHeaders[HTTP_QUERY_STATUS_CODE], status_code );
2022     HTTP_ReplaceHeaderValue( &lpwhr->StdHeaders[HTTP_QUERY_STATUS_TEXT], status_text );
2023
2024     /* Parse each response line */
2025     do
2026     {
2027         buflen = MAX_REPLY_LEN;
2028         if (NETCON_getNextLine(&lpwhr->netConnection, bufferA, &buflen))
2029         {
2030             TRACE("got line %s, now interpretting\n", debugstr_a(bufferA));
2031             MultiByteToWideChar( CP_ACP, 0, bufferA, buflen, buffer, MAX_REPLY_LEN );
2032
2033             while (cchRawHeaders + buflen + strlenW(szCrLf) > cchMaxRawHeaders)
2034             {
2035                 cchMaxRawHeaders *= 2;
2036                 lpszRawHeaders = HeapReAlloc(GetProcessHeap(), 0, lpszRawHeaders, (cchMaxRawHeaders+1)*sizeof(WCHAR));
2037             }
2038             memcpy(lpszRawHeaders+cchRawHeaders, buffer, (buflen-1)*sizeof(WCHAR));
2039             cchRawHeaders += (buflen-1);
2040             memcpy(lpszRawHeaders+cchRawHeaders, szCrLf, sizeof(szCrLf));
2041             cchRawHeaders += sizeof(szCrLf)/sizeof(szCrLf[0])-1;
2042             lpszRawHeaders[cchRawHeaders] = '\0';
2043
2044             if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
2045                 break;
2046
2047             HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
2048         }
2049         else
2050         {
2051             cbreaks++;
2052             if (cbreaks >= 2)
2053                break;
2054         }
2055     }while(1);
2056
2057     if (lpwhr->lpszRawHeaders) HeapFree(GetProcessHeap(), 0, lpszRawHeaders);
2058     lpwhr->lpszRawHeaders = lpszRawHeaders;
2059     TRACE("raw headers: %s\n", debugstr_w(lpszRawHeaders));
2060     bSuccess = TRUE;
2061
2062 lend:
2063
2064     TRACE("<--\n");
2065     if (bSuccess)
2066         return rc;
2067     else
2068         return FALSE;
2069 }
2070
2071
2072 /***********************************************************************
2073  *           HTTP_InterpretHttpHeader (internal)
2074  *
2075  * Parse server response
2076  *
2077  * RETURNS
2078  *
2079  *   TRUE  on success
2080  *   FALSE on error
2081  */
2082 static INT stripSpaces(LPCWSTR lpszSrc, LPWSTR lpszStart, INT *len)
2083 {
2084     LPCWSTR lpsztmp;
2085     INT srclen;
2086
2087     srclen = 0;
2088
2089     while (*lpszSrc == ' ' && *lpszSrc != '\0')
2090         lpszSrc++;
2091
2092     lpsztmp = lpszSrc;
2093     while(*lpsztmp != '\0')
2094     {
2095         if (*lpsztmp != ' ')
2096             srclen = lpsztmp - lpszSrc + 1;
2097
2098         lpsztmp++;
2099     }
2100
2101     *len = min(*len, srclen);
2102     strncpyW(lpszStart, lpszSrc, *len);
2103     lpszStart[*len] = '\0';
2104
2105     return *len;
2106 }
2107
2108
2109 BOOL HTTP_InterpretHttpHeader(LPWSTR buffer, LPWSTR field, INT fieldlen, LPWSTR value, INT valuelen)
2110 {
2111     WCHAR *pd;
2112     BOOL bSuccess = FALSE;
2113
2114     TRACE("\n");
2115
2116     *field = '\0';
2117     *value = '\0';
2118
2119     pd = strchrW(buffer, ':');
2120     if (pd)
2121     {
2122         *pd = '\0';
2123         if (stripSpaces(buffer, field, &fieldlen) > 0)
2124         {
2125             if (stripSpaces(pd+1, value, &valuelen) > 0)
2126                 bSuccess = TRUE;
2127         }
2128     }
2129
2130     TRACE("%d: field(%s) Value(%s)\n", bSuccess, debugstr_w(field), debugstr_w(value));
2131     return bSuccess;
2132 }
2133
2134
2135 /***********************************************************************
2136  *           HTTP_GetStdHeaderIndex (internal)
2137  *
2138  * Lookup field index in standard http header array
2139  *
2140  * FIXME: This should be stuffed into a hash table
2141  */
2142 INT HTTP_GetStdHeaderIndex(LPCWSTR lpszField)
2143 {
2144     INT index = -1;
2145     static const WCHAR szContentLength[] = {
2146        'C','o','n','t','e','n','t','-','L','e','n','g','t','h',0};
2147     static const WCHAR szContentType[] = {
2148        'C','o','n','t','e','n','t','-','T','y','p','e',0};
2149     static const WCHAR szLastModified[] = {
2150        'L','a','s','t','-','M','o','d','i','f','i','e','d',0};
2151     static const WCHAR szLocation[] = {'L','o','c','a','t','i','o','n',0};
2152     static const WCHAR szAccept[] = {'A','c','c','e','p','t',0};
2153     static const WCHAR szReferer[] = { 'R','e','f','e','r','e','r',0};
2154     static const WCHAR szContentTrans[] = { 'C','o','n','t','e','n','t','-',
2155        'T','r','a','n','s','f','e','r','-','E','n','c','o','d','i','n','g',0};
2156     static const WCHAR szDate[] = { 'D','a','t','e',0};
2157     static const WCHAR szServer[] = { 'S','e','r','v','e','r',0};
2158     static const WCHAR szConnection[] = { 'C','o','n','n','e','c','t','i','o','n',0};
2159     static const WCHAR szETag[] = { 'E','T','a','g',0};
2160     static const WCHAR szAcceptRanges[] = {
2161        'A','c','c','e','p','t','-','R','a','n','g','e','s',0 };
2162     static const WCHAR szExpires[] = { 'E','x','p','i','r','e','s',0 };
2163     static const WCHAR szMimeVersion[] = {
2164        'M','i','m','e','-','V','e','r','s','i','o','n', 0};
2165     static const WCHAR szPragma[] = { 'P','r','a','g','m','a', 0};
2166     static const WCHAR szCacheControl[] = {
2167        'C','a','c','h','e','-','C','o','n','t','r','o','l',0};
2168     static const WCHAR szUserAgent[] = { 'U','s','e','r','-','A','g','e','n','t',0};
2169     static const WCHAR szProxyAuth[] = {
2170        'P','r','o','x','y','-',
2171        'A','u','t','h','e','n','t','i','c','a','t','e', 0};
2172     static const WCHAR szContentEncoding[] = {
2173        'C','o','n','t','e','n','t','-','E','n','c','o','d','i','n','g',0};
2174     static const WCHAR szCookie[] = {'C','o','o','k','i','e',0};
2175     static const WCHAR szVary[] = {'V','a','r','y',0};
2176     static const WCHAR szVia[] = {'V','i','a',0};
2177
2178     if (!strcmpiW(lpszField, szContentLength))
2179         index = HTTP_QUERY_CONTENT_LENGTH;
2180     else if (!strcmpiW(lpszField,szContentType))
2181         index = HTTP_QUERY_CONTENT_TYPE;
2182     else if (!strcmpiW(lpszField,szLastModified))
2183         index = HTTP_QUERY_LAST_MODIFIED;
2184     else if (!strcmpiW(lpszField,szLocation))
2185         index = HTTP_QUERY_LOCATION;
2186     else if (!strcmpiW(lpszField,szAccept))
2187         index = HTTP_QUERY_ACCEPT;
2188     else if (!strcmpiW(lpszField,szReferer))
2189         index = HTTP_QUERY_REFERER;
2190     else if (!strcmpiW(lpszField,szContentTrans))
2191         index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
2192     else if (!strcmpiW(lpszField,szDate))
2193         index = HTTP_QUERY_DATE;
2194     else if (!strcmpiW(lpszField,szServer))
2195         index = HTTP_QUERY_SERVER;
2196     else if (!strcmpiW(lpszField,szConnection))
2197         index = HTTP_QUERY_CONNECTION;
2198     else if (!strcmpiW(lpszField,szETag))
2199         index = HTTP_QUERY_ETAG;
2200     else if (!strcmpiW(lpszField,szAcceptRanges))
2201         index = HTTP_QUERY_ACCEPT_RANGES;
2202     else if (!strcmpiW(lpszField,szExpires))
2203         index = HTTP_QUERY_EXPIRES;
2204     else if (!strcmpiW(lpszField,szMimeVersion))
2205         index = HTTP_QUERY_MIME_VERSION;
2206     else if (!strcmpiW(lpszField,szPragma))
2207         index = HTTP_QUERY_PRAGMA;
2208     else if (!strcmpiW(lpszField,szCacheControl))
2209         index = HTTP_QUERY_CACHE_CONTROL;
2210     else if (!strcmpiW(lpszField,szUserAgent))
2211         index = HTTP_QUERY_USER_AGENT;
2212     else if (!strcmpiW(lpszField,szProxyAuth))
2213         index = HTTP_QUERY_PROXY_AUTHENTICATE;
2214     else if (!strcmpiW(lpszField,szContentEncoding))
2215         index = HTTP_QUERY_CONTENT_ENCODING;
2216     else if (!strcmpiW(lpszField,szCookie))
2217         index = HTTP_QUERY_COOKIE;
2218     else if (!strcmpiW(lpszField,szVary))
2219         index = HTTP_QUERY_VARY;
2220     else if (!strcmpiW(lpszField,szVia))
2221         index = HTTP_QUERY_VIA;
2222     else
2223     {
2224         TRACE("Couldn't find %s in standard header table\n", debugstr_w(lpszField));
2225     }
2226
2227     return index;
2228 }
2229
2230 /***********************************************************************
2231  *           HTTP_ReplaceHeaderValue (internal)
2232  */
2233 BOOL HTTP_ReplaceHeaderValue( LPHTTPHEADERW lphttpHdr, LPCWSTR value )
2234 {
2235     INT len = 0;
2236
2237     if( lphttpHdr->lpszValue )
2238         HeapFree( GetProcessHeap(), 0, lphttpHdr->lpszValue );
2239     lphttpHdr->lpszValue = NULL;
2240
2241     if( value )
2242         len = strlenW(value);
2243     if (len)
2244     {
2245         lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0,
2246                                         (len+1)*sizeof(WCHAR));
2247         strcpyW(lphttpHdr->lpszValue, value);
2248     }
2249     return TRUE;
2250 }
2251
2252 /***********************************************************************
2253  *           HTTP_ProcessHeader (internal)
2254  *
2255  * Stuff header into header tables according to <dwModifier>
2256  *
2257  */
2258
2259 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2260
2261 BOOL HTTP_ProcessHeader(LPWININETHTTPREQW lpwhr, LPCWSTR field, LPCWSTR value, DWORD dwModifier)
2262 {
2263     LPHTTPHEADERW lphttpHdr = NULL;
2264     BOOL bSuccess = FALSE;
2265     INT index;
2266
2267     TRACE("--> %s: %s - 0x%08x\n", debugstr_w(field), debugstr_w(value), (unsigned int)dwModifier);
2268
2269     /* Adjust modifier flags */
2270     if (dwModifier & COALESCEFLASG)
2271         dwModifier |= HTTP_ADDHDR_FLAG_ADD;
2272
2273     /* Try to get index into standard header array */
2274     index = HTTP_GetStdHeaderIndex(field);
2275     if (index >= 0)
2276     {
2277         lphttpHdr = &lpwhr->StdHeaders[index];
2278     }
2279     else /* Find or create new custom header */
2280     {
2281         index = HTTP_GetCustomHeaderIndex(lpwhr, field);
2282         if (index >= 0)
2283         {
2284             if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
2285             {
2286                 return FALSE;
2287             }
2288             lphttpHdr = &lpwhr->pCustHeaders[index];
2289         }
2290         else
2291         {
2292             HTTPHEADERW hdr;
2293
2294             hdr.lpszField = (LPWSTR)field;
2295             hdr.lpszValue = (LPWSTR)value;
2296             hdr.wFlags = hdr.wCount = 0;
2297
2298             if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2299                 hdr.wFlags |= HDR_ISREQUEST;
2300
2301             return HTTP_InsertCustomHeader(lpwhr, &hdr);
2302         }
2303     }
2304
2305     if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2306         lphttpHdr->wFlags |= HDR_ISREQUEST;
2307     else
2308         lphttpHdr->wFlags &= ~HDR_ISREQUEST;
2309
2310     if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
2311     {
2312         INT slen;
2313
2314         if (!lpwhr->StdHeaders[index].lpszField)
2315         {
2316             lphttpHdr->lpszField = WININET_strdupW(field);
2317
2318             if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
2319                 lphttpHdr->wFlags |= HDR_ISREQUEST;
2320         }
2321
2322         slen = strlenW(value) + 1;
2323         lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen*sizeof(WCHAR));
2324         if (lphttpHdr->lpszValue)
2325         {
2326             strcpyW(lphttpHdr->lpszValue, value);
2327             bSuccess = TRUE;
2328         }
2329         else
2330         {
2331             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2332         }
2333     }
2334     else if (lphttpHdr->lpszValue)
2335     {
2336         if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
2337             bSuccess = HTTP_ReplaceHeaderValue( lphttpHdr, value );
2338         else if (dwModifier & COALESCEFLASG)
2339         {
2340             LPWSTR lpsztmp;
2341             WCHAR ch = 0;
2342             INT len = 0;
2343             INT origlen = strlenW(lphttpHdr->lpszValue);
2344             INT valuelen = strlenW(value);
2345
2346             if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
2347             {
2348                 ch = ',';
2349                 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2350             }
2351             else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
2352             {
2353                 ch = ';';
2354                 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
2355             }
2356
2357             len = origlen + valuelen + ((ch > 0) ? 1 : 0);
2358
2359             lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,  lphttpHdr->lpszValue, (len+1)*sizeof(WCHAR));
2360             if (lpsztmp)
2361             {
2362                 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
2363                 if (ch > 0)
2364                 {
2365                     lphttpHdr->lpszValue[origlen] = ch;
2366                     origlen++;
2367                 }
2368
2369                 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen*sizeof(WCHAR));
2370                 lphttpHdr->lpszValue[len] = '\0';
2371                 bSuccess = TRUE;
2372             }
2373             else
2374             {
2375                 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
2376                 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2377             }
2378         }
2379     }
2380     TRACE("<-- %d\n",bSuccess);
2381     return bSuccess;
2382 }
2383
2384
2385 /***********************************************************************
2386  *           HTTP_CloseConnection (internal)
2387  *
2388  * Close socket connection
2389  *
2390  */
2391 VOID HTTP_CloseConnection(LPWININETHTTPREQW lpwhr)
2392 {
2393     LPWININETHTTPSESSIONW lpwhs = NULL;
2394     LPWININETAPPINFOW hIC = NULL;
2395
2396     TRACE("%p\n",lpwhr);
2397
2398     lpwhs = (LPWININETHTTPSESSIONW) lpwhr->hdr.lpwhparent;
2399     hIC = (LPWININETAPPINFOW) lpwhs->hdr.lpwhparent;
2400
2401     SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext,
2402                       INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
2403
2404     if (NETCON_connected(&lpwhr->netConnection))
2405     {
2406         NETCON_close(&lpwhr->netConnection);
2407     }
2408
2409     SendAsyncCallback(hIC, &lpwhr->hdr, lpwhr->hdr.dwContext,
2410                       INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
2411 }
2412
2413
2414 /***********************************************************************
2415  *           HTTP_CloseHTTPRequestHandle (internal)
2416  *
2417  * Deallocate request handle
2418  *
2419  */
2420 static void HTTP_CloseHTTPRequestHandle(LPWININETHANDLEHEADER hdr)
2421 {
2422     int i;
2423     LPWININETHTTPREQW lpwhr = (LPWININETHTTPREQW) hdr;
2424
2425     TRACE("\n");
2426
2427     if (NETCON_connected(&lpwhr->netConnection))
2428         HTTP_CloseConnection(lpwhr);
2429
2430     if (lpwhr->lpszPath)
2431         HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
2432     if (lpwhr->lpszVerb)
2433         HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
2434     if (lpwhr->lpszHostName)
2435         HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
2436     if (lpwhr->lpszRawHeaders)
2437         HeapFree(GetProcessHeap(), 0, lpwhr->lpszRawHeaders);
2438
2439     for (i = 0; i <= HTTP_QUERY_MAX; i++)
2440     {
2441            if (lpwhr->StdHeaders[i].lpszField)
2442             HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
2443            if (lpwhr->StdHeaders[i].lpszValue)
2444             HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
2445     }
2446
2447     for (i = 0; i < lpwhr->nCustHeaders; i++)
2448     {
2449            if (lpwhr->pCustHeaders[i].lpszField)
2450             HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
2451            if (lpwhr->pCustHeaders[i].lpszValue)
2452             HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
2453     }
2454
2455     HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
2456     HeapFree(GetProcessHeap(), 0, lpwhr);
2457 }
2458
2459
2460 /***********************************************************************
2461  *           HTTP_CloseHTTPSessionHandle (internal)
2462  *
2463  * Deallocate session handle
2464  *
2465  */
2466 void HTTP_CloseHTTPSessionHandle(LPWININETHANDLEHEADER hdr)
2467 {
2468     LPWININETHTTPSESSIONW lpwhs = (LPWININETHTTPSESSIONW) hdr;
2469
2470     TRACE("%p\n", lpwhs);
2471
2472     if (lpwhs->lpszServerName)
2473         HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
2474     if (lpwhs->lpszUserName)
2475         HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
2476     HeapFree(GetProcessHeap(), 0, lpwhs);
2477 }
2478
2479
2480 /***********************************************************************
2481  *           HTTP_GetCustomHeaderIndex (internal)
2482  *
2483  * Return index of custom header from header array
2484  *
2485  */
2486 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQW lpwhr, LPCWSTR lpszField)
2487 {
2488     INT index;
2489
2490     TRACE("%s\n", debugstr_w(lpszField));
2491
2492     for (index = 0; index < lpwhr->nCustHeaders; index++)
2493     {
2494         if (!strcmpiW(lpwhr->pCustHeaders[index].lpszField, lpszField))
2495             break;
2496
2497     }
2498
2499     if (index >= lpwhr->nCustHeaders)
2500         index = -1;
2501
2502     TRACE("Return: %d\n", index);
2503     return index;
2504 }
2505
2506
2507 /***********************************************************************
2508  *           HTTP_InsertCustomHeader (internal)
2509  *
2510  * Insert header into array
2511  *
2512  */
2513 BOOL HTTP_InsertCustomHeader(LPWININETHTTPREQW lpwhr, LPHTTPHEADERW lpHdr)
2514 {
2515     INT count;
2516     LPHTTPHEADERW lph = NULL;
2517     BOOL r = FALSE;
2518
2519     TRACE("--> %s: %s\n", debugstr_w(lpHdr->lpszField), debugstr_w(lpHdr->lpszValue));
2520     count = lpwhr->nCustHeaders + 1;
2521     if (count > 1)
2522         lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERW) * count);
2523     else
2524         lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERW) * count);
2525
2526     if (NULL != lph)
2527     {
2528         lpwhr->pCustHeaders = lph;
2529         lpwhr->pCustHeaders[count-1].lpszField = WININET_strdupW(lpHdr->lpszField);
2530         lpwhr->pCustHeaders[count-1].lpszValue = WININET_strdupW(lpHdr->lpszValue);
2531         lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
2532         lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
2533         lpwhr->nCustHeaders++;
2534         r = TRUE;
2535     }
2536     else
2537     {
2538         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
2539     }
2540
2541     return r;
2542 }
2543
2544
2545 /***********************************************************************
2546  *           HTTP_DeleteCustomHeader (internal)
2547  *
2548  * Delete header from array
2549  *  If this function is called, the indexs may change.
2550  */
2551 BOOL HTTP_DeleteCustomHeader(LPWININETHTTPREQW lpwhr, INT index)
2552 {
2553     if( lpwhr->nCustHeaders <= 0 )
2554         return FALSE;
2555     if( lpwhr->nCustHeaders >= index )
2556         return FALSE;
2557     lpwhr->nCustHeaders--;
2558
2559     memmove( &lpwhr->pCustHeaders[index], &lpwhr->pCustHeaders[index+1],
2560              (lpwhr->nCustHeaders - index)* sizeof(HTTPHEADERW) );
2561     memset( &lpwhr->pCustHeaders[lpwhr->nCustHeaders], 0, sizeof(HTTPHEADERW) );
2562
2563     return TRUE;
2564 }
2565
2566 /***********************************************************************
2567  *          IsHostInProxyBypassList (@)
2568  *
2569  * Undocumented
2570  *
2571  */
2572 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
2573 {
2574    FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length);
2575    return FALSE;
2576 }