2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
14 #include "debugtools.h"
20 #include <sys/types.h>
21 #ifdef HAVE_SYS_SOCKET_H
22 # include <sys/socket.h>
32 DEFAULT_DEBUG_CHANNEL(wininet
)
34 #define HTTPHEADER " HTTP/1.0"
35 #define HTTPHOSTHEADER "\r\nHost: "
36 #define MAXHOSTNAME 100
37 #define MAX_FIELD_VALUE_LEN 256
38 #define MAX_FIELD_LEN 256
41 #define HTTP_REFERER "Referer"
42 #define HTTP_ACCEPT "Accept"
44 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
45 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
46 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
47 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
48 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
49 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
50 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
53 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
);
54 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr
,
55 void *Buffer
, int BytesToWrite
);
56 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr
,
57 void *Buffer
, int BytesToRead
);
58 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
);
59 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
);
60 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
);
61 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
);
62 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
);
63 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
);
64 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
);
66 /***********************************************************************
67 * HttpAddRequestHeadersA (WININET.68)
69 * Adds one or more HTTP header to the request handler
76 INTERNETAPI BOOL WINAPI
HttpAddRequestHeadersA(HINTERNET hHttpRequest
,
77 LPCSTR lpszHeader
, DWORD dwHeaderLength
, DWORD dwModifier
)
82 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
83 BOOL bSuccess
= FALSE
;
84 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
86 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
88 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
92 buffer
= HEAP_strdupA(GetProcessHeap(), 0, lpszHeader
);
99 while (*lpszEnd
!= '\0')
101 if (*lpszEnd
== '\r' && *(lpszEnd
+ 1) == '\n')
106 if (*lpszEnd
== '\0')
111 if (HTTP_InterpretHttpHeader(lpszStart
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
112 bSuccess
= HTTP_ProcessHeader(lpwhr
, field
, value
, dwModifier
| HTTP_ADDHDR_FLAG_REQ
);
114 lpszStart
= lpszEnd
+ 2; /* Jump over \0\n */
118 HeapFree(GetProcessHeap(), 0, buffer
);
123 /***********************************************************************
124 * HttpOpenRequestA (WININET.72)
126 * Open a HTTP request handle
129 * HINTERNET a HTTP request handle on success
133 INTERNETAPI HINTERNET WINAPI
HttpOpenRequestA(HINTERNET hHttpSession
,
134 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
135 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
136 DWORD dwFlags
, DWORD dwContext
)
138 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
139 LPWININETAPPINFOA hIC
= NULL
;
143 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
145 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
149 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
151 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
153 WORKREQUEST workRequest
;
155 workRequest
.asyncall
= HTTPOPENREQUESTA
;
156 workRequest
.HFTPSESSION
= (DWORD
)hHttpSession
;
157 workRequest
.LPSZVERB
= (DWORD
)HEAP_strdupA(GetProcessHeap(), 0, lpszVerb
);
158 workRequest
.LPSZOBJECTNAME
= (DWORD
)HEAP_strdupA(GetProcessHeap(), 0, lpszObjectName
);
159 workRequest
.LPSZVERSION
= (DWORD
)HEAP_strdupA(GetProcessHeap(), 0, lpszVersion
);
160 workRequest
.LPSZREFERRER
= (DWORD
)HEAP_strdupA(GetProcessHeap(), 0, lpszReferrer
);
161 workRequest
.LPSZACCEPTTYPES
= (DWORD
)lpszAcceptTypes
;
162 workRequest
.DWFLAGS
= dwFlags
;
163 workRequest
.DWCONTEXT
= dwContext
;
165 return (HINTERNET
)INTERNET_AsyncCall(&workRequest
);
169 return HTTP_HttpOpenRequestA(hHttpSession
, lpszVerb
, lpszObjectName
,
170 lpszVersion
, lpszReferrer
, lpszAcceptTypes
, dwFlags
, dwContext
);
175 /***********************************************************************
176 * HTTP_HttpOpenRequestA (internal)
178 * Open a HTTP request handle
181 * HINTERNET a HTTP request handle on success
185 INTERNETAPI HINTERNET WINAPI
HTTP_HttpOpenRequestA(HINTERNET hHttpSession
,
186 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
187 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
188 DWORD dwFlags
, DWORD dwContext
)
190 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
191 LPWININETAPPINFOA hIC
= NULL
;
192 LPWININETHTTPREQA lpwhr
;
196 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
198 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
202 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
204 lpwhr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPREQA
));
207 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
208 return (HINTERNET
) NULL
;
211 lpwhr
->hdr
.htype
= WH_HHTTPREQ
;
212 lpwhr
->hdr
.lpwhparent
= hHttpSession
;
213 lpwhr
->hdr
.dwFlags
= dwFlags
;
214 lpwhr
->hdr
.dwContext
= dwContext
;
216 if (NULL
!= lpszObjectName
&& strlen(lpszObjectName
))
217 lpwhr
->lpszPath
= HEAP_strdupA(GetProcessHeap(), 0, lpszObjectName
);
219 if (NULL
!= lpszReferrer
&& strlen(lpszReferrer
))
220 HTTP_ProcessHeader(lpwhr
, HTTP_REFERER
, lpszReferrer
, HTTP_ADDHDR_FLAG_COALESCE
);
223 if (NULL
!= lpszAcceptTypes
&& strlen(*lpszAcceptTypes
))
224 HTTP_ProcessHeader(lpwhr
, HTTP_ACCEPT
, *lpszAcceptTypes
, HTTP_ADDHDR_FLAG_COALESCE
);
226 if (NULL
== lpszVerb
)
227 lpwhr
->lpszVerb
= HEAP_strdupA(GetProcessHeap(), 0, "GET");
228 else if (strlen(lpszVerb
))
229 lpwhr
->lpszVerb
= HEAP_strdupA(GetProcessHeap(), 0, lpszVerb
);
231 if (NULL
!= lpszReferrer
)
233 char buf
[MAXHOSTNAME
];
234 URL_COMPONENTSA UrlComponents
;
236 UrlComponents
.lpszExtraInfo
= NULL
;
237 UrlComponents
.lpszPassword
= NULL
;
238 UrlComponents
.lpszScheme
= NULL
;
239 UrlComponents
.lpszUrlPath
= NULL
;
240 UrlComponents
.lpszUserName
= NULL
;
241 UrlComponents
.lpszHostName
= buf
;
242 UrlComponents
.dwHostNameLength
= MAXHOSTNAME
;
244 InternetCrackUrlA(lpszReferrer
, 0, 0, &UrlComponents
);
245 if (strlen(UrlComponents
.lpszHostName
))
246 lpwhr
->lpszHostName
= HEAP_strdupA(GetProcessHeap(), 0, UrlComponents
.lpszHostName
);
249 if (hIC
->lpfnStatusCB
)
251 INTERNET_ASYNC_RESULT iar
;
253 iar
.dwResult
= (DWORD
)lpwhr
;
254 iar
.dwError
= ERROR_SUCCESS
;
256 hIC
->lpfnStatusCB(hHttpSession
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
257 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
260 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
262 INTERNET_ASYNC_RESULT iar
;
264 iar
.dwResult
= (DWORD
)lpwhr
;
265 iar
.dwError
= lpwhr
? ERROR_SUCCESS
: INTERNET_GetLastError();
266 hIC
->lpfnStatusCB(hHttpSession
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
267 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
270 return (HINTERNET
) lpwhr
;
274 /***********************************************************************
275 * HttpQueryInfoA (WININET.74)
277 * Queries for information about an HTTP request
284 BOOL WINAPI
HttpQueryInfoA(HINTERNET hHttpRequest
, DWORD dwInfoLevel
,
285 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
, LPDWORD lpdwIndex
)
287 LPHTTPHEADERA lphttpHdr
= NULL
;
288 BOOL bSuccess
= FALSE
;
289 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
291 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel
, dwInfoLevel
);
293 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
295 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
299 /* Find requested header structure */
300 if ((dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
) == HTTP_QUERY_CUSTOM
)
302 INT index
= HTTP_GetCustomHeaderIndex(lpwhr
, (LPSTR
)lpBuffer
);
307 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
311 INT index
= dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
;
313 if (index
== HTTP_QUERY_RAW_HEADERS_CRLF
|| index
== HTTP_QUERY_RAW_HEADERS
)
315 INT i
, delim
, size
= 0, cnt
= 0;
317 delim
= index
== HTTP_QUERY_RAW_HEADERS_CRLF
? 2 : 1;
319 /* Calculate length of custom reuqest headers */
320 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
322 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->pCustHeaders
[i
].lpszField
&&
323 lpwhr
->pCustHeaders
[i
].lpszValue
)
325 size
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
326 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + delim
+ 2;
330 /* Calculate the length of stadard request headers */
331 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
333 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->StdHeaders
[i
].lpszField
&&
334 lpwhr
->StdHeaders
[i
].lpszValue
)
336 size
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
337 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + delim
+ 2;
343 if (size
+ 1 > *lpdwBufferLength
)
345 *lpdwBufferLength
= size
+ 1;
346 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
350 /* Append standard request heades */
351 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
353 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
354 lpwhr
->StdHeaders
[i
].lpszField
&&
355 lpwhr
->StdHeaders
[i
].lpszValue
)
357 cnt
+= sprintf(lpBuffer
+ cnt
, "%s: %s%s", lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
,
358 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
362 /* Append custom request heades */
363 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
365 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
366 lpwhr
->pCustHeaders
[i
].lpszField
&&
367 lpwhr
->pCustHeaders
[i
].lpszValue
)
369 cnt
+= sprintf(lpBuffer
+ cnt
, "%s: %s%s",
370 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
,
371 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
375 strcpy(lpBuffer
+ cnt
, index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "");
377 *lpdwBufferLength
= cnt
+ delim
;
381 else if (index
>= 0 && index
<= HTTP_QUERY_MAX
&& lpwhr
->StdHeaders
[index
].lpszValue
)
383 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
389 /* Ensure header satisifies requested attributes */
390 if ((dwInfoLevel
& HTTP_QUERY_FLAG_REQUEST_HEADERS
) &&
391 (~lphttpHdr
->wFlags
& HDR_ISREQUEST
))
394 /* coalesce value to reuqested type */
395 if (dwInfoLevel
& HTTP_QUERY_FLAG_NUMBER
)
397 *(int *)lpBuffer
= atoi(lphttpHdr
->lpszValue
);
400 else if (dwInfoLevel
& HTTP_QUERY_FLAG_SYSTEMTIME
)
406 tmpTime
= ConvertTimeString(lphttpHdr
->lpszValue
);
408 tmpTM
= *gmtime(&tmpTime
);
409 STHook
= (SYSTEMTIME
*) lpBuffer
;
413 STHook
->wDay
= tmpTM
.tm_mday
;
414 STHook
->wHour
= tmpTM
.tm_hour
;
415 STHook
->wMilliseconds
= 0;
416 STHook
->wMinute
= tmpTM
.tm_min
;
417 STHook
->wDayOfWeek
= tmpTM
.tm_wday
;
418 STHook
->wMonth
= tmpTM
.tm_mon
+ 1;
419 STHook
->wSecond
= tmpTM
.tm_sec
;
420 STHook
->wYear
= tmpTM
.tm_year
;
424 else if (dwInfoLevel
& HTTP_QUERY_FLAG_COALESCE
)
426 if (*lpdwIndex
>= lphttpHdr
->wCount
)
428 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND
);
432 //! Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len);
438 INT len
= strlen(lphttpHdr
->lpszValue
);
440 if (len
+ 1 > *lpdwBufferLength
)
442 *lpdwBufferLength
= len
+ 1;
443 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
447 strncpy(lpBuffer
, lphttpHdr
->lpszValue
, len
);
448 *lpdwBufferLength
= len
;
453 TRACE("%d <--\n", bSuccess
);
457 /***********************************************************************
458 * HttpSendRequestA (WININET.76)
460 * Sends the specified request to the HTTP server
467 BOOL WINAPI
HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
468 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
470 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
471 LPWININETHTTPSESSIONA lpwhs
= NULL
;
472 LPWININETAPPINFOA hIC
= NULL
;
474 TRACE("0x%08lx\n", (unsigned long)hHttpRequest
);
476 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
478 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
482 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
483 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
485 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
489 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
490 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
492 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
496 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
498 WORKREQUEST workRequest
;
500 workRequest
.asyncall
= HTTPSENDREQUESTA
;
501 workRequest
.HFTPSESSION
= (DWORD
)hHttpRequest
;
502 workRequest
.LPSZHEADER
= (DWORD
)HEAP_strdupA(GetProcessHeap(), 0, lpszHeaders
);
503 workRequest
.DWHEADERLENGTH
= dwHeaderLength
;
504 workRequest
.LPOPTIONAL
= (DWORD
)lpOptional
;
505 workRequest
.DWOPTIONALLENGTH
= dwOptionalLength
;
507 return INTERNET_AsyncCall(&workRequest
);
511 return HTTP_HttpSendRequestA(hHttpRequest
, lpszHeaders
,
512 dwHeaderLength
, lpOptional
, dwOptionalLength
);
517 /***********************************************************************
518 * HTTP_HttpSendRequestA (internal)
520 * Sends the specified request to the HTTP server
527 BOOL WINAPI
HTTP_HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
528 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
532 BOOL bSuccess
= FALSE
;
533 LPSTR requestString
= NULL
;
534 INT requestStringLen
;
535 INT headerLength
= 0;
536 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
537 LPWININETHTTPSESSIONA lpwhs
= NULL
;
538 LPWININETAPPINFOA hIC
= NULL
;
540 TRACE("0x%08lx\n", (ULONG
)hHttpRequest
);
542 /* Verify our tree of internet handles */
543 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
545 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
549 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
550 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
552 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
556 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
557 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
559 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
563 /* Clear any error information */
564 INTERNET_SetLastError(0);
566 /* We must have a verb */
567 if (NULL
== lpwhr
->lpszVerb
)
572 /* If we don't have a path we set it to root */
573 if (NULL
== lpwhr
->lpszPath
)
574 lpwhr
->lpszPath
= HEAP_strdupA(GetProcessHeap(), 0, "/");
576 /* Calculate length of request string */
578 strlen(lpwhr
->lpszVerb
) +
579 strlen(lpwhr
->lpszPath
) +
580 (lpwhr
->lpszHostName
? (strlen(HTTPHOSTHEADER
) + strlen(lpwhr
->lpszHostName
)) : 0) +
584 /* Add length of passed headers */
587 headerLength
= -1 == dwHeaderLength
? strlen(lpszHeaders
) : dwHeaderLength
;
588 requestStringLen
+= headerLength
+ 2; /* \r\n */
591 /* Calculate length of custom reuqest headers */
592 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
594 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
596 requestStringLen
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
597 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + 4; /*: \r\n */
601 /* Calculate the length of stadard request headers */
602 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
604 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
606 requestStringLen
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
607 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + 4; /*: \r\n */
611 /* Allocate string to hold entire request */
612 requestString
= HeapAlloc(GetProcessHeap(), 0, requestStringLen
+ 1);
613 if (NULL
== requestString
)
615 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
619 /* Build request string */
620 cnt
= sprintf(requestString
, "%s %s%s%s",
623 lpwhr
->lpszHostName
? (HTTPHEADER HTTPHOSTHEADER
) : HTTPHEADER
,
624 lpwhr
->lpszHostName
? lpwhr
->lpszHostName
: "");
626 /* Append standard request heades */
627 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
629 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
631 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
632 lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
);
636 /* Append custom request heades */
637 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
639 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
641 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
642 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
);
646 /* Append passed request headers */
649 strcpy(requestString
+ cnt
, "\r\n");
651 strcpy(requestString
+ cnt
, lpszHeaders
);
655 /* Set termination string for request */
656 strcpy(requestString
+ cnt
, "\r\n\r\n");
658 if (hIC
->lpfnStatusCB
)
659 hIC
->lpfnStatusCB(hHttpRequest
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
661 TRACE("(%s) len(%d)\n", requestString
, requestStringLen
);
662 /* Send the request and store the results */
663 if (!HTTP_OpenConnection(lpwhr
))
666 cnt
= INTERNET_WriteDataToStream(lpwhr
->nSocketFD
, requestString
, requestStringLen
);
671 if (HTTP_GetResponseHeaders(lpwhr
))
677 HeapFree(GetProcessHeap(), 0, requestString
);
679 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
681 INTERNET_ASYNC_RESULT iar
;
683 iar
.dwResult
= (DWORD
)bSuccess
;
684 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
685 hIC
->lpfnStatusCB(hHttpRequest
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
686 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
694 /***********************************************************************
695 * HTTP_Connect (internal)
697 * Create http session handle
700 * HINTERNET a session handle on success
704 HINTERNET
HTTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
705 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
706 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
708 BOOL bSuccess
= FALSE
;
709 LPWININETAPPINFOA hIC
= NULL
;
710 LPWININETHTTPSESSIONA lpwhs
= NULL
;
714 if (((LPWININETHANDLEHEADER
)hInternet
)->htype
!= WH_HINIT
)
717 hIC
= (LPWININETAPPINFOA
) hInternet
;
719 lpwhs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPSESSIONA
));
722 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
726 if (hIC
->lpfnStatusCB
)
727 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
728 (LPVOID
)lpszServerName
, strlen(lpszServerName
));
730 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
731 nServerPort
= INTERNET_DEFAULT_HTTP_PORT
;
733 if (!GetAddress(lpszServerName
, nServerPort
, &lpwhs
->phostent
, &lpwhs
->socketAddress
))
735 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
739 if (hIC
->lpfnStatusCB
)
740 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
741 (LPVOID
)lpszServerName
, strlen(lpszServerName
));
743 lpwhs
->hdr
.htype
= WH_HHTTPSESSION
;
744 lpwhs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
745 lpwhs
->hdr
.dwFlags
= dwFlags
;
746 lpwhs
->hdr
.dwContext
= dwContext
;
747 if (NULL
!= lpszServerName
)
748 lpwhs
->lpszServerName
= HEAP_strdupA(GetProcessHeap(), 0, lpszServerName
);
749 if (NULL
!= lpszUserName
)
750 lpwhs
->lpszUserName
= HEAP_strdupA(GetProcessHeap(), 0, lpszUserName
);
751 lpwhs
->nServerPort
= nServerPort
;
753 if (hIC
->lpfnStatusCB
)
755 INTERNET_ASYNC_RESULT iar
;
757 iar
.dwResult
= (DWORD
)lpwhs
;
758 iar
.dwError
= ERROR_SUCCESS
;
760 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
761 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
767 if (!bSuccess
&& lpwhs
)
769 HeapFree(GetProcessHeap(), 0, lpwhs
);
773 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
775 INTERNET_ASYNC_RESULT iar
;
777 iar
.dwResult
= (DWORD
)lpwhs
;
778 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
779 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
780 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
783 return (HINTERNET
)lpwhs
;
787 /***********************************************************************
788 * HTTP_OpenConnection (internal)
790 * Connect to a web server
797 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
)
799 BOOL bSuccess
= FALSE
;
801 LPWININETHTTPSESSIONA lpwhs
;
805 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
807 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
811 lpwhs
= (LPWININETHTTPSESSIONA
)lpwhr
->hdr
.lpwhparent
;
813 lpwhr
->nSocketFD
= socket(lpwhs
->phostent
->h_addrtype
,SOCK_STREAM
,0);
814 if (INVALID_SOCKET
== lpwhr
->nSocketFD
)
816 WARN("Socket creation failed\n");
820 result
= connect(lpwhr
->nSocketFD
, (struct sockaddr
*)&lpwhs
->socketAddress
,
821 sizeof(lpwhs
->socketAddress
));
823 if (SOCKET_ERROR
== result
)
825 WARN("Unable to connect to host: %d\n", errno
);
832 TRACE(": %d\n", bSuccess
);
837 /***********************************************************************
838 * HTTP_GetResponseHeaders (internal)
840 * Read server response
847 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
)
850 CHAR buffer
[MAX_REPLY_LEN
];
851 DWORD buflen
= MAX_REPLY_LEN
;
852 BOOL bSuccess
= FALSE
;
853 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
857 if (INVALID_SOCKET
== lpwhr
->nSocketFD
)
861 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
863 if (!INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
866 if (strncmp(buffer
, "HTTP", 4) != 0)
870 HTTP_ProcessHeader(lpwhr
, "Status", buffer
+9, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
872 /* Parse each response line */
875 buflen
= MAX_REPLY_LEN
;
876 if (INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
878 if (!HTTP_InterpretHttpHeader(buffer
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
881 HTTP_ProcessHeader(lpwhr
, field
, value
, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
899 /***********************************************************************
900 * HTTP_InterpretHttpHeader (internal)
902 * Parse server response
909 INT
stripSpaces(LPCSTR lpszSrc
, LPSTR lpszStart
, INT
*len
)
916 while (*lpszSrc
== ' ' && *lpszSrc
!= '\0')
920 while(*lpsztmp
!= '\0')
923 srclen
= lpsztmp
- lpszSrc
+ 1;
928 *len
= min(*len
, srclen
);
929 strncpy(lpszStart
, lpszSrc
, *len
);
930 lpszStart
[*len
] = '\0';
936 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
)
939 BOOL bSuccess
= FALSE
;
946 pd
= strchr(buffer
, ':');
950 if (stripSpaces(buffer
, field
, &fieldlen
) > 0)
952 if (stripSpaces(pd
+1, value
, &valuelen
) > 0)
957 TRACE("%d: field(%s) Value(%s)\n", bSuccess
, field
, value
);
962 /***********************************************************************
963 * HTTP_GetStdHeaderIndex (internal)
965 * Lookup field index in stadard http header array
967 * FIXME: This should be stuffed into a hash table
969 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
)
973 if (!_stricmp(lpszField
, "Content-Length"))
974 index
= HTTP_QUERY_CONTENT_LENGTH
;
975 else if (!_stricmp(lpszField
,"Status"))
976 index
= HTTP_QUERY_STATUS_CODE
;
977 else if (!_stricmp(lpszField
,"Content-Type"))
978 index
= HTTP_QUERY_CONTENT_TYPE
;
979 else if (!_stricmp(lpszField
,"Last-Modified"))
980 index
= HTTP_QUERY_LAST_MODIFIED
;
981 else if (!_stricmp(lpszField
,"Location"))
982 index
= HTTP_QUERY_LOCATION
;
983 else if (!_stricmp(lpszField
,"Accept"))
984 index
= HTTP_QUERY_ACCEPT
;
985 else if (!_stricmp(lpszField
,"Referer"))
986 index
= HTTP_QUERY_REFERER
;
987 else if (!_stricmp(lpszField
,"Content-Transfer-Encoding"))
988 index
= HTTP_QUERY_CONTENT_TRANSFER_ENCODING
;
991 FIXME("Couldn't find %s in standard header table\n", lpszField
);
998 /***********************************************************************
999 * HTTP_ProcessHeader (internal)
1001 * Stuff header into header tables according to <dwModifier>
1005 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1007 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
)
1009 LPHTTPHEADERA lphttpHdr
= NULL
;
1010 BOOL bSuccess
= FALSE
;
1013 TRACE("%s:%s - 0x%08x\n", field
, value
, (unsigned int)dwModifier
);
1015 /* Adjust modifier flags */
1016 if (dwModifier
& COALESCEFLASG
)
1017 dwModifier
|= HTTP_ADDHDR_FLAG_ADD
;
1019 /* Try to get index into standard header array */
1020 index
= HTTP_GetStdHeaderIndex(field
);
1023 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
1025 else /* Find or create new custom header */
1027 index
= HTTP_GetCustomHeaderIndex(lpwhr
, field
);
1030 if (dwModifier
& HTTP_ADDHDR_FLAG_ADD_IF_NEW
)
1034 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
1040 hdr
.lpszField
= (LPSTR
)field
;
1041 hdr
.lpszValue
= (LPSTR
)value
;
1042 hdr
.wFlags
= hdr
.wCount
= 0;
1044 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1045 hdr
.wFlags
|= HDR_ISREQUEST
;
1047 index
= HTTP_InsertCustomHeader(lpwhr
, &hdr
);
1052 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1053 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1055 lphttpHdr
->wFlags
&= ~HDR_ISREQUEST
;
1057 if (!lphttpHdr
->lpszValue
&& (dwModifier
& (HTTP_ADDHDR_FLAG_ADD
|HTTP_ADDHDR_FLAG_ADD_IF_NEW
)))
1061 if (!lpwhr
->StdHeaders
[index
].lpszField
)
1063 lphttpHdr
->lpszField
= HEAP_strdupA(GetProcessHeap(), 0, field
);
1065 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1066 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1069 slen
= strlen(value
) + 1;
1070 lphttpHdr
->lpszValue
= HeapAlloc(GetProcessHeap(), 0, slen
);
1071 if (lphttpHdr
->lpszValue
)
1073 memcpy(lphttpHdr
->lpszValue
, value
, slen
);
1078 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1081 else if (lphttpHdr
->lpszValue
)
1083 if (dwModifier
& HTTP_ADDHDR_FLAG_REPLACE
)
1088 len
= strlen(value
);
1092 //! if custom header delete from array
1093 HeapFree(GetProcessHeap(), 0, lphttpHdr
->lpszValue
);
1094 lphttpHdr
->lpszValue
= NULL
;
1099 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1102 lphttpHdr
->lpszValue
= lpsztmp
;
1103 strcpy(lpsztmp
, value
);
1108 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1112 else if (dwModifier
& COALESCEFLASG
)
1117 INT origlen
= strlen(lphttpHdr
->lpszValue
);
1118 INT valuelen
= strlen(value
);
1120 if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA
)
1123 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1125 else if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON
)
1128 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1131 len
= origlen
+ valuelen
+ (ch
> 0) ? 1 : 0;
1133 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1136 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1139 lphttpHdr
->lpszValue
[origlen
] = ch
;
1143 memcpy(&lphttpHdr
->lpszValue
[origlen
], value
, valuelen
);
1144 lphttpHdr
->lpszValue
[len
] = '\0';
1149 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1158 /***********************************************************************
1159 * HTTP_CloseConnection (internal)
1161 * Close socket connection
1164 VOID
HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
)
1166 if (lpwhr
->nSocketFD
!= INVALID_SOCKET
)
1168 close(lpwhr
->nSocketFD
);
1169 lpwhr
->nSocketFD
= INVALID_SOCKET
;
1174 /***********************************************************************
1175 * HTTP_CloseHTTPRequestHandle (internal)
1177 * Deallocate request handle
1180 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr
)
1186 if (lpwhr
->nSocketFD
!= INVALID_SOCKET
)
1187 HTTP_CloseConnection(lpwhr
);
1189 if (lpwhr
->lpszPath
)
1190 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszPath
);
1191 if (lpwhr
->lpszVerb
)
1192 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszVerb
);
1193 if (lpwhr
->lpszHostName
)
1194 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszHostName
);
1196 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
1198 if (lpwhr
->StdHeaders
[i
].lpszField
)
1199 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszField
);
1200 if (lpwhr
->StdHeaders
[i
].lpszValue
)
1201 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszValue
);
1204 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
1206 if (lpwhr
->pCustHeaders
[i
].lpszField
)
1207 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszField
);
1208 if (lpwhr
->pCustHeaders
[i
].lpszValue
)
1209 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszValue
);
1212 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
);
1213 HeapFree(GetProcessHeap(), 0, lpwhr
);
1217 /***********************************************************************
1218 * HTTP_CloseHTTPSessionHandle (internal)
1220 * Deallocate session handle
1223 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs
)
1227 if (lpwhs
->lpszServerName
)
1228 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszServerName
);
1229 if (lpwhs
->lpszUserName
)
1230 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszUserName
);
1231 HeapFree(GetProcessHeap(), 0, lpwhs
);
1235 /***********************************************************************
1236 * HTTP_GetCustomHeaderIndex (internal)
1238 * Return index of custom header from header array
1241 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
)
1245 TRACE("%s\n", lpszField
);
1247 for (index
= 0; index
< lpwhr
->nCustHeaders
; index
++)
1249 if (!_stricmp(lpwhr
->pCustHeaders
[index
].lpszField
, lpszField
))
1254 if (index
>= lpwhr
->nCustHeaders
)
1257 TRACE("Return: %d\n", index
);
1262 /***********************************************************************
1263 * HTTP_InsertCustomHeader (internal)
1265 * Insert header into array
1268 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
)
1271 LPHTTPHEADERA lph
= NULL
;
1273 TRACE("%s: %s\n", lpHdr
->lpszField
, lpHdr
->lpszValue
);
1274 count
= lpwhr
->nCustHeaders
+ 1;
1276 lph
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpwhr
->pCustHeaders
, sizeof(HTTPHEADERA
) * count
);
1278 lph
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HTTPHEADERA
) * count
);
1282 lpwhr
->pCustHeaders
= lph
;
1283 lpwhr
->pCustHeaders
[count
-1].lpszField
= HEAP_strdupA(GetProcessHeap(), 0, lpHdr
->lpszField
);
1284 lpwhr
->pCustHeaders
[count
-1].lpszValue
= HEAP_strdupA(GetProcessHeap(), 0, lpHdr
->lpszValue
);
1285 lpwhr
->pCustHeaders
[count
-1].wFlags
= lpHdr
->wFlags
;
1286 lpwhr
->pCustHeaders
[count
-1].wCount
= lpHdr
->wCount
;
1287 lpwhr
->nCustHeaders
++;
1291 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1295 TRACE("%d <--\n", count
-1);
1300 /***********************************************************************
1301 * HTTP_DeleteCustomHeader (internal)
1303 * Delete header from array
1306 BOOL
HTTP_DeleteCustomHeader(INT index
)