2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
14 #include "debugtools.h"
19 #include <sys/types.h>
20 #ifdef HAVE_SYS_SOCKET_H
21 # include <sys/socket.h>
31 DEFAULT_DEBUG_CHANNEL(wininet
)
33 #define HTTPHEADER " HTTP/1.0"
34 #define HTTPHOSTHEADER "\r\nHost: "
35 #define MAXHOSTNAME 100
36 #define MAX_FIELD_VALUE_LEN 256
37 #define MAX_FIELD_LEN 256
40 #define HTTP_REFERER "Referer"
41 #define HTTP_ACCEPT "Accept"
43 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
44 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
45 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
46 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
47 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
48 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
49 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
52 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
);
53 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr
,
54 void *Buffer
, int BytesToWrite
);
55 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr
,
56 void *Buffer
, int BytesToRead
);
57 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
);
58 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
);
59 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
);
60 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
);
61 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
);
62 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
);
63 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
);
65 /***********************************************************************
66 * HttpAddRequestHeadersA (WININET.68)
68 * Adds one or more HTTP header to the request handler
75 INTERNETAPI BOOL WINAPI
HttpAddRequestHeadersA(HINTERNET hHttpRequest
,
76 LPCSTR lpszHeader
, DWORD dwHeaderLength
, DWORD dwModifier
)
81 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
82 BOOL bSuccess
= FALSE
;
83 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
85 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
87 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
91 buffer
= HEAP_strdupA(GetProcessHeap(), 0, lpszHeader
);
98 while (*lpszEnd
!= '\0')
100 if (*lpszEnd
== '\r' && *(lpszEnd
+ 1) == '\n')
105 if (*lpszEnd
== '\0')
110 if (HTTP_InterpretHttpHeader(lpszStart
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
111 bSuccess
= HTTP_ProcessHeader(lpwhr
, field
, value
, dwModifier
| HTTP_ADDHDR_FLAG_REQ
);
113 lpszStart
= lpszEnd
+ 2; /* Jump over \0\n */
117 HeapFree(GetProcessHeap(), 0, buffer
);
122 /***********************************************************************
123 * HttpOpenRequestA (WININET.72)
125 * Open a HTTP request handle
128 * HINTERNET a HTTP request handle on success
132 INTERNETAPI HINTERNET WINAPI
HttpOpenRequestA(HINTERNET hHttpSession
,
133 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
134 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
135 DWORD dwFlags
, DWORD dwContext
)
137 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
138 LPWININETAPPINFOA hIC
= NULL
;
142 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
144 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
148 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
150 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
152 WORKREQUEST workRequest
;
154 workRequest
.asyncall
= HTTPOPENREQUESTA
;
155 workRequest
.HFTPSESSION
= (DWORD
)hHttpSession
;
156 workRequest
.LPSZVERB
= (DWORD
)HEAP_strdupA(GetProcessHeap(), 0, lpszVerb
);
157 workRequest
.LPSZOBJECTNAME
= (DWORD
)HEAP_strdupA(GetProcessHeap(), 0, lpszObjectName
);
158 workRequest
.LPSZVERSION
= (DWORD
)HEAP_strdupA(GetProcessHeap(), 0, lpszVersion
);
159 workRequest
.LPSZREFERRER
= (DWORD
)HEAP_strdupA(GetProcessHeap(), 0, lpszReferrer
);
160 workRequest
.LPSZACCEPTTYPES
= (DWORD
)lpszAcceptTypes
;
161 workRequest
.DWFLAGS
= dwFlags
;
162 workRequest
.DWCONTEXT
= dwContext
;
164 return (HINTERNET
)INTERNET_AsyncCall(&workRequest
);
168 return HTTP_HttpOpenRequestA(hHttpSession
, lpszVerb
, lpszObjectName
,
169 lpszVersion
, lpszReferrer
, lpszAcceptTypes
, dwFlags
, dwContext
);
174 /***********************************************************************
175 * HTTP_HttpOpenRequestA (internal)
177 * Open a HTTP request handle
180 * HINTERNET a HTTP request handle on success
184 INTERNETAPI HINTERNET WINAPI
HTTP_HttpOpenRequestA(HINTERNET hHttpSession
,
185 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
186 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
187 DWORD dwFlags
, DWORD dwContext
)
189 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
190 LPWININETAPPINFOA hIC
= NULL
;
191 LPWININETHTTPREQA lpwhr
;
195 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
197 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
201 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
203 lpwhr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPREQA
));
206 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
207 return (HINTERNET
) NULL
;
210 lpwhr
->hdr
.htype
= WH_HHTTPREQ
;
211 lpwhr
->hdr
.lpwhparent
= hHttpSession
;
212 lpwhr
->hdr
.dwFlags
= dwFlags
;
213 lpwhr
->hdr
.dwContext
= dwContext
;
215 if (NULL
!= lpszObjectName
&& strlen(lpszObjectName
))
216 lpwhr
->lpszPath
= HEAP_strdupA(GetProcessHeap(), 0, lpszObjectName
);
218 if (NULL
!= lpszReferrer
&& strlen(lpszReferrer
))
219 HTTP_ProcessHeader(lpwhr
, HTTP_REFERER
, lpszReferrer
, HTTP_ADDHDR_FLAG_COALESCE
);
222 if (NULL
!= lpszAcceptTypes
&& strlen(*lpszAcceptTypes
))
223 HTTP_ProcessHeader(lpwhr
, HTTP_ACCEPT
, *lpszAcceptTypes
, HTTP_ADDHDR_FLAG_COALESCE
);
225 if (NULL
== lpszVerb
)
226 lpwhr
->lpszVerb
= HEAP_strdupA(GetProcessHeap(), 0, "GET");
227 else if (strlen(lpszVerb
))
228 lpwhr
->lpszVerb
= HEAP_strdupA(GetProcessHeap(), 0, lpszVerb
);
230 if (NULL
!= lpszReferrer
)
232 char buf
[MAXHOSTNAME
];
233 URL_COMPONENTSA UrlComponents
;
235 UrlComponents
.lpszExtraInfo
= NULL
;
236 UrlComponents
.lpszPassword
= NULL
;
237 UrlComponents
.lpszScheme
= NULL
;
238 UrlComponents
.lpszUrlPath
= NULL
;
239 UrlComponents
.lpszUserName
= NULL
;
240 UrlComponents
.lpszHostName
= buf
;
241 UrlComponents
.dwHostNameLength
= MAXHOSTNAME
;
243 InternetCrackUrlA(lpszReferrer
, 0, 0, &UrlComponents
);
244 if (strlen(UrlComponents
.lpszHostName
))
245 lpwhr
->lpszHostName
= HEAP_strdupA(GetProcessHeap(), 0, UrlComponents
.lpszHostName
);
247 lpwhr
->lpszHostName
= HEAP_strdupA(GetProcessHeap(), 0,
248 lpwhs
->lpszServerName
);
251 if (hIC
->lpfnStatusCB
)
253 INTERNET_ASYNC_RESULT iar
;
255 iar
.dwResult
= (DWORD
)lpwhr
;
256 iar
.dwError
= ERROR_SUCCESS
;
258 hIC
->lpfnStatusCB(hHttpSession
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
259 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
262 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
264 INTERNET_ASYNC_RESULT iar
;
266 iar
.dwResult
= (DWORD
)lpwhr
;
267 iar
.dwError
= lpwhr
? ERROR_SUCCESS
: INTERNET_GetLastError();
268 hIC
->lpfnStatusCB(hHttpSession
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
269 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
272 return (HINTERNET
) lpwhr
;
276 /***********************************************************************
277 * HttpQueryInfoA (WININET.74)
279 * Queries for information about an HTTP request
286 BOOL WINAPI
HttpQueryInfoA(HINTERNET hHttpRequest
, DWORD dwInfoLevel
,
287 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
, LPDWORD lpdwIndex
)
289 LPHTTPHEADERA lphttpHdr
= NULL
;
290 BOOL bSuccess
= FALSE
;
291 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
293 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel
, dwInfoLevel
);
295 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
297 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
301 /* Find requested header structure */
302 if ((dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
) == HTTP_QUERY_CUSTOM
)
304 INT index
= HTTP_GetCustomHeaderIndex(lpwhr
, (LPSTR
)lpBuffer
);
309 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
313 INT index
= dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
;
315 if (index
== HTTP_QUERY_RAW_HEADERS_CRLF
|| index
== HTTP_QUERY_RAW_HEADERS
)
317 INT i
, delim
, size
= 0, cnt
= 0;
319 delim
= index
== HTTP_QUERY_RAW_HEADERS_CRLF
? 2 : 1;
321 /* Calculate length of custom reuqest headers */
322 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
324 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->pCustHeaders
[i
].lpszField
&&
325 lpwhr
->pCustHeaders
[i
].lpszValue
)
327 size
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
328 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + delim
+ 2;
332 /* Calculate the length of stadard request headers */
333 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
335 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->StdHeaders
[i
].lpszField
&&
336 lpwhr
->StdHeaders
[i
].lpszValue
)
338 size
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
339 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + delim
+ 2;
345 if (size
+ 1 > *lpdwBufferLength
)
347 *lpdwBufferLength
= size
+ 1;
348 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
352 /* Append standard request heades */
353 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
355 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
356 lpwhr
->StdHeaders
[i
].lpszField
&&
357 lpwhr
->StdHeaders
[i
].lpszValue
)
359 cnt
+= sprintf(lpBuffer
+ cnt
, "%s: %s%s", lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
,
360 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
364 /* Append custom request heades */
365 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
367 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
368 lpwhr
->pCustHeaders
[i
].lpszField
&&
369 lpwhr
->pCustHeaders
[i
].lpszValue
)
371 cnt
+= sprintf(lpBuffer
+ cnt
, "%s: %s%s",
372 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
,
373 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
377 strcpy(lpBuffer
+ cnt
, index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "");
379 *lpdwBufferLength
= cnt
+ delim
;
383 else if (index
>= 0 && index
<= HTTP_QUERY_MAX
&& lpwhr
->StdHeaders
[index
].lpszValue
)
385 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
391 /* Ensure header satisifies requested attributes */
392 if ((dwInfoLevel
& HTTP_QUERY_FLAG_REQUEST_HEADERS
) &&
393 (~lphttpHdr
->wFlags
& HDR_ISREQUEST
))
396 /* coalesce value to reuqested type */
397 if (dwInfoLevel
& HTTP_QUERY_FLAG_NUMBER
)
399 *(int *)lpBuffer
= atoi(lphttpHdr
->lpszValue
);
402 else if (dwInfoLevel
& HTTP_QUERY_FLAG_SYSTEMTIME
)
408 tmpTime
= ConvertTimeString(lphttpHdr
->lpszValue
);
410 tmpTM
= *gmtime(&tmpTime
);
411 STHook
= (SYSTEMTIME
*) lpBuffer
;
415 STHook
->wDay
= tmpTM
.tm_mday
;
416 STHook
->wHour
= tmpTM
.tm_hour
;
417 STHook
->wMilliseconds
= 0;
418 STHook
->wMinute
= tmpTM
.tm_min
;
419 STHook
->wDayOfWeek
= tmpTM
.tm_wday
;
420 STHook
->wMonth
= tmpTM
.tm_mon
+ 1;
421 STHook
->wSecond
= tmpTM
.tm_sec
;
422 STHook
->wYear
= tmpTM
.tm_year
;
426 else if (dwInfoLevel
& HTTP_QUERY_FLAG_COALESCE
)
428 if (*lpdwIndex
>= lphttpHdr
->wCount
)
430 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND
);
434 //! Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len);
440 INT len
= strlen(lphttpHdr
->lpszValue
);
442 if (len
+ 1 > *lpdwBufferLength
)
444 *lpdwBufferLength
= len
+ 1;
445 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
449 strncpy(lpBuffer
, lphttpHdr
->lpszValue
, len
);
450 *lpdwBufferLength
= len
;
455 TRACE("%d <--\n", bSuccess
);
460 /***********************************************************************
461 * HttpSendRequestExA (WININET)
463 * Sends the specified request to the HTTP server and allows chunked
466 BOOL WINAPI
HttpSendRequestExA(HINTERNET hRequest
,
467 LPINTERNET_BUFFERSA lpBuffersIn
,
468 LPINTERNET_BUFFERSA lpBuffersOut
,
469 DWORD dwFlags
, DWORD dwContext
)
471 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest
, lpBuffersIn
,
472 lpBuffersOut
, dwFlags
, dwContext
);
476 /***********************************************************************
477 * HttpSendRequestA (WININET.76)
479 * Sends the specified request to the HTTP server
486 BOOL WINAPI
HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
487 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
489 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
490 LPWININETHTTPSESSIONA lpwhs
= NULL
;
491 LPWININETAPPINFOA hIC
= NULL
;
493 TRACE("0x%08lx\n", (unsigned long)hHttpRequest
);
495 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
497 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
501 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
502 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
504 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
508 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
509 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
511 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
515 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
517 WORKREQUEST workRequest
;
519 workRequest
.asyncall
= HTTPSENDREQUESTA
;
520 workRequest
.HFTPSESSION
= (DWORD
)hHttpRequest
;
521 workRequest
.LPSZHEADER
= (DWORD
)HEAP_strdupA(GetProcessHeap(), 0, lpszHeaders
);
522 workRequest
.DWHEADERLENGTH
= dwHeaderLength
;
523 workRequest
.LPOPTIONAL
= (DWORD
)lpOptional
;
524 workRequest
.DWOPTIONALLENGTH
= dwOptionalLength
;
526 return INTERNET_AsyncCall(&workRequest
);
530 return HTTP_HttpSendRequestA(hHttpRequest
, lpszHeaders
,
531 dwHeaderLength
, lpOptional
, dwOptionalLength
);
536 /***********************************************************************
537 * HTTP_HttpSendRequestA (internal)
539 * Sends the specified request to the HTTP server
546 BOOL WINAPI
HTTP_HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
547 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
551 BOOL bSuccess
= FALSE
;
552 LPSTR requestString
= NULL
;
553 INT requestStringLen
;
554 INT headerLength
= 0;
555 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
556 LPWININETHTTPSESSIONA lpwhs
= NULL
;
557 LPWININETAPPINFOA hIC
= NULL
;
559 TRACE("0x%08lx\n", (ULONG
)hHttpRequest
);
561 /* Verify our tree of internet handles */
562 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
564 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
568 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
569 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
571 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
575 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
576 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
578 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
582 /* Clear any error information */
583 INTERNET_SetLastError(0);
585 /* We must have a verb */
586 if (NULL
== lpwhr
->lpszVerb
)
591 /* If we don't have a path we set it to root */
592 if (NULL
== lpwhr
->lpszPath
)
593 lpwhr
->lpszPath
= HEAP_strdupA(GetProcessHeap(), 0, "/");
595 /* Calculate length of request string */
597 strlen(lpwhr
->lpszVerb
) +
598 strlen(lpwhr
->lpszPath
) +
599 (lpwhr
->lpszHostName
? (strlen(HTTPHOSTHEADER
) + strlen(lpwhr
->lpszHostName
)) : 0) +
603 /* Add length of passed headers */
606 headerLength
= -1 == dwHeaderLength
? strlen(lpszHeaders
) : dwHeaderLength
;
607 requestStringLen
+= headerLength
+ 2; /* \r\n */
610 /* Calculate length of custom request headers */
611 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
613 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
615 requestStringLen
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
616 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + 4; /*: \r\n */
620 /* Calculate the length of standard request headers */
621 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
623 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
625 requestStringLen
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
626 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + 4; /*: \r\n */
630 /* Allocate string to hold entire request */
631 requestString
= HeapAlloc(GetProcessHeap(), 0, requestStringLen
+ 1);
632 if (NULL
== requestString
)
634 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
638 /* Build request string */
639 cnt
= sprintf(requestString
, "%s %s%s%s",
642 lpwhr
->lpszHostName
? (HTTPHEADER HTTPHOSTHEADER
) : HTTPHEADER
,
643 lpwhr
->lpszHostName
? lpwhr
->lpszHostName
: "");
645 /* Append standard request headers */
646 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
648 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
650 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
651 lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
);
655 /* Append custom request heades */
656 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
658 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
660 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
661 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
);
665 /* Append passed request headers */
668 strcpy(requestString
+ cnt
, "\r\n");
670 strcpy(requestString
+ cnt
, lpszHeaders
);
674 /* Set termination string for request */
675 strcpy(requestString
+ cnt
, "\r\n\r\n");
677 if (hIC
->lpfnStatusCB
)
678 hIC
->lpfnStatusCB(hHttpRequest
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
680 TRACE("(%s) len(%d)\n", requestString
, requestStringLen
);
681 /* Send the request and store the results */
682 if (!HTTP_OpenConnection(lpwhr
))
685 cnt
= INTERNET_WriteDataToStream(lpwhr
->nSocketFD
, requestString
, requestStringLen
);
690 if (HTTP_GetResponseHeaders(lpwhr
))
696 HeapFree(GetProcessHeap(), 0, requestString
);
698 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
700 INTERNET_ASYNC_RESULT iar
;
702 iar
.dwResult
= (DWORD
)bSuccess
;
703 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
704 hIC
->lpfnStatusCB(hHttpRequest
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
705 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
713 /***********************************************************************
714 * HTTP_Connect (internal)
716 * Create http session handle
719 * HINTERNET a session handle on success
723 HINTERNET
HTTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
724 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
725 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
727 BOOL bSuccess
= FALSE
;
728 LPWININETAPPINFOA hIC
= NULL
;
729 LPWININETHTTPSESSIONA lpwhs
= NULL
;
733 if (((LPWININETHANDLEHEADER
)hInternet
)->htype
!= WH_HINIT
)
736 hIC
= (LPWININETAPPINFOA
) hInternet
;
738 lpwhs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPSESSIONA
));
741 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
745 if (hIC
->lpfnStatusCB
)
746 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
747 (LPVOID
)lpszServerName
, strlen(lpszServerName
));
749 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
750 nServerPort
= INTERNET_DEFAULT_HTTP_PORT
;
752 if (!GetAddress(lpszServerName
, nServerPort
, &lpwhs
->phostent
, &lpwhs
->socketAddress
))
754 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
758 if (hIC
->lpfnStatusCB
)
759 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
760 (LPVOID
)lpszServerName
, strlen(lpszServerName
));
762 lpwhs
->hdr
.htype
= WH_HHTTPSESSION
;
763 lpwhs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
764 lpwhs
->hdr
.dwFlags
= dwFlags
;
765 lpwhs
->hdr
.dwContext
= dwContext
;
766 if (NULL
!= lpszServerName
)
767 lpwhs
->lpszServerName
= HEAP_strdupA(GetProcessHeap(), 0, lpszServerName
);
768 if (NULL
!= lpszUserName
)
769 lpwhs
->lpszUserName
= HEAP_strdupA(GetProcessHeap(), 0, lpszUserName
);
770 lpwhs
->nServerPort
= nServerPort
;
772 if (hIC
->lpfnStatusCB
)
774 INTERNET_ASYNC_RESULT iar
;
776 iar
.dwResult
= (DWORD
)lpwhs
;
777 iar
.dwError
= ERROR_SUCCESS
;
779 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
780 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
786 if (!bSuccess
&& lpwhs
)
788 HeapFree(GetProcessHeap(), 0, lpwhs
);
792 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
794 INTERNET_ASYNC_RESULT iar
;
796 iar
.dwResult
= (DWORD
)lpwhs
;
797 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
798 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
799 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
802 return (HINTERNET
)lpwhs
;
806 /***********************************************************************
807 * HTTP_OpenConnection (internal)
809 * Connect to a web server
816 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
)
818 BOOL bSuccess
= FALSE
;
820 LPWININETHTTPSESSIONA lpwhs
;
824 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
826 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
830 lpwhs
= (LPWININETHTTPSESSIONA
)lpwhr
->hdr
.lpwhparent
;
832 lpwhr
->nSocketFD
= socket(lpwhs
->phostent
->h_addrtype
,SOCK_STREAM
,0);
833 if (INVALID_SOCKET
== lpwhr
->nSocketFD
)
835 WARN("Socket creation failed\n");
839 result
= connect(lpwhr
->nSocketFD
, (struct sockaddr
*)&lpwhs
->socketAddress
,
840 sizeof(lpwhs
->socketAddress
));
842 if (SOCKET_ERROR
== result
)
844 WARN("Unable to connect to host (%s)\n", strerror(errno
));
851 TRACE(": %d\n", bSuccess
);
856 /***********************************************************************
857 * HTTP_GetResponseHeaders (internal)
859 * Read server response
866 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
)
869 CHAR buffer
[MAX_REPLY_LEN
];
870 DWORD buflen
= MAX_REPLY_LEN
;
871 BOOL bSuccess
= FALSE
;
872 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
876 if (INVALID_SOCKET
== lpwhr
->nSocketFD
)
880 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
882 if (!INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
885 if (strncmp(buffer
, "HTTP", 4) != 0)
889 HTTP_ProcessHeader(lpwhr
, "Status", buffer
+9, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
891 /* Parse each response line */
894 buflen
= MAX_REPLY_LEN
;
895 if (INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
897 if (!HTTP_InterpretHttpHeader(buffer
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
900 HTTP_ProcessHeader(lpwhr
, field
, value
, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
918 /***********************************************************************
919 * HTTP_InterpretHttpHeader (internal)
921 * Parse server response
928 INT
stripSpaces(LPCSTR lpszSrc
, LPSTR lpszStart
, INT
*len
)
935 while (*lpszSrc
== ' ' && *lpszSrc
!= '\0')
939 while(*lpsztmp
!= '\0')
942 srclen
= lpsztmp
- lpszSrc
+ 1;
947 *len
= min(*len
, srclen
);
948 strncpy(lpszStart
, lpszSrc
, *len
);
949 lpszStart
[*len
] = '\0';
955 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
)
958 BOOL bSuccess
= FALSE
;
965 pd
= strchr(buffer
, ':');
969 if (stripSpaces(buffer
, field
, &fieldlen
) > 0)
971 if (stripSpaces(pd
+1, value
, &valuelen
) > 0)
976 TRACE("%d: field(%s) Value(%s)\n", bSuccess
, field
, value
);
981 /***********************************************************************
982 * HTTP_GetStdHeaderIndex (internal)
984 * Lookup field index in standard http header array
986 * FIXME: This should be stuffed into a hash table
988 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
)
992 if (!strcasecmp(lpszField
, "Content-Length"))
993 index
= HTTP_QUERY_CONTENT_LENGTH
;
994 else if (!strcasecmp(lpszField
,"Status"))
995 index
= HTTP_QUERY_STATUS_CODE
;
996 else if (!strcasecmp(lpszField
,"Content-Type"))
997 index
= HTTP_QUERY_CONTENT_TYPE
;
998 else if (!strcasecmp(lpszField
,"Last-Modified"))
999 index
= HTTP_QUERY_LAST_MODIFIED
;
1000 else if (!strcasecmp(lpszField
,"Location"))
1001 index
= HTTP_QUERY_LOCATION
;
1002 else if (!strcasecmp(lpszField
,"Accept"))
1003 index
= HTTP_QUERY_ACCEPT
;
1004 else if (!strcasecmp(lpszField
,"Referer"))
1005 index
= HTTP_QUERY_REFERER
;
1006 else if (!strcasecmp(lpszField
,"Content-Transfer-Encoding"))
1007 index
= HTTP_QUERY_CONTENT_TRANSFER_ENCODING
;
1008 else if (!strcasecmp(lpszField
,"Date"))
1009 index
= HTTP_QUERY_DATE
;
1010 else if (!strcasecmp(lpszField
,"Server"))
1011 index
= HTTP_QUERY_SERVER
;
1012 else if (!strcasecmp(lpszField
,"Connection"))
1013 index
= HTTP_QUERY_CONNECTION
;
1014 else if (!strcasecmp(lpszField
,"ETag"))
1015 index
= HTTP_QUERY_ETAG
;
1016 else if (!strcasecmp(lpszField
,"Accept-Ranges"))
1017 index
= HTTP_QUERY_ACCEPT_RANGES
;
1018 else if (!strcasecmp(lpszField
,"Expires"))
1019 index
= HTTP_QUERY_EXPIRES
;
1020 else if (!strcasecmp(lpszField
,"Mime-Version"))
1021 index
= HTTP_QUERY_MIME_VERSION
;
1024 FIXME("Couldn't find %s in standard header table\n", lpszField
);
1031 /***********************************************************************
1032 * HTTP_ProcessHeader (internal)
1034 * Stuff header into header tables according to <dwModifier>
1038 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1040 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
)
1042 LPHTTPHEADERA lphttpHdr
= NULL
;
1043 BOOL bSuccess
= FALSE
;
1046 TRACE("%s:%s - 0x%08x\n", field
, value
, (unsigned int)dwModifier
);
1048 /* Adjust modifier flags */
1049 if (dwModifier
& COALESCEFLASG
)
1050 dwModifier
|= HTTP_ADDHDR_FLAG_ADD
;
1052 /* Try to get index into standard header array */
1053 index
= HTTP_GetStdHeaderIndex(field
);
1056 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
1058 else /* Find or create new custom header */
1060 index
= HTTP_GetCustomHeaderIndex(lpwhr
, field
);
1063 if (dwModifier
& HTTP_ADDHDR_FLAG_ADD_IF_NEW
)
1067 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
1073 hdr
.lpszField
= (LPSTR
)field
;
1074 hdr
.lpszValue
= (LPSTR
)value
;
1075 hdr
.wFlags
= hdr
.wCount
= 0;
1077 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1078 hdr
.wFlags
|= HDR_ISREQUEST
;
1080 index
= HTTP_InsertCustomHeader(lpwhr
, &hdr
);
1085 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1086 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1088 lphttpHdr
->wFlags
&= ~HDR_ISREQUEST
;
1090 if (!lphttpHdr
->lpszValue
&& (dwModifier
& (HTTP_ADDHDR_FLAG_ADD
|HTTP_ADDHDR_FLAG_ADD_IF_NEW
)))
1094 if (!lpwhr
->StdHeaders
[index
].lpszField
)
1096 lphttpHdr
->lpszField
= HEAP_strdupA(GetProcessHeap(), 0, field
);
1098 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1099 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1102 slen
= strlen(value
) + 1;
1103 lphttpHdr
->lpszValue
= HeapAlloc(GetProcessHeap(), 0, slen
);
1104 if (lphttpHdr
->lpszValue
)
1106 memcpy(lphttpHdr
->lpszValue
, value
, slen
);
1111 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1114 else if (lphttpHdr
->lpszValue
)
1116 if (dwModifier
& HTTP_ADDHDR_FLAG_REPLACE
)
1121 len
= strlen(value
);
1125 //! if custom header delete from array
1126 HeapFree(GetProcessHeap(), 0, lphttpHdr
->lpszValue
);
1127 lphttpHdr
->lpszValue
= NULL
;
1132 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1135 lphttpHdr
->lpszValue
= lpsztmp
;
1136 strcpy(lpsztmp
, value
);
1141 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1145 else if (dwModifier
& COALESCEFLASG
)
1150 INT origlen
= strlen(lphttpHdr
->lpszValue
);
1151 INT valuelen
= strlen(value
);
1153 if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA
)
1156 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1158 else if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON
)
1161 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1164 len
= origlen
+ valuelen
+ (ch
> 0) ? 1 : 0;
1166 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1169 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1172 lphttpHdr
->lpszValue
[origlen
] = ch
;
1176 memcpy(&lphttpHdr
->lpszValue
[origlen
], value
, valuelen
);
1177 lphttpHdr
->lpszValue
[len
] = '\0';
1182 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1191 /***********************************************************************
1192 * HTTP_CloseConnection (internal)
1194 * Close socket connection
1197 VOID
HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
)
1199 if (lpwhr
->nSocketFD
!= INVALID_SOCKET
)
1201 close(lpwhr
->nSocketFD
);
1202 lpwhr
->nSocketFD
= INVALID_SOCKET
;
1207 /***********************************************************************
1208 * HTTP_CloseHTTPRequestHandle (internal)
1210 * Deallocate request handle
1213 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr
)
1219 if (lpwhr
->nSocketFD
!= INVALID_SOCKET
)
1220 HTTP_CloseConnection(lpwhr
);
1222 if (lpwhr
->lpszPath
)
1223 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszPath
);
1224 if (lpwhr
->lpszVerb
)
1225 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszVerb
);
1226 if (lpwhr
->lpszHostName
)
1227 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszHostName
);
1229 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
1231 if (lpwhr
->StdHeaders
[i
].lpszField
)
1232 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszField
);
1233 if (lpwhr
->StdHeaders
[i
].lpszValue
)
1234 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszValue
);
1237 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
1239 if (lpwhr
->pCustHeaders
[i
].lpszField
)
1240 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszField
);
1241 if (lpwhr
->pCustHeaders
[i
].lpszValue
)
1242 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszValue
);
1245 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
);
1246 HeapFree(GetProcessHeap(), 0, lpwhr
);
1250 /***********************************************************************
1251 * HTTP_CloseHTTPSessionHandle (internal)
1253 * Deallocate session handle
1256 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs
)
1260 if (lpwhs
->lpszServerName
)
1261 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszServerName
);
1262 if (lpwhs
->lpszUserName
)
1263 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszUserName
);
1264 HeapFree(GetProcessHeap(), 0, lpwhs
);
1268 /***********************************************************************
1269 * HTTP_GetCustomHeaderIndex (internal)
1271 * Return index of custom header from header array
1274 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
)
1278 TRACE("%s\n", lpszField
);
1280 for (index
= 0; index
< lpwhr
->nCustHeaders
; index
++)
1282 if (!strcasecmp(lpwhr
->pCustHeaders
[index
].lpszField
, lpszField
))
1287 if (index
>= lpwhr
->nCustHeaders
)
1290 TRACE("Return: %d\n", index
);
1295 /***********************************************************************
1296 * HTTP_InsertCustomHeader (internal)
1298 * Insert header into array
1301 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
)
1304 LPHTTPHEADERA lph
= NULL
;
1306 TRACE("%s: %s\n", lpHdr
->lpszField
, lpHdr
->lpszValue
);
1307 count
= lpwhr
->nCustHeaders
+ 1;
1309 lph
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpwhr
->pCustHeaders
, sizeof(HTTPHEADERA
) * count
);
1311 lph
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HTTPHEADERA
) * count
);
1315 lpwhr
->pCustHeaders
= lph
;
1316 lpwhr
->pCustHeaders
[count
-1].lpszField
= HEAP_strdupA(GetProcessHeap(), 0, lpHdr
->lpszField
);
1317 lpwhr
->pCustHeaders
[count
-1].lpszValue
= HEAP_strdupA(GetProcessHeap(), 0, lpHdr
->lpszValue
);
1318 lpwhr
->pCustHeaders
[count
-1].wFlags
= lpHdr
->wFlags
;
1319 lpwhr
->pCustHeaders
[count
-1].wCount
= lpHdr
->wCount
;
1320 lpwhr
->nCustHeaders
++;
1324 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1328 TRACE("%d <--\n", count
-1);
1333 /***********************************************************************
1334 * HTTP_DeleteCustomHeader (internal)
1336 * Delete header from array
1339 BOOL
HTTP_DeleteCustomHeader(INT index
)