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