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