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.
745 lines
16 KiB
745 lines
16 KiB
/*++
|
|
|
|
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);
|
|
}
|