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