You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
639 lines
18 KiB
639 lines
18 KiB
/*++
|
|
|
|
Copyright (c) 1994 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
open.cxx
|
|
|
|
Abstract:
|
|
|
|
This file contains the implementation of the HttpOpenRequestA API.
|
|
|
|
The following functions are exported by this module:
|
|
|
|
HttpOpenRequestA
|
|
WinHttpOpenRequest
|
|
ParseHttpUrl
|
|
ParseHttpUrl_Fsm
|
|
|
|
Author:
|
|
|
|
Keith Moore (keithmo) 16-Nov-1994
|
|
|
|
Revision History:
|
|
|
|
Modified to make HttpOpenRequestA remotable. madana (2/8/95)
|
|
|
|
--*/
|
|
|
|
#include <wininetp.h>
|
|
#include "httpp.h"
|
|
|
|
//
|
|
// functions
|
|
//
|
|
|
|
|
|
INTERNETAPI
|
|
HINTERNET
|
|
WINAPI
|
|
HttpOpenRequestA(
|
|
IN HINTERNET hConnect,
|
|
IN LPCSTR lpszVerb OPTIONAL,
|
|
IN LPCSTR lpszObjectName OPTIONAL,
|
|
IN LPCSTR lpszVersion OPTIONAL,
|
|
IN LPCSTR lpszReferrer OPTIONAL,
|
|
IN LPCSTR FAR * lplpszAcceptTypes OPTIONAL,
|
|
IN DWORD dwFlags,
|
|
IN DWORD_PTR dwContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a new HTTP request handle and stores the specified parameters
|
|
in that context.
|
|
|
|
Arguments:
|
|
|
|
hConnect - An open Internet handle returned by InternetConnect()
|
|
|
|
lpszVerb - The verb to use in the request. May be NULL in which
|
|
case "GET" will be used
|
|
|
|
lpszObjectName - The target object for the specified verb. This is
|
|
typically a file name, an executable module, or a
|
|
search specifier. May be NULL in which case the empty
|
|
string will be used
|
|
|
|
lpszVersion - The version string for the request. May be NULL in
|
|
which case "HTTP/1.0" will be used
|
|
|
|
lpszReferrer - Specifies the address (URI) of the document from
|
|
which the URI in the request (lpszObjectName) was
|
|
obtained. May be NULL in which case no referer is
|
|
specified
|
|
|
|
lplpszAcceptTypes - Points to a NULL-terminated array of LPCTSTR pointers
|
|
to content-types accepted by the client. This value
|
|
may be NULL in which case the default content-type
|
|
(text/html) is used
|
|
|
|
dwFlags - open options
|
|
|
|
dwContext - app-supplied context value for call-backs
|
|
|
|
BUGBUG: WHAT IS THE DEFAULT CONTENT-TRANSFER-ENCODING?
|
|
|
|
Return Value:
|
|
|
|
HINTERNET
|
|
|
|
Success - non-NULL (open) handle to an HTTP request
|
|
|
|
Failure - NULL. Error status is available by calling GetLastError()
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER_API((DBG_API,
|
|
Handle,
|
|
"HttpOpenRequestA",
|
|
"%#x, %.80q, %.80q, %.80q, %.80q, %#x, %#08x, %#08x",
|
|
hConnect,
|
|
lpszVerb,
|
|
lpszObjectName,
|
|
lpszVersion,
|
|
lpszReferrer,
|
|
lplpszAcceptTypes,
|
|
dwFlags,
|
|
dwContext
|
|
));
|
|
|
|
DWORD error;
|
|
HINTERNET hConnectMapped = NULL;
|
|
BOOL fRequestUsingProxy;
|
|
HINTERNET hRequest = NULL;
|
|
|
|
if (!GlobalDataInitialized) {
|
|
error = ERROR_WINHTTP_NOT_INITIALIZED;
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// get the per-thread info
|
|
//
|
|
|
|
LPINTERNET_THREAD_INFO lpThreadInfo;
|
|
|
|
lpThreadInfo = InternetGetThreadInfo();
|
|
if (lpThreadInfo == NULL) {
|
|
error = ERROR_WINHTTP_INTERNAL_ERROR;
|
|
goto done;
|
|
}
|
|
|
|
_InternetIncNestingCount();
|
|
|
|
//
|
|
// map the handle
|
|
//
|
|
|
|
error = MapHandleToAddress(hConnect, (LPVOID *)&hConnectMapped, FALSE);
|
|
if (error != ERROR_SUCCESS) {
|
|
goto quit;
|
|
}
|
|
|
|
//
|
|
// find path from internet handle and validate handle
|
|
//
|
|
|
|
BOOL isLocal;
|
|
BOOL isAsync;
|
|
|
|
error = RIsHandleLocal(hConnectMapped,
|
|
&isLocal,
|
|
&isAsync,
|
|
TypeHttpConnectHandle
|
|
);
|
|
if (error != ERROR_SUCCESS) {
|
|
goto quit;
|
|
}
|
|
|
|
//
|
|
// validate parameters. Allow lpszVerb to default to "GET" if a NULL pointer
|
|
// is supplied
|
|
//
|
|
|
|
if (!ARGUMENT_PRESENT(lpszVerb) || (*lpszVerb == '\0')) {
|
|
lpszVerb = DEFAULT_HTTP_REQUEST_VERB;
|
|
}
|
|
|
|
//
|
|
// if a NULL pointer or empty string is supplied for the object name, then
|
|
// convert to the default object name (root object)
|
|
//
|
|
|
|
if (!ARGUMENT_PRESENT(lpszObjectName) || (*lpszObjectName == '\0')) {
|
|
lpszObjectName = "/";
|
|
}
|
|
|
|
// check the rest of the parameters
|
|
if (dwFlags & ~WINHTTP_OPEN_REQUEST_FLAGS_MASK)
|
|
{
|
|
error = ERROR_INVALID_PARAMETER;
|
|
goto quit;
|
|
}
|
|
|
|
// default to the current supported version
|
|
char versionBuffer[sizeof("HTTP/4294967295.4294967295")];
|
|
DWORD verMajor;
|
|
DWORD verMinor;
|
|
|
|
if (!ARGUMENT_PRESENT(lpszVersion) || (*lpszVersion == '\0')) {
|
|
wsprintf(versionBuffer,
|
|
"HTTP/%d.%d",
|
|
HttpVersionInfo.dwMajorVersion,
|
|
HttpVersionInfo.dwMinorVersion
|
|
);
|
|
lpszVersion = versionBuffer;
|
|
verMajor = HttpVersionInfo.dwMajorVersion;
|
|
verMinor = HttpVersionInfo.dwMinorVersion;
|
|
} else if (strnicmp(lpszVersion, "HTTP/", sizeof("HTTP/") - 1) == 0) {
|
|
|
|
LPSTR p = (LPSTR)lpszVersion + sizeof("HTTP/") - 1;
|
|
|
|
ExtractInt(&p, 0, (LPINT)&verMajor);
|
|
while (!isdigit(*p) && (*p != '\0')) {
|
|
++p;
|
|
}
|
|
ExtractInt(&p, 0, (LPINT)&verMinor);
|
|
} else {
|
|
verMajor = 1;
|
|
verMinor = 0;
|
|
}
|
|
|
|
//
|
|
// if we have HTTP 1.1 enabled in the registry and the version is < 1.1
|
|
// then convert
|
|
//
|
|
|
|
if (GlobalEnableHttp1_1
|
|
&& (((verMajor == 1) && (verMinor == 0)) || (verMajor < 1))) {
|
|
lpszVersion = "HTTP/1.1";
|
|
}
|
|
|
|
//
|
|
// allow empty strings to be equivalent to NULL pointer
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT(lpszReferrer) && (*lpszReferrer == '\0')) {
|
|
lpszReferrer = NULL;
|
|
}
|
|
|
|
// get the target port
|
|
INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
|
|
pConnect = (INTERNET_CONNECT_HANDLE_OBJECT *)hConnectMapped;
|
|
INTERNET_PORT hostPort;
|
|
hostPort = pConnect->GetHostPort();
|
|
|
|
//
|
|
// set the per-thread info: parent handle object
|
|
//
|
|
|
|
_InternetSetObjectHandle(lpThreadInfo, hConnect, hConnectMapped);
|
|
|
|
//
|
|
// make local HTTP request handle object before we can add headers to it
|
|
//
|
|
|
|
error = RMakeHttpReqObjectHandle(hConnectMapped,
|
|
&hRequest,
|
|
NULL, // (CLOSE_HANDLE_FUNC)wHttpCloseRequest
|
|
dwFlags,
|
|
dwContext
|
|
);
|
|
if (error != ERROR_SUCCESS) {
|
|
goto quit;
|
|
}
|
|
|
|
HTTP_REQUEST_HANDLE_OBJECT * pRequest;
|
|
|
|
pRequest = (HTTP_REQUEST_HANDLE_OBJECT *)hRequest;
|
|
|
|
//
|
|
// add the request line
|
|
//
|
|
|
|
INET_ASSERT((lpszVerb != NULL) && (*lpszVerb != '\0'));
|
|
INET_ASSERT((lpszObjectName != NULL) && (*lpszObjectName != '\0'));
|
|
INET_ASSERT((lpszVersion != NULL) && (*lpszVersion != '\0'));
|
|
|
|
if (!pRequest->LockHeaders())
|
|
{
|
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto quit;
|
|
}
|
|
|
|
//
|
|
// encode the URL-path
|
|
//
|
|
|
|
error = pRequest->AddRequest((LPSTR)lpszVerb,
|
|
(LPSTR)lpszObjectName,
|
|
(LPSTR)lpszVersion
|
|
);
|
|
if (error != ERROR_SUCCESS) {
|
|
pRequest->UnlockHeaders();
|
|
goto quit;
|
|
}
|
|
|
|
//
|
|
// set the method type from the verb
|
|
//
|
|
|
|
pRequest->SetMethodType(lpszVerb);
|
|
|
|
//
|
|
// add the headers
|
|
//
|
|
|
|
if (lpszReferrer != NULL) {
|
|
error = pRequest->AddRequestHeader(HTTP_QUERY_REFERER,
|
|
(LPSTR)lpszReferrer,
|
|
lstrlen(lpszReferrer),
|
|
0,
|
|
CLEAN_HEADER
|
|
);
|
|
if (error != ERROR_SUCCESS) {
|
|
pRequest->UnlockHeaders();
|
|
goto quit;
|
|
}
|
|
}
|
|
|
|
if (lplpszAcceptTypes != NULL) {
|
|
while (*lplpszAcceptTypes) {
|
|
error = pRequest->AddRequestHeader(HTTP_QUERY_ACCEPT,
|
|
(LPSTR)*lplpszAcceptTypes,
|
|
lstrlen(*(LPSTR*)lplpszAcceptTypes),
|
|
0,
|
|
CLEAN_HEADER | COALESCE_HEADER_WITH_COMMA
|
|
);
|
|
if (error != ERROR_SUCCESS) {
|
|
pRequest->UnlockHeaders();
|
|
goto quit;
|
|
}
|
|
++lplpszAcceptTypes;
|
|
}
|
|
}
|
|
|
|
INET_ASSERT(error == ERROR_SUCCESS);
|
|
|
|
pRequest->UnlockHeaders();
|
|
|
|
//
|
|
// change the object state to opened
|
|
//
|
|
|
|
pRequest->SetState(HttpRequestStateOpen);
|
|
((HTTP_REQUEST_HANDLE_OBJECT *)hRequest)->SetRequestUsingProxy(
|
|
FALSE
|
|
);
|
|
|
|
if (hostPort == INTERNET_INVALID_PORT_NUMBER)
|
|
{
|
|
if (dwFlags & WINHTTP_FLAG_SECURE)
|
|
{
|
|
pRequest->SetHostPort(INTERNET_DEFAULT_HTTPS_PORT);
|
|
}
|
|
else
|
|
{
|
|
pRequest->SetHostPort(INTERNET_DEFAULT_HTTP_PORT);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pRequest->SetHostPort(hostPort);
|
|
}
|
|
|
|
//
|
|
// if the object name is not set then all cache methods fail
|
|
//
|
|
|
|
URLGEN_FUNC fn;
|
|
fn = (URLGEN_FUNC)pHttpGetUrlString;
|
|
|
|
//
|
|
// BUGBUG - change prototype to take LPCSTR
|
|
//
|
|
|
|
error = pRequest->SetObjectName((LPSTR)lpszObjectName,
|
|
NULL,
|
|
&fn
|
|
);
|
|
|
|
quit:
|
|
|
|
_InternetDecNestingCount(1);
|
|
|
|
done:
|
|
|
|
if (error != ERROR_SUCCESS) {
|
|
if (hRequest != NULL) {
|
|
WinHttpCloseHandle(((HANDLE_OBJECT *)hRequest)->GetPseudoHandle());
|
|
}
|
|
|
|
DEBUG_ERROR(HTTP, error);
|
|
|
|
SetLastError(error);
|
|
hRequest = NULL;
|
|
} else {
|
|
|
|
//
|
|
// success - don't return the object address, return the pseudo-handle
|
|
// value we generated
|
|
//
|
|
|
|
hRequest = ((HANDLE_OBJECT *)hRequest)->GetPseudoHandle();
|
|
}
|
|
|
|
if (hConnectMapped != NULL) {
|
|
DereferenceObject((LPVOID)hConnectMapped);
|
|
}
|
|
|
|
DEBUG_LEAVE_API(hRequest);
|
|
|
|
return hRequest;
|
|
}
|
|
|
|
|
|
INTERNETAPI
|
|
HINTERNET
|
|
WINAPI
|
|
WinHttpOpenRequest(
|
|
IN HINTERNET hConnect,
|
|
IN LPCWSTR lpszVerb,
|
|
IN LPCWSTR lpszObjectName,
|
|
IN LPCWSTR lpszVersion,
|
|
IN LPCWSTR lpszReferrer OPTIONAL,
|
|
IN LPCWSTR FAR * lplpszAcceptTypes OPTIONAL,
|
|
IN DWORD dwFlags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a new HTTP request handle and stores the specified parameters
|
|
in that context.
|
|
|
|
Arguments:
|
|
|
|
hHttpSession - An open Internet handle returned by InternetConnect()
|
|
|
|
lpszVerb - The verb to use in the request
|
|
|
|
lpszObjectName - The target object for the specified verb. This is
|
|
typically a file name, an executable module, or a
|
|
search specifier
|
|
|
|
lpszVersion - The version string for the request
|
|
|
|
lpszReferrer - Specifies the address (URI) of the document from
|
|
which the URI in the request (lpszObjectName) was
|
|
obtained. May be NULL in which case no referer is
|
|
specified
|
|
|
|
lplpszAcceptTypes - Points to a NULL-terminated array of LPCTSTR pointers
|
|
to content-types accepted by the client. This value
|
|
may be NULL in which case the default content-type
|
|
(text/html) is used
|
|
|
|
dwFlags - open options
|
|
|
|
BUGBUG: WHAT IS THE DEFAULT CONTENT-TRANSFER-ENCODING?
|
|
|
|
Return Value:
|
|
|
|
!NULL - An open handle to an HTTP request.
|
|
|
|
NULL - The operation failed. Error status is available by calling
|
|
GetLastError().
|
|
|
|
Comments:
|
|
|
|
--*/
|
|
|
|
{
|
|
DEBUG_ENTER_API((DBG_API,
|
|
Handle,
|
|
"WinHttpOpenRequest",
|
|
"%#x, %.80wq, %.80wq, %.80wq, %.80wq, %#x, %#08x",
|
|
hConnect,
|
|
lpszVerb,
|
|
lpszObjectName,
|
|
lpszVersion,
|
|
lpszReferrer,
|
|
lplpszAcceptTypes,
|
|
dwFlags
|
|
));
|
|
|
|
HINTERNET hConnectMapped = NULL;
|
|
INTERNET_CONNECT_HANDLE_OBJECT * pConnect;
|
|
DWORD dwErr = ERROR_SUCCESS;
|
|
HINTERNET hInternet = NULL;
|
|
MEMORYPACKET mpVerb, mpObjectName, mpVersion, mpReferrer;
|
|
MEMORYPACKETTABLE mptAcceptTypes;
|
|
BOOL isLocal;
|
|
BOOL isAsync;
|
|
|
|
if (dwFlags &~ (WINHTTP_OPEN_REQUEST_FLAGS_MASK))
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
|
|
// map the handle
|
|
dwErr = MapHandleToAddress(hConnect, (LPVOID *)&hConnectMapped, FALSE);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
// find path from internet handle and validate handle
|
|
dwErr = RIsHandleLocal(hConnectMapped,
|
|
&isLocal,
|
|
&isAsync,
|
|
TypeHttpConnectHandle
|
|
);
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
|
|
if (lpszVerb)
|
|
{
|
|
if (IsBadStringPtrW(lpszVerb, -1))
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
ALLOC_MB(lpszVerb,0,mpVerb);
|
|
if (!mpVerb.psStr)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
UNICODE_TO_ANSI(lpszVerb,mpVerb);
|
|
}
|
|
if (lpszObjectName)
|
|
{
|
|
if (IsBadStringPtrW(lpszObjectName, -1))
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
pConnect = (INTERNET_CONNECT_HANDLE_OBJECT*)hConnectMapped;
|
|
DWORD dwCodePage = pConnect->GetCodePage();
|
|
dwErr = ConvertUnicodeToMultiByte(lpszObjectName, dwCodePage, &mpObjectName,
|
|
(dwFlags&(WINHTTP_FLAG_ESCAPE_PERCENT|WINHTTP_FLAG_NULL_CODEPAGE))|WINHTTP_FLAG_DEFAULT_ESCAPE );
|
|
if (dwErr != ERROR_SUCCESS)
|
|
{
|
|
goto cleanup;
|
|
}
|
|
}
|
|
if (lpszVersion)
|
|
{
|
|
if (IsBadStringPtrW(lpszVersion, -1))
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
ALLOC_MB(lpszVersion,0,mpVersion);
|
|
if (!mpVersion.psStr)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
UNICODE_TO_ANSI(lpszVersion,mpVersion);
|
|
}
|
|
if (lpszReferrer)
|
|
{
|
|
if (IsBadStringPtrW(lpszReferrer, -1))
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
ALLOC_MB(lpszReferrer,0,mpReferrer);
|
|
if (!mpReferrer.psStr)
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
UNICODE_TO_ANSI(lpszReferrer,mpReferrer);
|
|
}
|
|
|
|
// Create a table of ansi strings
|
|
if (lplpszAcceptTypes)
|
|
{
|
|
WORD csTmp=0;
|
|
do
|
|
{
|
|
if (IsBadReadPtr(lplpszAcceptTypes+csTmp*sizeof(LPCWSTR), sizeof(LPCWSTR)))
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
|
|
if (lplpszAcceptTypes[csTmp])
|
|
{
|
|
if (IsBadStringPtrW(lplpszAcceptTypes[csTmp++], -1))
|
|
{
|
|
dwErr = ERROR_INVALID_PARAMETER;
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
while (TRUE);
|
|
|
|
mptAcceptTypes.SetUpFor(csTmp);
|
|
for (WORD ce=0; ce < csTmp; ce++)
|
|
{
|
|
mptAcceptTypes.pdwAlloc[ce] = (lstrlenW(lplpszAcceptTypes[ce]) + 1)*sizeof(WCHAR);
|
|
mptAcceptTypes.ppsStr[ce] = (LPSTR)ALLOC_BYTES(mptAcceptTypes.pdwAlloc[ce]*sizeof(CHAR));
|
|
if (!mptAcceptTypes.ppsStr[ce])
|
|
{
|
|
dwErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto cleanup;
|
|
}
|
|
mptAcceptTypes.pdwSize[ce] = WideCharToMultiByte(CP_ACP,
|
|
0,
|
|
lplpszAcceptTypes[ce],
|
|
mptAcceptTypes.pdwAlloc[ce]/sizeof(WCHAR),
|
|
mptAcceptTypes.ppsStr[ce],
|
|
mptAcceptTypes.pdwAlloc[ce],NULL,NULL);
|
|
}
|
|
}
|
|
|
|
hInternet = HttpOpenRequestA(hConnect, mpVerb.psStr, mpObjectName.psStr, mpVersion.psStr,
|
|
mpReferrer.psStr, (LPCSTR*)mptAcceptTypes.ppsStr,
|
|
dwFlags, NULL);
|
|
|
|
cleanup:
|
|
if (hConnectMapped != NULL)
|
|
{
|
|
DereferenceObject((LPVOID)hConnectMapped);
|
|
}
|
|
|
|
if (dwErr!=ERROR_SUCCESS)
|
|
{
|
|
SetLastError(dwErr);
|
|
DEBUG_ERROR(HTTP, dwErr);
|
|
}
|
|
DEBUG_LEAVE_API(hInternet);
|
|
return hInternet;
|
|
}
|
|
|