|
|
/*++
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); }
|