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