Display thread id instead of %fs in relay trace.
[wine.git] / dlls / wininet / http.c
blobbfba5c494909a7cb4b19b87268df5b1fe974a0a4
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"
18 #include "shlwapi.h"
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_SOCKET_H
22 # include <sys/socket.h>
23 #endif
24 #ifdef HAVE_NETDB_H
25 # include <netdb.h>
26 #endif
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <time.h>
34 #include "internet.h"
36 DEFAULT_DEBUG_CHANNEL(wininet);
38 #define HTTPHEADER " HTTP/1.0"
39 #define HTTPHOSTHEADER "\r\nHost: "
40 #define MAXHOSTNAME 100
41 #define MAX_FIELD_VALUE_LEN 256
42 #define MAX_FIELD_LEN 256
45 #define HTTP_REFERER "Referer"
46 #define HTTP_ACCEPT "Accept"
48 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
49 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
50 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
51 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
52 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
53 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
54 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
57 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr);
58 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr,
59 void *Buffer, int BytesToWrite);
60 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr,
61 void *Buffer, int BytesToRead);
62 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr);
63 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier);
64 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr);
65 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen);
66 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField);
67 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr);
68 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField);
70 inline static LPSTR HTTP_strdup( LPCSTR str )
72 LPSTR ret = HeapAlloc( GetProcessHeap(), 0, strlen(str) + 1 );
73 if (ret) strcpy( ret, str );
74 return ret;
77 /***********************************************************************
78 * HttpAddRequestHeadersA (WININET.68)
80 * Adds one or more HTTP header to the request handler
82 * RETURNS
83 * TRUE on success
84 * FALSE on failure
87 INTERNETAPI BOOL WINAPI HttpAddRequestHeadersA(HINTERNET hHttpRequest,
88 LPCSTR lpszHeader, DWORD dwHeaderLength, DWORD dwModifier)
90 LPSTR lpszStart;
91 LPSTR lpszEnd;
92 LPSTR buffer;
93 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
94 BOOL bSuccess = FALSE;
95 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
97 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
99 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
100 return FALSE;
103 buffer = HTTP_strdup(lpszHeader);
104 lpszStart = buffer;
108 lpszEnd = lpszStart;
110 while (*lpszEnd != '\0')
112 if (*lpszEnd == '\r' && *(lpszEnd + 1) == '\n')
113 break;
114 lpszEnd++;
117 if (*lpszEnd == '\0')
118 break;
120 *lpszEnd = '\0';
122 if (HTTP_InterpretHttpHeader(lpszStart, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
123 bSuccess = HTTP_ProcessHeader(lpwhr, field, value, dwModifier | HTTP_ADDHDR_FLAG_REQ);
125 lpszStart = lpszEnd + 2; /* Jump over \0\n */
127 } while (bSuccess);
129 HeapFree(GetProcessHeap(), 0, buffer);
130 return bSuccess;
134 /***********************************************************************
135 * HttpOpenRequestA (WININET.72)
137 * Open a HTTP request handle
139 * RETURNS
140 * HINTERNET a HTTP request handle on success
141 * NULL on failure
144 INTERNETAPI HINTERNET WINAPI HttpOpenRequestA(HINTERNET hHttpSession,
145 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
146 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
147 DWORD dwFlags, DWORD dwContext)
149 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
150 LPWININETAPPINFOA hIC = NULL;
152 TRACE("\n");
154 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
156 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
157 return FALSE;
160 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
162 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
164 WORKREQUEST workRequest;
166 workRequest.asyncall = HTTPOPENREQUESTA;
167 workRequest.HFTPSESSION = (DWORD)hHttpSession;
168 workRequest.LPSZVERB = (DWORD)HTTP_strdup(lpszVerb);
169 workRequest.LPSZOBJECTNAME = (DWORD)HTTP_strdup(lpszObjectName);
170 workRequest.LPSZVERSION = (DWORD)HTTP_strdup(lpszVersion);
171 workRequest.LPSZREFERRER = (DWORD)HTTP_strdup(lpszReferrer);
172 workRequest.LPSZACCEPTTYPES = (DWORD)lpszAcceptTypes;
173 workRequest.DWFLAGS = dwFlags;
174 workRequest.DWCONTEXT = dwContext;
176 return (HINTERNET)INTERNET_AsyncCall(&workRequest);
178 else
180 return HTTP_HttpOpenRequestA(hHttpSession, lpszVerb, lpszObjectName,
181 lpszVersion, lpszReferrer, lpszAcceptTypes, dwFlags, dwContext);
186 /***********************************************************************
187 * HTTP_HttpOpenRequestA (internal)
189 * Open a HTTP request handle
191 * RETURNS
192 * HINTERNET a HTTP request handle on success
193 * NULL on failure
196 INTERNETAPI HINTERNET WINAPI HTTP_HttpOpenRequestA(HINTERNET hHttpSession,
197 LPCSTR lpszVerb, LPCSTR lpszObjectName, LPCSTR lpszVersion,
198 LPCSTR lpszReferrer , LPCSTR *lpszAcceptTypes,
199 DWORD dwFlags, DWORD dwContext)
201 LPWININETHTTPSESSIONA lpwhs = (LPWININETHTTPSESSIONA) hHttpSession;
202 LPWININETAPPINFOA hIC = NULL;
203 LPWININETHTTPREQA lpwhr;
205 TRACE("\n");
207 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
209 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
210 return FALSE;
213 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
215 lpwhr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPREQA));
216 if (NULL == lpwhr)
218 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
219 return (HINTERNET) NULL;
222 lpwhr->hdr.htype = WH_HHTTPREQ;
223 lpwhr->hdr.lpwhparent = hHttpSession;
224 lpwhr->hdr.dwFlags = dwFlags;
225 lpwhr->hdr.dwContext = dwContext;
226 lpwhr->nSocketFD = INVALID_SOCKET;
228 if (NULL != lpszObjectName && strlen(lpszObjectName)) {
229 DWORD needed = 0;
230 UrlEscapeA(lpszObjectName, NULL, &needed, URL_ESCAPE_SPACES_ONLY);
231 lpwhr->lpszPath = HeapAlloc(GetProcessHeap(), 0, needed);
232 UrlEscapeA(lpszObjectName, lpwhr->lpszPath, &needed,
233 URL_ESCAPE_SPACES_ONLY);
236 if (NULL != lpszReferrer && strlen(lpszReferrer))
237 HTTP_ProcessHeader(lpwhr, HTTP_REFERER, lpszReferrer, HTTP_ADDHDR_FLAG_COALESCE);
239 //! FIXME
240 if (NULL != lpszAcceptTypes && strlen(*lpszAcceptTypes))
241 HTTP_ProcessHeader(lpwhr, HTTP_ACCEPT, *lpszAcceptTypes, HTTP_ADDHDR_FLAG_COALESCE);
243 if (NULL == lpszVerb)
244 lpwhr->lpszVerb = HTTP_strdup("GET");
245 else if (strlen(lpszVerb))
246 lpwhr->lpszVerb = HTTP_strdup(lpszVerb);
248 if (NULL != lpszReferrer)
250 char buf[MAXHOSTNAME];
251 URL_COMPONENTSA UrlComponents;
253 UrlComponents.lpszExtraInfo = NULL;
254 UrlComponents.lpszPassword = NULL;
255 UrlComponents.lpszScheme = NULL;
256 UrlComponents.lpszUrlPath = NULL;
257 UrlComponents.lpszUserName = NULL;
258 UrlComponents.lpszHostName = buf;
259 UrlComponents.dwHostNameLength = MAXHOSTNAME;
261 InternetCrackUrlA(lpszReferrer, 0, 0, &UrlComponents);
262 if (strlen(UrlComponents.lpszHostName))
263 lpwhr->lpszHostName = HTTP_strdup(UrlComponents.lpszHostName);
264 } else {
265 lpwhr->lpszHostName = HTTP_strdup(lpwhs->lpszServerName);
268 if (hIC->lpfnStatusCB)
270 INTERNET_ASYNC_RESULT iar;
272 iar.dwResult = (DWORD)lpwhr;
273 iar.dwError = ERROR_SUCCESS;
275 hIC->lpfnStatusCB(hHttpSession, dwContext, INTERNET_STATUS_HANDLE_CREATED,
276 &iar, sizeof(INTERNET_ASYNC_RESULT));
279 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
281 INTERNET_ASYNC_RESULT iar;
283 iar.dwResult = (DWORD)lpwhr;
284 iar.dwError = lpwhr ? ERROR_SUCCESS : INTERNET_GetLastError();
285 hIC->lpfnStatusCB(hHttpSession, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
286 &iar, sizeof(INTERNET_ASYNC_RESULT));
289 return (HINTERNET) lpwhr;
293 /***********************************************************************
294 * HttpQueryInfoA (WININET.74)
296 * Queries for information about an HTTP request
298 * RETURNS
299 * TRUE on success
300 * FALSE on failure
303 BOOL WINAPI HttpQueryInfoA(HINTERNET hHttpRequest, DWORD dwInfoLevel,
304 LPVOID lpBuffer, LPDWORD lpdwBufferLength, LPDWORD lpdwIndex)
306 LPHTTPHEADERA lphttpHdr = NULL;
307 BOOL bSuccess = FALSE;
308 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
310 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel, dwInfoLevel);
312 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
314 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
315 return FALSE;
318 /* Find requested header structure */
319 if ((dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK) == HTTP_QUERY_CUSTOM)
321 INT index = HTTP_GetCustomHeaderIndex(lpwhr, (LPSTR)lpBuffer);
323 if (index < 0)
324 goto lend;
326 lphttpHdr = &lpwhr->pCustHeaders[index];
328 else
330 INT index = dwInfoLevel & ~HTTP_QUERY_MODIFIER_FLAGS_MASK;
332 if (index == HTTP_QUERY_RAW_HEADERS_CRLF || index == HTTP_QUERY_RAW_HEADERS)
334 INT i, delim, size = 0, cnt = 0;
336 delim = index == HTTP_QUERY_RAW_HEADERS_CRLF ? 2 : 1;
338 /* Calculate length of custom reuqest headers */
339 for (i = 0; i < lpwhr->nCustHeaders; i++)
341 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->pCustHeaders[i].lpszField &&
342 lpwhr->pCustHeaders[i].lpszValue)
344 size += strlen(lpwhr->pCustHeaders[i].lpszField) +
345 strlen(lpwhr->pCustHeaders[i].lpszValue) + delim + 2;
349 /* Calculate the length of stadard request headers */
350 for (i = 0; i <= HTTP_QUERY_MAX; i++)
352 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) && lpwhr->StdHeaders[i].lpszField &&
353 lpwhr->StdHeaders[i].lpszValue)
355 size += strlen(lpwhr->StdHeaders[i].lpszField) +
356 strlen(lpwhr->StdHeaders[i].lpszValue) + delim + 2;
360 size += delim;
362 if (size + 1 > *lpdwBufferLength)
364 *lpdwBufferLength = size + 1;
365 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
366 goto lend;
369 /* Append standard request heades */
370 for (i = 0; i <= HTTP_QUERY_MAX; i++)
372 if ((~lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST) &&
373 lpwhr->StdHeaders[i].lpszField &&
374 lpwhr->StdHeaders[i].lpszValue)
376 cnt += sprintf(lpBuffer + cnt, "%s: %s%s", lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue,
377 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
381 /* Append custom request heades */
382 for (i = 0; i < lpwhr->nCustHeaders; i++)
384 if ((~lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST) &&
385 lpwhr->pCustHeaders[i].lpszField &&
386 lpwhr->pCustHeaders[i].lpszValue)
388 cnt += sprintf(lpBuffer + cnt, "%s: %s%s",
389 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue,
390 index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "\0");
394 strcpy(lpBuffer + cnt, index == HTTP_QUERY_RAW_HEADERS_CRLF ? "\r\n" : "");
396 *lpdwBufferLength = cnt + delim;
397 bSuccess = TRUE;
398 goto lend;
400 else if (index >= 0 && index <= HTTP_QUERY_MAX && lpwhr->StdHeaders[index].lpszValue)
402 lphttpHdr = &lpwhr->StdHeaders[index];
404 else
405 goto lend;
408 /* Ensure header satisifies requested attributes */
409 if ((dwInfoLevel & HTTP_QUERY_FLAG_REQUEST_HEADERS) &&
410 (~lphttpHdr->wFlags & HDR_ISREQUEST))
411 goto lend;
413 /* coalesce value to reuqested type */
414 if (dwInfoLevel & HTTP_QUERY_FLAG_NUMBER)
416 *(int *)lpBuffer = atoi(lphttpHdr->lpszValue);
417 bSuccess = TRUE;
419 else if (dwInfoLevel & HTTP_QUERY_FLAG_SYSTEMTIME)
421 time_t tmpTime;
422 struct tm tmpTM;
423 SYSTEMTIME *STHook;
425 tmpTime = ConvertTimeString(lphttpHdr->lpszValue);
427 tmpTM = *gmtime(&tmpTime);
428 STHook = (SYSTEMTIME *) lpBuffer;
429 if(STHook==NULL)
430 goto lend;
432 STHook->wDay = tmpTM.tm_mday;
433 STHook->wHour = tmpTM.tm_hour;
434 STHook->wMilliseconds = 0;
435 STHook->wMinute = tmpTM.tm_min;
436 STHook->wDayOfWeek = tmpTM.tm_wday;
437 STHook->wMonth = tmpTM.tm_mon + 1;
438 STHook->wSecond = tmpTM.tm_sec;
439 STHook->wYear = tmpTM.tm_year;
441 bSuccess = TRUE;
443 else if (dwInfoLevel & HTTP_QUERY_FLAG_COALESCE)
445 if (*lpdwIndex >= lphttpHdr->wCount)
447 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND);
449 else
451 //! Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len);
452 (*lpdwIndex)++;
455 else
457 INT len = strlen(lphttpHdr->lpszValue);
459 if (len + 1 > *lpdwBufferLength)
461 *lpdwBufferLength = len + 1;
462 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER);
463 goto lend;
466 strncpy(lpBuffer, lphttpHdr->lpszValue, len);
467 *lpdwBufferLength = len;
468 bSuccess = TRUE;
471 lend:
472 TRACE("%d <--\n", bSuccess);
473 return bSuccess;
477 /***********************************************************************
478 * HttpSendRequestExA (WININET)
480 * Sends the specified request to the HTTP server and allows chunked
481 * transfers
483 BOOL WINAPI HttpSendRequestExA(HINTERNET hRequest,
484 LPINTERNET_BUFFERSA lpBuffersIn,
485 LPINTERNET_BUFFERSA lpBuffersOut,
486 DWORD dwFlags, DWORD dwContext)
488 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest, lpBuffersIn,
489 lpBuffersOut, dwFlags, dwContext);
490 return FALSE;
493 /***********************************************************************
494 * HttpSendRequestA (WININET.76)
496 * Sends the specified request to the HTTP server
498 * RETURNS
499 * TRUE on success
500 * FALSE on failure
503 BOOL WINAPI HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
504 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
506 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
507 LPWININETHTTPSESSIONA lpwhs = NULL;
508 LPWININETAPPINFOA hIC = NULL;
510 TRACE("0x%08lx\n", (unsigned long)hHttpRequest);
512 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
514 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
515 return FALSE;
518 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
519 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
521 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
522 return FALSE;
525 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
526 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
528 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
529 return FALSE;
532 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
534 WORKREQUEST workRequest;
536 workRequest.asyncall = HTTPSENDREQUESTA;
537 workRequest.HFTPSESSION = (DWORD)hHttpRequest;
538 workRequest.LPSZHEADER = (DWORD)HTTP_strdup(lpszHeaders);
539 workRequest.DWHEADERLENGTH = dwHeaderLength;
540 workRequest.LPOPTIONAL = (DWORD)lpOptional;
541 workRequest.DWOPTIONALLENGTH = dwOptionalLength;
543 return INTERNET_AsyncCall(&workRequest);
545 else
547 return HTTP_HttpSendRequestA(hHttpRequest, lpszHeaders,
548 dwHeaderLength, lpOptional, dwOptionalLength);
553 /***********************************************************************
554 * HTTP_HttpSendRequestA (internal)
556 * Sends the specified request to the HTTP server
558 * RETURNS
559 * TRUE on success
560 * FALSE on failure
563 BOOL WINAPI HTTP_HttpSendRequestA(HINTERNET hHttpRequest, LPCSTR lpszHeaders,
564 DWORD dwHeaderLength, LPVOID lpOptional ,DWORD dwOptionalLength)
566 INT cnt;
567 INT i;
568 BOOL bSuccess = FALSE;
569 LPSTR requestString = NULL;
570 INT requestStringLen;
571 INT headerLength = 0;
572 LPWININETHTTPREQA lpwhr = (LPWININETHTTPREQA) hHttpRequest;
573 LPWININETHTTPSESSIONA lpwhs = NULL;
574 LPWININETAPPINFOA hIC = NULL;
576 TRACE("0x%08lx\n", (ULONG)hHttpRequest);
578 /* Verify our tree of internet handles */
579 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
581 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
582 return FALSE;
585 lpwhs = (LPWININETHTTPSESSIONA) lpwhr->hdr.lpwhparent;
586 if (NULL == lpwhs || lpwhs->hdr.htype != WH_HHTTPSESSION)
588 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
589 return FALSE;
592 hIC = (LPWININETAPPINFOA) lpwhs->hdr.lpwhparent;
593 if (NULL == hIC || hIC->hdr.htype != WH_HINIT)
595 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE);
596 return FALSE;
599 /* Clear any error information */
600 INTERNET_SetLastError(0);
602 /* We must have a verb */
603 if (NULL == lpwhr->lpszVerb)
605 goto lend;
608 /* If we don't have a path we set it to root */
609 if (NULL == lpwhr->lpszPath)
610 lpwhr->lpszPath = HTTP_strdup("/");
612 /* Calculate length of request string */
613 requestStringLen =
614 strlen(lpwhr->lpszVerb) +
615 strlen(lpwhr->lpszPath) +
616 (lpwhr->lpszHostName ? (strlen(HTTPHOSTHEADER) + strlen(lpwhr->lpszHostName)) : 0) +
617 strlen(HTTPHEADER) +
618 5; /* " \r\n\r\n" */
620 /* Add length of passed headers */
621 if (lpszHeaders)
623 headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength;
624 requestStringLen += headerLength + 2; /* \r\n */
627 /* Calculate length of custom request headers */
628 for (i = 0; i < lpwhr->nCustHeaders; i++)
630 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
632 requestStringLen += strlen(lpwhr->pCustHeaders[i].lpszField) +
633 strlen(lpwhr->pCustHeaders[i].lpszValue) + 4; /*: \r\n */
637 /* Calculate the length of standard request headers */
638 for (i = 0; i <= HTTP_QUERY_MAX; i++)
640 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
642 requestStringLen += strlen(lpwhr->StdHeaders[i].lpszField) +
643 strlen(lpwhr->StdHeaders[i].lpszValue) + 4; /*: \r\n */
647 /* Allocate string to hold entire request */
648 requestString = HeapAlloc(GetProcessHeap(), 0, requestStringLen + 1);
649 if (NULL == requestString)
651 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
652 goto lend;
655 /* Build request string */
656 cnt = sprintf(requestString, "%s %s%s%s",
657 lpwhr->lpszVerb,
658 lpwhr->lpszPath,
659 lpwhr->lpszHostName ? (HTTPHEADER HTTPHOSTHEADER) : HTTPHEADER,
660 lpwhr->lpszHostName ? lpwhr->lpszHostName : "");
662 /* Append standard request headers */
663 for (i = 0; i <= HTTP_QUERY_MAX; i++)
665 if (lpwhr->StdHeaders[i].wFlags & HDR_ISREQUEST)
667 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
668 lpwhr->StdHeaders[i].lpszField, lpwhr->StdHeaders[i].lpszValue);
672 /* Append custom request heades */
673 for (i = 0; i < lpwhr->nCustHeaders; i++)
675 if (lpwhr->pCustHeaders[i].wFlags & HDR_ISREQUEST)
677 cnt += sprintf(requestString + cnt, "\r\n%s: %s",
678 lpwhr->pCustHeaders[i].lpszField, lpwhr->pCustHeaders[i].lpszValue);
682 /* Append passed request headers */
683 if (lpszHeaders)
685 strcpy(requestString + cnt, "\r\n");
686 cnt += 2;
687 strcpy(requestString + cnt, lpszHeaders);
688 cnt += headerLength;
691 /* Set termination string for request */
692 strcpy(requestString + cnt, "\r\n\r\n");
694 if (hIC->lpfnStatusCB)
695 hIC->lpfnStatusCB(hHttpRequest, lpwhr->hdr.dwContext, INTERNET_STATUS_SENDING_REQUEST, NULL, 0);
697 TRACE("(%s) len(%d)\n", requestString, requestStringLen);
698 /* Send the request and store the results */
699 if (!HTTP_OpenConnection(lpwhr))
700 goto lend;
702 cnt = INTERNET_WriteDataToStream(lpwhr->nSocketFD, requestString, requestStringLen);
704 if (cnt < 0)
705 goto lend;
707 if (HTTP_GetResponseHeaders(lpwhr))
708 bSuccess = TRUE;
710 lend:
712 if (requestString)
713 HeapFree(GetProcessHeap(), 0, requestString);
715 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
717 INTERNET_ASYNC_RESULT iar;
719 iar.dwResult = (DWORD)bSuccess;
720 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
721 hIC->lpfnStatusCB(hHttpRequest, lpwhr->hdr.dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
722 &iar, sizeof(INTERNET_ASYNC_RESULT));
725 TRACE("<--\n");
726 return bSuccess;
730 /***********************************************************************
731 * HTTP_Connect (internal)
733 * Create http session handle
735 * RETURNS
736 * HINTERNET a session handle on success
737 * NULL on failure
740 HINTERNET HTTP_Connect(HINTERNET hInternet, LPCSTR lpszServerName,
741 INTERNET_PORT nServerPort, LPCSTR lpszUserName,
742 LPCSTR lpszPassword, DWORD dwFlags, DWORD dwContext)
744 BOOL bSuccess = FALSE;
745 LPWININETAPPINFOA hIC = NULL;
746 LPWININETHTTPSESSIONA lpwhs = NULL;
748 TRACE("\n");
750 if (((LPWININETHANDLEHEADER)hInternet)->htype != WH_HINIT)
751 goto lerror;
753 hIC = (LPWININETAPPINFOA) hInternet;
755 lpwhs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WININETHTTPSESSIONA));
756 if (NULL == lpwhs)
758 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
759 goto lerror;
762 if (hIC->lpfnStatusCB)
763 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_RESOLVING_NAME,
764 (LPVOID)lpszServerName, strlen(lpszServerName));
766 if (nServerPort == INTERNET_INVALID_PORT_NUMBER)
767 nServerPort = INTERNET_DEFAULT_HTTP_PORT;
769 if (!GetAddress(lpszServerName, nServerPort, &lpwhs->phostent, &lpwhs->socketAddress))
771 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED);
772 goto lerror;
775 if (hIC->lpfnStatusCB)
776 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_NAME_RESOLVED,
777 (LPVOID)lpszServerName, strlen(lpszServerName));
779 lpwhs->hdr.htype = WH_HHTTPSESSION;
780 lpwhs->hdr.lpwhparent = (LPWININETHANDLEHEADER)hInternet;
781 lpwhs->hdr.dwFlags = dwFlags;
782 lpwhs->hdr.dwContext = dwContext;
783 if (NULL != lpszServerName)
784 lpwhs->lpszServerName = HTTP_strdup(lpszServerName);
785 if (NULL != lpszUserName)
786 lpwhs->lpszUserName = HTTP_strdup(lpszUserName);
787 lpwhs->nServerPort = nServerPort;
789 if (hIC->lpfnStatusCB)
791 INTERNET_ASYNC_RESULT iar;
793 iar.dwResult = (DWORD)lpwhs;
794 iar.dwError = ERROR_SUCCESS;
796 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_HANDLE_CREATED,
797 &iar, sizeof(INTERNET_ASYNC_RESULT));
800 bSuccess = TRUE;
802 lerror:
803 if (!bSuccess && lpwhs)
805 HeapFree(GetProcessHeap(), 0, lpwhs);
806 lpwhs = NULL;
809 if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC && hIC->lpfnStatusCB)
811 INTERNET_ASYNC_RESULT iar;
813 iar.dwResult = (DWORD)lpwhs;
814 iar.dwError = bSuccess ? ERROR_SUCCESS : INTERNET_GetLastError();
815 hIC->lpfnStatusCB(hInternet, dwContext, INTERNET_STATUS_REQUEST_COMPLETE,
816 &iar, sizeof(INTERNET_ASYNC_RESULT));
818 TRACE("<--\n");
819 return (HINTERNET)lpwhs;
823 /***********************************************************************
824 * HTTP_OpenConnection (internal)
826 * Connect to a web server
828 * RETURNS
830 * TRUE on success
831 * FALSE on failure
833 BOOL HTTP_OpenConnection(LPWININETHTTPREQA lpwhr)
835 BOOL bSuccess = FALSE;
836 INT result;
837 LPWININETHTTPSESSIONA lpwhs;
839 TRACE("\n");
841 if (NULL == lpwhr || lpwhr->hdr.htype != WH_HHTTPREQ)
843 INTERNET_SetLastError(ERROR_INVALID_PARAMETER);
844 goto lend;
847 lpwhs = (LPWININETHTTPSESSIONA)lpwhr->hdr.lpwhparent;
849 lpwhr->nSocketFD = socket(lpwhs->phostent->h_addrtype,SOCK_STREAM,0);
850 if (INVALID_SOCKET == lpwhr->nSocketFD)
852 WARN("Socket creation failed\n");
853 goto lend;
856 result = connect(lpwhr->nSocketFD, (struct sockaddr *)&lpwhs->socketAddress,
857 sizeof(lpwhs->socketAddress));
859 if (SOCKET_ERROR == result)
861 WARN("Unable to connect to host (%s)\n", strerror(errno));
862 goto lend;
865 bSuccess = TRUE;
867 lend:
868 TRACE(": %d\n", bSuccess);
869 return bSuccess;
873 /***********************************************************************
874 * HTTP_GetResponseHeaders (internal)
876 * Read server response
878 * RETURNS
880 * TRUE on success
881 * FALSE on error
883 BOOL HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr)
885 INT cbreaks = 0;
886 CHAR buffer[MAX_REPLY_LEN];
887 DWORD buflen = MAX_REPLY_LEN;
888 BOOL bSuccess = FALSE;
889 CHAR value[MAX_FIELD_VALUE_LEN], field[MAX_FIELD_LEN];
891 TRACE("\n");
893 if (INVALID_SOCKET == lpwhr->nSocketFD)
894 goto lend;
897 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
899 if (!INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
900 goto lend;
902 if (strncmp(buffer, "HTTP", 4) != 0)
903 goto lend;
905 buffer[12]='\0';
906 HTTP_ProcessHeader(lpwhr, "Status", buffer+9, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
908 /* Parse each response line */
911 buflen = MAX_REPLY_LEN;
912 if (INTERNET_GetNextLine(lpwhr->nSocketFD, buffer, &buflen))
914 if (!HTTP_InterpretHttpHeader(buffer, field, MAX_FIELD_LEN, value, MAX_FIELD_VALUE_LEN))
915 break;
917 HTTP_ProcessHeader(lpwhr, field, value, (HTTP_ADDREQ_FLAG_ADD | HTTP_ADDREQ_FLAG_REPLACE));
919 else
921 cbreaks++;
922 if (cbreaks >= 2)
923 break;
925 }while(1);
927 bSuccess = TRUE;
929 lend:
931 return bSuccess;
935 /***********************************************************************
936 * HTTP_InterpretHttpHeader (internal)
938 * Parse server response
940 * RETURNS
942 * TRUE on success
943 * FALSE on error
945 INT stripSpaces(LPCSTR lpszSrc, LPSTR lpszStart, INT *len)
947 LPCSTR lpsztmp;
948 INT srclen;
950 srclen = 0;
952 while (*lpszSrc == ' ' && *lpszSrc != '\0')
953 lpszSrc++;
955 lpsztmp = lpszSrc;
956 while(*lpsztmp != '\0')
958 if (*lpsztmp != ' ')
959 srclen = lpsztmp - lpszSrc + 1;
961 lpsztmp++;
964 *len = min(*len, srclen);
965 strncpy(lpszStart, lpszSrc, *len);
966 lpszStart[*len] = '\0';
968 return *len;
972 BOOL HTTP_InterpretHttpHeader(LPSTR buffer, LPSTR field, INT fieldlen, LPSTR value, INT valuelen)
974 CHAR *pd;
975 BOOL bSuccess = FALSE;
977 TRACE("\n");
979 *field = '\0';
980 *value = '\0';
982 pd = strchr(buffer, ':');
983 if (pd)
985 *pd = '\0';
986 if (stripSpaces(buffer, field, &fieldlen) > 0)
988 if (stripSpaces(pd+1, value, &valuelen) > 0)
989 bSuccess = TRUE;
993 TRACE("%d: field(%s) Value(%s)\n", bSuccess, field, value);
994 return bSuccess;
998 /***********************************************************************
999 * HTTP_GetStdHeaderIndex (internal)
1001 * Lookup field index in standard http header array
1003 * FIXME: This should be stuffed into a hash table
1005 INT HTTP_GetStdHeaderIndex(LPCSTR lpszField)
1007 INT index = -1;
1009 if (!strcasecmp(lpszField, "Content-Length"))
1010 index = HTTP_QUERY_CONTENT_LENGTH;
1011 else if (!strcasecmp(lpszField,"Status"))
1012 index = HTTP_QUERY_STATUS_CODE;
1013 else if (!strcasecmp(lpszField,"Content-Type"))
1014 index = HTTP_QUERY_CONTENT_TYPE;
1015 else if (!strcasecmp(lpszField,"Last-Modified"))
1016 index = HTTP_QUERY_LAST_MODIFIED;
1017 else if (!strcasecmp(lpszField,"Location"))
1018 index = HTTP_QUERY_LOCATION;
1019 else if (!strcasecmp(lpszField,"Accept"))
1020 index = HTTP_QUERY_ACCEPT;
1021 else if (!strcasecmp(lpszField,"Referer"))
1022 index = HTTP_QUERY_REFERER;
1023 else if (!strcasecmp(lpszField,"Content-Transfer-Encoding"))
1024 index = HTTP_QUERY_CONTENT_TRANSFER_ENCODING;
1025 else if (!strcasecmp(lpszField,"Date"))
1026 index = HTTP_QUERY_DATE;
1027 else if (!strcasecmp(lpszField,"Server"))
1028 index = HTTP_QUERY_SERVER;
1029 else if (!strcasecmp(lpszField,"Connection"))
1030 index = HTTP_QUERY_CONNECTION;
1031 else if (!strcasecmp(lpszField,"ETag"))
1032 index = HTTP_QUERY_ETAG;
1033 else if (!strcasecmp(lpszField,"Accept-Ranges"))
1034 index = HTTP_QUERY_ACCEPT_RANGES;
1035 else if (!strcasecmp(lpszField,"Expires"))
1036 index = HTTP_QUERY_EXPIRES;
1037 else if (!strcasecmp(lpszField,"Mime-Version"))
1038 index = HTTP_QUERY_MIME_VERSION;
1039 else
1041 FIXME("Couldn't find %s in standard header table\n", lpszField);
1044 return index;
1048 /***********************************************************************
1049 * HTTP_ProcessHeader (internal)
1051 * Stuff header into header tables according to <dwModifier>
1055 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1057 BOOL HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr, LPCSTR field, LPCSTR value, DWORD dwModifier)
1059 LPHTTPHEADERA lphttpHdr = NULL;
1060 BOOL bSuccess = FALSE;
1061 INT index;
1063 TRACE("%s:%s - 0x%08x\n", field, value, (unsigned int)dwModifier);
1065 /* Adjust modifier flags */
1066 if (dwModifier & COALESCEFLASG)
1067 dwModifier |= HTTP_ADDHDR_FLAG_ADD;
1069 /* Try to get index into standard header array */
1070 index = HTTP_GetStdHeaderIndex(field);
1071 if (index >= 0)
1073 lphttpHdr = &lpwhr->StdHeaders[index];
1075 else /* Find or create new custom header */
1077 index = HTTP_GetCustomHeaderIndex(lpwhr, field);
1078 if (index >= 0)
1080 if (dwModifier & HTTP_ADDHDR_FLAG_ADD_IF_NEW)
1082 return FALSE;
1084 lphttpHdr = &lpwhr->pCustHeaders[index];
1086 else
1088 HTTPHEADERA hdr;
1090 hdr.lpszField = (LPSTR)field;
1091 hdr.lpszValue = (LPSTR)value;
1092 hdr.wFlags = hdr.wCount = 0;
1094 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1095 hdr.wFlags |= HDR_ISREQUEST;
1097 index = HTTP_InsertCustomHeader(lpwhr, &hdr);
1098 return index >= 0;
1102 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1103 lphttpHdr->wFlags |= HDR_ISREQUEST;
1104 else
1105 lphttpHdr->wFlags &= ~HDR_ISREQUEST;
1107 if (!lphttpHdr->lpszValue && (dwModifier & (HTTP_ADDHDR_FLAG_ADD|HTTP_ADDHDR_FLAG_ADD_IF_NEW)))
1109 INT slen;
1111 if (!lpwhr->StdHeaders[index].lpszField)
1113 lphttpHdr->lpszField = HTTP_strdup(field);
1115 if (dwModifier & HTTP_ADDHDR_FLAG_REQ)
1116 lphttpHdr->wFlags |= HDR_ISREQUEST;
1119 slen = strlen(value) + 1;
1120 lphttpHdr->lpszValue = HeapAlloc(GetProcessHeap(), 0, slen);
1121 if (lphttpHdr->lpszValue)
1123 memcpy(lphttpHdr->lpszValue, value, slen);
1124 bSuccess = TRUE;
1126 else
1128 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1131 else if (lphttpHdr->lpszValue)
1133 if (dwModifier & HTTP_ADDHDR_FLAG_REPLACE)
1135 LPSTR lpsztmp;
1136 INT len;
1138 len = strlen(value);
1140 if (len <= 0)
1142 //! if custom header delete from array
1143 HeapFree(GetProcessHeap(), 0, lphttpHdr->lpszValue);
1144 lphttpHdr->lpszValue = NULL;
1145 bSuccess = TRUE;
1147 else
1149 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1150 if (lpsztmp)
1152 lphttpHdr->lpszValue = lpsztmp;
1153 strcpy(lpsztmp, value);
1154 bSuccess = TRUE;
1156 else
1158 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1162 else if (dwModifier & COALESCEFLASG)
1164 LPSTR lpsztmp;
1165 CHAR ch = 0;
1166 INT len = 0;
1167 INT origlen = strlen(lphttpHdr->lpszValue);
1168 INT valuelen = strlen(value);
1170 if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA)
1172 ch = ',';
1173 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1175 else if (dwModifier & HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1177 ch = ';';
1178 lphttpHdr->wFlags |= HDR_COMMADELIMITED;
1181 len = origlen + valuelen + (ch > 0) ? 1 : 0;
1183 lpsztmp = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lphttpHdr->lpszValue, len+1);
1184 if (lpsztmp)
1186 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1187 if (ch > 0)
1189 lphttpHdr->lpszValue[origlen] = ch;
1190 origlen++;
1193 memcpy(&lphttpHdr->lpszValue[origlen], value, valuelen);
1194 lphttpHdr->lpszValue[len] = '\0';
1195 bSuccess = TRUE;
1197 else
1199 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1204 return bSuccess;
1208 /***********************************************************************
1209 * HTTP_CloseConnection (internal)
1211 * Close socket connection
1214 VOID HTTP_CloseConnection(LPWININETHTTPREQA lpwhr)
1216 if (lpwhr->nSocketFD != INVALID_SOCKET)
1218 close(lpwhr->nSocketFD);
1219 lpwhr->nSocketFD = INVALID_SOCKET;
1224 /***********************************************************************
1225 * HTTP_CloseHTTPRequestHandle (internal)
1227 * Deallocate request handle
1230 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr)
1232 int i;
1234 TRACE("\n");
1236 if (lpwhr->nSocketFD != INVALID_SOCKET)
1237 HTTP_CloseConnection(lpwhr);
1239 if (lpwhr->lpszPath)
1240 HeapFree(GetProcessHeap(), 0, lpwhr->lpszPath);
1241 if (lpwhr->lpszVerb)
1242 HeapFree(GetProcessHeap(), 0, lpwhr->lpszVerb);
1243 if (lpwhr->lpszHostName)
1244 HeapFree(GetProcessHeap(), 0, lpwhr->lpszHostName);
1246 for (i = 0; i <= HTTP_QUERY_MAX; i++)
1248 if (lpwhr->StdHeaders[i].lpszField)
1249 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszField);
1250 if (lpwhr->StdHeaders[i].lpszValue)
1251 HeapFree(GetProcessHeap(), 0, lpwhr->StdHeaders[i].lpszValue);
1254 for (i = 0; i < lpwhr->nCustHeaders; i++)
1256 if (lpwhr->pCustHeaders[i].lpszField)
1257 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszField);
1258 if (lpwhr->pCustHeaders[i].lpszValue)
1259 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders[i].lpszValue);
1262 HeapFree(GetProcessHeap(), 0, lpwhr->pCustHeaders);
1263 HeapFree(GetProcessHeap(), 0, lpwhr);
1267 /***********************************************************************
1268 * HTTP_CloseHTTPSessionHandle (internal)
1270 * Deallocate session handle
1273 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs)
1275 TRACE("\n");
1277 if (lpwhs->lpszServerName)
1278 HeapFree(GetProcessHeap(), 0, lpwhs->lpszServerName);
1279 if (lpwhs->lpszUserName)
1280 HeapFree(GetProcessHeap(), 0, lpwhs->lpszUserName);
1281 HeapFree(GetProcessHeap(), 0, lpwhs);
1285 /***********************************************************************
1286 * HTTP_GetCustomHeaderIndex (internal)
1288 * Return index of custom header from header array
1291 INT HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr, LPCSTR lpszField)
1293 INT index;
1295 TRACE("%s\n", lpszField);
1297 for (index = 0; index < lpwhr->nCustHeaders; index++)
1299 if (!strcasecmp(lpwhr->pCustHeaders[index].lpszField, lpszField))
1300 break;
1304 if (index >= lpwhr->nCustHeaders)
1305 index = -1;
1307 TRACE("Return: %d\n", index);
1308 return index;
1312 /***********************************************************************
1313 * HTTP_InsertCustomHeader (internal)
1315 * Insert header into array
1318 INT HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr, LPHTTPHEADERA lpHdr)
1320 INT count;
1321 LPHTTPHEADERA lph = NULL;
1323 TRACE("%s: %s\n", lpHdr->lpszField, lpHdr->lpszValue);
1324 count = lpwhr->nCustHeaders + 1;
1325 if (count > 1)
1326 lph = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, lpwhr->pCustHeaders, sizeof(HTTPHEADERA) * count);
1327 else
1328 lph = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HTTPHEADERA) * count);
1330 if (NULL != lph)
1332 lpwhr->pCustHeaders = lph;
1333 lpwhr->pCustHeaders[count-1].lpszField = HTTP_strdup(lpHdr->lpszField);
1334 lpwhr->pCustHeaders[count-1].lpszValue = HTTP_strdup(lpHdr->lpszValue);
1335 lpwhr->pCustHeaders[count-1].wFlags = lpHdr->wFlags;
1336 lpwhr->pCustHeaders[count-1].wCount= lpHdr->wCount;
1337 lpwhr->nCustHeaders++;
1339 else
1341 INTERNET_SetLastError(ERROR_OUTOFMEMORY);
1342 count = 0;
1345 TRACE("%d <--\n", count-1);
1346 return count - 1;
1350 /***********************************************************************
1351 * HTTP_DeleteCustomHeader (internal)
1353 * Delete header from array
1356 BOOL HTTP_DeleteCustomHeader(INT index)
1358 TRACE("\n");
1359 return FALSE;