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