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