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