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>
43 #define NO_SHLWAPI_STREAM
47 #include "wine/debug.h"
49 WINE_DEFAULT_DEBUG_CHANNEL(wininet
);
51 #define HTTPHEADER " HTTP/1.0"
52 #define HTTPHOSTHEADER "\r\nHost: "
53 #define MAXHOSTNAME 100
54 #define MAX_FIELD_VALUE_LEN 256
55 #define MAX_FIELD_LEN 256
58 #define HTTP_REFERER "Referer"
59 #define HTTP_ACCEPT "Accept"
61 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
62 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
63 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
64 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
65 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
66 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
67 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
70 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
);
71 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr
,
72 void *Buffer
, int BytesToWrite
);
73 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr
,
74 void *Buffer
, int BytesToRead
);
75 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
);
76 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
);
77 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
);
78 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
);
79 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
);
80 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
);
81 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
);
83 inline static LPSTR
HTTP_strdup( LPCSTR str
)
85 LPSTR ret
= HeapAlloc( GetProcessHeap(), 0, strlen(str
) + 1 );
86 if (ret
) strcpy( ret
, str
);
90 /***********************************************************************
91 * HttpAddRequestHeadersA (WININET.@)
93 * Adds one or more HTTP header to the request handler
100 BOOL WINAPI
HttpAddRequestHeadersA(HINTERNET hHttpRequest
,
101 LPCSTR lpszHeader
, DWORD dwHeaderLength
, DWORD dwModifier
)
106 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
107 BOOL bSuccess
= FALSE
;
108 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
112 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
114 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
118 buffer
= HTTP_strdup(lpszHeader
);
125 while (*lpszEnd
!= '\0')
127 if (*lpszEnd
== '\r' && *(lpszEnd
+ 1) == '\n')
132 if (*lpszEnd
== '\0')
137 if (HTTP_InterpretHttpHeader(lpszStart
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
138 bSuccess
= HTTP_ProcessHeader(lpwhr
, field
, value
, dwModifier
| HTTP_ADDHDR_FLAG_REQ
);
140 lpszStart
= lpszEnd
+ 2; /* Jump over \0\n */
144 HeapFree(GetProcessHeap(), 0, buffer
);
149 /***********************************************************************
150 * HttpOpenRequestA (WININET.@)
152 * Open a HTTP request handle
155 * HINTERNET a HTTP request handle on success
159 HINTERNET WINAPI
HttpOpenRequestA(HINTERNET hHttpSession
,
160 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
161 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
162 DWORD dwFlags
, DWORD dwContext
)
164 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
165 LPWININETAPPINFOA hIC
= NULL
;
169 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
171 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
174 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
177 * My tests seem to show that the windows version does not
178 * become asynchronous until after this point. And anyhow
179 * if this call was asynchronous then how would you get the
180 * necessary HINTERNET pointer returned by this function.
182 * I am leaving this here just in case I am wrong
184 * if (hIC->hdr.dwFlags & INTERNET_FLAG_ASYNC)
188 WORKREQUEST workRequest
;
190 workRequest
.asyncall
= HTTPOPENREQUESTA
;
191 workRequest
.HFTPSESSION
= (DWORD
)hHttpSession
;
192 workRequest
.LPSZVERB
= (DWORD
)HTTP_strdup(lpszVerb
);
193 workRequest
.LPSZOBJECTNAME
= (DWORD
)HTTP_strdup(lpszObjectName
);
195 workRequest
.LPSZVERSION
= (DWORD
)HTTP_strdup(lpszVersion
);
197 workRequest
.LPSZVERSION
= 0;
199 workRequest
.LPSZREFERRER
= (DWORD
)HTTP_strdup(lpszReferrer
);
201 workRequest
.LPSZREFERRER
= 0;
202 workRequest
.LPSZACCEPTTYPES
= (DWORD
)lpszAcceptTypes
;
203 workRequest
.DWFLAGS
= dwFlags
;
204 workRequest
.DWCONTEXT
= dwContext
;
206 INTERNET_AsyncCall(&workRequest
);
211 return HTTP_HttpOpenRequestA(hHttpSession
, lpszVerb
, lpszObjectName
,
212 lpszVersion
, lpszReferrer
, lpszAcceptTypes
, dwFlags
, dwContext
);
217 /***********************************************************************
218 * HTTP_HttpOpenRequestA (internal)
220 * Open a HTTP request handle
223 * HINTERNET a HTTP request handle on success
227 HINTERNET WINAPI
HTTP_HttpOpenRequestA(HINTERNET hHttpSession
,
228 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
229 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
230 DWORD dwFlags
, DWORD dwContext
)
232 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
233 LPWININETAPPINFOA hIC
= NULL
;
234 LPWININETHTTPREQA lpwhr
;
238 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
240 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
244 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
246 lpwhr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPREQA
));
249 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
250 return (HINTERNET
) NULL
;
253 lpwhr
->hdr
.htype
= WH_HHTTPREQ
;
254 lpwhr
->hdr
.lpwhparent
= hHttpSession
;
255 lpwhr
->hdr
.dwFlags
= dwFlags
;
256 lpwhr
->hdr
.dwContext
= dwContext
;
257 lpwhr
->nSocketFD
= -1;
259 if (NULL
!= lpszObjectName
&& strlen(lpszObjectName
)) {
262 rc
= UrlEscapeA(lpszObjectName
, NULL
, &needed
, URL_ESCAPE_SPACES_ONLY
);
264 needed
= strlen(lpszObjectName
)+1;
265 lpwhr
->lpszPath
= HeapAlloc(GetProcessHeap(), 0, needed
);
266 rc
= UrlEscapeA(lpszObjectName
, lpwhr
->lpszPath
, &needed
,
267 URL_ESCAPE_SPACES_ONLY
);
270 ERR("Unable to escape string!(%s) (%ld)\n",lpszObjectName
,rc
);
271 strcpy(lpwhr
->lpszPath
,lpszObjectName
);
275 if (NULL
!= lpszReferrer
&& strlen(lpszReferrer
))
276 HTTP_ProcessHeader(lpwhr
, HTTP_REFERER
, lpszReferrer
, HTTP_ADDHDR_FLAG_COALESCE
);
279 if (NULL
!= lpszAcceptTypes
&& strlen(*lpszAcceptTypes
))
280 HTTP_ProcessHeader(lpwhr
, HTTP_ACCEPT
, *lpszAcceptTypes
, HTTP_ADDHDR_FLAG_COALESCE
);
282 if (NULL
== lpszVerb
)
283 lpwhr
->lpszVerb
= HTTP_strdup("GET");
284 else if (strlen(lpszVerb
))
285 lpwhr
->lpszVerb
= HTTP_strdup(lpszVerb
);
287 if (NULL
!= lpszReferrer
)
289 char buf
[MAXHOSTNAME
];
290 URL_COMPONENTSA UrlComponents
;
292 UrlComponents
.lpszExtraInfo
= NULL
;
293 UrlComponents
.lpszPassword
= NULL
;
294 UrlComponents
.lpszScheme
= NULL
;
295 UrlComponents
.lpszUrlPath
= NULL
;
296 UrlComponents
.lpszUserName
= NULL
;
297 UrlComponents
.lpszHostName
= buf
;
298 UrlComponents
.dwHostNameLength
= MAXHOSTNAME
;
300 InternetCrackUrlA(lpszReferrer
, 0, 0, &UrlComponents
);
301 if (strlen(UrlComponents
.lpszHostName
))
302 lpwhr
->lpszHostName
= HTTP_strdup(UrlComponents
.lpszHostName
);
304 lpwhr
->lpszHostName
= HTTP_strdup(lpwhs
->lpszServerName
);
307 if (hIC
->lpfnStatusCB
)
309 INTERNET_ASYNC_RESULT iar
;
311 iar
.dwResult
= (DWORD
)lpwhr
;
312 iar
.dwError
= ERROR_SUCCESS
;
314 SendAsyncCallback(hIC
, hHttpSession
, dwContext
,
315 INTERNET_STATUS_HANDLE_CREATED
, &iar
,
316 sizeof(INTERNET_ASYNC_RESULT
));
320 * A STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on windows
324 * According to my tests. The name is not resolved until a request is Opened
326 SendAsyncCallback(hIC
, hHttpSession
, dwContext
,
327 INTERNET_STATUS_RESOLVING_NAME
,
328 lpwhs
->lpszServerName
,
329 strlen(lpwhs
->lpszServerName
)+1);
331 if (!GetAddress(lpwhs
->lpszServerName
, lpwhs
->nServerPort
,
332 &lpwhs
->phostent
, &lpwhs
->socketAddress
))
334 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
338 SendAsyncCallback(hIC
, hHttpSession
, lpwhr
->hdr
.dwContext
,
339 INTERNET_STATUS_NAME_RESOLVED
,
340 &(lpwhs
->socketAddress
),
341 sizeof(struct sockaddr_in
));
344 return (HINTERNET
) lpwhr
;
348 /***********************************************************************
349 * HttpQueryInfoA (WININET.@)
351 * Queries for information about an HTTP request
358 BOOL WINAPI
HttpQueryInfoA(HINTERNET hHttpRequest
, DWORD dwInfoLevel
,
359 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
, LPDWORD lpdwIndex
)
361 LPHTTPHEADERA lphttpHdr
= NULL
;
362 BOOL bSuccess
= FALSE
;
363 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
365 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel
, dwInfoLevel
);
367 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
369 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
373 /* Find requested header structure */
374 if ((dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
) == HTTP_QUERY_CUSTOM
)
376 INT index
= HTTP_GetCustomHeaderIndex(lpwhr
, (LPSTR
)lpBuffer
);
381 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
385 INT index
= dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
;
387 if (index
== HTTP_QUERY_RAW_HEADERS_CRLF
|| index
== HTTP_QUERY_RAW_HEADERS
)
389 INT i
, delim
, size
= 0, cnt
= 0;
391 delim
= index
== HTTP_QUERY_RAW_HEADERS_CRLF
? 2 : 1;
393 /* Calculate length of custom reuqest headers */
394 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
396 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->pCustHeaders
[i
].lpszField
&&
397 lpwhr
->pCustHeaders
[i
].lpszValue
)
399 size
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
400 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + delim
+ 2;
404 /* Calculate the length of stadard request headers */
405 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
407 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->StdHeaders
[i
].lpszField
&&
408 lpwhr
->StdHeaders
[i
].lpszValue
)
410 size
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
411 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + delim
+ 2;
416 if (size
+ 1 > *lpdwBufferLength
)
418 *lpdwBufferLength
= size
+ 1;
419 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
423 /* Append standard request heades */
424 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
426 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
427 lpwhr
->StdHeaders
[i
].lpszField
&&
428 lpwhr
->StdHeaders
[i
].lpszValue
)
430 cnt
+= sprintf(lpBuffer
+ cnt
, "%s: %s%s", lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
,
431 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
435 /* Append custom request heades */
436 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
438 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
439 lpwhr
->pCustHeaders
[i
].lpszField
&&
440 lpwhr
->pCustHeaders
[i
].lpszValue
)
442 cnt
+= sprintf(lpBuffer
+ cnt
, "%s: %s%s",
443 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
,
444 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
448 strcpy(lpBuffer
+ cnt
, index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "");
450 *lpdwBufferLength
= cnt
+ delim
;
454 else if (index
>= 0 && index
<= HTTP_QUERY_MAX
&& lpwhr
->StdHeaders
[index
].lpszValue
)
456 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
462 /* Ensure header satisifies requested attributes */
463 if ((dwInfoLevel
& HTTP_QUERY_FLAG_REQUEST_HEADERS
) &&
464 (~lphttpHdr
->wFlags
& HDR_ISREQUEST
))
467 /* coalesce value to reuqested type */
468 if (dwInfoLevel
& HTTP_QUERY_FLAG_NUMBER
)
470 *(int *)lpBuffer
= atoi(lphttpHdr
->lpszValue
);
473 else if (dwInfoLevel
& HTTP_QUERY_FLAG_SYSTEMTIME
)
479 tmpTime
= ConvertTimeString(lphttpHdr
->lpszValue
);
481 tmpTM
= *gmtime(&tmpTime
);
482 STHook
= (SYSTEMTIME
*) lpBuffer
;
486 STHook
->wDay
= tmpTM
.tm_mday
;
487 STHook
->wHour
= tmpTM
.tm_hour
;
488 STHook
->wMilliseconds
= 0;
489 STHook
->wMinute
= tmpTM
.tm_min
;
490 STHook
->wDayOfWeek
= tmpTM
.tm_wday
;
491 STHook
->wMonth
= tmpTM
.tm_mon
+ 1;
492 STHook
->wSecond
= tmpTM
.tm_sec
;
493 STHook
->wYear
= tmpTM
.tm_year
;
497 else if (dwInfoLevel
& HTTP_QUERY_FLAG_COALESCE
)
499 if (*lpdwIndex
>= lphttpHdr
->wCount
)
501 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND
);
505 /* Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len); */
511 INT len
= strlen(lphttpHdr
->lpszValue
);
513 if (len
+ 1 > *lpdwBufferLength
)
515 *lpdwBufferLength
= len
+ 1;
516 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
520 strncpy(lpBuffer
, lphttpHdr
->lpszValue
, len
);
521 ((char*)lpBuffer
)[len
]=0;
522 *lpdwBufferLength
= len
;
527 TRACE("%d <--\n", bSuccess
);
532 /***********************************************************************
533 * HttpSendRequestExA (WININET.@)
535 * Sends the specified request to the HTTP server and allows chunked
538 BOOL WINAPI
HttpSendRequestExA(HINTERNET hRequest
,
539 LPINTERNET_BUFFERSA lpBuffersIn
,
540 LPINTERNET_BUFFERSA lpBuffersOut
,
541 DWORD dwFlags
, DWORD dwContext
)
543 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest
, lpBuffersIn
,
544 lpBuffersOut
, dwFlags
, dwContext
);
548 /***********************************************************************
549 * HttpSendRequestA (WININET.@)
551 * Sends the specified request to the HTTP server
558 BOOL WINAPI
HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
559 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
561 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
562 LPWININETHTTPSESSIONA lpwhs
= NULL
;
563 LPWININETAPPINFOA hIC
= NULL
;
565 TRACE("0x%08lx\n", (unsigned long)hHttpRequest
);
567 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
569 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
573 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
574 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
576 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
580 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
581 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
583 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
587 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
589 WORKREQUEST workRequest
;
591 workRequest
.asyncall
= HTTPSENDREQUESTA
;
592 workRequest
.HFTPSESSION
= (DWORD
)hHttpRequest
;
594 workRequest
.LPSZHEADER
= (DWORD
)HTTP_strdup(lpszHeaders
);
596 workRequest
.LPSZHEADER
= 0;
597 workRequest
.DWHEADERLENGTH
= dwHeaderLength
;
598 workRequest
.LPOPTIONAL
= (DWORD
)lpOptional
;
599 workRequest
.DWOPTIONALLENGTH
= dwOptionalLength
;
601 INTERNET_AsyncCall(&workRequest
);
603 * This is from windows. I do not know what the name is
610 return HTTP_HttpSendRequestA(hHttpRequest
, lpszHeaders
,
611 dwHeaderLength
, lpOptional
, dwOptionalLength
);
616 /***********************************************************************
617 * HTTP_HttpSendRequestA (internal)
619 * Sends the specified request to the HTTP server
626 BOOL WINAPI
HTTP_HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
627 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
631 BOOL bSuccess
= FALSE
;
632 LPSTR requestString
= NULL
;
633 INT requestStringLen
;
635 INT headerLength
= 0;
636 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
637 LPWININETHTTPSESSIONA lpwhs
= NULL
;
638 LPWININETAPPINFOA hIC
= NULL
;
640 TRACE("--> 0x%08lx\n", (ULONG
)hHttpRequest
);
642 /* Verify our tree of internet handles */
643 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
645 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
649 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
650 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
652 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
656 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
657 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
659 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
663 /* Clear any error information */
664 INTERNET_SetLastError(0);
667 /* We must have a verb */
668 if (NULL
== lpwhr
->lpszVerb
)
673 /* If we don't have a path we set it to root */
674 if (NULL
== lpwhr
->lpszPath
)
675 lpwhr
->lpszPath
= HTTP_strdup("/");
677 if(lpwhr
->lpszPath
[0] != '/') /* not an absolute path ?? --> fix it !! */
679 char *fixurl
= HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr
->lpszPath
) + 2);
681 strcpy(fixurl
+ 1, lpwhr
->lpszPath
);
682 HeapFree( GetProcessHeap(), 0, lpwhr
->lpszPath
);
683 lpwhr
->lpszPath
= fixurl
;
686 /* Calculate length of request string */
688 strlen(lpwhr
->lpszVerb
) +
689 strlen(lpwhr
->lpszPath
) +
690 (lpwhr
->lpszHostName
? (strlen(HTTPHOSTHEADER
) + strlen(lpwhr
->lpszHostName
)) : 0) +
694 /* Add length of passed headers */
697 headerLength
= -1 == dwHeaderLength
? strlen(lpszHeaders
) : dwHeaderLength
;
698 requestStringLen
+= headerLength
+ 2; /* \r\n */
701 /* Calculate length of custom request headers */
702 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
704 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
706 requestStringLen
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
707 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + 4; /*: \r\n */
711 /* Calculate the length of standard request headers */
712 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
714 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
716 requestStringLen
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
717 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + 4; /*: \r\n */
721 /* Allocate string to hold entire request */
722 requestString
= HeapAlloc(GetProcessHeap(), 0, requestStringLen
+ 1);
723 if (NULL
== requestString
)
725 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
729 /* Build request string */
730 cnt
= sprintf(requestString
, "%s %s%s%s",
733 lpwhr
->lpszHostName
? (HTTPHEADER HTTPHOSTHEADER
) : HTTPHEADER
,
734 lpwhr
->lpszHostName
? lpwhr
->lpszHostName
: "");
736 /* Append standard request headers */
737 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
739 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
741 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
742 lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
);
746 /* Append custom request heades */
747 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
749 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
751 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
752 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
);
756 /* Append passed request headers */
759 strcpy(requestString
+ cnt
, "\r\n");
761 strcpy(requestString
+ cnt
, lpszHeaders
);
765 /* Set termination string for request */
766 strcpy(requestString
+ cnt
, "\r\n\r\n");
768 TRACE("(%s) len(%d)\n", requestString
, requestStringLen
);
769 /* Send the request and store the results */
770 if (!HTTP_OpenConnection(lpwhr
))
773 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
774 INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
776 cnt
= send(lpwhr
->nSocketFD
, requestString
, requestStringLen
, 0);
778 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
779 INTERNET_STATUS_REQUEST_SENT
,
780 &requestStringLen
,sizeof(DWORD
));
782 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
783 INTERNET_STATUS_RECEIVING_RESPONSE
, NULL
, 0);
788 responseLen
= HTTP_GetResponseHeaders(lpwhr
);
792 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
793 INTERNET_STATUS_RESPONSE_RECEIVED
, &responseLen
,
799 HeapFree(GetProcessHeap(), 0, requestString
);
802 if (hIC
->lpfnStatusCB
)
804 INTERNET_ASYNC_RESULT iar
;
806 iar
.dwResult
= (DWORD
)bSuccess
;
807 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
809 SendAsyncCallback(hIC
, hHttpRequest
, lpwhr
->hdr
.dwContext
,
810 INTERNET_STATUS_REQUEST_COMPLETE
, &iar
,
811 sizeof(INTERNET_ASYNC_RESULT
));
819 /***********************************************************************
820 * HTTP_Connect (internal)
822 * Create http session handle
825 * HINTERNET a session handle on success
829 HINTERNET
HTTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
830 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
831 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
833 BOOL bSuccess
= FALSE
;
834 LPWININETAPPINFOA hIC
= NULL
;
835 LPWININETHTTPSESSIONA lpwhs
= NULL
;
839 if (((LPWININETHANDLEHEADER
)hInternet
)->htype
!= WH_HINIT
)
842 hIC
= (LPWININETAPPINFOA
) hInternet
;
843 hIC
->hdr
.dwContext
= dwContext
;
845 lpwhs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPSESSIONA
));
848 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
853 * According to my tests. The name is not resolved until a request is sent
856 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
857 nServerPort
= INTERNET_DEFAULT_HTTP_PORT
;
859 lpwhs
->hdr
.htype
= WH_HHTTPSESSION
;
860 lpwhs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
861 lpwhs
->hdr
.dwFlags
= dwFlags
;
862 lpwhs
->hdr
.dwContext
= dwContext
;
863 if (NULL
!= lpszServerName
)
864 lpwhs
->lpszServerName
= HTTP_strdup(lpszServerName
);
865 if (NULL
!= lpszUserName
)
866 lpwhs
->lpszUserName
= HTTP_strdup(lpszUserName
);
867 lpwhs
->nServerPort
= nServerPort
;
869 if (hIC
->lpfnStatusCB
)
871 INTERNET_ASYNC_RESULT iar
;
873 iar
.dwResult
= (DWORD
)lpwhs
;
874 iar
.dwError
= ERROR_SUCCESS
;
876 SendAsyncCallback(hIC
, hInternet
, dwContext
,
877 INTERNET_STATUS_HANDLE_CREATED
, &iar
,
878 sizeof(INTERNET_ASYNC_RESULT
));
884 if (!bSuccess
&& lpwhs
)
886 HeapFree(GetProcessHeap(), 0, lpwhs
);
891 * a INTERNET_STATUS_REQUEST_COMPLETE is NOT sent here as per my tests on
896 return (HINTERNET
)lpwhs
;
900 /***********************************************************************
901 * HTTP_OpenConnection (internal)
903 * Connect to a web server
910 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
)
912 BOOL bSuccess
= FALSE
;
914 LPWININETHTTPSESSIONA lpwhs
;
915 LPWININETAPPINFOA hIC
= NULL
;
920 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
922 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
926 lpwhs
= (LPWININETHTTPSESSIONA
)lpwhr
->hdr
.lpwhparent
;
928 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
929 SendAsyncCallback(hIC
, lpwhr
, lpwhr
->hdr
.dwContext
,
930 INTERNET_STATUS_CONNECTING_TO_SERVER
,
931 &(lpwhs
->socketAddress
),
932 sizeof(struct sockaddr_in
));
934 lpwhr
->nSocketFD
= socket(lpwhs
->phostent
->h_addrtype
,SOCK_STREAM
,0);
935 if (lpwhr
->nSocketFD
== -1)
937 WARN("Socket creation failed\n");
941 result
= connect(lpwhr
->nSocketFD
, (struct sockaddr
*)&lpwhs
->socketAddress
,
942 sizeof(lpwhs
->socketAddress
));
946 WARN("Unable to connect to host (%s)\n", strerror(errno
));
950 SendAsyncCallback(hIC
, lpwhr
, lpwhr
->hdr
.dwContext
,
951 INTERNET_STATUS_CONNECTED_TO_SERVER
,
952 &(lpwhs
->socketAddress
),
953 sizeof(struct sockaddr_in
));
958 TRACE("%d <--\n", bSuccess
);
963 /***********************************************************************
964 * HTTP_GetResponseHeaders (internal)
966 * Read server response
973 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
)
976 CHAR buffer
[MAX_REPLY_LEN
];
977 DWORD buflen
= MAX_REPLY_LEN
;
978 BOOL bSuccess
= FALSE
;
980 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
984 if (lpwhr
->nSocketFD
== -1)
988 * HACK peek at the buffer
990 rc
= recv(lpwhr
->nSocketFD
,buffer
,buflen
,MSG_PEEK
);
993 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
995 buflen
= MAX_REPLY_LEN
;
996 if (!INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
999 if (strncmp(buffer
, "HTTP", 4) != 0)
1003 HTTP_ProcessHeader(lpwhr
, "Status", buffer
+9, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
1005 /* Parse each response line */
1008 buflen
= MAX_REPLY_LEN
;
1009 if (INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
1011 if (!HTTP_InterpretHttpHeader(buffer
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
1014 HTTP_ProcessHeader(lpwhr
, field
, value
, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
1036 /***********************************************************************
1037 * HTTP_InterpretHttpHeader (internal)
1039 * Parse server response
1046 INT
stripSpaces(LPCSTR lpszSrc
, LPSTR lpszStart
, INT
*len
)
1053 while (*lpszSrc
== ' ' && *lpszSrc
!= '\0')
1057 while(*lpsztmp
!= '\0')
1059 if (*lpsztmp
!= ' ')
1060 srclen
= lpsztmp
- lpszSrc
+ 1;
1065 *len
= min(*len
, srclen
);
1066 strncpy(lpszStart
, lpszSrc
, *len
);
1067 lpszStart
[*len
] = '\0';
1073 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
)
1076 BOOL bSuccess
= FALSE
;
1083 pd
= strchr(buffer
, ':');
1087 if (stripSpaces(buffer
, field
, &fieldlen
) > 0)
1089 if (stripSpaces(pd
+1, value
, &valuelen
) > 0)
1094 TRACE("%d: field(%s) Value(%s)\n", bSuccess
, field
, value
);
1099 /***********************************************************************
1100 * HTTP_GetStdHeaderIndex (internal)
1102 * Lookup field index in standard http header array
1104 * FIXME: This should be stuffed into a hash table
1106 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
)
1110 if (!strcasecmp(lpszField
, "Content-Length"))
1111 index
= HTTP_QUERY_CONTENT_LENGTH
;
1112 else if (!strcasecmp(lpszField
,"Status"))
1113 index
= HTTP_QUERY_STATUS_CODE
;
1114 else if (!strcasecmp(lpszField
,"Content-Type"))
1115 index
= HTTP_QUERY_CONTENT_TYPE
;
1116 else if (!strcasecmp(lpszField
,"Last-Modified"))
1117 index
= HTTP_QUERY_LAST_MODIFIED
;
1118 else if (!strcasecmp(lpszField
,"Location"))
1119 index
= HTTP_QUERY_LOCATION
;
1120 else if (!strcasecmp(lpszField
,"Accept"))
1121 index
= HTTP_QUERY_ACCEPT
;
1122 else if (!strcasecmp(lpszField
,"Referer"))
1123 index
= HTTP_QUERY_REFERER
;
1124 else if (!strcasecmp(lpszField
,"Content-Transfer-Encoding"))
1125 index
= HTTP_QUERY_CONTENT_TRANSFER_ENCODING
;
1126 else if (!strcasecmp(lpszField
,"Date"))
1127 index
= HTTP_QUERY_DATE
;
1128 else if (!strcasecmp(lpszField
,"Server"))
1129 index
= HTTP_QUERY_SERVER
;
1130 else if (!strcasecmp(lpszField
,"Connection"))
1131 index
= HTTP_QUERY_CONNECTION
;
1132 else if (!strcasecmp(lpszField
,"ETag"))
1133 index
= HTTP_QUERY_ETAG
;
1134 else if (!strcasecmp(lpszField
,"Accept-Ranges"))
1135 index
= HTTP_QUERY_ACCEPT_RANGES
;
1136 else if (!strcasecmp(lpszField
,"Expires"))
1137 index
= HTTP_QUERY_EXPIRES
;
1138 else if (!strcasecmp(lpszField
,"Mime-Version"))
1139 index
= HTTP_QUERY_MIME_VERSION
;
1140 else if (!strcasecmp(lpszField
,"Pragma"))
1141 index
= HTTP_QUERY_PRAGMA
;
1142 else if (!strcasecmp(lpszField
,"Cache-Control"))
1143 index
= HTTP_QUERY_CACHE_CONTROL
;
1144 else if (!strcasecmp(lpszField
,"Content-Length"))
1145 index
= HTTP_QUERY_CONTENT_LENGTH
;
1146 else if (!strcasecmp(lpszField
,"User-Agent"))
1147 index
= HTTP_QUERY_USER_AGENT
;
1150 TRACE("Couldn't find %s in standard header table\n", lpszField
);
1157 /***********************************************************************
1158 * HTTP_ProcessHeader (internal)
1160 * Stuff header into header tables according to <dwModifier>
1164 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1166 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
)
1168 LPHTTPHEADERA lphttpHdr
= NULL
;
1169 BOOL bSuccess
= FALSE
;
1172 TRACE("--> %s:%s - 0x%08x\n", field
, value
, (unsigned int)dwModifier
);
1174 /* Adjust modifier flags */
1175 if (dwModifier
& COALESCEFLASG
)
1176 dwModifier
|= HTTP_ADDHDR_FLAG_ADD
;
1178 /* Try to get index into standard header array */
1179 index
= HTTP_GetStdHeaderIndex(field
);
1182 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
1184 else /* Find or create new custom header */
1186 index
= HTTP_GetCustomHeaderIndex(lpwhr
, field
);
1189 if (dwModifier
& HTTP_ADDHDR_FLAG_ADD_IF_NEW
)
1193 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
1199 hdr
.lpszField
= (LPSTR
)field
;
1200 hdr
.lpszValue
= (LPSTR
)value
;
1201 hdr
.wFlags
= hdr
.wCount
= 0;
1203 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1204 hdr
.wFlags
|= HDR_ISREQUEST
;
1206 index
= HTTP_InsertCustomHeader(lpwhr
, &hdr
);
1211 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1212 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1214 lphttpHdr
->wFlags
&= ~HDR_ISREQUEST
;
1216 if (!lphttpHdr
->lpszValue
&& (dwModifier
& (HTTP_ADDHDR_FLAG_ADD
|HTTP_ADDHDR_FLAG_ADD_IF_NEW
)))
1220 if (!lpwhr
->StdHeaders
[index
].lpszField
)
1222 lphttpHdr
->lpszField
= HTTP_strdup(field
);
1224 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1225 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1228 slen
= strlen(value
) + 1;
1229 lphttpHdr
->lpszValue
= HeapAlloc(GetProcessHeap(), 0, slen
);
1230 if (lphttpHdr
->lpszValue
)
1232 memcpy(lphttpHdr
->lpszValue
, value
, slen
);
1237 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1240 else if (lphttpHdr
->lpszValue
)
1242 if (dwModifier
& HTTP_ADDHDR_FLAG_REPLACE
)
1247 len
= strlen(value
);
1251 /* if custom header delete from array */
1252 HeapFree(GetProcessHeap(), 0, lphttpHdr
->lpszValue
);
1253 lphttpHdr
->lpszValue
= NULL
;
1258 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1261 lphttpHdr
->lpszValue
= lpsztmp
;
1262 strcpy(lpsztmp
, value
);
1267 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1271 else if (dwModifier
& COALESCEFLASG
)
1276 INT origlen
= strlen(lphttpHdr
->lpszValue
);
1277 INT valuelen
= strlen(value
);
1279 if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA
)
1282 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1284 else if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON
)
1287 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1290 len
= origlen
+ valuelen
+ (ch
> 0) ? 1 : 0;
1292 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1295 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1298 lphttpHdr
->lpszValue
[origlen
] = ch
;
1302 memcpy(&lphttpHdr
->lpszValue
[origlen
], value
, valuelen
);
1303 lphttpHdr
->lpszValue
[len
] = '\0';
1308 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1317 /***********************************************************************
1318 * HTTP_CloseConnection (internal)
1320 * Close socket connection
1323 VOID
HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
)
1327 LPWININETHTTPSESSIONA lpwhs
= NULL
;
1328 LPWININETAPPINFOA hIC
= NULL
;
1330 TRACE("%p\n",lpwhr
);
1332 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
1333 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
1335 SendAsyncCallback(hIC
, lpwhr
, lpwhr
->hdr
.dwContext
,
1336 INTERNET_STATUS_CLOSING_CONNECTION
, 0, 0);
1338 if (lpwhr
->nSocketFD
!= -1)
1340 close(lpwhr
->nSocketFD
);
1341 lpwhr
->nSocketFD
= -1;
1344 SendAsyncCallback(hIC
, lpwhr
, lpwhr
->hdr
.dwContext
,
1345 INTERNET_STATUS_CONNECTION_CLOSED
, 0, 0);
1349 /***********************************************************************
1350 * HTTP_CloseHTTPRequestHandle (internal)
1352 * Deallocate request handle
1355 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr
)
1358 LPWININETHTTPSESSIONA lpwhs
= NULL
;
1359 LPWININETAPPINFOA hIC
= NULL
;
1363 if (lpwhr
->nSocketFD
!= -1)
1364 HTTP_CloseConnection(lpwhr
);
1366 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
1367 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
1369 SendAsyncCallback(hIC
, lpwhr
, lpwhr
->hdr
.dwContext
,
1370 INTERNET_STATUS_HANDLE_CLOSING
, lpwhr
,
1373 if (lpwhr
->lpszPath
)
1374 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszPath
);
1375 if (lpwhr
->lpszVerb
)
1376 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszVerb
);
1377 if (lpwhr
->lpszHostName
)
1378 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszHostName
);
1380 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
1382 if (lpwhr
->StdHeaders
[i
].lpszField
)
1383 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszField
);
1384 if (lpwhr
->StdHeaders
[i
].lpszValue
)
1385 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszValue
);
1388 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
1390 if (lpwhr
->pCustHeaders
[i
].lpszField
)
1391 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszField
);
1392 if (lpwhr
->pCustHeaders
[i
].lpszValue
)
1393 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszValue
);
1396 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
);
1397 HeapFree(GetProcessHeap(), 0, lpwhr
);
1401 /***********************************************************************
1402 * HTTP_CloseHTTPSessionHandle (internal)
1404 * Deallocate session handle
1407 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs
)
1409 LPWININETAPPINFOA hIC
= NULL
;
1412 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
1414 SendAsyncCallback(hIC
, lpwhs
, lpwhs
->hdr
.dwContext
,
1415 INTERNET_STATUS_HANDLE_CLOSING
, lpwhs
,
1418 if (lpwhs
->lpszServerName
)
1419 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszServerName
);
1420 if (lpwhs
->lpszUserName
)
1421 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszUserName
);
1422 HeapFree(GetProcessHeap(), 0, lpwhs
);
1426 /***********************************************************************
1427 * HTTP_GetCustomHeaderIndex (internal)
1429 * Return index of custom header from header array
1432 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
)
1436 TRACE("%s\n", lpszField
);
1438 for (index
= 0; index
< lpwhr
->nCustHeaders
; index
++)
1440 if (!strcasecmp(lpwhr
->pCustHeaders
[index
].lpszField
, lpszField
))
1445 if (index
>= lpwhr
->nCustHeaders
)
1448 TRACE("Return: %d\n", index
);
1453 /***********************************************************************
1454 * HTTP_InsertCustomHeader (internal)
1456 * Insert header into array
1459 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
)
1462 LPHTTPHEADERA lph
= NULL
;
1464 TRACE("--> %s: %s\n", lpHdr
->lpszField
, lpHdr
->lpszValue
);
1465 count
= lpwhr
->nCustHeaders
+ 1;
1467 lph
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpwhr
->pCustHeaders
, sizeof(HTTPHEADERA
) * count
);
1469 lph
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HTTPHEADERA
) * count
);
1473 lpwhr
->pCustHeaders
= lph
;
1474 lpwhr
->pCustHeaders
[count
-1].lpszField
= HTTP_strdup(lpHdr
->lpszField
);
1475 lpwhr
->pCustHeaders
[count
-1].lpszValue
= HTTP_strdup(lpHdr
->lpszValue
);
1476 lpwhr
->pCustHeaders
[count
-1].wFlags
= lpHdr
->wFlags
;
1477 lpwhr
->pCustHeaders
[count
-1].wCount
= lpHdr
->wCount
;
1478 lpwhr
->nCustHeaders
++;
1482 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1486 TRACE("%d <--\n", count
-1);
1491 /***********************************************************************
1492 * HTTP_DeleteCustomHeader (internal)
1494 * Delete header from array
1497 BOOL
HTTP_DeleteCustomHeader(INT index
)