2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
14 #include "debugtools.h"
18 #include <sys/types.h>
19 #ifdef HAVE_SYS_SOCKET_H
20 # include <sys/socket.h>
30 DEFAULT_DEBUG_CHANNEL(wininet
);
32 #define HTTPHEADER " HTTP/1.0"
33 #define HTTPHOSTHEADER "\r\nHost: "
34 #define MAXHOSTNAME 100
35 #define MAX_FIELD_VALUE_LEN 256
36 #define MAX_FIELD_LEN 256
39 #define HTTP_REFERER "Referer"
40 #define HTTP_ACCEPT "Accept"
42 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
43 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
44 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
45 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
46 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
47 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
48 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
51 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
);
52 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr
,
53 void *Buffer
, int BytesToWrite
);
54 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr
,
55 void *Buffer
, int BytesToRead
);
56 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
);
57 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
);
58 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
);
59 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
);
60 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
);
61 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
);
62 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
);
64 inline static LPSTR
HTTP_strdup( LPCSTR str
)
66 LPSTR ret
= HeapAlloc( GetProcessHeap(), 0, strlen(str
) + 1 );
67 if (ret
) strcpy( ret
, str
);
71 /***********************************************************************
72 * HttpAddRequestHeadersA (WININET.68)
74 * Adds one or more HTTP header to the request handler
81 INTERNETAPI BOOL WINAPI
HttpAddRequestHeadersA(HINTERNET hHttpRequest
,
82 LPCSTR lpszHeader
, DWORD dwHeaderLength
, DWORD dwModifier
)
87 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
88 BOOL bSuccess
= FALSE
;
89 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
91 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
93 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
97 buffer
= HTTP_strdup(lpszHeader
);
104 while (*lpszEnd
!= '\0')
106 if (*lpszEnd
== '\r' && *(lpszEnd
+ 1) == '\n')
111 if (*lpszEnd
== '\0')
116 if (HTTP_InterpretHttpHeader(lpszStart
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
117 bSuccess
= HTTP_ProcessHeader(lpwhr
, field
, value
, dwModifier
| HTTP_ADDHDR_FLAG_REQ
);
119 lpszStart
= lpszEnd
+ 2; /* Jump over \0\n */
123 HeapFree(GetProcessHeap(), 0, buffer
);
128 /***********************************************************************
129 * HttpOpenRequestA (WININET.72)
131 * Open a HTTP request handle
134 * HINTERNET a HTTP request handle on success
138 INTERNETAPI HINTERNET WINAPI
HttpOpenRequestA(HINTERNET hHttpSession
,
139 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
140 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
141 DWORD dwFlags
, DWORD dwContext
)
143 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
144 LPWININETAPPINFOA hIC
= NULL
;
148 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
150 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
154 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
156 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
158 WORKREQUEST workRequest
;
160 workRequest
.asyncall
= HTTPOPENREQUESTA
;
161 workRequest
.HFTPSESSION
= (DWORD
)hHttpSession
;
162 workRequest
.LPSZVERB
= (DWORD
)HTTP_strdup(lpszVerb
);
163 workRequest
.LPSZOBJECTNAME
= (DWORD
)HTTP_strdup(lpszObjectName
);
164 workRequest
.LPSZVERSION
= (DWORD
)HTTP_strdup(lpszVersion
);
165 workRequest
.LPSZREFERRER
= (DWORD
)HTTP_strdup(lpszReferrer
);
166 workRequest
.LPSZACCEPTTYPES
= (DWORD
)lpszAcceptTypes
;
167 workRequest
.DWFLAGS
= dwFlags
;
168 workRequest
.DWCONTEXT
= dwContext
;
170 return (HINTERNET
)INTERNET_AsyncCall(&workRequest
);
174 return HTTP_HttpOpenRequestA(hHttpSession
, lpszVerb
, lpszObjectName
,
175 lpszVersion
, lpszReferrer
, lpszAcceptTypes
, dwFlags
, dwContext
);
180 /***********************************************************************
181 * HTTP_HttpOpenRequestA (internal)
183 * Open a HTTP request handle
186 * HINTERNET a HTTP request handle on success
190 INTERNETAPI HINTERNET WINAPI
HTTP_HttpOpenRequestA(HINTERNET hHttpSession
,
191 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
192 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
193 DWORD dwFlags
, DWORD dwContext
)
195 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
196 LPWININETAPPINFOA hIC
= NULL
;
197 LPWININETHTTPREQA lpwhr
;
201 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
203 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
207 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
209 lpwhr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPREQA
));
212 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
213 return (HINTERNET
) NULL
;
216 lpwhr
->hdr
.htype
= WH_HHTTPREQ
;
217 lpwhr
->hdr
.lpwhparent
= hHttpSession
;
218 lpwhr
->hdr
.dwFlags
= dwFlags
;
219 lpwhr
->hdr
.dwContext
= dwContext
;
220 lpwhr
->nSocketFD
= INVALID_SOCKET
;
222 if (NULL
!= lpszObjectName
&& strlen(lpszObjectName
))
223 lpwhr
->lpszPath
= HTTP_strdup(lpszObjectName
);
225 if (NULL
!= lpszReferrer
&& strlen(lpszReferrer
))
226 HTTP_ProcessHeader(lpwhr
, HTTP_REFERER
, lpszReferrer
, HTTP_ADDHDR_FLAG_COALESCE
);
229 if (NULL
!= lpszAcceptTypes
&& strlen(*lpszAcceptTypes
))
230 HTTP_ProcessHeader(lpwhr
, HTTP_ACCEPT
, *lpszAcceptTypes
, HTTP_ADDHDR_FLAG_COALESCE
);
232 if (NULL
== lpszVerb
)
233 lpwhr
->lpszVerb
= HTTP_strdup("GET");
234 else if (strlen(lpszVerb
))
235 lpwhr
->lpszVerb
= HTTP_strdup(lpszVerb
);
237 if (NULL
!= lpszReferrer
)
239 char buf
[MAXHOSTNAME
];
240 URL_COMPONENTSA UrlComponents
;
242 UrlComponents
.lpszExtraInfo
= NULL
;
243 UrlComponents
.lpszPassword
= NULL
;
244 UrlComponents
.lpszScheme
= NULL
;
245 UrlComponents
.lpszUrlPath
= NULL
;
246 UrlComponents
.lpszUserName
= NULL
;
247 UrlComponents
.lpszHostName
= buf
;
248 UrlComponents
.dwHostNameLength
= MAXHOSTNAME
;
250 InternetCrackUrlA(lpszReferrer
, 0, 0, &UrlComponents
);
251 if (strlen(UrlComponents
.lpszHostName
))
252 lpwhr
->lpszHostName
= HTTP_strdup(UrlComponents
.lpszHostName
);
254 lpwhr
->lpszHostName
= HTTP_strdup(lpwhs
->lpszServerName
);
257 if (hIC
->lpfnStatusCB
)
259 INTERNET_ASYNC_RESULT iar
;
261 iar
.dwResult
= (DWORD
)lpwhr
;
262 iar
.dwError
= ERROR_SUCCESS
;
264 hIC
->lpfnStatusCB(hHttpSession
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
265 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
268 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
270 INTERNET_ASYNC_RESULT iar
;
272 iar
.dwResult
= (DWORD
)lpwhr
;
273 iar
.dwError
= lpwhr
? ERROR_SUCCESS
: INTERNET_GetLastError();
274 hIC
->lpfnStatusCB(hHttpSession
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
275 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
278 return (HINTERNET
) lpwhr
;
282 /***********************************************************************
283 * HttpQueryInfoA (WININET.74)
285 * Queries for information about an HTTP request
292 BOOL WINAPI
HttpQueryInfoA(HINTERNET hHttpRequest
, DWORD dwInfoLevel
,
293 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
, LPDWORD lpdwIndex
)
295 LPHTTPHEADERA lphttpHdr
= NULL
;
296 BOOL bSuccess
= FALSE
;
297 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
299 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel
, dwInfoLevel
);
301 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
303 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
307 /* Find requested header structure */
308 if ((dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
) == HTTP_QUERY_CUSTOM
)
310 INT index
= HTTP_GetCustomHeaderIndex(lpwhr
, (LPSTR
)lpBuffer
);
315 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
319 INT index
= dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
;
321 if (index
== HTTP_QUERY_RAW_HEADERS_CRLF
|| index
== HTTP_QUERY_RAW_HEADERS
)
323 INT i
, delim
, size
= 0, cnt
= 0;
325 delim
= index
== HTTP_QUERY_RAW_HEADERS_CRLF
? 2 : 1;
327 /* Calculate length of custom reuqest headers */
328 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
330 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->pCustHeaders
[i
].lpszField
&&
331 lpwhr
->pCustHeaders
[i
].lpszValue
)
333 size
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
334 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + delim
+ 2;
338 /* Calculate the length of stadard request headers */
339 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
341 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->StdHeaders
[i
].lpszField
&&
342 lpwhr
->StdHeaders
[i
].lpszValue
)
344 size
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
345 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + delim
+ 2;
351 if (size
+ 1 > *lpdwBufferLength
)
353 *lpdwBufferLength
= size
+ 1;
354 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
358 /* Append standard request heades */
359 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
361 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
362 lpwhr
->StdHeaders
[i
].lpszField
&&
363 lpwhr
->StdHeaders
[i
].lpszValue
)
365 cnt
+= sprintf(lpBuffer
+ cnt
, "%s: %s%s", lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
,
366 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
370 /* Append custom request heades */
371 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
373 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
374 lpwhr
->pCustHeaders
[i
].lpszField
&&
375 lpwhr
->pCustHeaders
[i
].lpszValue
)
377 cnt
+= sprintf(lpBuffer
+ cnt
, "%s: %s%s",
378 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
,
379 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
383 strcpy(lpBuffer
+ cnt
, index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "");
385 *lpdwBufferLength
= cnt
+ delim
;
389 else if (index
>= 0 && index
<= HTTP_QUERY_MAX
&& lpwhr
->StdHeaders
[index
].lpszValue
)
391 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
397 /* Ensure header satisifies requested attributes */
398 if ((dwInfoLevel
& HTTP_QUERY_FLAG_REQUEST_HEADERS
) &&
399 (~lphttpHdr
->wFlags
& HDR_ISREQUEST
))
402 /* coalesce value to reuqested type */
403 if (dwInfoLevel
& HTTP_QUERY_FLAG_NUMBER
)
405 *(int *)lpBuffer
= atoi(lphttpHdr
->lpszValue
);
408 else if (dwInfoLevel
& HTTP_QUERY_FLAG_SYSTEMTIME
)
414 tmpTime
= ConvertTimeString(lphttpHdr
->lpszValue
);
416 tmpTM
= *gmtime(&tmpTime
);
417 STHook
= (SYSTEMTIME
*) lpBuffer
;
421 STHook
->wDay
= tmpTM
.tm_mday
;
422 STHook
->wHour
= tmpTM
.tm_hour
;
423 STHook
->wMilliseconds
= 0;
424 STHook
->wMinute
= tmpTM
.tm_min
;
425 STHook
->wDayOfWeek
= tmpTM
.tm_wday
;
426 STHook
->wMonth
= tmpTM
.tm_mon
+ 1;
427 STHook
->wSecond
= tmpTM
.tm_sec
;
428 STHook
->wYear
= tmpTM
.tm_year
;
432 else if (dwInfoLevel
& HTTP_QUERY_FLAG_COALESCE
)
434 if (*lpdwIndex
>= lphttpHdr
->wCount
)
436 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND
);
440 //! Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len);
446 INT len
= strlen(lphttpHdr
->lpszValue
);
448 if (len
+ 1 > *lpdwBufferLength
)
450 *lpdwBufferLength
= len
+ 1;
451 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
455 strncpy(lpBuffer
, lphttpHdr
->lpszValue
, len
);
456 *lpdwBufferLength
= len
;
461 TRACE("%d <--\n", bSuccess
);
466 /***********************************************************************
467 * HttpSendRequestExA (WININET)
469 * Sends the specified request to the HTTP server and allows chunked
472 BOOL WINAPI
HttpSendRequestExA(HINTERNET hRequest
,
473 LPINTERNET_BUFFERSA lpBuffersIn
,
474 LPINTERNET_BUFFERSA lpBuffersOut
,
475 DWORD dwFlags
, DWORD dwContext
)
477 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest
, lpBuffersIn
,
478 lpBuffersOut
, dwFlags
, dwContext
);
482 /***********************************************************************
483 * HttpSendRequestA (WININET.76)
485 * Sends the specified request to the HTTP server
492 BOOL WINAPI
HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
493 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
495 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
496 LPWININETHTTPSESSIONA lpwhs
= NULL
;
497 LPWININETAPPINFOA hIC
= NULL
;
499 TRACE("0x%08lx\n", (unsigned long)hHttpRequest
);
501 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
503 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
507 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
508 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
510 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
514 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
515 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
517 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
521 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
523 WORKREQUEST workRequest
;
525 workRequest
.asyncall
= HTTPSENDREQUESTA
;
526 workRequest
.HFTPSESSION
= (DWORD
)hHttpRequest
;
527 workRequest
.LPSZHEADER
= (DWORD
)HTTP_strdup(lpszHeaders
);
528 workRequest
.DWHEADERLENGTH
= dwHeaderLength
;
529 workRequest
.LPOPTIONAL
= (DWORD
)lpOptional
;
530 workRequest
.DWOPTIONALLENGTH
= dwOptionalLength
;
532 return INTERNET_AsyncCall(&workRequest
);
536 return HTTP_HttpSendRequestA(hHttpRequest
, lpszHeaders
,
537 dwHeaderLength
, lpOptional
, dwOptionalLength
);
542 /***********************************************************************
543 * HTTP_HttpSendRequestA (internal)
545 * Sends the specified request to the HTTP server
552 BOOL WINAPI
HTTP_HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
553 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
557 BOOL bSuccess
= FALSE
;
558 LPSTR requestString
= NULL
;
559 INT requestStringLen
;
560 INT headerLength
= 0;
561 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
562 LPWININETHTTPSESSIONA lpwhs
= NULL
;
563 LPWININETAPPINFOA hIC
= NULL
;
565 TRACE("0x%08lx\n", (ULONG
)hHttpRequest
);
567 /* Verify our tree of internet handles */
568 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
570 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
574 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
575 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
577 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
581 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
582 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
584 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
588 /* Clear any error information */
589 INTERNET_SetLastError(0);
591 /* We must have a verb */
592 if (NULL
== lpwhr
->lpszVerb
)
597 /* If we don't have a path we set it to root */
598 if (NULL
== lpwhr
->lpszPath
)
599 lpwhr
->lpszPath
= HTTP_strdup("/");
601 /* Calculate length of request string */
603 strlen(lpwhr
->lpszVerb
) +
604 strlen(lpwhr
->lpszPath
) +
605 (lpwhr
->lpszHostName
? (strlen(HTTPHOSTHEADER
) + strlen(lpwhr
->lpszHostName
)) : 0) +
609 /* Add length of passed headers */
612 headerLength
= -1 == dwHeaderLength
? strlen(lpszHeaders
) : dwHeaderLength
;
613 requestStringLen
+= headerLength
+ 2; /* \r\n */
616 /* Calculate length of custom request headers */
617 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
619 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
621 requestStringLen
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
622 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + 4; /*: \r\n */
626 /* Calculate the length of standard request headers */
627 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
629 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
631 requestStringLen
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
632 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + 4; /*: \r\n */
636 /* Allocate string to hold entire request */
637 requestString
= HeapAlloc(GetProcessHeap(), 0, requestStringLen
+ 1);
638 if (NULL
== requestString
)
640 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
644 /* Build request string */
645 cnt
= sprintf(requestString
, "%s %s%s%s",
648 lpwhr
->lpszHostName
? (HTTPHEADER HTTPHOSTHEADER
) : HTTPHEADER
,
649 lpwhr
->lpszHostName
? lpwhr
->lpszHostName
: "");
651 /* Append standard request headers */
652 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
654 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
656 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
657 lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
);
661 /* Append custom request heades */
662 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
664 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
666 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
667 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
);
671 /* Append passed request headers */
674 strcpy(requestString
+ cnt
, "\r\n");
676 strcpy(requestString
+ cnt
, lpszHeaders
);
680 /* Set termination string for request */
681 strcpy(requestString
+ cnt
, "\r\n\r\n");
683 if (hIC
->lpfnStatusCB
)
684 hIC
->lpfnStatusCB(hHttpRequest
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
686 TRACE("(%s) len(%d)\n", requestString
, requestStringLen
);
687 /* Send the request and store the results */
688 if (!HTTP_OpenConnection(lpwhr
))
691 cnt
= INTERNET_WriteDataToStream(lpwhr
->nSocketFD
, requestString
, requestStringLen
);
696 if (HTTP_GetResponseHeaders(lpwhr
))
702 HeapFree(GetProcessHeap(), 0, requestString
);
704 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
706 INTERNET_ASYNC_RESULT iar
;
708 iar
.dwResult
= (DWORD
)bSuccess
;
709 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
710 hIC
->lpfnStatusCB(hHttpRequest
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
711 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
719 /***********************************************************************
720 * HTTP_Connect (internal)
722 * Create http session handle
725 * HINTERNET a session handle on success
729 HINTERNET
HTTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
730 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
731 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
733 BOOL bSuccess
= FALSE
;
734 LPWININETAPPINFOA hIC
= NULL
;
735 LPWININETHTTPSESSIONA lpwhs
= NULL
;
739 if (((LPWININETHANDLEHEADER
)hInternet
)->htype
!= WH_HINIT
)
742 hIC
= (LPWININETAPPINFOA
) hInternet
;
744 lpwhs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPSESSIONA
));
747 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
751 if (hIC
->lpfnStatusCB
)
752 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
753 (LPVOID
)lpszServerName
, strlen(lpszServerName
));
755 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
756 nServerPort
= INTERNET_DEFAULT_HTTP_PORT
;
758 if (!GetAddress(lpszServerName
, nServerPort
, &lpwhs
->phostent
, &lpwhs
->socketAddress
))
760 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
764 if (hIC
->lpfnStatusCB
)
765 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
766 (LPVOID
)lpszServerName
, strlen(lpszServerName
));
768 lpwhs
->hdr
.htype
= WH_HHTTPSESSION
;
769 lpwhs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
770 lpwhs
->hdr
.dwFlags
= dwFlags
;
771 lpwhs
->hdr
.dwContext
= dwContext
;
772 if (NULL
!= lpszServerName
)
773 lpwhs
->lpszServerName
= HTTP_strdup(lpszServerName
);
774 if (NULL
!= lpszUserName
)
775 lpwhs
->lpszUserName
= HTTP_strdup(lpszUserName
);
776 lpwhs
->nServerPort
= nServerPort
;
778 if (hIC
->lpfnStatusCB
)
780 INTERNET_ASYNC_RESULT iar
;
782 iar
.dwResult
= (DWORD
)lpwhs
;
783 iar
.dwError
= ERROR_SUCCESS
;
785 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
786 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
792 if (!bSuccess
&& lpwhs
)
794 HeapFree(GetProcessHeap(), 0, lpwhs
);
798 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
800 INTERNET_ASYNC_RESULT iar
;
802 iar
.dwResult
= (DWORD
)lpwhs
;
803 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
804 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
805 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
808 return (HINTERNET
)lpwhs
;
812 /***********************************************************************
813 * HTTP_OpenConnection (internal)
815 * Connect to a web server
822 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
)
824 BOOL bSuccess
= FALSE
;
826 LPWININETHTTPSESSIONA lpwhs
;
830 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
832 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
836 lpwhs
= (LPWININETHTTPSESSIONA
)lpwhr
->hdr
.lpwhparent
;
838 lpwhr
->nSocketFD
= socket(lpwhs
->phostent
->h_addrtype
,SOCK_STREAM
,0);
839 if (INVALID_SOCKET
== lpwhr
->nSocketFD
)
841 WARN("Socket creation failed\n");
845 result
= connect(lpwhr
->nSocketFD
, (struct sockaddr
*)&lpwhs
->socketAddress
,
846 sizeof(lpwhs
->socketAddress
));
848 if (SOCKET_ERROR
== result
)
850 WARN("Unable to connect to host (%s)\n", strerror(errno
));
857 TRACE(": %d\n", bSuccess
);
862 /***********************************************************************
863 * HTTP_GetResponseHeaders (internal)
865 * Read server response
872 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
)
875 CHAR buffer
[MAX_REPLY_LEN
];
876 DWORD buflen
= MAX_REPLY_LEN
;
877 BOOL bSuccess
= FALSE
;
878 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
882 if (INVALID_SOCKET
== lpwhr
->nSocketFD
)
886 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
888 if (!INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
891 if (strncmp(buffer
, "HTTP", 4) != 0)
895 HTTP_ProcessHeader(lpwhr
, "Status", buffer
+9, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
897 /* Parse each response line */
900 buflen
= MAX_REPLY_LEN
;
901 if (INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
903 if (!HTTP_InterpretHttpHeader(buffer
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
906 HTTP_ProcessHeader(lpwhr
, field
, value
, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
924 /***********************************************************************
925 * HTTP_InterpretHttpHeader (internal)
927 * Parse server response
934 INT
stripSpaces(LPCSTR lpszSrc
, LPSTR lpszStart
, INT
*len
)
941 while (*lpszSrc
== ' ' && *lpszSrc
!= '\0')
945 while(*lpsztmp
!= '\0')
948 srclen
= lpsztmp
- lpszSrc
+ 1;
953 *len
= min(*len
, srclen
);
954 strncpy(lpszStart
, lpszSrc
, *len
);
955 lpszStart
[*len
] = '\0';
961 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
)
964 BOOL bSuccess
= FALSE
;
971 pd
= strchr(buffer
, ':');
975 if (stripSpaces(buffer
, field
, &fieldlen
) > 0)
977 if (stripSpaces(pd
+1, value
, &valuelen
) > 0)
982 TRACE("%d: field(%s) Value(%s)\n", bSuccess
, field
, value
);
987 /***********************************************************************
988 * HTTP_GetStdHeaderIndex (internal)
990 * Lookup field index in standard http header array
992 * FIXME: This should be stuffed into a hash table
994 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
)
998 if (!strcasecmp(lpszField
, "Content-Length"))
999 index
= HTTP_QUERY_CONTENT_LENGTH
;
1000 else if (!strcasecmp(lpszField
,"Status"))
1001 index
= HTTP_QUERY_STATUS_CODE
;
1002 else if (!strcasecmp(lpszField
,"Content-Type"))
1003 index
= HTTP_QUERY_CONTENT_TYPE
;
1004 else if (!strcasecmp(lpszField
,"Last-Modified"))
1005 index
= HTTP_QUERY_LAST_MODIFIED
;
1006 else if (!strcasecmp(lpszField
,"Location"))
1007 index
= HTTP_QUERY_LOCATION
;
1008 else if (!strcasecmp(lpszField
,"Accept"))
1009 index
= HTTP_QUERY_ACCEPT
;
1010 else if (!strcasecmp(lpszField
,"Referer"))
1011 index
= HTTP_QUERY_REFERER
;
1012 else if (!strcasecmp(lpszField
,"Content-Transfer-Encoding"))
1013 index
= HTTP_QUERY_CONTENT_TRANSFER_ENCODING
;
1014 else if (!strcasecmp(lpszField
,"Date"))
1015 index
= HTTP_QUERY_DATE
;
1016 else if (!strcasecmp(lpszField
,"Server"))
1017 index
= HTTP_QUERY_SERVER
;
1018 else if (!strcasecmp(lpszField
,"Connection"))
1019 index
= HTTP_QUERY_CONNECTION
;
1020 else if (!strcasecmp(lpszField
,"ETag"))
1021 index
= HTTP_QUERY_ETAG
;
1022 else if (!strcasecmp(lpszField
,"Accept-Ranges"))
1023 index
= HTTP_QUERY_ACCEPT_RANGES
;
1024 else if (!strcasecmp(lpszField
,"Expires"))
1025 index
= HTTP_QUERY_EXPIRES
;
1026 else if (!strcasecmp(lpszField
,"Mime-Version"))
1027 index
= HTTP_QUERY_MIME_VERSION
;
1030 FIXME("Couldn't find %s in standard header table\n", lpszField
);
1037 /***********************************************************************
1038 * HTTP_ProcessHeader (internal)
1040 * Stuff header into header tables according to <dwModifier>
1044 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1046 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
)
1048 LPHTTPHEADERA lphttpHdr
= NULL
;
1049 BOOL bSuccess
= FALSE
;
1052 TRACE("%s:%s - 0x%08x\n", field
, value
, (unsigned int)dwModifier
);
1054 /* Adjust modifier flags */
1055 if (dwModifier
& COALESCEFLASG
)
1056 dwModifier
|= HTTP_ADDHDR_FLAG_ADD
;
1058 /* Try to get index into standard header array */
1059 index
= HTTP_GetStdHeaderIndex(field
);
1062 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
1064 else /* Find or create new custom header */
1066 index
= HTTP_GetCustomHeaderIndex(lpwhr
, field
);
1069 if (dwModifier
& HTTP_ADDHDR_FLAG_ADD_IF_NEW
)
1073 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
1079 hdr
.lpszField
= (LPSTR
)field
;
1080 hdr
.lpszValue
= (LPSTR
)value
;
1081 hdr
.wFlags
= hdr
.wCount
= 0;
1083 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1084 hdr
.wFlags
|= HDR_ISREQUEST
;
1086 index
= HTTP_InsertCustomHeader(lpwhr
, &hdr
);
1091 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1092 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1094 lphttpHdr
->wFlags
&= ~HDR_ISREQUEST
;
1096 if (!lphttpHdr
->lpszValue
&& (dwModifier
& (HTTP_ADDHDR_FLAG_ADD
|HTTP_ADDHDR_FLAG_ADD_IF_NEW
)))
1100 if (!lpwhr
->StdHeaders
[index
].lpszField
)
1102 lphttpHdr
->lpszField
= HTTP_strdup(field
);
1104 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1105 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1108 slen
= strlen(value
) + 1;
1109 lphttpHdr
->lpszValue
= HeapAlloc(GetProcessHeap(), 0, slen
);
1110 if (lphttpHdr
->lpszValue
)
1112 memcpy(lphttpHdr
->lpszValue
, value
, slen
);
1117 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1120 else if (lphttpHdr
->lpszValue
)
1122 if (dwModifier
& HTTP_ADDHDR_FLAG_REPLACE
)
1127 len
= strlen(value
);
1131 //! if custom header delete from array
1132 HeapFree(GetProcessHeap(), 0, lphttpHdr
->lpszValue
);
1133 lphttpHdr
->lpszValue
= NULL
;
1138 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1141 lphttpHdr
->lpszValue
= lpsztmp
;
1142 strcpy(lpsztmp
, value
);
1147 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1151 else if (dwModifier
& COALESCEFLASG
)
1156 INT origlen
= strlen(lphttpHdr
->lpszValue
);
1157 INT valuelen
= strlen(value
);
1159 if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA
)
1162 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1164 else if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON
)
1167 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1170 len
= origlen
+ valuelen
+ (ch
> 0) ? 1 : 0;
1172 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1175 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1178 lphttpHdr
->lpszValue
[origlen
] = ch
;
1182 memcpy(&lphttpHdr
->lpszValue
[origlen
], value
, valuelen
);
1183 lphttpHdr
->lpszValue
[len
] = '\0';
1188 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1197 /***********************************************************************
1198 * HTTP_CloseConnection (internal)
1200 * Close socket connection
1203 VOID
HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
)
1205 if (lpwhr
->nSocketFD
!= INVALID_SOCKET
)
1207 close(lpwhr
->nSocketFD
);
1208 lpwhr
->nSocketFD
= INVALID_SOCKET
;
1213 /***********************************************************************
1214 * HTTP_CloseHTTPRequestHandle (internal)
1216 * Deallocate request handle
1219 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr
)
1225 if (lpwhr
->nSocketFD
!= INVALID_SOCKET
)
1226 HTTP_CloseConnection(lpwhr
);
1228 if (lpwhr
->lpszPath
)
1229 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszPath
);
1230 if (lpwhr
->lpszVerb
)
1231 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszVerb
);
1232 if (lpwhr
->lpszHostName
)
1233 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszHostName
);
1235 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
1237 if (lpwhr
->StdHeaders
[i
].lpszField
)
1238 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszField
);
1239 if (lpwhr
->StdHeaders
[i
].lpszValue
)
1240 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszValue
);
1243 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
1245 if (lpwhr
->pCustHeaders
[i
].lpszField
)
1246 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszField
);
1247 if (lpwhr
->pCustHeaders
[i
].lpszValue
)
1248 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszValue
);
1251 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
);
1252 HeapFree(GetProcessHeap(), 0, lpwhr
);
1256 /***********************************************************************
1257 * HTTP_CloseHTTPSessionHandle (internal)
1259 * Deallocate session handle
1262 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs
)
1266 if (lpwhs
->lpszServerName
)
1267 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszServerName
);
1268 if (lpwhs
->lpszUserName
)
1269 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszUserName
);
1270 HeapFree(GetProcessHeap(), 0, lpwhs
);
1274 /***********************************************************************
1275 * HTTP_GetCustomHeaderIndex (internal)
1277 * Return index of custom header from header array
1280 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
)
1284 TRACE("%s\n", lpszField
);
1286 for (index
= 0; index
< lpwhr
->nCustHeaders
; index
++)
1288 if (!strcasecmp(lpwhr
->pCustHeaders
[index
].lpszField
, lpszField
))
1293 if (index
>= lpwhr
->nCustHeaders
)
1296 TRACE("Return: %d\n", index
);
1301 /***********************************************************************
1302 * HTTP_InsertCustomHeader (internal)
1304 * Insert header into array
1307 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
)
1310 LPHTTPHEADERA lph
= NULL
;
1312 TRACE("%s: %s\n", lpHdr
->lpszField
, lpHdr
->lpszValue
);
1313 count
= lpwhr
->nCustHeaders
+ 1;
1315 lph
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpwhr
->pCustHeaders
, sizeof(HTTPHEADERA
) * count
);
1317 lph
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HTTPHEADERA
) * count
);
1321 lpwhr
->pCustHeaders
= lph
;
1322 lpwhr
->pCustHeaders
[count
-1].lpszField
= HTTP_strdup(lpHdr
->lpszField
);
1323 lpwhr
->pCustHeaders
[count
-1].lpszValue
= HTTP_strdup(lpHdr
->lpszValue
);
1324 lpwhr
->pCustHeaders
[count
-1].wFlags
= lpHdr
->wFlags
;
1325 lpwhr
->pCustHeaders
[count
-1].wCount
= lpHdr
->wCount
;
1326 lpwhr
->nCustHeaders
++;
1330 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1334 TRACE("%d <--\n", count
-1);
1339 /***********************************************************************
1340 * HTTP_DeleteCustomHeader (internal)
1342 * Delete header from array
1345 BOOL
HTTP_DeleteCustomHeader(INT index
)