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