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