Some borken memory monitoring programs divide by dwTotalPageFile,
[wine/testsucceed.git] / dlls / wininet / http.c
blob784912a6233ef1b2f13e14df65a15a7bda9d9831
1 /*
2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
6 * Ulrich Czekalla
8 */
10 #include "config.h"
12 #include "windef.h"
13 #include "winbase.h"
14 #include "wininet.h"
15 #include "debugtools.h"
16 #include "winerror.h"
17 #include "winsock.h"
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>
31 #include "internet.h"
33 DEFAULT_DEBUG_CHANNEL(wininet);
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
42 #define HTTP_REFERER "Referer"
43 #define HTTP_ACCEPT "Accept"
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
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);
67 inline static LPSTR HTTP_strdup( LPCSTR str )
69 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
70 if (ret) strcpy( ret, str );
71 return ret;
74 /***********************************************************************
75 * HttpAddRequestHeadersA (WININET.68)
77 * Adds one or more HTTP header to the request handler
79 * RETURNS
80 * TRUE on success
81 * FALSE on failure
84 INTERNETAPI BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
85 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
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;
94 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
96 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
97 return FALSE;
100 buffer = HTTP_strdup(lpszHeader);
101 lpszStart = buffer;
105 lpszEnd = lpszStart;
107 while (*lpszEnd != '\0')
109 if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
110 break;
111 lpszEnd++;
114 if (*lpszEnd == '\0')
115 break;
117 *lpszEnd = '\0';
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);
122 lpszStart = lpszEnd + 2; /* Jump over \0\n */
124 } while (bSuccess);
126 HeapFree(GetProcessHeap(), 0, buffer);
127 return bSuccess;
131 /***********************************************************************
132 * HttpOpenRequestA (WININET.72)
134 * Open a HTTP request handle
136 * RETURNS
137 * HINTERNET a HTTP request handle on success
138 * NULL on failure
141 INTERNETAPI HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
142 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
143 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
144 DWORD dwFlags, DWORD dwContext)
146 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
147 LPWININETAPPINFOA hIC = NULL;
149 TRACE("\n");
151 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
153 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
154 return FALSE;
157 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
159 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
161 WORKREQUEST workRequest;
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;
173 return (HINTERNET)INTERNET_AsyncCall(&workRequest);
175 else
177 return HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName,
178 lpszVersion, lpszReferrer, lpszAcceptTypes, dwFlags, dwContext);
183 /***********************************************************************
184 * HTTP_HttpOpenRequestA (internal)
186 * Open a HTTP request handle
188 * RETURNS
189 * HINTERNET a HTTP request handle on success
190 * NULL on failure
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)
198 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
199 LPWININETAPPINFOA hIC = NULL;
200 LPWININETHTTPREQA lpwhr;
202 TRACE("\n");
204 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
206 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
207 return FALSE;
210 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
212 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
213 if (NULL == lpwhr)
215 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
216 return (HINTERNET) NULL;
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;
225 if (NULL != lpszObjectName && strlen(lpszObjectName))
226 lpwhr->lpszPath = HTTP_strdup(lpszObjectName);
228 if (NULL != lpszReferrer && strlen(lpszReferrer))
229 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
231 //! FIXME
232 if (NULL != lpszAcceptTypes && strlen(*lpszAcceptTypes))
233 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, *lpszAcceptTypes, HTTP_ADDHDR_FLAG_COALESCE);
235 if (NULL == lpszVerb)
236 lpwhr->lpszVerb = HTTP_strdup("GET");
237 else if (strlen(lpszVerb))
238 lpwhr->lpszVerb = HTTP_strdup(lpszVerb);
240 if (NULL != lpszReferrer)
242 char buf[MAXHOSTNAME];
243 URL_COMPONENTSA UrlComponents;
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;
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);
260 if (hIC->lpfnStatusCB)
262 INTERNET_ASYNC_RESULT iar;
264 iar.dwResult = (DWORD)lpwhr;
265 iar.dwError = ERROR_SUCCESS;
267 hIC->lpfnStatusCB(hHttpSession, dwContext, INTERNET_STATUS_HANDLE_CREATED,
268 &iar, sizeof(INTERNET_ASYNC_RESULT));
271 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
273 INTERNET_ASYNC_RESULT iar;
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));
281 return (HINTERNET) lpwhr;
285 /***********************************************************************
286 * HttpQueryInfoA (WININET.74)
288 * Queries for information about an HTTP request
290 * RETURNS
291 * TRUE on success
292 * FALSE on failure
295 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
296 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
298 LPHTTPHEADERA lphttpHdr = NULL;
299 BOOL bSuccess = FALSE;
300 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
302 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel, dwInfoLevel);
304 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
306 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
307 return FALSE;
310 /* Find requested header structure */
311 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
313 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
315 if (index < 0)
316 goto lend;
318 lphttpHdr = &lpwhr->pCustHeaders[index];
320 else
322 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
324 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
326 INT i, delim, size = 0, cnt = 0;
328 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
330 /* Calculate length of custom reuqest headers */
331 for (i = 0; i < lpwhr->nCustHeaders; i++)
333 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
334 lpwhr->pCustHeaders[i].lpszValue)
336 size += strlen(lpwhr->pCustHeaders[i].lpszField) +
337 strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
341 /* Calculate the length of stadard request headers */
342 for (i = 0; i <= HTTP_QUERY_MAX; i++)
344 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
345 lpwhr->StdHeaders[i].lpszValue)
347 size += strlen(lpwhr->StdHeaders[i].lpszField) +
348 strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
352 size += delim;
354 if (size + 1 > *lpdwBufferLength)
356 *lpdwBufferLength = size + 1;
357 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
358 goto lend;
361 /* Append standard request heades */
362 for (i = 0; i <= HTTP_QUERY_MAX; i++)
364 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
365 lpwhr->StdHeaders[i].lpszField &&
366 lpwhr->StdHeaders[i].lpszValue)
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");
373 /* Append custom request heades */
374 for (i = 0; i < lpwhr->nCustHeaders; i++)
376 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
377 lpwhr->pCustHeaders[i].lpszField &&
378 lpwhr->pCustHeaders[i].lpszValue)
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");
386 strcpy(lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
388 *lpdwBufferLength = cnt + delim;
389 bSuccess = TRUE;
390 goto lend;
392 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
394 lphttpHdr = &lpwhr->StdHeaders[index];
396 else
397 goto lend;
400 /* Ensure header satisifies requested attributes */
401 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
402 (~lphttpHdr->wFlags & HDR_ISREQUEST))
403 goto lend;
405 /* coalesce value to reuqested type */
406 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
408 *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
409 bSuccess = TRUE;
411 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
413 time_t tmpTime;
414 struct tm tmpTM;
415 SYSTEMTIME *STHook;
417 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
419 tmpTM = *gmtime(&tmpTime);
420 STHook = (SYSTEMTIME *) lpBuffer;
421 if(STHook==NULL)
422 goto lend;
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;
433 bSuccess = TRUE;
435 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
437 if (*lpdwIndex >= lphttpHdr->wCount)
439 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
441 else
443 //! Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len);
444 (*lpdwIndex)++;
447 else
449 INT len = strlen(lphttpHdr->lpszValue);
451 if (len + 1 > *lpdwBufferLength)
453 *lpdwBufferLength = len + 1;
454 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
455 goto lend;
458 strncpy(lpBuffer, lphttpHdr->lpszValue, len);
459 *lpdwBufferLength = len;
460 bSuccess = TRUE;
463 lend:
464 TRACE("%d <--\n", bSuccess);
465 return bSuccess;
469 /***********************************************************************
470 * HttpSendRequestExA (WININET)
472 * Sends the specified request to the HTTP server and allows chunked
473 * transfers
475 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
476 LPINTERNET_BUFFERSA lpBuffersIn,
477 LPINTERNET_BUFFERSA lpBuffersOut,
478 DWORD dwFlags, DWORD dwContext)
480 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
481 lpBuffersOut, dwFlags, dwContext);
482 return FALSE;
485 /***********************************************************************
486 * HttpSendRequestA (WININET.76)
488 * Sends the specified request to the HTTP server
490 * RETURNS
491 * TRUE on success
492 * FALSE on failure
495 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
496 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
498 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
499 LPWININETHTTPSESSIONA lpwhs = NULL;
500 LPWININETAPPINFOA hIC = NULL;
502 TRACE("0x%08lx\n", (unsigned long)hHttpRequest);
504 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
506 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
507 return FALSE;
510 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
511 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
513 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
514 return FALSE;
517 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
518 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
520 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
521 return FALSE;
524 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
526 WORKREQUEST workRequest;
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;
535 return INTERNET_AsyncCall(&workRequest);
537 else
539 return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
540 dwHeaderLength, lpOptional, dwOptionalLength);
545 /***********************************************************************
546 * HTTP_HttpSendRequestA (internal)
548 * Sends the specified request to the HTTP server
550 * RETURNS
551 * TRUE on success
552 * FALSE on failure
555 BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
556 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
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;
568 TRACE("0x%08lx\n", (ULONG)hHttpRequest);
570 /* Verify our tree of internet handles */
571 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
573 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
574 return FALSE;
577 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
578 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
580 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
581 return FALSE;
584 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
585 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
587 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
588 return FALSE;
591 /* Clear any error information */
592 INTERNET_SetLastError(0);
594 /* We must have a verb */
595 if (NULL == lpwhr->lpszVerb)
597 goto lend;
600 /* If we don't have a path we set it to root */
601 if (NULL == lpwhr->lpszPath)
602 lpwhr->lpszPath = HTTP_strdup("/");
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" */
612 /* Add length of passed headers */
613 if (lpszHeaders)
615 headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength;
616 requestStringLen += headerLength + 2; /* \r\n */
619 /* Calculate length of custom request headers */
620 for (i = 0; i < lpwhr->nCustHeaders; i++)
622 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
624 requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
625 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
629 /* Calculate the length of standard request headers */
630 for (i = 0; i <= HTTP_QUERY_MAX; i++)
632 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
634 requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
635 strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
639 /* Allocate string to hold entire request */
640 requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
641 if (NULL == requestString)
643 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
644 goto lend;
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 : "");
654 /* Append standard request headers */
655 for (i = 0; i <= HTTP_QUERY_MAX; i++)
657 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
659 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
660 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
664 /* Append custom request heades */
665 for (i = 0; i < lpwhr->nCustHeaders; i++)
667 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
669 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
670 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
674 /* Append passed request headers */
675 if (lpszHeaders)
677 strcpy(requestString + cnt, "\r\n");
678 cnt += 2;
679 strcpy(requestString + cnt, lpszHeaders);
680 cnt += headerLength;
683 /* Set termination string for request */
684 strcpy(requestString + cnt, "\r\n\r\n");
686 if (hIC->lpfnStatusCB)
687 hIC->lpfnStatusCB(hHttpRequest, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
689 TRACE("(%s) len(%d)\n", requestString, requestStringLen);
690 /* Send the request and store the results */
691 if (!HTTP_OpenConnection(lpwhr))
692 goto lend;
694 cnt = INTERNET_WriteDataToStream(lpwhr->nSocketFD, requestString, requestStringLen);
696 if (cnt < 0)
697 goto lend;
699 if (HTTP_GetResponseHeaders(lpwhr))
700 bSuccess = TRUE;
702 lend:
704 if (requestString)
705 HeapFree(GetProcessHeap(), 0, requestString);
707 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
709 INTERNET_ASYNC_RESULT iar;
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));
717 TRACE("<--\n");
718 return bSuccess;
722 /***********************************************************************
723 * HTTP_Connect (internal)
725 * Create http session handle
727 * RETURNS
728 * HINTERNET a session handle on success
729 * NULL on failure
732 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
733 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
734 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
736 BOOL bSuccess = FALSE;
737 LPWININETAPPINFOA hIC = NULL;
738 LPWININETHTTPSESSIONA lpwhs = NULL;
740 TRACE("\n");
742 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
743 goto lerror;
745 hIC = (LPWININETAPPINFOA) hInternet;
747 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
748 if (NULL == lpwhs)
750 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
751 goto lerror;
754 if (hIC->lpfnStatusCB)
755 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
756 (LPVOID)lpszServerName, strlen(lpszServerName));
758 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
759 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
761 if (!GetAddress(lpszServerName, nServerPort, &lpwhs->phostent, &lpwhs->socketAddress))
763 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
764 goto lerror;
767 if (hIC->lpfnStatusCB)
768 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
769 (LPVOID)lpszServerName, strlen(lpszServerName));
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;
781 if (hIC->lpfnStatusCB)
783 INTERNET_ASYNC_RESULT iar;
785 iar.dwResult = (DWORD)lpwhs;
786 iar.dwError = ERROR_SUCCESS;
788 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
789 &iar, sizeof(INTERNET_ASYNC_RESULT));
792 bSuccess = TRUE;
794 lerror:
795 if (!bSuccess && lpwhs)
797 HeapFree(GetProcessHeap(), 0, lpwhs);
798 lpwhs = NULL;
801 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
803 INTERNET_ASYNC_RESULT iar;
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));
810 TRACE("<--\n");
811 return (HINTERNET)lpwhs;
815 /***********************************************************************
816 * HTTP_OpenConnection (internal)
818 * Connect to a web server
820 * RETURNS
822 * TRUE on success
823 * FALSE on failure
825 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
827 BOOL bSuccess = FALSE;
828 INT result;
829 LPWININETHTTPSESSIONA lpwhs;
831 TRACE("\n");
833 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
835 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
836 goto lend;
839 lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
841 lpwhr->nSocketFD = socket(lpwhs->phostent->h_addrtype,SOCK_STREAM,0);
842 if (INVALID_SOCKET == lpwhr->nSocketFD)
844 WARN("Socket creation failed\n");
845 goto lend;
848 result = connect(lpwhr->nSocketFD, (struct sockaddr *)&lpwhs->socketAddress,
849 sizeof(lpwhs->socketAddress));
851 if (SOCKET_ERROR == result)
853 WARN("Unable to connect to host (%s)\n", strerror(errno));
854 goto lend;
857 bSuccess = TRUE;
859 lend:
860 TRACE(": %d\n", bSuccess);
861 return bSuccess;
865 /***********************************************************************
866 * HTTP_GetResponseHeaders (internal)
868 * Read server response
870 * RETURNS
872 * TRUE on success
873 * FALSE on error
875 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
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];
883 TRACE("\n");
885 if (INVALID_SOCKET == lpwhr->nSocketFD)
886 goto lend;
889 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
891 if (!INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
892 goto lend;
894 if (strncmp(buffer, "HTTP", 4) != 0)
895 goto lend;
897 buffer[12]='\0';
898 HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
900 /* Parse each response line */
903 buflen = MAX_REPLY_LEN;
904 if (INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
906 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
907 break;
909 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
911 else
913 cbreaks++;
914 if (cbreaks >= 2)
915 break;
917 }while(1);
919 bSuccess = TRUE;
921 lend:
923 return bSuccess;
927 /***********************************************************************
928 * HTTP_InterpretHttpHeader (internal)
930 * Parse server response
932 * RETURNS
934 * TRUE on success
935 * FALSE on error
937 INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
939 LPCSTR lpsztmp;
940 INT srclen;
942 srclen = 0;
944 while (*lpszSrc == ' ' && *lpszSrc != '\0')
945 lpszSrc++;
947 lpsztmp = lpszSrc;
948 while(*lpsztmp != '\0')
950 if (*lpsztmp != ' ')
951 srclen = lpsztmp - lpszSrc + 1;
953 lpsztmp++;
956 *len = min(*len, srclen);
957 strncpy(lpszStart, lpszSrc, *len);
958 lpszStart[*len] = '\0';
960 return *len;
964 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
966 CHAR *pd;
967 BOOL bSuccess = FALSE;
969 TRACE("\n");
971 *field = '\0';
972 *value = '\0';
974 pd = strchr(buffer, ':');
975 if (pd)
977 *pd = '\0';
978 if (stripSpaces(buffer, field, &fieldlen) > 0)
980 if (stripSpaces(pd+1, value, &valuelen) > 0)
981 bSuccess = TRUE;
985 TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
986 return bSuccess;
990 /***********************************************************************
991 * HTTP_GetStdHeaderIndex (internal)
993 * Lookup field index in standard http header array
995 * FIXME: This should be stuffed into a hash table
997 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
999 INT index = -1;
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
1033 FIXME("Couldn't find %s in standard header table\n", lpszField);
1036 return index;
1040 /***********************************************************************
1041 * HTTP_ProcessHeader (internal)
1043 * Stuff header into header tables according to <dwModifier>
1047 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1049 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
1051 LPHTTPHEADERA lphttpHdr = NULL;
1052 BOOL bSuccess = FALSE;
1053 INT index;
1055 TRACE("%s:%s - 0x%08x\n", field, value, (unsigned int)dwModifier);
1057 /* Adjust modifier flags */
1058 if (dwModifier & COALESCEFLASG)
1059 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
1061 /* Try to get index into standard header array */
1062 index = HTTP_GetStdHeaderIndex(field);
1063 if (index >= 0)
1065 lphttpHdr = &lpwhr->StdHeaders[index];
1067 else /* Find or create new custom header */
1069 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
1070 if (index >= 0)
1072 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
1074 return FALSE;
1076 lphttpHdr = &lpwhr->pCustHeaders[index];
1078 else
1080 HTTPHEADERA hdr;
1082 hdr.lpszField = (LPSTR)field;
1083 hdr.lpszValue = (LPSTR)value;
1084 hdr.wFlags = hdr.wCount = 0;
1086 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1087 hdr.wFlags |= HDR_ISREQUEST;
1089 index = HTTP_InsertCustomHeader(lpwhr, &hdr);
1090 return index >= 0;
1094 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1095 lphttpHdr->wFlags |= HDR_ISREQUEST;
1096 else
1097 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
1099 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
1101 INT slen;
1103 if (!lpwhr->StdHeaders[index].lpszField)
1105 lphttpHdr->lpszField = HTTP_strdup(field);
1107 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1108 lphttpHdr->wFlags |= HDR_ISREQUEST;
1111 slen = strlen(value) + 1;
1112 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
1113 if (lphttpHdr->lpszValue)
1115 memcpy(lphttpHdr->lpszValue, value, slen);
1116 bSuccess = TRUE;
1118 else
1120 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1123 else if (lphttpHdr->lpszValue)
1125 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
1127 LPSTR lpsztmp;
1128 INT len;
1130 len = strlen(value);
1132 if (len <= 0)
1134 //! if custom header delete from array
1135 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
1136 lphttpHdr->lpszValue = NULL;
1137 bSuccess = TRUE;
1139 else
1141 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1142 if (lpsztmp)
1144 lphttpHdr->lpszValue = lpsztmp;
1145 strcpy(lpsztmp, value);
1146 bSuccess = TRUE;
1148 else
1150 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1154 else if (dwModifier & COALESCEFLASG)
1156 LPSTR lpsztmp;
1157 CHAR ch = 0;
1158 INT len = 0;
1159 INT origlen = strlen(lphttpHdr->lpszValue);
1160 INT valuelen = strlen(value);
1162 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
1164 ch = ',';
1165 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1167 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1169 ch = ';';
1170 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1173 len = origlen + valuelen + (ch > 0) ? 1 : 0;
1175 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1176 if (lpsztmp)
1178 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1179 if (ch > 0)
1181 lphttpHdr->lpszValue[origlen] = ch;
1182 origlen++;
1185 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
1186 lphttpHdr->lpszValue[len] = '\0';
1187 bSuccess = TRUE;
1189 else
1191 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1196 return bSuccess;
1200 /***********************************************************************
1201 * HTTP_CloseConnection (internal)
1203 * Close socket connection
1206 VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
1208 if (lpwhr->nSocketFD != INVALID_SOCKET)
1210 close(lpwhr->nSocketFD);
1211 lpwhr->nSocketFD = INVALID_SOCKET;
1216 /***********************************************************************
1217 * HTTP_CloseHTTPRequestHandle (internal)
1219 * Deallocate request handle
1222 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
1224 int i;
1226 TRACE("\n");
1228 if (lpwhr->nSocketFD != INVALID_SOCKET)
1229 HTTP_CloseConnection(lpwhr);
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);
1238 for (i = 0; i <= HTTP_QUERY_MAX; i++)
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);
1246 for (i = 0; i < lpwhr->nCustHeaders; i++)
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);
1254 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1255 HeapFree(GetProcessHeap(), 0, lpwhr);
1259 /***********************************************************************
1260 * HTTP_CloseHTTPSessionHandle (internal)
1262 * Deallocate session handle
1265 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
1267 TRACE("\n");
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);
1277 /***********************************************************************
1278 * HTTP_GetCustomHeaderIndex (internal)
1280 * Return index of custom header from header array
1283 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
1285 INT index;
1287 TRACE("%s\n", lpszField);
1289 for (index = 0; index < lpwhr->nCustHeaders; index++)
1291 if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
1292 break;
1296 if (index >= lpwhr->nCustHeaders)
1297 index = -1;
1299 TRACE("Return: %d\n", index);
1300 return index;
1304 /***********************************************************************
1305 * HTTP_InsertCustomHeader (internal)
1307 * Insert header into array
1310 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
1312 INT count;
1313 LPHTTPHEADERA lph = NULL;
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);
1322 if (NULL != lph)
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++;
1331 else
1333 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1334 count = 0;
1337 TRACE("%d <--\n", count-1);
1338 return count - 1;
1342 /***********************************************************************
1343 * HTTP_DeleteCustomHeader (internal)
1345 * Delete header from array
1348 BOOL HTTP_DeleteCustomHeader(INT index)
1350 TRACE("\n");
1351 return FALSE;