Windows2003-3790/inetcore/wininet/handles/http.cxx
2020-09-30 16:53:55 +02:00

746 lines
16 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1994 Microsoft Corporation
Module Name:
http.cxx
Abstract:
Contains methods for HTTP_REQUEST_HANDLE_OBJECT class
Contents:
RMakeHttpReqObjectHandle
HTTP_REQUEST_HANDLE_OBJECT::HTTP_REQUEST_HANDLE_OBJECT
HTTP_REQUEST_HANDLE_OBJECT::~HTTP_REQUEST_HANDLE_OBJECT
HTTP_REQUEST_HANDLE_OBJECT::GetHandle
HTTP_REQUEST_HANDLE_OBJECT::SetProxyName
HTTP_REQUEST_HANDLE_OBJECT::GetProxyName
HTTP_REQUEST_HANDLE_OBJECT::ReuseObject
HTTP_REQUEST_HANDLE_OBJECT::ResetObject
HTTP_REQUEST_HANDLE_OBJECT::UrlCacheUnlock
HTTP_REQUEST_HANDLE_OBJECT::SetAuthenticated
HTTP_REQUEST_HANDLE_OBJECT::IsAuthenticated
Author:
Madan Appiah (madana) 16-Nov-1994
Environment:
User Mode - Win32
Revision History:
Sophia Chung (sophiac) 14-Feb-1995 (added FTP and Archie class impl.)
(code adopted from madana)
--*/
#include <wininetp.h>
//
// functions
//
DWORD
RMakeHttpReqObjectHandle(
IN HINTERNET ParentHandle,
IN OUT HINTERNET * ChildHandle,
IN CLOSE_HANDLE_FUNC wCloseFunc,
IN DWORD dwFlags,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
C-callable wrapper for creating an HTTP_REQUEST_HANDLE_OBJECT
Arguments:
ParentHandle - mapped address of parent (connect) handle
ChildHandle - IN: protocol-specific handle value associated with object
*** NOT USED FOR HTTP ***
OUT: mapped address of HTTP_REQUEST_HANDLE_OBJECT
wCloseFunc - address of protocol-specific function to be called when
object is closed
*** NOT USED FOR HTTP ***
dwFlags - app-supplied flags
dwContext - app-supplied context value
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure - ERROR_NOT_ENOUGH_MEMORY
--*/
{
DWORD error;
HTTP_REQUEST_HANDLE_OBJECT * hHttp;
hHttp = new HTTP_REQUEST_HANDLE_OBJECT(
(INTERNET_CONNECT_HANDLE_OBJECT *)ParentHandle,
*ChildHandle,
wCloseFunc,
dwFlags,
dwContext
);
if (hHttp != NULL) {
error = hHttp->GetStatus();
if (error == ERROR_SUCCESS) {
//
// inform the app of the new handle
//
error = InternetIndicateStatusNewHandle((LPVOID)hHttp);
//
// ERROR_INTERNET_OPERATION_CANCELLED is the only error that we are
// expecting here. If we get this error then the app has cancelled
// the operation. Either way, the handle we just generated will be
// already deleted
//
if (error != ERROR_SUCCESS) {
INET_ASSERT(error == ERROR_INTERNET_OPERATION_CANCELLED);
hHttp = NULL;
}
} else {
delete hHttp;
hHttp = NULL;
}
} else {
error = ERROR_NOT_ENOUGH_MEMORY;
}
*ChildHandle = (HINTERNET)hHttp;
if(hHttp)
{
hHttp->Dereference();
}
return error;
}
//
// HTTP_REQUEST_HANDLE_OBJECT class implementation
//
HTTP_REQUEST_HANDLE_OBJECT::HTTP_REQUEST_HANDLE_OBJECT(
INTERNET_CONNECT_HANDLE_OBJECT * Parent,
HINTERNET Child,
CLOSE_HANDLE_FUNC wCloseFunc,
DWORD dwFlags,
DWORD_PTR dwContext
) : INTERNET_CONNECT_HANDLE_OBJECT(Parent)
/*++
Routine Description:
Constructor for direct-to-net HTTP_REQUEST_HANDLE_OBJECT
Arguments:
Parent - parent object
Child - IN: HTTPREQ structure pointer
OUT: pointer to created HTTP_REQUEST_HANDLE_OBJECT
wCloseFunc - address of function that closes/destroys HTTPREQ structure
dwFlags - open flags (e.g. INTERNET_FLAG_RELOAD)
dwContext - caller-supplied request context value
Return Value:
None.
--*/
{
Reference();
_Context = dwContext;
_Socket = NULL;
_QueryBuffer = NULL;
_QueryBufferLength = 0;
_QueryOffset = 0;
_QueryBytesAvailable = 0;
_bKeepAliveConnection = FALSE;
_bNoLongerKeepAlive = FALSE;
_OpenFlags = dwFlags;
_State = HttpRequestStateCreating;
_RequestMethod = HTTP_METHOD_TYPE_UNKNOWN;
_dwOptionalSaved = 0;
_lpOptionalSaved = NULL;
_fOptionalSaved = FALSE;
_ResponseBuffer = NULL;
_ResponseBufferLength = 0;
ResetResponseVariables();
_RequestHeaders.SetIsRequestHeaders(TRUE);
_ResponseHeaders.SetIsRequestHeaders(FALSE);
_fTalkingToSecureServerViaProxy = FALSE;
_fRequestUsingProxy = FALSE;
_bWantKeepAlive = FALSE;
_bRefresh = FALSE;
_RefreshHeader = NULL;
_redirectCount = GlobalMaxHttpRedirects;
_redirectCountedOut = FALSE;
_fIgnoreOffline = FALSE;
_f3rdPartyCookies = FALSE;
_fBlockedOnPrompt = FALSE;
SetObjectType(TypeHttpRequestHandle);
_pCacheEntryInfo = NULL;
_dwCacheEntryType = 0;
_pAuthCtx = NULL;
_pTunnelAuthCtx = NULL;
_pPWC = NULL;
_lpBlockingFilter = NULL;
_dwCredPolicy = 0xFFFFFFFF;
_NoResetBits.Dword = 0; // only here are we ever allowed to assign to Dword.
SetDisableNTLMPreauth(GlobalDisableNTLMPreAuth);
_ProxyHostName = NULL;
_ProxyHostNameLength = NULL;
_ProxyPort = INTERNET_INVALID_PORT_NUMBER;
_SocksProxyHostName = NULL;
_SocksProxyHostNameLength = NULL;
_SocksProxyPort = INTERNET_INVALID_PORT_NUMBER;
HttpFiltOpen(); // enumerate http filters if not already active
_HaveReadFileExData = FALSE;
memset(&_BuffersOut, 0, sizeof(_BuffersOut));
_BuffersOut.dwStructSize = sizeof(_BuffersOut);
_BuffersOut.lpvBuffer = (LPVOID)&_ReadFileExData;
_fAutoProxyChecked = FALSE;
m_pSecurityInfo = NULL;
m_AuthFlag = 0x00000000;
m_fPPAbortSend = FALSE;
_fSendUTF8ServerNameToProxy = FALSE;
SetPriority(0);
_dwSecurityZone = 0xffffffff; /* initialize to invalid zone value */
#ifdef RLF_TEST_CODE
static long l = 0;
SetPriority(l++);
#endif
_RTT = 0;
_CP = CP_ACP;
if (_Status == ERROR_SUCCESS) {
_Status = _RequestHeaders.GetError();
if (_Status == ERROR_SUCCESS) {
_Status = _ResponseHeaders.GetError();
}
}
_dwSocketSendBufferLength = -1;
if ((_OpenFlags & INTERNET_FLAG_SECURE) &&
(_Status = LoadSecurity()) == ERROR_SUCCESS)
{
m_pSecurityInfo = GlobalCertCache.Find(GetHostName());
if (NULL == m_pSecurityInfo)
{
m_pSecurityInfo = new SECURITY_CACHE_LIST_ENTRY(GetHostName());
// Force a net hit, since this hasn't been fully validated.
SetCacheReadDisabled();
}
}
else
{
m_pSecurityInfo = NULL;
}
}
HTTP_REQUEST_HANDLE_OBJECT::~HTTP_REQUEST_HANDLE_OBJECT(
VOID
)
/*++
Routine Description:
Destructor for HTTP_REQUEST_HANDLE_OBJECT
Arguments:
None.
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_OBJECTS,
None,
"~HTTP_REQUEST_HANDLE_OBJECT",
"%#x",
this
));
//
// close the socket (or free it to the pool if keep-alive)
//
//
// Authentication Note:
// The CloseConnection parameter to force the connection closed
// is set if we received a challenge but didn't respond, otherwise
// IIS will get confused when a subsequent request recycles the
// socket from the keep-alive pool.
//
CloseConnection(GetAuthState() == AUTHSTATE_CHALLENGE);
if (IsCacheWriteInProgress()) {
LocalEndCacheWrite(IsEndOfFile());
}
if (IsCacheReadInProgress()) {
INET_ASSERT (_pCacheEntryInfo);
FREE_MEMORY (_pCacheEntryInfo);
// Rest is cleaned up in INTERNET_CONNECT_HANDLE_OBJECT::EndCacheWrite
} else {
UrlCacheUnlock();
}
//
// If there's an authentication context, unload the provider.
//
if (_pAuthCtx) {
delete _pAuthCtx;
}
if (_pTunnelAuthCtx) {
delete _pTunnelAuthCtx;
}
//
// free the various buffers
//
FreeResponseBuffer();
FreeQueryBuffer();
SetProxyName(NULL,NULL,0);
if (m_pSecurityInfo != NULL) {
m_pSecurityInfo->Release();
}
DEBUG_LEAVE(0);
}
HINTERNET
HTTP_REQUEST_HANDLE_OBJECT::GetHandle(
VOID
)
/*++
Routine Description:
Returns child handle value. NULL for HTTP
Arguments:
None.
Return Value:
HINTERNET
NULL
--*/
{
return NULL;
}
VOID
HTTP_REQUEST_HANDLE_OBJECT::SetProxyName(
IN LPSTR lpszProxyHostName,
IN DWORD dwProxyHostNameLength,
IN INTERNET_PORT ProxyPort
)
/*++
Routine Description:
Set proxy name in object. If already have name, free it. Don't set name if
current pointer is input
Arguments:
lpszProxyHostName - pointer to proxy name to add
dwProxyHostNameLength - length of proxy name
ProxyPort - port
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_HTTP,
None,
"HTTP_REQUEST_HANDLE_OBJECT::SetProxyName",
"{%q, %d, %d}%q, %d, %d",
_ProxyHostName,
_ProxyHostNameLength,
_ProxyPort,
lpszProxyHostName,
dwProxyHostNameLength,
ProxyPort
));
if (lpszProxyHostName != _ProxyHostName) {
if (_ProxyHostName != NULL) {
_ProxyHostName = (LPSTR)FREE_MEMORY(_ProxyHostName);
INET_ASSERT(_ProxyHostName == NULL);
SetOverrideProxyMode(FALSE);
}
if (lpszProxyHostName != NULL) {
_ProxyHostName = NEW_STRING(lpszProxyHostName);
if (_ProxyHostName == NULL) {
dwProxyHostNameLength = 0;
}
}
_ProxyHostNameLength = dwProxyHostNameLength;
_ProxyPort = ProxyPort;
} else if (lpszProxyHostName != NULL) {
DEBUG_PRINT(HTTP,
WARNING,
("!!! lpszProxyHostName == _ProxyHostName (%#x)\n",
lpszProxyHostName
));
INET_ASSERT(dwProxyHostNameLength == _ProxyHostNameLength);
INET_ASSERT(ProxyPort == _ProxyPort);
}
DEBUG_LEAVE(0);
}
VOID
HTTP_REQUEST_HANDLE_OBJECT::GetProxyName(
OUT LPSTR* lplpszProxyHostName,
OUT LPDWORD lpdwProxyHostNameLength,
OUT LPINTERNET_PORT lpProxyPort
)
/*++
Routine Description:
Return address & length of proxy name plus proxy port
Arguments:
lplpszProxyHostName - returned address of name
lpdwProxyHostNameLength - returned length of name
lpProxyPort - returned port
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_HTTP,
None,
"HTTP_REQUEST_HANDLE_OBJECT::GetProxyName",
"{%q, %d, %d}%#x, %#x, %#x",
_ProxyHostName,
_ProxyHostNameLength,
_ProxyPort,
lplpszProxyHostName,
lpdwProxyHostNameLength,
lpProxyPort
));
*lplpszProxyHostName = _ProxyHostName;
*lpdwProxyHostNameLength = _ProxyHostNameLength;
*lpProxyPort = _ProxyPort;
DEBUG_LEAVE(0);
}
VOID
HTTP_REQUEST_HANDLE_OBJECT::ReuseObject(
VOID
)
/*++
Routine Description:
Make the object re-usable: clear out any received data and headers and
reset the state to open
Arguments:
None.
Return Value:
None.
--*/
{
DEBUG_ENTER((DBG_HTTP,
None,
"HTTP_REQUEST_HANDLE_OBJECT::ReuseObject",
NULL
));
_ResponseHeaders.FreeHeaders();
FreeResponseBuffer();
ResetResponseVariables();
_ResponseHeaders.Initialize();
_dwCurrentStreamPosition = 0;
SetState(HttpRequestStateOpen);
ResetEndOfFile();
_ctChunkInfo.Reset();
_QueryOffset = 0;
_QueryBytesAvailable = 0;
_dwQuerySetCookieHeader = 0;
if (m_pSecurityInfo) {
m_pSecurityInfo->Release();
}
m_pSecurityInfo = NULL;
DEBUG_LEAVE(0);
}
DWORD
HTTP_REQUEST_HANDLE_OBJECT::ResetObject(
IN BOOL bForce,
IN BOOL bFreeRequestHeaders
)
/*++
Routine Description:
This method is called when we we are clearing out a partially completed
transaction, mainly for when we have determined that an if-modified-since
request, or a response that has not invalidated the cache entry can be
retrieved from cache (this is a speed issue)
Abort the connection and clear out the response headers and response
buffer; clear the response variables (all done by AbortConnection()).
If bFreeRequestHeaders, clear out the request headers.
Reinitialize the response headers. We do not reset the object state, but we
do reset the end-of-file status
Arguments:
bForce - TRUE if connection is forced closed
bFreeRequestHeaders - TRUE if request headers should be freed
Return Value:
DWORD
Success - ERROR_SUCCESS
Failure -
--*/
{
DEBUG_ENTER((DBG_HTTP,
Dword,
"HTTP_REQUEST_HANDLE_OBJECT::ResetObject",
"%B, %B",
bForce,
bFreeRequestHeaders
));
DWORD error;
error = AbortConnection(bForce);
if (error == ERROR_SUCCESS) {
if (bFreeRequestHeaders) {
_RequestHeaders.FreeHeaders();
}
_ResponseHeaders.Initialize();
ResetEndOfFile();
}
DEBUG_LEAVE(error);
return error;
}
VOID
HTTP_REQUEST_HANDLE_OBJECT::UrlCacheUnlock(
VOID
)
/*++
Routine Description:
description-of-function.
Arguments:
None.
Return Value:
None.
--*/
{
INET_ASSERT (!_CacheReadInProgress);
if (_hCacheStream)
{
UnlockUrlCacheEntryStream (_hCacheStream, 0);
_hCacheStream = NULL;
}
if (_pCacheEntryInfo)
{
if (_pCacheEntryInfo->CacheEntryType & SPARSE_CACHE_ENTRY)
{
//
// We can't use the partial cache entry because it is
// stale, so delete the data file we got from cache.
//
INET_ASSERT (_CacheFileHandle != INVALID_HANDLE_VALUE);
CloseHandle (_CacheFileHandle);
_CacheFileHandle = INVALID_HANDLE_VALUE;
DeleteFile (_pCacheEntryInfo->lpszLocalFileName);
}
FREE_MEMORY (_pCacheEntryInfo);
_pCacheEntryInfo = NULL;
}
}
VOID
HTTP_REQUEST_HANDLE_OBJECT::SetAuthenticated(
VOID
)
/*++
Routine Description:
description-of-function.
Arguments:
SetAuthenticated -
Return Value:
None.
--*/
{
if (!_Socket)
{
INET_ASSERT(FALSE);
}
else
{
_Socket->SetAuthenticated();
}
}
BOOL
HTTP_REQUEST_HANDLE_OBJECT::IsAuthenticated(
VOID
)
/*++
Routine Description:
description-of-function.
Arguments:
IsAuthenticated -
Return Value:
BOOL
--*/
{
return (_Socket ? _Socket->IsAuthenticated() : FALSE);
}