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