2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
5 * Copyright 2002 CodeWeavers Inc.
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
28 #ifdef HAVE_SYS_SOCKET_H
29 # include <sys/socket.h>
45 #define NO_SHLWAPI_STREAM
49 #include "wine/debug.h"
51 WINE_DEFAULT_DEBUG_CHANNEL(wininet);
53 #define HTTPHEADER " HTTP/1.0"
54 #define HTTPHOSTHEADER "\r\nHost: "
55 #define MAXHOSTNAME 100
56 #define MAX_FIELD_VALUE_LEN 256
57 #define MAX_FIELD_LEN 256
60 #define HTTP_REFERER "Referer"
61 #define HTTP_ACCEPT "Accept"
63 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
64 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
65 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
66 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
67 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
68 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
69 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
72 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr);
73 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr,
74 void *Buffer, int BytesToWrite);
75 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr,
76 void *Buffer, int BytesToRead);
77 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr);
78 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier);
79 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr);
80 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen);
81 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField);
82 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr);
83 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField);
85 inline static LPSTR HTTP_strdup( LPCSTR str )
87 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
88 if (ret) strcpy( ret, str );
92 /***********************************************************************
93 * HttpAddRequestHeadersA (WININET.@)
95 * Adds one or more HTTP header to the request handler
102 BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
103 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
108 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
109 BOOL bSuccess = FALSE;
110 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
114 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
116 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
120 buffer = HTTP_strdup(lpszHeader);
127 while (*lpszEnd != '\0')
129 if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
134 if (*lpszEnd == '\0')
139 if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
140 bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
142 lpszStart = lpszEnd + 2; /* Jump over \0\n */
146 HeapFree(GetProcessHeap(), 0, buffer);
150 /***********************************************************************
151 * HttpEndRequestA (WININET.@)
153 * Ends an HTTP request that was started by HttpSendRequestEx
160 BOOL WINAPI HttpEndRequestA(HINTERNET hRequest, LPINTERNET_BUFFERSA lpBuffersOut,
161 DWORD dwFlags, DWORD dwContext)
167 /***********************************************************************
168 * HttpEndRequestW (WININET.@)
170 * Ends an HTTP request that was started by HttpSendRequestEx
177 BOOL WINAPI HttpEndRequestW(HINTERNET hRequest, LPINTERNET_BUFFERSW lpBuffersOut,
178 DWORD dwFlags, DWORD dwContext)
184 /***********************************************************************
185 * HttpOpenRequestA (WININET.@)
187 * Open a HTTP request handle
190 * HINTERNET a HTTP request handle on success
194 HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
195 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
196 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
197 DWORD dwFlags, DWORD dwContext)
199 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
200 LPWININETAPPINFOA hIC = NULL;
204 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
206 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
209 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
212 * My tests seem to show that the windows version does not
213 * become asynchronous until after this point. And anyhow
214 * if this call was asynchronous then how would you get the
215 * necessary HINTERNET pointer returned by this function.
217 * I am leaving this here just in case I am wrong
219 * if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
223 WORKREQUEST workRequest;
225 workRequest.asyncall = HTTPOPENREQUESTA;
226 workRequest.HFTPSESSION = (DWORD)hHttpSession;
227 workRequest.LPSZVERB = (DWORD)HTTP_strdup(lpszVerb);
228 workRequest.LPSZOBJECTNAME = (DWORD)HTTP_strdup(lpszObjectName);
230 workRequest.LPSZVERSION = (DWORD)HTTP_strdup(lpszVersion);
232 workRequest.LPSZVERSION = 0;
234 workRequest.LPSZREFERRER = (DWORD)HTTP_strdup(lpszReferrer);
236 workRequest.LPSZREFERRER = 0;
237 workRequest.LPSZACCEPTTYPES = (DWORD)lpszAcceptTypes;
238 workRequest.DWFLAGS = dwFlags;
239 workRequest.DWCONTEXT = dwContext;
241 INTERNET_AsyncCall(&workRequest);
246 return HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName,
247 lpszVersion, lpszReferrer, lpszAcceptTypes, dwFlags, dwContext);
252 /***********************************************************************
253 * HTTP_HttpOpenRequestA (internal)
255 * Open a HTTP request handle
258 * HINTERNET a HTTP request handle on success
262 HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
263 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
264 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
265 DWORD dwFlags, DWORD dwContext)
267 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
268 LPWININETAPPINFOA hIC = NULL;
269 LPWININETHTTPREQA lpwhr;
273 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
275 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
279 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
281 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
284 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
285 return (HINTERNET) NULL;
288 lpwhr->hdr.htype = WH_HHTTPREQ;
289 lpwhr->hdr.lpwhparent = hHttpSession;
290 lpwhr->hdr.dwFlags = dwFlags;
291 lpwhr->hdr.dwContext = dwContext;
292 lpwhr->nSocketFD = -1;
294 if (NULL != lpszObjectName && strlen(lpszObjectName)) {
297 rc = UrlEscapeA(lpszObjectName, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
299 needed = strlen(lpszObjectName)+1;
300 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
301 rc = UrlEscapeA(lpszObjectName, lpwhr->lpszPath, &needed,
302 URL_ESCAPE_SPACES_ONLY);
305 ERR("Unable to escape string!(%s) (%ld)\n",lpszObjectName,rc);
306 strcpy(lpwhr->lpszPath,lpszObjectName);
310 if (NULL != lpszReferrer && strlen(lpszReferrer))
311 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
314 if (NULL != lpszAcceptTypes && strlen(*lpszAcceptTypes))
315 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, *lpszAcceptTypes, HTTP_ADDHDR_FLAG_COALESCE);
317 if (NULL == lpszVerb)
318 lpwhr->lpszVerb = HTTP_strdup("GET");
319 else if (strlen(lpszVerb))
320 lpwhr->lpszVerb = HTTP_strdup(lpszVerb);
322 if (NULL != lpszReferrer)
324 char buf[MAXHOSTNAME];
325 URL_COMPONENTSA UrlComponents;
327 UrlComponents.lpszExtraInfo = NULL;
328 UrlComponents.lpszPassword = NULL;
329 UrlComponents.lpszScheme = NULL;
330 UrlComponents.lpszUrlPath = NULL;
331 UrlComponents.lpszUserName = NULL;
332 UrlComponents.lpszHostName = buf;
333 UrlComponents.dwHostNameLength = MAXHOSTNAME;
335 InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
336 if (strlen(UrlComponents.lpszHostName))
337 lpwhr->lpszHostName = HTTP_strdup(UrlComponents.lpszHostName);
339 lpwhr->lpszHostName = HTTP_strdup(lpwhs->lpszServerName);
342 if (hIC->lpfnStatusCB)
344 INTERNET_ASYNC_RESULT iar;
346 iar.dwResult = (DWORD)lpwhr;
347 iar.dwError = ERROR_SUCCESS;
349 SendAsyncCallback(hIC, hHttpSession, dwContext,
350 INTERNET_STATUS_HANDLE_CREATED, &iar,
351 sizeof(INTERNET_ASYNC_RESULT));
355 * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
359 * According to my tests. The name is not resolved until a request is Opened
361 SendAsyncCallback(hIC, hHttpSession, dwContext,
362 INTERNET_STATUS_RESOLVING_NAME,
363 lpwhs->lpszServerName,
364 strlen(lpwhs->lpszServerName)+1);
366 if (!GetAddress(lpwhs->lpszServerName, lpwhs->nServerPort,
367 &lpwhs->phostent, &lpwhs->socketAddress))
369 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
373 SendAsyncCallback(hIC, hHttpSession, lpwhr->hdr.dwContext,
374 INTERNET_STATUS_NAME_RESOLVED,
375 &(lpwhs->socketAddress),
376 sizeof(struct sockaddr_in));
379 return (HINTERNET) lpwhr;
383 /***********************************************************************
384 * HttpQueryInfoA (WININET.@)
386 * Queries for information about an HTTP request
393 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
394 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
396 LPHTTPHEADERA lphttpHdr = NULL;
397 BOOL bSuccess = FALSE;
398 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
400 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel, dwInfoLevel);
402 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
404 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
408 /* Find requested header structure */
409 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
411 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
416 lphttpHdr = &lpwhr->pCustHeaders[index];
420 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
422 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
424 INT i, delim, size = 0, cnt = 0;
426 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
428 /* Calculate length of custom reuqest headers */
429 for (i = 0; i < lpwhr->nCustHeaders; i++)
431 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
432 lpwhr->pCustHeaders[i].lpszValue)
434 size += strlen(lpwhr->pCustHeaders[i].lpszField) +
435 strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
439 /* Calculate the length of stadard request headers */
440 for (i = 0; i <= HTTP_QUERY_MAX; i++)
442 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
443 lpwhr->StdHeaders[i].lpszValue)
445 size += strlen(lpwhr->StdHeaders[i].lpszField) +
446 strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
451 if (size + 1 > *lpdwBufferLength)
453 *lpdwBufferLength = size + 1;
454 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
458 /* Append standard request heades */
459 for (i = 0; i <= HTTP_QUERY_MAX; i++)
461 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
462 lpwhr->StdHeaders[i].lpszField &&
463 lpwhr->StdHeaders[i].lpszValue)
465 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
466 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
470 /* Append custom request heades */
471 for (i = 0; i < lpwhr->nCustHeaders; i++)
473 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
474 lpwhr->pCustHeaders[i].lpszField &&
475 lpwhr->pCustHeaders[i].lpszValue)
477 cnt += sprintf((char*)lpBuffer + cnt, "%s: %s%s",
478 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
479 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
483 strcpy((char*)lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
485 *lpdwBufferLength = cnt + delim;
489 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
491 lphttpHdr = &lpwhr->StdHeaders[index];
497 /* Ensure header satisifies requested attributes */
498 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
499 (~lphttpHdr->wFlags & HDR_ISREQUEST))
502 /* coalesce value to reuqested type */
503 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
505 *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
508 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
514 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
516 tmpTM = *gmtime(&tmpTime);
517 STHook = (SYSTEMTIME *) lpBuffer;
521 STHook->wDay = tmpTM.tm_mday;
522 STHook->wHour = tmpTM.tm_hour;
523 STHook->wMilliseconds = 0;
524 STHook->wMinute = tmpTM.tm_min;
525 STHook->wDayOfWeek = tmpTM.tm_wday;
526 STHook->wMonth = tmpTM.tm_mon + 1;
527 STHook->wSecond = tmpTM.tm_sec;
528 STHook->wYear = tmpTM.tm_year;
532 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
534 if (*lpdwIndex >= lphttpHdr->wCount)
536 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
540 /* Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len); */
546 INT len = strlen(lphttpHdr->lpszValue);
548 if (len + 1 > *lpdwBufferLength)
550 *lpdwBufferLength = len + 1;
551 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
555 strncpy(lpBuffer, lphttpHdr->lpszValue, len);
556 ((char*)lpBuffer)[len]=0;
557 *lpdwBufferLength = len;
562 TRACE("%d <--\n", bSuccess);
567 /***********************************************************************
568 * HttpSendRequestExA (WININET.@)
570 * Sends the specified request to the HTTP server and allows chunked
573 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
574 LPINTERNET_BUFFERSA lpBuffersIn,
575 LPINTERNET_BUFFERSA lpBuffersOut,
576 DWORD dwFlags, DWORD dwContext)
578 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
579 lpBuffersOut, dwFlags, dwContext);
583 /***********************************************************************
584 * HttpSendRequestA (WININET.@)
586 * Sends the specified request to the HTTP server
593 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
594 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
596 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
597 LPWININETHTTPSESSIONA lpwhs = NULL;
598 LPWININETAPPINFOA hIC = NULL;
600 TRACE("0x%08lx\n", (unsigned long)hHttpRequest);
602 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
604 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
608 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
609 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
611 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
615 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
616 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
618 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
622 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
624 WORKREQUEST workRequest;
626 workRequest.asyncall = HTTPSENDREQUESTA;
627 workRequest.HFTPSESSION = (DWORD)hHttpRequest;
629 workRequest.LPSZHEADER = (DWORD)HTTP_strdup(lpszHeaders);
631 workRequest.LPSZHEADER = 0;
632 workRequest.DWHEADERLENGTH = dwHeaderLength;
633 workRequest.LPOPTIONAL = (DWORD)lpOptional;
634 workRequest.DWOPTIONALLENGTH = dwOptionalLength;
636 INTERNET_AsyncCall(&workRequest);
638 * This is from windows. I do not know what the name is
645 return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
646 dwHeaderLength, lpOptional, dwOptionalLength);
651 /***********************************************************************
652 * HTTP_HttpSendRequestA (internal)
654 * Sends the specified request to the HTTP server
661 BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
662 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
666 BOOL bSuccess = FALSE;
667 LPSTR requestString = NULL;
668 INT requestStringLen;
670 INT headerLength = 0;
671 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
672 LPWININETHTTPSESSIONA lpwhs = NULL;
673 LPWININETAPPINFOA hIC = NULL;
675 TRACE("--> 0x%08lx\n", (ULONG)hHttpRequest);
677 /* Verify our tree of internet handles */
678 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
680 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
684 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
685 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
687 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
691 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
692 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
694 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
698 /* Clear any error information */
699 INTERNET_SetLastError(0);
702 /* We must have a verb */
703 if (NULL == lpwhr->lpszVerb)
708 /* If we don't have a path we set it to root */
709 if (NULL == lpwhr->lpszPath)
710 lpwhr->lpszPath = HTTP_strdup("/");
712 if(lpwhr->lpszPath[0] != '/') /* not an absolute path ?? --> fix it !! */
714 char *fixurl = HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr->lpszPath) + 2);
716 strcpy(fixurl + 1, lpwhr->lpszPath);
717 HeapFree( GetProcessHeap(), 0, lpwhr->lpszPath );
718 lpwhr->lpszPath = fixurl;
721 /* Calculate length of request string */
723 strlen(lpwhr->lpszVerb) +
724 strlen(lpwhr->lpszPath) +
725 (lpwhr->lpszHostName ? (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName)) : 0) +
729 /* Add length of passed headers */
732 headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength;
733 requestStringLen += headerLength + 2; /* \r\n */
736 /* Calculate length of custom request headers */
737 for (i = 0; i < lpwhr->nCustHeaders; i++)
739 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
741 requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
742 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
746 /* Calculate the length of standard request headers */
747 for (i = 0; i <= HTTP_QUERY_MAX; i++)
749 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
751 requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
752 strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
756 /* Allocate string to hold entire request */
757 requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
758 if (NULL == requestString)
760 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
764 /* Build request string */
765 cnt = sprintf(requestString, "%s %s%s%s",
768 lpwhr->lpszHostName ? (HTTPHEADER HTTPHOSTHEADER) : HTTPHEADER,
769 lpwhr->lpszHostName ? lpwhr->lpszHostName : "");
771 /* Append standard request headers */
772 for (i = 0; i <= HTTP_QUERY_MAX; i++)
774 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
776 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
777 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
781 /* Append custom request heades */
782 for (i = 0; i < lpwhr->nCustHeaders; i++)
784 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
786 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
787 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
791 /* Append passed request headers */
794 strcpy(requestString + cnt, "\r\n");
796 strcpy(requestString + cnt, lpszHeaders);
800 /* Set termination string for request */
801 strcpy(requestString + cnt, "\r\n\r\n");
803 TRACE("(%s) len(%d)\n", requestString, requestStringLen);
804 /* Send the request and store the results */
805 if (!HTTP_OpenConnection(lpwhr))
808 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
809 INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
811 cnt = send(lpwhr->nSocketFD, requestString, requestStringLen, 0);
813 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
814 INTERNET_STATUS_REQUEST_SENT,
815 &requestStringLen,sizeof(DWORD));
817 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
818 INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
823 responseLen = HTTP_GetResponseHeaders(lpwhr);
827 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
828 INTERNET_STATUS_RESPONSE_RECEIVED, &responseLen,
834 HeapFree(GetProcessHeap(), 0, requestString);
837 if (hIC->lpfnStatusCB)
839 INTERNET_ASYNC_RESULT iar;
841 iar.dwResult = (DWORD)bSuccess;
842 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
844 SendAsyncCallback(hIC, hHttpRequest, lpwhr->hdr.dwContext,
845 INTERNET_STATUS_REQUEST_COMPLETE, &iar,
846 sizeof(INTERNET_ASYNC_RESULT));
854 /***********************************************************************
855 * HTTP_Connect (internal)
857 * Create http session handle
860 * HINTERNET a session handle on success
864 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
865 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
866 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
868 BOOL bSuccess = FALSE;
869 LPWININETAPPINFOA hIC = NULL;
870 LPWININETHTTPSESSIONA lpwhs = NULL;
874 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
877 hIC = (LPWININETAPPINFOA) hInternet;
878 hIC->hdr.dwContext = dwContext;
880 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
883 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
888 * According to my tests. The name is not resolved until a request is sent
891 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
892 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
894 lpwhs->hdr.htype = WH_HHTTPSESSION;
895 lpwhs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
896 lpwhs->hdr.dwFlags = dwFlags;
897 lpwhs->hdr.dwContext = dwContext;
898 if (NULL != lpszServerName)
899 lpwhs->lpszServerName = HTTP_strdup(lpszServerName);
900 if (NULL != lpszUserName)
901 lpwhs->lpszUserName = HTTP_strdup(lpszUserName);
902 lpwhs->nServerPort = nServerPort;
904 if (hIC->lpfnStatusCB)
906 INTERNET_ASYNC_RESULT iar;
908 iar.dwResult = (DWORD)lpwhs;
909 iar.dwError = ERROR_SUCCESS;
911 SendAsyncCallback(hIC, hInternet, dwContext,
912 INTERNET_STATUS_HANDLE_CREATED, &iar,
913 sizeof(INTERNET_ASYNC_RESULT));
919 if (!bSuccess && lpwhs)
921 HeapFree(GetProcessHeap(), 0, lpwhs);
926 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
931 return (HINTERNET)lpwhs;
935 /***********************************************************************
936 * HTTP_OpenConnection (internal)
938 * Connect to a web server
945 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
947 BOOL bSuccess = FALSE;
949 LPWININETHTTPSESSIONA lpwhs;
950 LPWININETAPPINFOA hIC = NULL;
955 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
957 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
961 lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
963 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
964 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
965 INTERNET_STATUS_CONNECTING_TO_SERVER,
966 &(lpwhs->socketAddress),
967 sizeof(struct sockaddr_in));
969 lpwhr->nSocketFD = socket(lpwhs->phostent->h_addrtype,SOCK_STREAM,0);
970 if (lpwhr->nSocketFD == -1)
972 WARN("Socket creation failed\n");
976 result = connect(lpwhr->nSocketFD, (struct sockaddr *)&lpwhs->socketAddress,
977 sizeof(lpwhs->socketAddress));
981 WARN("Unable to connect to host (%s)\n", strerror(errno));
985 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
986 INTERNET_STATUS_CONNECTED_TO_SERVER,
987 &(lpwhs->socketAddress),
988 sizeof(struct sockaddr_in));
993 TRACE("%d <--\n", bSuccess);
998 /***********************************************************************
999 * HTTP_GetResponseHeaders (internal)
1001 * Read server response
1008 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
1011 CHAR buffer[MAX_REPLY_LEN];
1012 DWORD buflen = MAX_REPLY_LEN;
1013 BOOL bSuccess = FALSE;
1015 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
1019 if (lpwhr->nSocketFD == -1)
1023 * HACK peek at the buffer
1025 rc = recv(lpwhr->nSocketFD,buffer,buflen,MSG_PEEK);
1028 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
1030 buflen = MAX_REPLY_LEN;
1031 if (!INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
1034 if (strncmp(buffer, "HTTP", 4) != 0)
1038 HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1040 /* Parse each response line */
1043 buflen = MAX_REPLY_LEN;
1044 if (INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
1046 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
1049 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
1071 /***********************************************************************
1072 * HTTP_InterpretHttpHeader (internal)
1074 * Parse server response
1081 INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
1088 while (*lpszSrc == ' ' && *lpszSrc != '\0')
1092 while(*lpsztmp != '\0')
1094 if (*lpsztmp != ' ')
1095 srclen = lpsztmp - lpszSrc + 1;
1100 *len = min(*len, srclen);
1101 strncpy(lpszStart, lpszSrc, *len);
1102 lpszStart[*len] = '\0';
1108 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
1111 BOOL bSuccess = FALSE;
1118 pd = strchr(buffer, ':');
1122 if (stripSpaces(buffer, field, &fieldlen) > 0)
1124 if (stripSpaces(pd+1, value, &valuelen) > 0)
1129 TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
1134 /***********************************************************************
1135 * HTTP_GetStdHeaderIndex (internal)
1137 * Lookup field index in standard http header array
1139 * FIXME: This should be stuffed into a hash table
1141 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
1145 if (!strcasecmp(lpszField, "Content-Length"))
1146 index = HTTP_QUERY_CONTENT_LENGTH;
1147 else if (!strcasecmp(lpszField,"Status"))
1148 index = HTTP_QUERY_STATUS_CODE;
1149 else if (!strcasecmp(lpszField,"Content-Type"))
1150 index = HTTP_QUERY_CONTENT_TYPE;
1151 else if (!strcasecmp(lpszField,"Last-Modified"))
1152 index = HTTP_QUERY_LAST_MODIFIED;
1153 else if (!strcasecmp(lpszField,"Location"))
1154 index = HTTP_QUERY_LOCATION;
1155 else if (!strcasecmp(lpszField,"Accept"))
1156 index = HTTP_QUERY_ACCEPT;
1157 else if (!strcasecmp(lpszField,"Referer"))
1158 index = HTTP_QUERY_REFERER;
1159 else if (!strcasecmp(lpszField,"Content-Transfer-Encoding"))
1160 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
1161 else if (!strcasecmp(lpszField,"Date"))
1162 index = HTTP_QUERY_DATE;
1163 else if (!strcasecmp(lpszField,"Server"))
1164 index = HTTP_QUERY_SERVER;
1165 else if (!strcasecmp(lpszField,"Connection"))
1166 index = HTTP_QUERY_CONNECTION;
1167 else if (!strcasecmp(lpszField,"ETag"))
1168 index = HTTP_QUERY_ETAG;
1169 else if (!strcasecmp(lpszField,"Accept-Ranges"))
1170 index = HTTP_QUERY_ACCEPT_RANGES;
1171 else if (!strcasecmp(lpszField,"Expires"))
1172 index = HTTP_QUERY_EXPIRES;
1173 else if (!strcasecmp(lpszField,"Mime-Version"))
1174 index = HTTP_QUERY_MIME_VERSION;
1175 else if (!strcasecmp(lpszField,"Pragma"))
1176 index = HTTP_QUERY_PRAGMA;
1177 else if (!strcasecmp(lpszField,"Cache-Control"))
1178 index = HTTP_QUERY_CACHE_CONTROL;
1179 else if (!strcasecmp(lpszField,"Content-Length"))
1180 index = HTTP_QUERY_CONTENT_LENGTH;
1181 else if (!strcasecmp(lpszField,"User-Agent"))
1182 index = HTTP_QUERY_USER_AGENT;
1185 TRACE("Couldn't find %s in standard header table\n", lpszField);
1192 /***********************************************************************
1193 * HTTP_ProcessHeader (internal)
1195 * Stuff header into header tables according to <dwModifier>
1199 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1201 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
1203 LPHTTPHEADERA lphttpHdr = NULL;
1204 BOOL bSuccess = FALSE;
1207 TRACE("--> %s:%s - 0x%08x\n", field, value, (unsigned int)dwModifier);
1209 /* Adjust modifier flags */
1210 if (dwModifier & COALESCEFLASG)
1211 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
1213 /* Try to get index into standard header array */
1214 index = HTTP_GetStdHeaderIndex(field);
1217 lphttpHdr = &lpwhr->StdHeaders[index];
1219 else /* Find or create new custom header */
1221 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
1224 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
1228 lphttpHdr = &lpwhr->pCustHeaders[index];
1234 hdr.lpszField = (LPSTR)field;
1235 hdr.lpszValue = (LPSTR)value;
1236 hdr.wFlags = hdr.wCount = 0;
1238 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1239 hdr.wFlags |= HDR_ISREQUEST;
1241 index = HTTP_InsertCustomHeader(lpwhr, &hdr);
1246 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1247 lphttpHdr->wFlags |= HDR_ISREQUEST;
1249 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
1251 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
1255 if (!lpwhr->StdHeaders[index].lpszField)
1257 lphttpHdr->lpszField = HTTP_strdup(field);
1259 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1260 lphttpHdr->wFlags |= HDR_ISREQUEST;
1263 slen = strlen(value) + 1;
1264 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
1265 if (lphttpHdr->lpszValue)
1267 memcpy(lphttpHdr->lpszValue, value, slen);
1272 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1275 else if (lphttpHdr->lpszValue)
1277 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
1282 len = strlen(value);
1286 /* if custom header delete from array */
1287 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
1288 lphttpHdr->lpszValue = NULL;
1293 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1296 lphttpHdr->lpszValue = lpsztmp;
1297 strcpy(lpsztmp, value);
1302 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1306 else if (dwModifier & COALESCEFLASG)
1311 INT origlen = strlen(lphttpHdr->lpszValue);
1312 INT valuelen = strlen(value);
1314 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
1317 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1319 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1322 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1325 len = origlen + valuelen + (ch > 0) ? 1 : 0;
1327 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1330 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1333 lphttpHdr->lpszValue[origlen] = ch;
1337 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
1338 lphttpHdr->lpszValue[len] = '\0';
1343 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1352 /***********************************************************************
1353 * HTTP_CloseConnection (internal)
1355 * Close socket connection
1358 VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
1362 LPWININETHTTPSESSIONA lpwhs = NULL;
1363 LPWININETAPPINFOA hIC = NULL;
1365 TRACE("%p\n",lpwhr);
1367 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1368 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1370 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1371 INTERNET_STATUS_CLOSING_CONNECTION, 0, 0);
1373 if (lpwhr->nSocketFD != -1)
1375 close(lpwhr->nSocketFD);
1376 lpwhr->nSocketFD = -1;
1379 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1380 INTERNET_STATUS_CONNECTION_CLOSED, 0, 0);
1384 /***********************************************************************
1385 * HTTP_CloseHTTPRequestHandle (internal)
1387 * Deallocate request handle
1390 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
1393 LPWININETHTTPSESSIONA lpwhs = NULL;
1394 LPWININETAPPINFOA hIC = NULL;
1398 if (lpwhr->nSocketFD != -1)
1399 HTTP_CloseConnection(lpwhr);
1401 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
1402 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1404 SendAsyncCallback(hIC, lpwhr, lpwhr->hdr.dwContext,
1405 INTERNET_STATUS_HANDLE_CLOSING, lpwhr,
1408 if (lpwhr->lpszPath)
1409 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1410 if (lpwhr->lpszVerb)
1411 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1412 if (lpwhr->lpszHostName)
1413 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1415 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1417 if (lpwhr->StdHeaders[i].lpszField)
1418 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
1419 if (lpwhr->StdHeaders[i].lpszValue)
1420 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
1423 for (i = 0; i < lpwhr->nCustHeaders; i++)
1425 if (lpwhr->pCustHeaders[i].lpszField)
1426 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
1427 if (lpwhr->pCustHeaders[i].lpszValue)
1428 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
1431 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1432 HeapFree(GetProcessHeap(), 0, lpwhr);
1436 /***********************************************************************
1437 * HTTP_CloseHTTPSessionHandle (internal)
1439 * Deallocate session handle
1442 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
1444 LPWININETAPPINFOA hIC = NULL;
1447 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
1449 SendAsyncCallback(hIC, lpwhs, lpwhs->hdr.dwContext,
1450 INTERNET_STATUS_HANDLE_CLOSING, lpwhs,
1453 if (lpwhs->lpszServerName)
1454 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1455 if (lpwhs->lpszUserName)
1456 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1457 HeapFree(GetProcessHeap(), 0, lpwhs);
1461 /***********************************************************************
1462 * HTTP_GetCustomHeaderIndex (internal)
1464 * Return index of custom header from header array
1467 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
1471 TRACE("%s\n", lpszField);
1473 for (index = 0; index < lpwhr->nCustHeaders; index++)
1475 if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
1480 if (index >= lpwhr->nCustHeaders)
1483 TRACE("Return: %d\n", index);
1488 /***********************************************************************
1489 * HTTP_InsertCustomHeader (internal)
1491 * Insert header into array
1494 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
1497 LPHTTPHEADERA lph = NULL;
1499 TRACE("--> %s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
1500 count = lpwhr->nCustHeaders + 1;
1502 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
1504 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
1508 lpwhr->pCustHeaders = lph;
1509 lpwhr->pCustHeaders[count-1].lpszField = HTTP_strdup(lpHdr->lpszField);
1510 lpwhr->pCustHeaders[count-1].lpszValue = HTTP_strdup(lpHdr->lpszValue);
1511 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
1512 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
1513 lpwhr->nCustHeaders++;
1517 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1521 TRACE("%d <--\n", count-1);
1526 /***********************************************************************
1527 * HTTP_DeleteCustomHeader (internal)
1529 * Delete header from array
1532 BOOL HTTP_DeleteCustomHeader(INT index)