Fixed a race condition on RPC worker thread creation, and a typo.
[wine] / dlls / wininet / http.c
1 /*
2  * Wininet - Http Implementation
3  *
4  * Copyright 1999 Corel Corporation
5  * Copyright 2002 CodeWeavers Inc.
6  *
7  * Ulrich Czekalla
8  * Aric Stewart
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #include "config.h"
26
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_SOCKET_H
29 # include <sys/socket.h>
30 #endif
31 #include <stdio.h>
32 #include <stdlib.h>
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include <errno.h>
37 #include <string.h>
38 #include <time.h>
39
40 #include "windef.h"
41 #include "winbase.h"
42 #include "wininet.h"
43 #include "winreg.h"
44 #include "winerror.h"
45 #define NO_SHLWAPI_STREAM
46 #include "shlwapi.h"
47
48 #include "internet.h"
49 #include "wine/debug.h"
50 #include "wine/unicode.h"
51
52 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
53
54 #define HTTPHEADER " HTTP/1.0"
55 #define HTTPHOSTHEADER "\r\nHost: "
56 #define MAXHOSTNAME 100
57 #define MAX_FIELD_VALUE_LEN 256
58 #define MAX_FIELD_LEN 256
59
60
61 #define HTTP_REFERER    "Referer"
62 #define HTTP_ACCEPT     "Accept"
63 #define HTTP_USERAGENT  "User-Agent"
64
65 #define HTTP_ADDHDR_FLAG_ADD                            0x20000000
66 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW                     0x10000000
67 #define HTTP_ADDHDR_FLAG_COALESCE                       0x40000000
68 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA            0x40000000
69 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON        0x01000000
70 #define HTTP_ADDHDR_FLAG_REPLACE                        0x80000000
71 #define HTTP_ADDHDR_FLAG_REQ                            0x02000000
72
73
74 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr);
75 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr,
76         void *Buffer, int BytesToWrite);
77 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr,
78         void *Buffer, int BytesToRead);
79 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr);
80 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier);
81 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr);
82 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen);
83 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField);
84 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr);
85 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField);
86
87 inline static LPSTR HTTP_strdup( LPCSTR str )
88 {
89     LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
90     if (ret) strcpy( ret, str );
91     return ret;
92 }
93
94 /***********************************************************************
95  *           HttpAddRequestHeadersA (WININET.@)
96  *
97  * Adds one or more HTTP header to the request handler
98  *
99  * RETURNS
100  *    TRUE  on success
101  *    FALSE on failure
102  *
103  */
104 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
105         LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
106 {
107     LPSTR lpszStart;
108     LPSTR lpszEnd;
109     LPSTR buffer;
110     CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
111     BOOL bSuccess = FALSE;
112     LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
113
114     TRACE("\n");
115
116     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
117     {
118         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
119         return FALSE;
120     }
121
122     if (!lpszHeader) 
123       return TRUE;
124     buffer = HTTP_strdup(lpszHeader);
125     lpszStart = buffer;
126
127     do
128     {
129         lpszEnd = lpszStart;
130
131         while (*lpszEnd != '\0')
132         {
133             if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
134                  break;
135             lpszEnd++;
136         }
137
138         if (*lpszEnd == '\0')
139             break;
140
141         *lpszEnd = '\0';
142
143         if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
144             bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
145
146         lpszStart = lpszEnd + 2; /* Jump over \0\n */
147
148     } while (bSuccess);
149
150     HeapFree(GetProcessHeap(), 0, buffer);
151     return bSuccess;
152 }
153
154 /***********************************************************************
155  *           HttpEndRequestA (WININET.@)
156  *
157  * Ends an HTTP request that was started by HttpSendRequestEx
158  *
159  * RETURNS
160  *    TRUE      if successful
161  *    FALSE     on failure
162  *
163  */
164 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, LPINTERNET_BUFFERSA lpBuffersOut, 
165           DWORD dwFlags, DWORD dwContext)
166 {
167   FIXME("stub\n");
168   return FALSE;
169 }
170
171 /***********************************************************************
172  *           HttpEndRequestW (WININET.@)
173  *
174  * Ends an HTTP request that was started by HttpSendRequestEx
175  *
176  * RETURNS
177  *    TRUE      if successful
178  *    FALSE     on failure
179  *
180  */
181 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, LPINTERNET_BUFFERSW lpBuffersOut, 
182           DWORD dwFlags, DWORD dwContext)
183 {
184   FIXME("stub\n");
185   return FALSE;
186 }
187
188 /***********************************************************************
189  *           HttpOpenRequestA (WININET.@)
190  *
191  * Open a HTTP request handle
192  *
193  * RETURNS
194  *    HINTERNET  a HTTP request handle on success
195  *    NULL       on failure
196  *
197  */
198 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
199         LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
200         LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
201         DWORD dwFlags, DWORD dwContext)
202 {
203     LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
204     LPWININETAPPINFOA hIC = NULL;
205
206     TRACE("(%s, %s, %s, %s, %ld, %ld)\n", lpszVerb, lpszObjectName, lpszVersion, lpszReferrer, dwFlags, dwContext);
207     if(lpszAcceptTypes!=NULL)
208     {
209         int i;
210         for(i=0;lpszAcceptTypes[i]!=NULL;i++)
211             TRACE("\taccept type: %s\n",lpszAcceptTypes[i]);
212     }    
213
214     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
215     {
216         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
217         return FALSE;
218     }
219     hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
220
221     /*
222      * My tests seem to show that the windows version does not
223      * become asynchronous until after this point. And anyhow
224      * if this call was asynchronous then how would you get the
225      * necessary HINTERNET pointer returned by this function.
226      *
227      * I am leaving this here just in case I am wrong
228      *
229      * if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
230      */
231     if (0)
232     {
233         WORKREQUEST workRequest;
234
235         workRequest.asyncall = HTTPOPENREQUESTA;
236         workRequest.HFTPSESSION = (DWORD)hHttpSession;
237         workRequest.LPSZVERB = (DWORD)HTTP_strdup(lpszVerb);
238         workRequest.LPSZOBJECTNAME = (DWORD)HTTP_strdup(lpszObjectName);
239         if (lpszVersion)
240             workRequest.LPSZVERSION = (DWORD)HTTP_strdup(lpszVersion);
241         else
242             workRequest.LPSZVERSION = 0;
243         if (lpszReferrer)
244             workRequest.LPSZREFERRER = (DWORD)HTTP_strdup(lpszReferrer);
245         else
246             workRequest.LPSZREFERRER = 0;
247         workRequest.LPSZACCEPTTYPES = (DWORD)lpszAcceptTypes;
248         workRequest.DWFLAGS = dwFlags;
249         workRequest.DWCONTEXT = dwContext;
250
251         INTERNET_AsyncCall(&workRequest);
252         return NULL;
253     }
254     else
255     {
256         return HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName,
257                 lpszVersion, lpszReferrer, lpszAcceptTypes, dwFlags, dwContext);
258     }
259 }
260
261 /***********************************************************************
262  *           HttpOpenRequestW (WININET.@)
263  *
264  * Open a HTTP request handle
265  *
266  * RETURNS
267  *    HINTERNET  a HTTP request handle on success
268  *    NULL       on failure
269  *
270  */
271 HINTERNET WINAPI HttpOpenRequestW(HINTERNET hHttpSession,
272         LPCWSTR lpszVerb, LPCWSTR lpszObjectName, LPCWSTR lpszVersion,
273         LPCWSTR lpszReferrer , LPCWSTR *lpszAcceptTypes,
274         DWORD dwFlags, DWORD dwContext)
275 {
276     char szVerb[20],
277          szObjectName[INTERNET_MAX_PATH_LENGTH];
278     TRACE("(%s, %s, %s, %s, %ld, %ld)\n", debugstr_w(lpszVerb), debugstr_w(lpszObjectName), debugstr_w(lpszVersion), debugstr_w(lpszReferrer), dwFlags, dwContext);
279
280     if(lpszVerb!=NULL)
281         WideCharToMultiByte(CP_ACP,0,lpszVerb,-1,szVerb,20,NULL,NULL);
282     else
283         szVerb[0]=0;
284     if(lpszObjectName!=NULL)
285         WideCharToMultiByte(CP_ACP,0,lpszObjectName,-1,szObjectName,INTERNET_MAX_PATH_LENGTH,NULL,NULL);
286     else
287         szObjectName[0]=0;
288     TRACE("object name=%s\n",szObjectName);
289     FIXME("lpszVersion, lpszReferrer and lpszAcceptTypes ignored\n");
290     return HttpOpenRequestA(hHttpSession, szVerb[0]?szVerb:NULL, szObjectName, NULL, NULL, NULL, dwFlags, dwContext);
291 }
292
293 /***********************************************************************
294  *           HTTP_HttpOpenRequestA (internal)
295  *
296  * Open a HTTP request handle
297  *
298  * RETURNS
299  *    HINTERNET  a HTTP request handle on success
300  *    NULL       on failure
301  *
302  */
303 HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
304         LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
305         LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
306         DWORD dwFlags, DWORD dwContext)
307 {
308     LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
309     LPWININETAPPINFOA hIC = NULL;
310     LPWININETHTTPREQA lpwhr;
311
312     TRACE("--> \n");
313
314     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
315     {
316         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
317         return FALSE;
318     }
319
320     hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
321
322     lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
323     if (NULL == lpwhr)
324     {
325         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
326         return (HINTERNET) NULL;
327     }
328
329     lpwhr->hdr.htype = WH_HHTTPREQ;
330     lpwhr->hdr.lpwhparent = hHttpSession;
331     lpwhr->hdr.dwFlags = dwFlags;
332     lpwhr->hdr.dwContext = dwContext;
333     lpwhr->nSocketFD = -1;
334
335     if (NULL != lpszObjectName && strlen(lpszObjectName)) {
336         DWORD needed = 0;
337         HRESULT rc;
338         rc = UrlEscapeA(lpszObjectName, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
339         if (rc != E_POINTER)
340             needed = strlen(lpszObjectName)+1;
341         lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
342         rc = UrlEscapeA(lpszObjectName, lpwhr->lpszPath, &needed,
343                    URL_ESCAPE_SPACES_ONLY);
344         if (rc)
345         {
346             ERR("Unable to escape string!(%s) (%ld)\n",lpszObjectName,rc);
347             strcpy(lpwhr->lpszPath,lpszObjectName);
348         }
349     }
350
351     if (NULL != hIC->lpszAgent && strlen(hIC->lpszAgent))
352         HTTP_ProcessHeader(lpwhr, HTTP_USERAGENT, hIC->lpszAgent, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
353
354     if (NULL != lpszReferrer && strlen(lpszReferrer))
355         HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
356
357     if(lpszAcceptTypes!=NULL)
358     {
359         int i;
360         for(i=0;lpszAcceptTypes[i]!=NULL;i++)
361             HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, lpszAcceptTypes[i], HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_REQ|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
362     }
363
364     if (NULL == lpszVerb)
365         lpwhr->lpszVerb = HTTP_strdup("GET");
366     else if (strlen(lpszVerb))
367         lpwhr->lpszVerb = HTTP_strdup(lpszVerb);
368
369     if (NULL != lpszReferrer)
370     {
371         char buf[MAXHOSTNAME];
372         URL_COMPONENTSA UrlComponents;
373
374         UrlComponents.lpszExtraInfo = NULL;
375         UrlComponents.lpszPassword = NULL;
376         UrlComponents.lpszScheme = NULL;
377         UrlComponents.lpszUrlPath = NULL;
378         UrlComponents.lpszUserName = NULL;
379         UrlComponents.lpszHostName = buf;
380         UrlComponents.dwHostNameLength = MAXHOSTNAME;
381
382         InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
383         if (strlen(UrlComponents.lpszHostName))
384             lpwhr->lpszHostName = HTTP_strdup(UrlComponents.lpszHostName);
385     } else if (NULL != hIC->lpszProxy && hIC->lpszProxy[0] != 0) {
386         char buf[MAXHOSTNAME];
387         char proxy[MAXHOSTNAME + 13]; /* 13 == "http://" + sizeof(port#) + ":/\0" */
388         URL_COMPONENTSA UrlComponents;
389
390         UrlComponents.lpszExtraInfo = NULL;
391         UrlComponents.lpszPassword = NULL;
392         UrlComponents.lpszScheme = NULL;
393         UrlComponents.lpszUrlPath = NULL;
394         UrlComponents.lpszUserName = NULL;
395         UrlComponents.lpszHostName = buf;
396         UrlComponents.dwHostNameLength = MAXHOSTNAME;
397
398         sprintf(proxy, "http://%s/", hIC->lpszProxy);
399         InternetCrackUrlA(proxy, 0, 0, &UrlComponents);
400         if (strlen(UrlComponents.lpszHostName)) {
401                          /* for constant 13 see above */
402              char* url = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszHostName) + strlen(lpwhr->lpszPath) + 13);
403
404              if(UrlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
405                  UrlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
406                         
407             if(lpwhr->lpszHostName != 0) {
408                 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
409                 lpwhr->lpszHostName = 0;
410             }
411             sprintf(url, "http://%s:%d/%s", lpwhs->lpszServerName, lpwhs->nServerPort, lpwhr->lpszPath);
412             if(lpwhr->lpszPath)
413                 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
414             lpwhr->lpszPath = url;
415             /* FIXME: Do I have to free lpwhs->lpszServerName here ? */
416             lpwhs->lpszServerName = HTTP_strdup(UrlComponents.lpszHostName);
417             lpwhs->nServerPort = UrlComponents.nPort;
418         }
419     } else {
420         lpwhr->lpszHostName = HTTP_strdup(lpwhs->lpszServerName);
421     }
422
423     if (hIC->lpfnStatusCB)
424     {
425         INTERNET_ASYNC_RESULT iar;
426
427         iar.dwResult = (DWORD)lpwhr;
428         iar.dwError = ERROR_SUCCESS;
429
430         SendAsyncCallback(hIC, hHttpSession, dwContext,
431                       INTERNET_STATUS_HANDLE_CREATED, &iar,
432                       sizeof(INTERNET_ASYNC_RESULT));
433     }
434
435     /*
436      * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
437      */
438
439     /*
440      * According to my tests. The name is not resolved until a request is Opened
441      */
442     SendAsyncCallback(hIC, hHttpSession, dwContext,
443                       INTERNET_STATUS_RESOLVING_NAME,
444                       lpwhs->lpszServerName,
445                       strlen(lpwhs->lpszServerName)+1);
446
447     if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
448                     &lpwhs->phostent, &lpwhs->socketAddress))
449     {
450         INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
451         return FALSE;
452     }
453
454     SendAsyncCallback(hIC, hHttpSession, lpwhr->hdr.dwContext,
455                       INTERNET_STATUS_NAME_RESOLVED,
456                       &(lpwhs->socketAddress),
457                       sizeof(struct sockaddr_in));
458
459     TRACE("<--\n");
460     return (HINTERNET) lpwhr;
461 }
462
463
464 /***********************************************************************
465  *           HttpQueryInfoA (WININET.@)
466  *
467  * Queries for information about an HTTP request
468  *
469  * RETURNS
470  *    TRUE  on success
471  *    FALSE on failure
472  *
473  */
474 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
475         LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
476 {
477     LPHTTPHEADERA lphttpHdr = NULL;
478     BOOL bSuccess = FALSE;
479     LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
480
481     TRACE("(0x%08lx)--> %ld\n", dwInfoLevel, dwInfoLevel);
482
483     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
484     {
485         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
486         return FALSE;
487     }
488
489     /* Find requested header structure */
490     if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
491     {
492         INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
493
494         if (index < 0)
495             goto lend;
496
497         lphttpHdr = &lpwhr->pCustHeaders[index];
498     }
499     else
500     {
501         INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
502
503         if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
504         {
505             INT i, delim, size = 0, cnt = 0;
506
507             delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
508
509            /* Calculate length of custom reuqest headers */
510            for (i = 0; i < lpwhr->nCustHeaders; i++)
511            {
512                if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
513                    lpwhr->pCustHeaders[i].lpszValue)
514                {
515                   size += strlen(lpwhr->pCustHeaders[i].lpszField) +
516                        strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
517                }
518            }
519
520            /* Calculate the length of stadard request headers */
521            for (i = 0; i <= HTTP_QUERY_MAX; i++)
522            {
523               if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
524                    lpwhr->StdHeaders[i].lpszValue)
525               {
526                  size += strlen(lpwhr->StdHeaders[i].lpszField) +
527                     strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
528               }
529            }
530            size += delim;
531
532            if (size + 1 > *lpdwBufferLength)
533            {
534               *lpdwBufferLength = size + 1;
535               INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
536               goto lend;
537            }
538
539            /* Append standard request heades */
540            for (i = 0; i <= HTTP_QUERY_MAX; i++)
541            {
542                if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
543                                            lpwhr->StdHeaders[i].lpszField &&
544                                            lpwhr->StdHeaders[i].lpszValue)
545                {
546                    cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
547                           index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
548                }
549             }
550
551             /* Append custom request heades */
552             for (i = 0; i < lpwhr->nCustHeaders; i++)
553             {
554                 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
555                                                 lpwhr->pCustHeaders[i].lpszField &&
556                                                 lpwhr->pCustHeaders[i].lpszValue)
557                 {
558                    cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s",
559                     lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
560                                         index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
561                 }
562             }
563
564             strcpy((char*)lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
565
566            *lpdwBufferLength = cnt + delim;
567            bSuccess = TRUE;
568                 goto lend;
569         }
570         else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
571         {
572             lphttpHdr = &lpwhr->StdHeaders[index];
573         }
574         else
575             goto lend;
576     }
577
578     /* Ensure header satisifies requested attributes */
579     if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
580             (~lphttpHdr->wFlags & HDR_ISREQUEST))
581         goto lend;
582
583     /* coalesce value to reuqested type */
584     if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
585     {
586        *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
587            bSuccess = TRUE;
588     }
589     else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
590     {
591         time_t tmpTime;
592         struct tm tmpTM;
593         SYSTEMTIME *STHook;
594
595         tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
596
597         tmpTM = *gmtime(&tmpTime);
598         STHook = (SYSTEMTIME *) lpBuffer;
599         if(STHook==NULL)
600             goto lend;
601
602             STHook->wDay = tmpTM.tm_mday;
603             STHook->wHour = tmpTM.tm_hour;
604             STHook->wMilliseconds = 0;
605             STHook->wMinute = tmpTM.tm_min;
606             STHook->wDayOfWeek = tmpTM.tm_wday;
607             STHook->wMonth = tmpTM.tm_mon + 1;
608             STHook->wSecond = tmpTM.tm_sec;
609             STHook->wYear = tmpTM.tm_year;
610
611             bSuccess = TRUE;
612     }
613     else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
614     {
615             if (*lpdwIndex >= lphttpHdr->wCount)
616                 {
617                 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
618                 }
619             else
620             {
621             /* Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len); */
622             (*lpdwIndex)++;
623             }
624     }
625     else
626     {
627         INT len = strlen(lphttpHdr->lpszValue);
628
629         if (len + 1 > *lpdwBufferLength)
630         {
631             *lpdwBufferLength = len + 1;
632             INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
633             goto lend;
634         }
635
636         strncpy(lpBuffer, lphttpHdr->lpszValue, len);
637         ((char*)lpBuffer)[len]=0;
638         *lpdwBufferLength = len;
639         bSuccess = TRUE;
640     }
641
642 lend:
643     TRACE("%d <--\n", bSuccess);
644     return bSuccess;
645 }
646
647 /***********************************************************************
648  *           HttpQueryInfoW (WININET.@)
649  *
650  * Queries for information about an HTTP request
651  *
652  * RETURNS
653  *    TRUE  on success
654  *    FALSE on failure
655  *
656  */
657 BOOL WINAPI HttpQueryInfoW(HINTERNET hHttpRequest, DWORD dwInfoLevel,
658         LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
659 {
660     BOOL result;
661     DWORD charLen=*lpdwBufferLength;
662     char* tempBuffer=HeapAlloc(GetProcessHeap(), 0, charLen);
663     result=HttpQueryInfoA(hHttpRequest, dwInfoLevel, tempBuffer, &charLen, lpdwIndex);
664     if((dwInfoLevel & HTTP_QUERY_FLAG_NUMBER) ||
665        (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME))
666     {
667         memcpy(lpBuffer,tempBuffer,charLen);
668     }
669     else
670     {
671         int nChars=MultiByteToWideChar(CP_ACP,0, tempBuffer,charLen,lpBuffer,*lpdwBufferLength);
672         *lpdwBufferLength=nChars;
673     }
674     HeapFree(GetProcessHeap(), 0, tempBuffer);
675     return result;
676 }
677
678 /***********************************************************************
679  *           HttpSendRequestExA (WININET.@)
680  *
681  * Sends the specified request to the HTTP server and allows chunked
682  * transfers
683  */
684 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
685                                LPINTERNET_BUFFERSA lpBuffersIn,
686                                LPINTERNET_BUFFERSA lpBuffersOut,
687                                DWORD dwFlags, DWORD dwContext)
688 {
689   FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
690         lpBuffersOut, dwFlags, dwContext);
691   return FALSE;
692 }
693
694 /***********************************************************************
695  *           HttpSendRequestA (WININET.@)
696  *
697  * Sends the specified request to the HTTP server
698  *
699  * RETURNS
700  *    TRUE  on success
701  *    FALSE on failure
702  *
703  */
704 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
705         DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
706 {
707     LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
708     LPWININETHTTPSESSIONA lpwhs = NULL;
709     LPWININETAPPINFOA hIC = NULL;
710
711     TRACE("0x%08lx\n", (unsigned long)hHttpRequest);
712
713     if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
714     {
715         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
716         return FALSE;
717     }
718
719     lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
720     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
721     {
722         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
723         return FALSE;
724     }
725
726     hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
727     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT)
728     {
729         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
730         return FALSE;
731     }
732
733     if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
734     {
735         WORKREQUEST workRequest;
736
737         workRequest.asyncall = HTTPSENDREQUESTA;
738         workRequest.HFTPSESSION = (DWORD)hHttpRequest;
739         if (lpszHeaders)
740             workRequest.LPSZHEADER = (DWORD)HTTP_strdup(lpszHeaders);
741         else
742             workRequest.LPSZHEADER = 0;
743         workRequest.DWHEADERLENGTH = dwHeaderLength;
744         workRequest.LPOPTIONAL = (DWORD)lpOptional;
745         workRequest.DWOPTIONALLENGTH = dwOptionalLength;
746
747         INTERNET_AsyncCall(&workRequest);
748         /*
749          * This is from windows.
750          */
751         SetLastError(ERROR_IO_PENDING);
752         return 0;
753     }
754     else
755     {
756         return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
757                 dwHeaderLength, lpOptional, dwOptionalLength);
758     }
759 }
760
761 /***********************************************************************
762  *           HttpSendRequestW (WININET.@)
763  *
764  * Sends the specified request to the HTTP server
765  *
766  * RETURNS
767  *    TRUE  on success
768  *    FALSE on failure
769  *
770  */
771 BOOL WINAPI HttpSendRequestW(HINTERNET hHttpRequest, LPCWSTR lpszHeaders,
772         DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
773 {
774     BOOL result;
775     char* szHeaders=NULL;
776     DWORD nLen=dwHeaderLength;
777     if(lpszHeaders!=NULL)
778     {
779         if(nLen==-1)
780             nLen=strlenW(lpszHeaders);
781         szHeaders=(char*)malloc(nLen+1);
782         WideCharToMultiByte(CP_ACP,0,lpszHeaders,nLen,szHeaders,nLen,NULL,NULL);
783     }
784     result=HttpSendRequestA(hHttpRequest, szHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
785     if(szHeaders!=NULL)
786         free(szHeaders);
787     return result;
788 }
789
790 /***********************************************************************
791  *           HTTP_HandleRedirect (internal)
792  */
793 static BOOL HTTP_HandleRedirect(LPWININETHTTPREQA lpwhr, LPCSTR lpszUrl, LPCSTR lpszHeaders,
794                                 DWORD dwHeaderLength, LPVOID lpOptional, DWORD dwOptionalLength)
795 {
796     LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
797     LPWININETAPPINFOA hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
798     char path[2048];
799     if(lpszUrl[0]=='/')
800     {
801         /* if it's an absolute path, keep the same session info */
802         strcpy(path,lpszUrl);
803     }
804     else
805     {
806         URL_COMPONENTSA urlComponents;
807         char protocol[32], hostName[MAXHOSTNAME], userName[1024];
808         char password[1024], extra[1024];
809         urlComponents.dwStructSize = sizeof(URL_COMPONENTSA);
810         urlComponents.lpszScheme = protocol;
811         urlComponents.dwSchemeLength = 32;
812         urlComponents.lpszHostName = hostName;
813         urlComponents.dwHostNameLength = MAXHOSTNAME;
814         urlComponents.lpszUserName = userName;
815         urlComponents.dwUserNameLength = 1024;
816         urlComponents.lpszPassword = password;
817         urlComponents.dwPasswordLength = 1024;
818         urlComponents.lpszUrlPath = path;
819         urlComponents.dwUrlPathLength = 2048;
820         urlComponents.lpszExtraInfo = extra;
821         urlComponents.dwExtraInfoLength = 1024;
822         if(!InternetCrackUrlA(lpszUrl, strlen(lpszUrl), 0, &urlComponents))
823             return FALSE;
824         
825         if (urlComponents.nPort == INTERNET_INVALID_PORT_NUMBER)
826             urlComponents.nPort = INTERNET_DEFAULT_HTTP_PORT;
827
828         /* consider the current host as the referef */
829         if (NULL != lpwhs->lpszServerName && strlen(lpwhs->lpszServerName))
830             HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpwhs->lpszServerName, HTTP_ADDHDR_FLAG_REQ|HTTP_ADDREQ_FLAG_REPLACE|HTTP_ADDHDR_FLAG_ADD_IF_NEW);
831         
832         if (NULL != lpwhs->lpszServerName)
833             HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
834         lpwhs->lpszServerName = HTTP_strdup(hostName);
835         if (NULL != lpwhs->lpszUserName)
836             HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
837         lpwhs->lpszUserName = HTTP_strdup(userName);
838         lpwhs->nServerPort = urlComponents.nPort;
839
840         if (NULL != lpwhr->lpszHostName)
841             HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
842         lpwhr->lpszHostName=HTTP_strdup(hostName);
843
844         SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
845                       INTERNET_STATUS_RESOLVING_NAME,
846                       lpwhs->lpszServerName,
847                       strlen(lpwhs->lpszServerName)+1);
848
849         if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
850                     &lpwhs->phostent, &lpwhs->socketAddress))
851         {
852             INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
853             return FALSE;
854         }
855
856         SendAsyncCallback(hIC, lpwhs, lpwhr->hdr.dwContext,
857                       INTERNET_STATUS_NAME_RESOLVED,
858                       &(lpwhs->socketAddress),
859                       sizeof(struct sockaddr_in));
860
861     }
862
863     if(lpwhr->lpszPath)
864         HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
865     lpwhr->lpszPath=NULL;
866     if (strlen(path))
867     {
868         DWORD needed = 0;
869         HRESULT rc;
870         rc = UrlEscapeA(path, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
871         if (rc != E_POINTER)
872             needed = strlen(path)+1;
873         lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
874         rc = UrlEscapeA(path, lpwhr->lpszPath, &needed,
875                         URL_ESCAPE_SPACES_ONLY);
876         if (rc)
877         {
878             ERR("Unable to escape string!(%s) (%ld)\n",path,rc);
879             strcpy(lpwhr->lpszPath,path);
880         }
881     }
882
883     return HttpSendRequestA((HINTERNET)lpwhr, lpszHeaders, dwHeaderLength, lpOptional, dwOptionalLength);
884 }
885
886 /***********************************************************************
887  *           HTTP_HttpSendRequestA (internal)
888  *
889  * Sends the specified request to the HTTP server
890  *
891  * RETURNS
892  *    TRUE  on success
893  *    FALSE on failure
894  *
895  */
896 BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
897         DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
898 {
899     INT cnt;
900     INT i;
901     BOOL bSuccess = FALSE;
902     LPSTR requestString = NULL;
903     INT requestStringLen;
904     INT responseLen;
905     INT headerLength = 0;
906     LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
907     LPWININETHTTPSESSIONA lpwhs = NULL;
908     LPWININETAPPINFOA hIC = NULL;
909
910     TRACE("--> 0x%08lx\n", (ULONG)hHttpRequest);
911
912     /* Verify our tree of internet handles */
913     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
914     {
915         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
916         return FALSE;
917     }
918
919     lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
920     if (NULL == lpwhs ||  lpwhs->hdr.htype != WH_HHTTPSESSION)
921     {
922         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
923         return FALSE;
924     }
925
926     hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
927     if (NULL == hIC ||  hIC->hdr.htype != WH_HINIT)
928     {
929         INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
930         return FALSE;
931     }
932
933     /* Clear any error information */
934     INTERNET_SetLastError(0);
935
936
937     /* We must have a verb */
938     if (NULL == lpwhr->lpszVerb)
939     {
940             goto lend;
941     }
942
943     /* If we don't have a path we set it to root */
944     if (NULL == lpwhr->lpszPath)
945         lpwhr->lpszPath = HTTP_strdup("/");
946
947     if(strncmp(lpwhr->lpszPath, "http://", sizeof("http://") -1) != 0
948         && lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
949     {
950         char *fixurl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszPath) + 2);
951         *fixurl = '/';
952         strcpy(fixurl + 1, lpwhr->lpszPath);
953         HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
954         lpwhr->lpszPath = fixurl;
955     }
956
957     /* Calculate length of request string */
958     requestStringLen =
959         strlen(lpwhr->lpszVerb) +
960         strlen(lpwhr->lpszPath) +
961         (lpwhr->lpszHostName ? (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName)) : 0) +
962         strlen(HTTPHEADER) +
963         5; /* " \r\n\r\n" */
964
965     /* Add length of passed headers */
966     if (lpszHeaders)
967     {
968         headerLength = -1 == dwHeaderLength ?  strlen(lpszHeaders) : dwHeaderLength;
969         requestStringLen += headerLength +  2; /* \r\n */
970     }
971
972     /* Calculate length of custom request headers */
973     for (i = 0; i < lpwhr->nCustHeaders; i++)
974     {
975             if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
976             {
977             requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
978                 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
979             }
980     }
981
982     /* Calculate the length of standard request headers */
983     for (i = 0; i <= HTTP_QUERY_MAX; i++)
984     {
985        if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
986        {
987           requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
988              strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
989        }
990     }
991
992     /* Allocate string to hold entire request */
993     requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
994     if (NULL == requestString)
995     {
996         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
997         goto lend;
998     }
999
1000     /* Build request string */
1001     cnt = sprintf(requestString, "%s %s%s%s",
1002         lpwhr->lpszVerb,
1003         lpwhr->lpszPath,
1004         lpwhr->lpszHostName ? (HTTPHEADER HTTPHOSTHEADER) : HTTPHEADER,
1005         lpwhr->lpszHostName ? lpwhr->lpszHostName : "");
1006
1007     /* Append standard request headers */
1008     for (i = 0; i <= HTTP_QUERY_MAX; i++)
1009     {
1010        if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
1011        {
1012            cnt += sprintf(requestString + cnt, "\r\n%s: %s",
1013                lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
1014            TRACE("Adding header %s (%s)\n",lpwhr->StdHeaders[i].lpszField,lpwhr->StdHeaders[i].lpszValue);
1015        }
1016     }
1017
1018     /* Append custom request heades */
1019     for (i = 0; i < lpwhr->nCustHeaders; i++)
1020     {
1021        if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
1022        {
1023            cnt += sprintf(requestString + cnt, "\r\n%s: %s",
1024                lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
1025            TRACE("Adding custom header %s (%s)\n",lpwhr->pCustHeaders[i].lpszField,lpwhr->pCustHeaders[i].lpszValue);
1026        }
1027     }
1028
1029     /* Append passed request headers */
1030     if (lpszHeaders)
1031     {
1032         strcpy(requestString + cnt, "\r\n");
1033         cnt += 2;
1034         strcpy(requestString + cnt, lpszHeaders);
1035         cnt += headerLength;
1036     }
1037
1038     /* Set termination string for request */
1039     strcpy(requestString + cnt, "\r\n\r\n");
1040
1041     TRACE("(%s) len(%d)\n", requestString, requestStringLen);
1042     /* Send the request and store the results */
1043     if (!HTTP_OpenConnection(lpwhr))
1044         goto lend;
1045
1046     SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1047                       INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
1048
1049     cnt = send(lpwhr->nSocketFD, requestString, requestStringLen, 0);
1050
1051     SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1052                       INTERNET_STATUS_REQUEST_SENT,
1053                       &requestStringLen,sizeof(DWORD));
1054
1055     SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1056                       INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
1057
1058     if (cnt < 0)
1059         goto lend;
1060
1061     responseLen = HTTP_GetResponseHeaders(lpwhr);
1062     if (responseLen)
1063             bSuccess = TRUE;
1064
1065     SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1066                       INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
1067                       sizeof(DWORD));
1068
1069 lend:
1070
1071     if (requestString)
1072         HeapFree(GetProcessHeap(), 0, requestString);
1073
1074     /* TODO: send notification for P3P header */
1075     
1076     if(!(hIC->hdr.dwFlags & INTERNET_FLAG_NO_AUTO_REDIRECT) && bSuccess)
1077     {
1078         DWORD dwCode,dwCodeLength=sizeof(DWORD),dwIndex=0;
1079         if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_FLAG_NUMBER|HTTP_QUERY_STATUS_CODE,&dwCode,&dwCodeLength,&dwIndex) &&
1080             (dwCode==302 || dwCode==301))
1081         {
1082             char szNewLocation[2048];
1083             DWORD dwBufferSize=2048;
1084             dwIndex=0;
1085             if(HttpQueryInfoA(hHttpRequest,HTTP_QUERY_LOCATION,szNewLocation,&dwBufferSize,&dwIndex))
1086             {
1087                 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1088                       INTERNET_STATUS_REDIRECT, szNewLocation,
1089                       dwBufferSize);
1090                 return HTTP_HandleRedirect(lpwhr, szNewLocation, lpszHeaders,
1091                                            dwHeaderLength, lpOptional, dwOptionalLength);
1092             }
1093         }
1094     }
1095
1096     if (hIC->lpfnStatusCB)
1097     {
1098         INTERNET_ASYNC_RESULT iar;
1099
1100         iar.dwResult = (DWORD)bSuccess;
1101         iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
1102
1103         SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
1104                       INTERNET_STATUS_REQUEST_COMPLETE, &iar,
1105                       sizeof(INTERNET_ASYNC_RESULT));
1106     }
1107
1108     TRACE("<--\n");
1109     return bSuccess;
1110 }
1111
1112
1113 /***********************************************************************
1114  *           HTTP_Connect  (internal)
1115  *
1116  * Create http session handle
1117  *
1118  * RETURNS
1119  *   HINTERNET a session handle on success
1120  *   NULL on failure
1121  *
1122  */
1123 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
1124         INTERNET_PORT nServerPort, LPCSTR lpszUserName,
1125         LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
1126 {
1127     BOOL bSuccess = FALSE;
1128     LPWININETAPPINFOA hIC = NULL;
1129     LPWININETHTTPSESSIONA lpwhs = NULL;
1130
1131     TRACE("-->\n");
1132
1133     if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
1134         goto lerror;
1135
1136     hIC = (LPWININETAPPINFOA) hInternet;
1137     hIC->hdr.dwContext = dwContext;
1138     
1139     lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
1140     if (NULL == lpwhs)
1141     {
1142         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1143         goto lerror;
1144     }
1145
1146    /*
1147     * According to my tests. The name is not resolved until a request is sent
1148     */
1149
1150     if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
1151         nServerPort = INTERNET_DEFAULT_HTTP_PORT;
1152
1153     lpwhs->hdr.htype = WH_HHTTPSESSION;
1154     lpwhs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
1155     lpwhs->hdr.dwFlags = dwFlags;
1156     lpwhs->hdr.dwContext = dwContext;
1157     if(hIC->lpszProxy && hIC->dwAccessType == INTERNET_OPEN_TYPE_PROXY) {
1158         if(strchr(hIC->lpszProxy, ' '))
1159             FIXME("Several proxies not implemented.\n");
1160         if(hIC->lpszProxyBypass)
1161             FIXME("Proxy bypass is ignored.\n");
1162     }
1163     if (NULL != lpszServerName)
1164         lpwhs->lpszServerName = HTTP_strdup(lpszServerName);
1165     if (NULL != lpszUserName)
1166         lpwhs->lpszUserName = HTTP_strdup(lpszUserName);
1167     lpwhs->nServerPort = nServerPort;
1168
1169     if (hIC->lpfnStatusCB)
1170     {
1171         INTERNET_ASYNC_RESULT iar;
1172
1173         iar.dwResult = (DWORD)lpwhs;
1174         iar.dwError = ERROR_SUCCESS;
1175
1176         SendAsyncCallback(hIC, hInternet, dwContext,
1177                       INTERNET_STATUS_HANDLE_CREATED, &iar,
1178                       sizeof(INTERNET_ASYNC_RESULT));
1179     }
1180
1181     bSuccess = TRUE;
1182
1183 lerror:
1184     if (!bSuccess && lpwhs)
1185     {
1186         HeapFree(GetProcessHeap(), 0, lpwhs);
1187         lpwhs = NULL;
1188     }
1189
1190 /*
1191  * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
1192  * windows
1193  */
1194
1195 TRACE("<--\n");
1196     return (HINTERNET)lpwhs;
1197 }
1198
1199
1200 /***********************************************************************
1201  *           HTTP_OpenConnection (internal)
1202  *
1203  * Connect to a web server
1204  *
1205  * RETURNS
1206  *
1207  *   TRUE  on success
1208  *   FALSE on failure
1209  */
1210 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
1211 {
1212     BOOL bSuccess = FALSE;
1213     INT result;
1214     LPWININETHTTPSESSIONA lpwhs;
1215     LPWININETAPPINFOA hIC = NULL;
1216
1217     TRACE("-->\n");
1218
1219
1220     if (NULL == lpwhr ||  lpwhr->hdr.htype != WH_HHTTPREQ)
1221     {
1222         INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
1223         goto lend;
1224     }
1225
1226     lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
1227
1228     hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1229     SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1230                       INTERNET_STATUS_CONNECTING_TO_SERVER,
1231                       &(lpwhs->socketAddress),
1232                        sizeof(struct sockaddr_in));
1233
1234     lpwhr->nSocketFD = socket(lpwhs->phostent->h_addrtype,SOCK_STREAM,0);
1235     if (lpwhr->nSocketFD == -1)
1236     {
1237         WARN("Socket creation failed\n");
1238         goto lend;
1239     }
1240
1241     result = connect(lpwhr->nSocketFD, (struct sockaddr *)&lpwhs->socketAddress,
1242         sizeof(lpwhs->socketAddress));
1243
1244     if (result == -1)
1245     {
1246        WARN("Unable to connect to host (%s)\n", strerror(errno));
1247        goto lend;
1248     }
1249
1250     SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1251                       INTERNET_STATUS_CONNECTED_TO_SERVER,
1252                       &(lpwhs->socketAddress),
1253                        sizeof(struct sockaddr_in));
1254
1255     bSuccess = TRUE;
1256
1257 lend:
1258     TRACE("%d <--\n", bSuccess);
1259     return bSuccess;
1260 }
1261
1262
1263 /***********************************************************************
1264  *           HTTP_GetResponseHeaders (internal)
1265  *
1266  * Read server response
1267  *
1268  * RETURNS
1269  *
1270  *   TRUE  on success
1271  *   FALSE on error
1272  */
1273 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
1274 {
1275     INT cbreaks = 0;
1276     CHAR buffer[MAX_REPLY_LEN];
1277     DWORD buflen = MAX_REPLY_LEN;
1278     BOOL bSuccess = FALSE;
1279     INT  rc = 0;
1280     CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1281
1282     TRACE("-->\n");
1283
1284     if (lpwhr->nSocketFD == -1)
1285         goto lend;
1286
1287     /*
1288      * HACK peek at the buffer
1289      */
1290     rc = recv(lpwhr->nSocketFD,buffer,buflen,MSG_PEEK);
1291
1292     /*
1293      * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1294      */
1295     buflen = MAX_REPLY_LEN;
1296     if (!INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
1297         goto lend;
1298
1299     if (strncmp(buffer, "HTTP", 4) != 0)
1300         goto lend;
1301
1302     buffer[12]='\0';
1303     HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1304
1305     /* Parse each response line */
1306     do
1307     {
1308         buflen = MAX_REPLY_LEN;
1309         if (INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
1310         {
1311             if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
1312                 break;
1313
1314             HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1315         }
1316         else
1317         {
1318             cbreaks++;
1319             if (cbreaks >= 2)
1320                break;
1321         }
1322     }while(1);
1323
1324     bSuccess = TRUE;
1325
1326 lend:
1327
1328     TRACE("<--\n");
1329     if (bSuccess)
1330         return rc;
1331     else
1332         return FALSE;
1333 }
1334
1335
1336 /***********************************************************************
1337  *           HTTP_InterpretHttpHeader (internal)
1338  *
1339  * Parse server response
1340  *
1341  * RETURNS
1342  *
1343  *   TRUE  on success
1344  *   FALSE on error
1345  */
1346 INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
1347 {
1348     LPCSTR lpsztmp;
1349     INT srclen;
1350
1351     srclen = 0;
1352
1353     while (*lpszSrc == ' ' && *lpszSrc != '\0')
1354         lpszSrc++;
1355
1356     lpsztmp = lpszSrc;
1357     while(*lpsztmp != '\0')
1358     {
1359         if (*lpsztmp != ' ')
1360             srclen = lpsztmp - lpszSrc + 1;
1361
1362         lpsztmp++;
1363     }
1364
1365     *len = min(*len, srclen);
1366     strncpy(lpszStart, lpszSrc, *len);
1367     lpszStart[*len] = '\0';
1368
1369     return *len;
1370 }
1371
1372
1373 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
1374 {
1375     CHAR *pd;
1376     BOOL bSuccess = FALSE;
1377
1378     TRACE("\n");
1379
1380     *field = '\0';
1381     *value = '\0';
1382
1383     pd = strchr(buffer, ':');
1384     if (pd)
1385     {
1386         *pd = '\0';
1387         if (stripSpaces(buffer, field, &fieldlen) > 0)
1388         {
1389             if (stripSpaces(pd+1, value, &valuelen) > 0)
1390                 bSuccess = TRUE;
1391         }
1392     }
1393
1394     TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
1395     return bSuccess;
1396 }
1397
1398
1399 /***********************************************************************
1400  *           HTTP_GetStdHeaderIndex (internal)
1401  *
1402  * Lookup field index in standard http header array
1403  *
1404  * FIXME: This should be stuffed into a hash table
1405  */
1406 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
1407 {
1408     INT index = -1;
1409
1410     if (!strcasecmp(lpszField, "Content-Length"))
1411         index = HTTP_QUERY_CONTENT_LENGTH;
1412     else if (!strcasecmp(lpszField,"Status"))
1413         index = HTTP_QUERY_STATUS_CODE;
1414     else if (!strcasecmp(lpszField,"Content-Type"))
1415         index = HTTP_QUERY_CONTENT_TYPE;
1416     else if (!strcasecmp(lpszField,"Last-Modified"))
1417         index = HTTP_QUERY_LAST_MODIFIED;
1418     else if (!strcasecmp(lpszField,"Location"))
1419         index = HTTP_QUERY_LOCATION;
1420     else if (!strcasecmp(lpszField,"Accept"))
1421         index = HTTP_QUERY_ACCEPT;
1422     else if (!strcasecmp(lpszField,"Referer"))
1423         index = HTTP_QUERY_REFERER;
1424     else if (!strcasecmp(lpszField,"Content-Transfer-Encoding"))
1425         index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
1426     else if (!strcasecmp(lpszField,"Date"))
1427         index = HTTP_QUERY_DATE;
1428     else if (!strcasecmp(lpszField,"Server"))
1429         index = HTTP_QUERY_SERVER;
1430     else if (!strcasecmp(lpszField,"Connection"))
1431         index = HTTP_QUERY_CONNECTION;
1432     else if (!strcasecmp(lpszField,"ETag"))
1433         index = HTTP_QUERY_ETAG;
1434     else if (!strcasecmp(lpszField,"Accept-Ranges"))
1435         index = HTTP_QUERY_ACCEPT_RANGES;
1436     else if (!strcasecmp(lpszField,"Expires"))
1437         index = HTTP_QUERY_EXPIRES;
1438     else if (!strcasecmp(lpszField,"Mime-Version"))
1439         index = HTTP_QUERY_MIME_VERSION;
1440     else if (!strcasecmp(lpszField,"Pragma"))
1441         index = HTTP_QUERY_PRAGMA;
1442     else if (!strcasecmp(lpszField,"Cache-Control"))
1443         index = HTTP_QUERY_CACHE_CONTROL;
1444     else if (!strcasecmp(lpszField,"Content-Length"))
1445         index = HTTP_QUERY_CONTENT_LENGTH;
1446     else if (!strcasecmp(lpszField,"User-Agent"))
1447         index = HTTP_QUERY_USER_AGENT;
1448     else
1449     {
1450        TRACE("Couldn't find %s in standard header table\n", lpszField);
1451     }
1452
1453     return index;
1454 }
1455
1456
1457 /***********************************************************************
1458  *           HTTP_ProcessHeader (internal)
1459  *
1460  * Stuff header into header tables according to <dwModifier>
1461  *
1462  */
1463
1464 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1465
1466 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
1467 {
1468     LPHTTPHEADERA lphttpHdr = NULL;
1469     BOOL bSuccess = FALSE;
1470     INT index;
1471
1472     TRACE("--> %s: %s - 0x%08x\n", field, value, (unsigned int)dwModifier);
1473
1474     /* Adjust modifier flags */
1475     if (dwModifier & COALESCEFLASG)
1476         dwModifier |= HTTP_ADDHDR_FLAG_ADD;
1477
1478     /* Try to get index into standard header array */
1479     index = HTTP_GetStdHeaderIndex(field);
1480     if (index >= 0)
1481     {
1482         lphttpHdr = &lpwhr->StdHeaders[index];
1483     }
1484     else /* Find or create new custom header */
1485     {
1486         index = HTTP_GetCustomHeaderIndex(lpwhr, field);
1487         if (index >= 0)
1488         {
1489             if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
1490             {
1491                 return FALSE;
1492             }
1493             lphttpHdr = &lpwhr->pCustHeaders[index];
1494         }
1495         else
1496         {
1497             HTTPHEADERA hdr;
1498
1499             hdr.lpszField = (LPSTR)field;
1500             hdr.lpszValue = (LPSTR)value;
1501             hdr.wFlags = hdr.wCount = 0;
1502
1503             if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1504                 hdr.wFlags |= HDR_ISREQUEST;
1505
1506             index = HTTP_InsertCustomHeader(lpwhr, &hdr);
1507             return index >= 0;
1508         }
1509     }
1510
1511     if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1512         lphttpHdr->wFlags |= HDR_ISREQUEST;
1513     else
1514         lphttpHdr->wFlags &= ~HDR_ISREQUEST;
1515
1516     if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
1517     {
1518         INT slen;
1519
1520         if (!lpwhr->StdHeaders[index].lpszField)
1521         {
1522             lphttpHdr->lpszField = HTTP_strdup(field);
1523
1524             if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1525                 lphttpHdr->wFlags |= HDR_ISREQUEST;
1526         }
1527
1528         slen = strlen(value) + 1;
1529         lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
1530         if (lphttpHdr->lpszValue)
1531         {
1532             memcpy(lphttpHdr->lpszValue, value, slen);
1533             bSuccess = TRUE;
1534         }
1535         else
1536         {
1537             INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1538         }
1539     }
1540     else if (lphttpHdr->lpszValue)
1541     {
1542         if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
1543         {
1544             LPSTR lpsztmp;
1545             INT len;
1546
1547             len = strlen(value);
1548
1549             if (len <= 0)
1550             {
1551                 /* if custom header delete from array */
1552                 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
1553                 lphttpHdr->lpszValue = NULL;
1554                 bSuccess = TRUE;
1555             }
1556             else
1557             {
1558                 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,  lphttpHdr->lpszValue, len+1);
1559                 if (lpsztmp)
1560                 {
1561                     lphttpHdr->lpszValue = lpsztmp;
1562                     strcpy(lpsztmp, value);
1563                     bSuccess = TRUE;
1564                 }
1565                 else
1566                 {
1567                     WARN("HeapReAlloc (%d bytes) failed\n",len+1);
1568                     INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1569                 }
1570             }
1571         }
1572         else if (dwModifier & COALESCEFLASG)
1573         {
1574             LPSTR lpsztmp;
1575             CHAR ch = 0;
1576             INT len = 0;
1577             INT origlen = strlen(lphttpHdr->lpszValue);
1578             INT valuelen = strlen(value);
1579
1580             if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
1581             {
1582                 ch = ',';
1583                 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1584             }
1585             else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1586             {
1587                 ch = ';';
1588                 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1589             }
1590
1591             len = origlen + valuelen + ((ch > 0) ? 1 : 0);
1592
1593             lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,  lphttpHdr->lpszValue, len+1);
1594             if (lpsztmp)
1595             {
1596                 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1597                 if (ch > 0)
1598                 {
1599                     lphttpHdr->lpszValue[origlen] = ch;
1600                     origlen++;
1601                 }
1602
1603                 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
1604                 lphttpHdr->lpszValue[len] = '\0';
1605                 bSuccess = TRUE;
1606             }
1607             else
1608             {
1609                 WARN("HeapReAlloc (%d bytes) failed\n",len+1);
1610                 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1611             }
1612         }
1613     }
1614     TRACE("<-- %d\n",bSuccess);
1615     return bSuccess;
1616 }
1617
1618
1619 /***********************************************************************
1620  *           HTTP_CloseConnection (internal)
1621  *
1622  * Close socket connection
1623  *
1624  */
1625 VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
1626 {
1627
1628
1629     LPWININETHTTPSESSIONA lpwhs = NULL;
1630     LPWININETAPPINFOA hIC = NULL;
1631
1632     TRACE("%p\n",lpwhr);
1633
1634     lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1635     hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1636
1637     SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1638                       INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
1639
1640         if (lpwhr->nSocketFD != -1)
1641         {
1642                 close(lpwhr->nSocketFD);
1643                 lpwhr->nSocketFD = -1;
1644         }
1645
1646     SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1647                       INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
1648 }
1649
1650
1651 /***********************************************************************
1652  *           HTTP_CloseHTTPRequestHandle (internal)
1653  *
1654  * Deallocate request handle
1655  *
1656  */
1657 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
1658 {
1659     int i;
1660     LPWININETHTTPSESSIONA lpwhs = NULL;
1661     LPWININETAPPINFOA hIC = NULL;
1662
1663     TRACE("\n");
1664
1665     if (lpwhr->nSocketFD != -1)
1666         HTTP_CloseConnection(lpwhr);
1667
1668     lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1669     hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1670
1671     SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1672                       INTERNET_STATUS_HANDLE_CLOSING, lpwhr,
1673                       sizeof(HINTERNET));
1674
1675     if (lpwhr->lpszPath)
1676         HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1677     if (lpwhr->lpszVerb)
1678         HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1679     if (lpwhr->lpszHostName)
1680         HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1681
1682     for (i = 0; i <= HTTP_QUERY_MAX; i++)
1683     {
1684            if (lpwhr->StdHeaders[i].lpszField)
1685             HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
1686            if (lpwhr->StdHeaders[i].lpszValue)
1687             HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
1688     }
1689
1690     for (i = 0; i < lpwhr->nCustHeaders; i++)
1691     {
1692            if (lpwhr->pCustHeaders[i].lpszField)
1693             HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
1694            if (lpwhr->pCustHeaders[i].lpszValue)
1695             HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
1696     }
1697
1698     HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1699     HeapFree(GetProcessHeap(), 0, lpwhr);
1700 }
1701
1702
1703 /***********************************************************************
1704  *           HTTP_CloseHTTPSessionHandle (internal)
1705  *
1706  * Deallocate session handle
1707  *
1708  */
1709 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
1710 {
1711     LPWININETAPPINFOA hIC = NULL;
1712     TRACE("\n");
1713
1714     hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1715
1716     SendAsyncCallback(hIC, lpwhs, lpwhs->hdr.dwContext,
1717                       INTERNET_STATUS_HANDLE_CLOSING, lpwhs,
1718                       sizeof(HINTERNET));
1719
1720     if (lpwhs->lpszServerName)
1721         HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1722     if (lpwhs->lpszUserName)
1723         HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1724     HeapFree(GetProcessHeap(), 0, lpwhs);
1725 }
1726
1727
1728 /***********************************************************************
1729  *           HTTP_GetCustomHeaderIndex (internal)
1730  *
1731  * Return index of custom header from header array
1732  *
1733  */
1734 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
1735 {
1736     INT index;
1737
1738     TRACE("%s\n", lpszField);
1739
1740     for (index = 0; index < lpwhr->nCustHeaders; index++)
1741     {
1742         if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
1743             break;
1744
1745     }
1746
1747     if (index >= lpwhr->nCustHeaders)
1748         index = -1;
1749
1750     TRACE("Return: %d\n", index);
1751     return index;
1752 }
1753
1754
1755 /***********************************************************************
1756  *           HTTP_InsertCustomHeader (internal)
1757  *
1758  * Insert header into array
1759  *
1760  */
1761 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
1762 {
1763     INT count;
1764     LPHTTPHEADERA lph = NULL;
1765
1766     TRACE("--> %s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
1767     count = lpwhr->nCustHeaders + 1;
1768     if (count > 1)
1769         lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
1770     else
1771         lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
1772
1773     if (NULL != lph)
1774     {
1775         lpwhr->pCustHeaders = lph;
1776         lpwhr->pCustHeaders[count-1].lpszField = HTTP_strdup(lpHdr->lpszField);
1777         lpwhr->pCustHeaders[count-1].lpszValue = HTTP_strdup(lpHdr->lpszValue);
1778         lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
1779         lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
1780         lpwhr->nCustHeaders++;
1781     }
1782     else
1783     {
1784         INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1785         count = 0;
1786     }
1787
1788     TRACE("%d <--\n", count-1);
1789     return count - 1;
1790 }
1791
1792
1793 /***********************************************************************
1794  *           HTTP_DeleteCustomHeader (internal)
1795  *
1796  * Delete header from array
1797  *
1798  */
1799 BOOL HTTP_DeleteCustomHeader(INT index)
1800 {
1801     FIXME("STUB\n");
1802     return FALSE;
1803 }
1804
1805 /***********************************************************************
1806  *          IsHostInProxyBypassList (@)
1807  *
1808  * Undocumented
1809  *
1810  */
1811 BOOL WINAPI IsHostInProxyBypassList(DWORD flags, LPCSTR szHost, DWORD length)
1812 {
1813    FIXME("STUB: flags=%ld host=%s length=%ld\n",flags,szHost,length);
1814    return FALSE;
1815 }