2 * Wininet - Http Implementation
4 * Copyright 1999 Corel Corporation
12 #include <sys/types.h>
13 #ifdef HAVE_SYS_SOCKET_H
14 # include <sys/socket.h>
28 #define NO_SHLWAPI_STREAM
32 #include "debugtools.h"
34 DEFAULT_DEBUG_CHANNEL(wininet
);
36 #define HTTPHEADER " HTTP/1.0"
37 #define HTTPHOSTHEADER "\r\nHost: "
38 #define MAXHOSTNAME 100
39 #define MAX_FIELD_VALUE_LEN 256
40 #define MAX_FIELD_LEN 256
43 #define HTTP_REFERER "Referer"
44 #define HTTP_ACCEPT "Accept"
46 #define HTTP_ADDHDR_FLAG_ADD 0x20000000
47 #define HTTP_ADDHDR_FLAG_ADD_IF_NEW 0x10000000
48 #define HTTP_ADDHDR_FLAG_COALESCE 0x40000000
49 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA 0x40000000
50 #define HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON 0x01000000
51 #define HTTP_ADDHDR_FLAG_REPLACE 0x80000000
52 #define HTTP_ADDHDR_FLAG_REQ 0x02000000
55 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
);
56 int HTTP_WriteDataToStream(LPWININETHTTPREQA lpwhr
,
57 void *Buffer
, int BytesToWrite
);
58 int HTTP_ReadDataFromStream(LPWININETHTTPREQA lpwhr
,
59 void *Buffer
, int BytesToRead
);
60 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
);
61 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
);
62 void HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
);
63 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
);
64 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
);
65 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
);
66 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
);
68 inline static LPSTR
HTTP_strdup( LPCSTR str
)
70 LPSTR ret
= HeapAlloc( GetProcessHeap(), 0, strlen(str
) + 1 );
71 if (ret
) strcpy( ret
, str
);
75 /***********************************************************************
76 * HttpAddRequestHeadersA (WININET.@)
78 * Adds one or more HTTP header to the request handler
85 BOOL WINAPI
HttpAddRequestHeadersA(HINTERNET hHttpRequest
,
86 LPCSTR lpszHeader
, DWORD dwHeaderLength
, DWORD dwModifier
)
91 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
92 BOOL bSuccess
= FALSE
;
93 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
95 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
97 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
101 buffer
= HTTP_strdup(lpszHeader
);
108 while (*lpszEnd
!= '\0')
110 if (*lpszEnd
== '\r' && *(lpszEnd
+ 1) == '\n')
115 if (*lpszEnd
== '\0')
120 if (HTTP_InterpretHttpHeader(lpszStart
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
121 bSuccess
= HTTP_ProcessHeader(lpwhr
, field
, value
, dwModifier
| HTTP_ADDHDR_FLAG_REQ
);
123 lpszStart
= lpszEnd
+ 2; /* Jump over \0\n */
127 HeapFree(GetProcessHeap(), 0, buffer
);
132 /***********************************************************************
133 * HttpOpenRequestA (WININET.@)
135 * Open a HTTP request handle
138 * HINTERNET a HTTP request handle on success
142 HINTERNET WINAPI
HttpOpenRequestA(HINTERNET hHttpSession
,
143 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
144 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
145 DWORD dwFlags
, DWORD dwContext
)
147 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
148 LPWININETAPPINFOA hIC
= NULL
;
152 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
154 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
158 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
160 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
162 WORKREQUEST workRequest
;
164 workRequest
.asyncall
= HTTPOPENREQUESTA
;
165 workRequest
.HFTPSESSION
= (DWORD
)hHttpSession
;
166 workRequest
.LPSZVERB
= (DWORD
)HTTP_strdup(lpszVerb
);
167 workRequest
.LPSZOBJECTNAME
= (DWORD
)HTTP_strdup(lpszObjectName
);
168 workRequest
.LPSZVERSION
= (DWORD
)HTTP_strdup(lpszVersion
);
169 workRequest
.LPSZREFERRER
= (DWORD
)HTTP_strdup(lpszReferrer
);
170 workRequest
.LPSZACCEPTTYPES
= (DWORD
)lpszAcceptTypes
;
171 workRequest
.DWFLAGS
= dwFlags
;
172 workRequest
.DWCONTEXT
= dwContext
;
174 return (HINTERNET
)INTERNET_AsyncCall(&workRequest
);
178 return HTTP_HttpOpenRequestA(hHttpSession
, lpszVerb
, lpszObjectName
,
179 lpszVersion
, lpszReferrer
, lpszAcceptTypes
, dwFlags
, dwContext
);
184 /***********************************************************************
185 * HTTP_HttpOpenRequestA (internal)
187 * Open a HTTP request handle
190 * HINTERNET a HTTP request handle on success
194 HINTERNET WINAPI
HTTP_HttpOpenRequestA(HINTERNET hHttpSession
,
195 LPCSTR lpszVerb
, LPCSTR lpszObjectName
, LPCSTR lpszVersion
,
196 LPCSTR lpszReferrer
, LPCSTR
*lpszAcceptTypes
,
197 DWORD dwFlags
, DWORD dwContext
)
199 LPWININETHTTPSESSIONA lpwhs
= (LPWININETHTTPSESSIONA
) hHttpSession
;
200 LPWININETAPPINFOA hIC
= NULL
;
201 LPWININETHTTPREQA lpwhr
;
205 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
207 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
211 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
213 lpwhr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPREQA
));
216 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
217 return (HINTERNET
) NULL
;
220 lpwhr
->hdr
.htype
= WH_HHTTPREQ
;
221 lpwhr
->hdr
.lpwhparent
= hHttpSession
;
222 lpwhr
->hdr
.dwFlags
= dwFlags
;
223 lpwhr
->hdr
.dwContext
= dwContext
;
224 lpwhr
->nSocketFD
= -1;
226 if (NULL
!= lpszObjectName
&& strlen(lpszObjectName
)) {
228 UrlEscapeA(lpszObjectName
, NULL
, &needed
, URL_ESCAPE_SPACES_ONLY
);
229 lpwhr
->lpszPath
= HeapAlloc(GetProcessHeap(), 0, needed
);
230 UrlEscapeA(lpszObjectName
, lpwhr
->lpszPath
, &needed
,
231 URL_ESCAPE_SPACES_ONLY
);
234 if (NULL
!= lpszReferrer
&& strlen(lpszReferrer
))
235 HTTP_ProcessHeader(lpwhr
, HTTP_REFERER
, lpszReferrer
, HTTP_ADDHDR_FLAG_COALESCE
);
238 if (NULL
!= lpszAcceptTypes
&& strlen(*lpszAcceptTypes
))
239 HTTP_ProcessHeader(lpwhr
, HTTP_ACCEPT
, *lpszAcceptTypes
, HTTP_ADDHDR_FLAG_COALESCE
);
241 if (NULL
== lpszVerb
)
242 lpwhr
->lpszVerb
= HTTP_strdup("GET");
243 else if (strlen(lpszVerb
))
244 lpwhr
->lpszVerb
= HTTP_strdup(lpszVerb
);
246 if (NULL
!= lpszReferrer
)
248 char buf
[MAXHOSTNAME
];
249 URL_COMPONENTSA UrlComponents
;
251 UrlComponents
.lpszExtraInfo
= NULL
;
252 UrlComponents
.lpszPassword
= NULL
;
253 UrlComponents
.lpszScheme
= NULL
;
254 UrlComponents
.lpszUrlPath
= NULL
;
255 UrlComponents
.lpszUserName
= NULL
;
256 UrlComponents
.lpszHostName
= buf
;
257 UrlComponents
.dwHostNameLength
= MAXHOSTNAME
;
259 InternetCrackUrlA(lpszReferrer
, 0, 0, &UrlComponents
);
260 if (strlen(UrlComponents
.lpszHostName
))
261 lpwhr
->lpszHostName
= HTTP_strdup(UrlComponents
.lpszHostName
);
263 lpwhr
->lpszHostName
= HTTP_strdup(lpwhs
->lpszServerName
);
266 if (hIC
->lpfnStatusCB
)
268 INTERNET_ASYNC_RESULT iar
;
270 iar
.dwResult
= (DWORD
)lpwhr
;
271 iar
.dwError
= ERROR_SUCCESS
;
273 hIC
->lpfnStatusCB(hHttpSession
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
274 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
277 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
279 INTERNET_ASYNC_RESULT iar
;
281 iar
.dwResult
= (DWORD
)lpwhr
;
282 iar
.dwError
= lpwhr
? ERROR_SUCCESS
: INTERNET_GetLastError();
283 hIC
->lpfnStatusCB(hHttpSession
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
284 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
287 return (HINTERNET
) lpwhr
;
291 /***********************************************************************
292 * HttpQueryInfoA (WININET.@)
294 * Queries for information about an HTTP request
301 BOOL WINAPI
HttpQueryInfoA(HINTERNET hHttpRequest
, DWORD dwInfoLevel
,
302 LPVOID lpBuffer
, LPDWORD lpdwBufferLength
, LPDWORD lpdwIndex
)
304 LPHTTPHEADERA lphttpHdr
= NULL
;
305 BOOL bSuccess
= FALSE
;
306 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
308 TRACE("(0x%08lx)--> %ld\n", dwInfoLevel
, dwInfoLevel
);
310 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
312 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
316 /* Find requested header structure */
317 if ((dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
) == HTTP_QUERY_CUSTOM
)
319 INT index
= HTTP_GetCustomHeaderIndex(lpwhr
, (LPSTR
)lpBuffer
);
324 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
328 INT index
= dwInfoLevel
& ~HTTP_QUERY_MODIFIER_FLAGS_MASK
;
330 if (index
== HTTP_QUERY_RAW_HEADERS_CRLF
|| index
== HTTP_QUERY_RAW_HEADERS
)
332 INT i
, delim
, size
= 0, cnt
= 0;
334 delim
= index
== HTTP_QUERY_RAW_HEADERS_CRLF
? 2 : 1;
336 /* Calculate length of custom reuqest headers */
337 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
339 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->pCustHeaders
[i
].lpszField
&&
340 lpwhr
->pCustHeaders
[i
].lpszValue
)
342 size
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
343 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + delim
+ 2;
347 /* Calculate the length of stadard request headers */
348 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
350 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) && lpwhr
->StdHeaders
[i
].lpszField
&&
351 lpwhr
->StdHeaders
[i
].lpszValue
)
353 size
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
354 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + delim
+ 2;
360 if (size
+ 1 > *lpdwBufferLength
)
362 *lpdwBufferLength
= size
+ 1;
363 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
367 /* Append standard request heades */
368 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
370 if ((~lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
371 lpwhr
->StdHeaders
[i
].lpszField
&&
372 lpwhr
->StdHeaders
[i
].lpszValue
)
374 cnt
+= sprintf(lpBuffer
+ cnt
, "%s: %s%s", lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
,
375 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
379 /* Append custom request heades */
380 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
382 if ((~lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
) &&
383 lpwhr
->pCustHeaders
[i
].lpszField
&&
384 lpwhr
->pCustHeaders
[i
].lpszValue
)
386 cnt
+= sprintf(lpBuffer
+ cnt
, "%s: %s%s",
387 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
,
388 index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "\0");
392 strcpy(lpBuffer
+ cnt
, index
== HTTP_QUERY_RAW_HEADERS_CRLF
? "\r\n" : "");
394 *lpdwBufferLength
= cnt
+ delim
;
398 else if (index
>= 0 && index
<= HTTP_QUERY_MAX
&& lpwhr
->StdHeaders
[index
].lpszValue
)
400 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
406 /* Ensure header satisifies requested attributes */
407 if ((dwInfoLevel
& HTTP_QUERY_FLAG_REQUEST_HEADERS
) &&
408 (~lphttpHdr
->wFlags
& HDR_ISREQUEST
))
411 /* coalesce value to reuqested type */
412 if (dwInfoLevel
& HTTP_QUERY_FLAG_NUMBER
)
414 *(int *)lpBuffer
= atoi(lphttpHdr
->lpszValue
);
417 else if (dwInfoLevel
& HTTP_QUERY_FLAG_SYSTEMTIME
)
423 tmpTime
= ConvertTimeString(lphttpHdr
->lpszValue
);
425 tmpTM
= *gmtime(&tmpTime
);
426 STHook
= (SYSTEMTIME
*) lpBuffer
;
430 STHook
->wDay
= tmpTM
.tm_mday
;
431 STHook
->wHour
= tmpTM
.tm_hour
;
432 STHook
->wMilliseconds
= 0;
433 STHook
->wMinute
= tmpTM
.tm_min
;
434 STHook
->wDayOfWeek
= tmpTM
.tm_wday
;
435 STHook
->wMonth
= tmpTM
.tm_mon
+ 1;
436 STHook
->wSecond
= tmpTM
.tm_sec
;
437 STHook
->wYear
= tmpTM
.tm_year
;
441 else if (dwInfoLevel
& HTTP_QUERY_FLAG_COALESCE
)
443 if (*lpdwIndex
>= lphttpHdr
->wCount
)
445 INTERNET_SetLastError(ERROR_HTTP_HEADER_NOT_FOUND
);
449 //! Copy strncpy(lpBuffer, lphttpHdr[*lpdwIndex], len);
455 INT len
= strlen(lphttpHdr
->lpszValue
);
457 if (len
+ 1 > *lpdwBufferLength
)
459 *lpdwBufferLength
= len
+ 1;
460 INTERNET_SetLastError(ERROR_INSUFFICIENT_BUFFER
);
464 strncpy(lpBuffer
, lphttpHdr
->lpszValue
, len
);
465 *lpdwBufferLength
= len
;
470 TRACE("%d <--\n", bSuccess
);
475 /***********************************************************************
476 * HttpSendRequestExA (WININET.@)
478 * Sends the specified request to the HTTP server and allows chunked
481 BOOL WINAPI
HttpSendRequestExA(HINTERNET hRequest
,
482 LPINTERNET_BUFFERSA lpBuffersIn
,
483 LPINTERNET_BUFFERSA lpBuffersOut
,
484 DWORD dwFlags
, DWORD dwContext
)
486 FIXME("(%p, %p, %p, %08lx, %08lx): stub\n", hRequest
, lpBuffersIn
,
487 lpBuffersOut
, dwFlags
, dwContext
);
491 /***********************************************************************
492 * HttpSendRequestA (WININET.@)
494 * Sends the specified request to the HTTP server
501 BOOL WINAPI
HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
502 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
504 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
505 LPWININETHTTPSESSIONA lpwhs
= NULL
;
506 LPWININETAPPINFOA hIC
= NULL
;
508 TRACE("0x%08lx\n", (unsigned long)hHttpRequest
);
510 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
512 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
516 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
517 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
519 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
523 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
524 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
526 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
530 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
)
532 WORKREQUEST workRequest
;
534 workRequest
.asyncall
= HTTPSENDREQUESTA
;
535 workRequest
.HFTPSESSION
= (DWORD
)hHttpRequest
;
536 workRequest
.LPSZHEADER
= (DWORD
)HTTP_strdup(lpszHeaders
);
537 workRequest
.DWHEADERLENGTH
= dwHeaderLength
;
538 workRequest
.LPOPTIONAL
= (DWORD
)lpOptional
;
539 workRequest
.DWOPTIONALLENGTH
= dwOptionalLength
;
541 return INTERNET_AsyncCall(&workRequest
);
545 return HTTP_HttpSendRequestA(hHttpRequest
, lpszHeaders
,
546 dwHeaderLength
, lpOptional
, dwOptionalLength
);
551 /***********************************************************************
552 * HTTP_HttpSendRequestA (internal)
554 * Sends the specified request to the HTTP server
561 BOOL WINAPI
HTTP_HttpSendRequestA(HINTERNET hHttpRequest
, LPCSTR lpszHeaders
,
562 DWORD dwHeaderLength
, LPVOID lpOptional
,DWORD dwOptionalLength
)
566 BOOL bSuccess
= FALSE
;
567 LPSTR requestString
= NULL
;
568 INT requestStringLen
;
569 INT headerLength
= 0;
570 LPWININETHTTPREQA lpwhr
= (LPWININETHTTPREQA
) hHttpRequest
;
571 LPWININETHTTPSESSIONA lpwhs
= NULL
;
572 LPWININETAPPINFOA hIC
= NULL
;
574 TRACE("0x%08lx\n", (ULONG
)hHttpRequest
);
576 /* Verify our tree of internet handles */
577 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
579 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
583 lpwhs
= (LPWININETHTTPSESSIONA
) lpwhr
->hdr
.lpwhparent
;
584 if (NULL
== lpwhs
|| lpwhs
->hdr
.htype
!= WH_HHTTPSESSION
)
586 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
590 hIC
= (LPWININETAPPINFOA
) lpwhs
->hdr
.lpwhparent
;
591 if (NULL
== hIC
|| hIC
->hdr
.htype
!= WH_HINIT
)
593 INTERNET_SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE
);
597 /* Clear any error information */
598 INTERNET_SetLastError(0);
600 /* We must have a verb */
601 if (NULL
== lpwhr
->lpszVerb
)
606 /* If we don't have a path we set it to root */
607 if (NULL
== lpwhr
->lpszPath
)
608 lpwhr
->lpszPath
= HTTP_strdup("/");
610 if(lpwhr
->lpszPath
[0] != '/') /* not an absolute path ?? --> fix it !! */
612 char *fixurl
= HeapAlloc(GetProcessHeap(), 0, strlen(lpwhr
->lpszPath
) + 2);
614 strcpy(fixurl
+ 1, lpwhr
->lpszPath
);
615 HeapFree( GetProcessHeap(), 0, lpwhr
->lpszPath
);
616 lpwhr
->lpszPath
= fixurl
;
619 /* Calculate length of request string */
621 strlen(lpwhr
->lpszVerb
) +
622 strlen(lpwhr
->lpszPath
) +
623 (lpwhr
->lpszHostName
? (strlen(HTTPHOSTHEADER
) + strlen(lpwhr
->lpszHostName
)) : 0) +
627 /* Add length of passed headers */
630 headerLength
= -1 == dwHeaderLength
? strlen(lpszHeaders
) : dwHeaderLength
;
631 requestStringLen
+= headerLength
+ 2; /* \r\n */
634 /* Calculate length of custom request headers */
635 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
637 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
639 requestStringLen
+= strlen(lpwhr
->pCustHeaders
[i
].lpszField
) +
640 strlen(lpwhr
->pCustHeaders
[i
].lpszValue
) + 4; /*: \r\n */
644 /* Calculate the length of standard request headers */
645 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
647 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
649 requestStringLen
+= strlen(lpwhr
->StdHeaders
[i
].lpszField
) +
650 strlen(lpwhr
->StdHeaders
[i
].lpszValue
) + 4; /*: \r\n */
654 /* Allocate string to hold entire request */
655 requestString
= HeapAlloc(GetProcessHeap(), 0, requestStringLen
+ 1);
656 if (NULL
== requestString
)
658 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
662 /* Build request string */
663 cnt
= sprintf(requestString
, "%s %s%s%s",
666 lpwhr
->lpszHostName
? (HTTPHEADER HTTPHOSTHEADER
) : HTTPHEADER
,
667 lpwhr
->lpszHostName
? lpwhr
->lpszHostName
: "");
669 /* Append standard request headers */
670 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
672 if (lpwhr
->StdHeaders
[i
].wFlags
& HDR_ISREQUEST
)
674 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
675 lpwhr
->StdHeaders
[i
].lpszField
, lpwhr
->StdHeaders
[i
].lpszValue
);
679 /* Append custom request heades */
680 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
682 if (lpwhr
->pCustHeaders
[i
].wFlags
& HDR_ISREQUEST
)
684 cnt
+= sprintf(requestString
+ cnt
, "\r\n%s: %s",
685 lpwhr
->pCustHeaders
[i
].lpszField
, lpwhr
->pCustHeaders
[i
].lpszValue
);
689 /* Append passed request headers */
692 strcpy(requestString
+ cnt
, "\r\n");
694 strcpy(requestString
+ cnt
, lpszHeaders
);
698 /* Set termination string for request */
699 strcpy(requestString
+ cnt
, "\r\n\r\n");
701 if (hIC
->lpfnStatusCB
)
702 hIC
->lpfnStatusCB(hHttpRequest
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_SENDING_REQUEST
, NULL
, 0);
704 TRACE("(%s) len(%d)\n", requestString
, requestStringLen
);
705 /* Send the request and store the results */
706 if (!HTTP_OpenConnection(lpwhr
))
709 cnt
= INTERNET_WriteDataToStream(lpwhr
->nSocketFD
, requestString
, requestStringLen
);
714 if (HTTP_GetResponseHeaders(lpwhr
))
720 HeapFree(GetProcessHeap(), 0, requestString
);
722 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
724 INTERNET_ASYNC_RESULT iar
;
726 iar
.dwResult
= (DWORD
)bSuccess
;
727 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
728 hIC
->lpfnStatusCB(hHttpRequest
, lpwhr
->hdr
.dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
729 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
737 /***********************************************************************
738 * HTTP_Connect (internal)
740 * Create http session handle
743 * HINTERNET a session handle on success
747 HINTERNET
HTTP_Connect(HINTERNET hInternet
, LPCSTR lpszServerName
,
748 INTERNET_PORT nServerPort
, LPCSTR lpszUserName
,
749 LPCSTR lpszPassword
, DWORD dwFlags
, DWORD dwContext
)
751 BOOL bSuccess
= FALSE
;
752 LPWININETAPPINFOA hIC
= NULL
;
753 LPWININETHTTPSESSIONA lpwhs
= NULL
;
757 if (((LPWININETHANDLEHEADER
)hInternet
)->htype
!= WH_HINIT
)
760 hIC
= (LPWININETAPPINFOA
) hInternet
;
762 lpwhs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(WININETHTTPSESSIONA
));
765 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
769 if (hIC
->lpfnStatusCB
)
770 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_RESOLVING_NAME
,
771 (LPVOID
)lpszServerName
, strlen(lpszServerName
));
773 if (nServerPort
== INTERNET_INVALID_PORT_NUMBER
)
774 nServerPort
= INTERNET_DEFAULT_HTTP_PORT
;
776 if (!GetAddress(lpszServerName
, nServerPort
, &lpwhs
->phostent
, &lpwhs
->socketAddress
))
778 INTERNET_SetLastError(ERROR_INTERNET_NAME_NOT_RESOLVED
);
782 if (hIC
->lpfnStatusCB
)
783 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_NAME_RESOLVED
,
784 (LPVOID
)lpszServerName
, strlen(lpszServerName
));
786 lpwhs
->hdr
.htype
= WH_HHTTPSESSION
;
787 lpwhs
->hdr
.lpwhparent
= (LPWININETHANDLEHEADER
)hInternet
;
788 lpwhs
->hdr
.dwFlags
= dwFlags
;
789 lpwhs
->hdr
.dwContext
= dwContext
;
790 if (NULL
!= lpszServerName
)
791 lpwhs
->lpszServerName
= HTTP_strdup(lpszServerName
);
792 if (NULL
!= lpszUserName
)
793 lpwhs
->lpszUserName
= HTTP_strdup(lpszUserName
);
794 lpwhs
->nServerPort
= nServerPort
;
796 if (hIC
->lpfnStatusCB
)
798 INTERNET_ASYNC_RESULT iar
;
800 iar
.dwResult
= (DWORD
)lpwhs
;
801 iar
.dwError
= ERROR_SUCCESS
;
803 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_HANDLE_CREATED
,
804 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
810 if (!bSuccess
&& lpwhs
)
812 HeapFree(GetProcessHeap(), 0, lpwhs
);
816 if (hIC
->hdr
.dwFlags
& INTERNET_FLAG_ASYNC
&& hIC
->lpfnStatusCB
)
818 INTERNET_ASYNC_RESULT iar
;
820 iar
.dwResult
= (DWORD
)lpwhs
;
821 iar
.dwError
= bSuccess
? ERROR_SUCCESS
: INTERNET_GetLastError();
822 hIC
->lpfnStatusCB(hInternet
, dwContext
, INTERNET_STATUS_REQUEST_COMPLETE
,
823 &iar
, sizeof(INTERNET_ASYNC_RESULT
));
826 return (HINTERNET
)lpwhs
;
830 /***********************************************************************
831 * HTTP_OpenConnection (internal)
833 * Connect to a web server
840 BOOL
HTTP_OpenConnection(LPWININETHTTPREQA lpwhr
)
842 BOOL bSuccess
= FALSE
;
844 LPWININETHTTPSESSIONA lpwhs
;
848 if (NULL
== lpwhr
|| lpwhr
->hdr
.htype
!= WH_HHTTPREQ
)
850 INTERNET_SetLastError(ERROR_INVALID_PARAMETER
);
854 lpwhs
= (LPWININETHTTPSESSIONA
)lpwhr
->hdr
.lpwhparent
;
856 lpwhr
->nSocketFD
= socket(lpwhs
->phostent
->h_addrtype
,SOCK_STREAM
,0);
857 if (lpwhr
->nSocketFD
== -1)
859 WARN("Socket creation failed\n");
863 result
= connect(lpwhr
->nSocketFD
, (struct sockaddr
*)&lpwhs
->socketAddress
,
864 sizeof(lpwhs
->socketAddress
));
868 WARN("Unable to connect to host (%s)\n", strerror(errno
));
875 TRACE(": %d\n", bSuccess
);
880 /***********************************************************************
881 * HTTP_GetResponseHeaders (internal)
883 * Read server response
890 BOOL
HTTP_GetResponseHeaders(LPWININETHTTPREQA lpwhr
)
893 CHAR buffer
[MAX_REPLY_LEN
];
894 DWORD buflen
= MAX_REPLY_LEN
;
895 BOOL bSuccess
= FALSE
;
896 CHAR value
[MAX_FIELD_VALUE_LEN
], field
[MAX_FIELD_LEN
];
900 if (lpwhr
->nSocketFD
== -1)
904 * We should first receive 'HTTP/1.x nnn' where nnn is the status code.
906 if (!INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
909 if (strncmp(buffer
, "HTTP", 4) != 0)
913 HTTP_ProcessHeader(lpwhr
, "Status", buffer
+9, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
915 /* Parse each response line */
918 buflen
= MAX_REPLY_LEN
;
919 if (INTERNET_GetNextLine(lpwhr
->nSocketFD
, buffer
, &buflen
))
921 if (!HTTP_InterpretHttpHeader(buffer
, field
, MAX_FIELD_LEN
, value
, MAX_FIELD_VALUE_LEN
))
924 HTTP_ProcessHeader(lpwhr
, field
, value
, (HTTP_ADDREQ_FLAG_ADD
| HTTP_ADDREQ_FLAG_REPLACE
));
942 /***********************************************************************
943 * HTTP_InterpretHttpHeader (internal)
945 * Parse server response
952 INT
stripSpaces(LPCSTR lpszSrc
, LPSTR lpszStart
, INT
*len
)
959 while (*lpszSrc
== ' ' && *lpszSrc
!= '\0')
963 while(*lpsztmp
!= '\0')
966 srclen
= lpsztmp
- lpszSrc
+ 1;
971 *len
= min(*len
, srclen
);
972 strncpy(lpszStart
, lpszSrc
, *len
);
973 lpszStart
[*len
] = '\0';
979 BOOL
HTTP_InterpretHttpHeader(LPSTR buffer
, LPSTR field
, INT fieldlen
, LPSTR value
, INT valuelen
)
982 BOOL bSuccess
= FALSE
;
989 pd
= strchr(buffer
, ':');
993 if (stripSpaces(buffer
, field
, &fieldlen
) > 0)
995 if (stripSpaces(pd
+1, value
, &valuelen
) > 0)
1000 TRACE("%d: field(%s) Value(%s)\n", bSuccess
, field
, value
);
1005 /***********************************************************************
1006 * HTTP_GetStdHeaderIndex (internal)
1008 * Lookup field index in standard http header array
1010 * FIXME: This should be stuffed into a hash table
1012 INT
HTTP_GetStdHeaderIndex(LPCSTR lpszField
)
1016 if (!strcasecmp(lpszField
, "Content-Length"))
1017 index
= HTTP_QUERY_CONTENT_LENGTH
;
1018 else if (!strcasecmp(lpszField
,"Status"))
1019 index
= HTTP_QUERY_STATUS_CODE
;
1020 else if (!strcasecmp(lpszField
,"Content-Type"))
1021 index
= HTTP_QUERY_CONTENT_TYPE
;
1022 else if (!strcasecmp(lpszField
,"Last-Modified"))
1023 index
= HTTP_QUERY_LAST_MODIFIED
;
1024 else if (!strcasecmp(lpszField
,"Location"))
1025 index
= HTTP_QUERY_LOCATION
;
1026 else if (!strcasecmp(lpszField
,"Accept"))
1027 index
= HTTP_QUERY_ACCEPT
;
1028 else if (!strcasecmp(lpszField
,"Referer"))
1029 index
= HTTP_QUERY_REFERER
;
1030 else if (!strcasecmp(lpszField
,"Content-Transfer-Encoding"))
1031 index
= HTTP_QUERY_CONTENT_TRANSFER_ENCODING
;
1032 else if (!strcasecmp(lpszField
,"Date"))
1033 index
= HTTP_QUERY_DATE
;
1034 else if (!strcasecmp(lpszField
,"Server"))
1035 index
= HTTP_QUERY_SERVER
;
1036 else if (!strcasecmp(lpszField
,"Connection"))
1037 index
= HTTP_QUERY_CONNECTION
;
1038 else if (!strcasecmp(lpszField
,"ETag"))
1039 index
= HTTP_QUERY_ETAG
;
1040 else if (!strcasecmp(lpszField
,"Accept-Ranges"))
1041 index
= HTTP_QUERY_ACCEPT_RANGES
;
1042 else if (!strcasecmp(lpszField
,"Expires"))
1043 index
= HTTP_QUERY_EXPIRES
;
1044 else if (!strcasecmp(lpszField
,"Mime-Version"))
1045 index
= HTTP_QUERY_MIME_VERSION
;
1046 else if (!strcasecmp(lpszField
,"Pragma"))
1047 index
= HTTP_QUERY_PRAGMA
;
1048 else if (!strcasecmp(lpszField
,"Cache-Control"))
1049 index
= HTTP_QUERY_CACHE_CONTROL
;
1050 else if (!strcasecmp(lpszField
,"Content-Length"))
1051 index
= HTTP_QUERY_CONTENT_LENGTH
;
1052 else if (!strcasecmp(lpszField
,"User-Agent"))
1053 index
= HTTP_QUERY_USER_AGENT
;
1056 FIXME("Couldn't find %s in standard header table\n", lpszField
);
1063 /***********************************************************************
1064 * HTTP_ProcessHeader (internal)
1066 * Stuff header into header tables according to <dwModifier>
1070 #define COALESCEFLASG (HTTP_ADDHDR_FLAG_COALESCE|HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA|HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON)
1072 BOOL
HTTP_ProcessHeader(LPWININETHTTPREQA lpwhr
, LPCSTR field
, LPCSTR value
, DWORD dwModifier
)
1074 LPHTTPHEADERA lphttpHdr
= NULL
;
1075 BOOL bSuccess
= FALSE
;
1078 TRACE("%s:%s - 0x%08x\n", field
, value
, (unsigned int)dwModifier
);
1080 /* Adjust modifier flags */
1081 if (dwModifier
& COALESCEFLASG
)
1082 dwModifier
|= HTTP_ADDHDR_FLAG_ADD
;
1084 /* Try to get index into standard header array */
1085 index
= HTTP_GetStdHeaderIndex(field
);
1088 lphttpHdr
= &lpwhr
->StdHeaders
[index
];
1090 else /* Find or create new custom header */
1092 index
= HTTP_GetCustomHeaderIndex(lpwhr
, field
);
1095 if (dwModifier
& HTTP_ADDHDR_FLAG_ADD_IF_NEW
)
1099 lphttpHdr
= &lpwhr
->pCustHeaders
[index
];
1105 hdr
.lpszField
= (LPSTR
)field
;
1106 hdr
.lpszValue
= (LPSTR
)value
;
1107 hdr
.wFlags
= hdr
.wCount
= 0;
1109 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1110 hdr
.wFlags
|= HDR_ISREQUEST
;
1112 index
= HTTP_InsertCustomHeader(lpwhr
, &hdr
);
1117 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1118 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1120 lphttpHdr
->wFlags
&= ~HDR_ISREQUEST
;
1122 if (!lphttpHdr
->lpszValue
&& (dwModifier
& (HTTP_ADDHDR_FLAG_ADD
|HTTP_ADDHDR_FLAG_ADD_IF_NEW
)))
1126 if (!lpwhr
->StdHeaders
[index
].lpszField
)
1128 lphttpHdr
->lpszField
= HTTP_strdup(field
);
1130 if (dwModifier
& HTTP_ADDHDR_FLAG_REQ
)
1131 lphttpHdr
->wFlags
|= HDR_ISREQUEST
;
1134 slen
= strlen(value
) + 1;
1135 lphttpHdr
->lpszValue
= HeapAlloc(GetProcessHeap(), 0, slen
);
1136 if (lphttpHdr
->lpszValue
)
1138 memcpy(lphttpHdr
->lpszValue
, value
, slen
);
1143 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1146 else if (lphttpHdr
->lpszValue
)
1148 if (dwModifier
& HTTP_ADDHDR_FLAG_REPLACE
)
1153 len
= strlen(value
);
1157 //! if custom header delete from array
1158 HeapFree(GetProcessHeap(), 0, lphttpHdr
->lpszValue
);
1159 lphttpHdr
->lpszValue
= NULL
;
1164 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1167 lphttpHdr
->lpszValue
= lpsztmp
;
1168 strcpy(lpsztmp
, value
);
1173 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1177 else if (dwModifier
& COALESCEFLASG
)
1182 INT origlen
= strlen(lphttpHdr
->lpszValue
);
1183 INT valuelen
= strlen(value
);
1185 if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_COMMA
)
1188 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1190 else if (dwModifier
& HTTP_ADDHDR_FLAG_COALESCE_WITH_SEMICOLON
)
1193 lphttpHdr
->wFlags
|= HDR_COMMADELIMITED
;
1196 len
= origlen
+ valuelen
+ (ch
> 0) ? 1 : 0;
1198 lpsztmp
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lphttpHdr
->lpszValue
, len
+1);
1201 /* FIXME: Increment lphttpHdr->wCount. Perhaps lpszValue should be an array */
1204 lphttpHdr
->lpszValue
[origlen
] = ch
;
1208 memcpy(&lphttpHdr
->lpszValue
[origlen
], value
, valuelen
);
1209 lphttpHdr
->lpszValue
[len
] = '\0';
1214 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1223 /***********************************************************************
1224 * HTTP_CloseConnection (internal)
1226 * Close socket connection
1229 VOID
HTTP_CloseConnection(LPWININETHTTPREQA lpwhr
)
1231 if (lpwhr
->nSocketFD
!= -1)
1233 close(lpwhr
->nSocketFD
);
1234 lpwhr
->nSocketFD
= -1;
1239 /***********************************************************************
1240 * HTTP_CloseHTTPRequestHandle (internal)
1242 * Deallocate request handle
1245 void HTTP_CloseHTTPRequestHandle(LPWININETHTTPREQA lpwhr
)
1251 if (lpwhr
->nSocketFD
!= -1)
1252 HTTP_CloseConnection(lpwhr
);
1254 if (lpwhr
->lpszPath
)
1255 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszPath
);
1256 if (lpwhr
->lpszVerb
)
1257 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszVerb
);
1258 if (lpwhr
->lpszHostName
)
1259 HeapFree(GetProcessHeap(), 0, lpwhr
->lpszHostName
);
1261 for (i
= 0; i
<= HTTP_QUERY_MAX
; i
++)
1263 if (lpwhr
->StdHeaders
[i
].lpszField
)
1264 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszField
);
1265 if (lpwhr
->StdHeaders
[i
].lpszValue
)
1266 HeapFree(GetProcessHeap(), 0, lpwhr
->StdHeaders
[i
].lpszValue
);
1269 for (i
= 0; i
< lpwhr
->nCustHeaders
; i
++)
1271 if (lpwhr
->pCustHeaders
[i
].lpszField
)
1272 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszField
);
1273 if (lpwhr
->pCustHeaders
[i
].lpszValue
)
1274 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
[i
].lpszValue
);
1277 HeapFree(GetProcessHeap(), 0, lpwhr
->pCustHeaders
);
1278 HeapFree(GetProcessHeap(), 0, lpwhr
);
1282 /***********************************************************************
1283 * HTTP_CloseHTTPSessionHandle (internal)
1285 * Deallocate session handle
1288 void HTTP_CloseHTTPSessionHandle(LPWININETHTTPSESSIONA lpwhs
)
1292 if (lpwhs
->lpszServerName
)
1293 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszServerName
);
1294 if (lpwhs
->lpszUserName
)
1295 HeapFree(GetProcessHeap(), 0, lpwhs
->lpszUserName
);
1296 HeapFree(GetProcessHeap(), 0, lpwhs
);
1300 /***********************************************************************
1301 * HTTP_GetCustomHeaderIndex (internal)
1303 * Return index of custom header from header array
1306 INT
HTTP_GetCustomHeaderIndex(LPWININETHTTPREQA lpwhr
, LPCSTR lpszField
)
1310 TRACE("%s\n", lpszField
);
1312 for (index
= 0; index
< lpwhr
->nCustHeaders
; index
++)
1314 if (!strcasecmp(lpwhr
->pCustHeaders
[index
].lpszField
, lpszField
))
1319 if (index
>= lpwhr
->nCustHeaders
)
1322 TRACE("Return: %d\n", index
);
1327 /***********************************************************************
1328 * HTTP_InsertCustomHeader (internal)
1330 * Insert header into array
1333 INT
HTTP_InsertCustomHeader(LPWININETHTTPREQA lpwhr
, LPHTTPHEADERA lpHdr
)
1336 LPHTTPHEADERA lph
= NULL
;
1338 TRACE("%s: %s\n", lpHdr
->lpszField
, lpHdr
->lpszValue
);
1339 count
= lpwhr
->nCustHeaders
+ 1;
1341 lph
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, lpwhr
->pCustHeaders
, sizeof(HTTPHEADERA
) * count
);
1343 lph
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(HTTPHEADERA
) * count
);
1347 lpwhr
->pCustHeaders
= lph
;
1348 lpwhr
->pCustHeaders
[count
-1].lpszField
= HTTP_strdup(lpHdr
->lpszField
);
1349 lpwhr
->pCustHeaders
[count
-1].lpszValue
= HTTP_strdup(lpHdr
->lpszValue
);
1350 lpwhr
->pCustHeaders
[count
-1].wFlags
= lpHdr
->wFlags
;
1351 lpwhr
->pCustHeaders
[count
-1].wCount
= lpHdr
->wCount
;
1352 lpwhr
->nCustHeaders
++;
1356 INTERNET_SetLastError(ERROR_OUTOFMEMORY
);
1360 TRACE("%d <--\n", count
-1);
1365 /***********************************************************************
1366 * HTTP_DeleteCustomHeader (internal)
1368 * Delete header from array
1371 BOOL
HTTP_DeleteCustomHeader(INT index
)