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