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