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