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