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