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.
366 lines
8.1 KiB
366 lines
8.1 KiB
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
// APPMAIN.CPP
|
|
//
|
|
// DAV ISAPI DLL entrypoints, main routine, global instance management
|
|
//
|
|
//
|
|
// Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
|
|
//
|
|
|
|
#include <_davprs.h>
|
|
|
|
#include <xatom.h> // XML atom cache
|
|
|
|
#include "instdata.h"
|
|
#include <langid.h>
|
|
#include "custerr.h"
|
|
#include "content.h"
|
|
|
|
|
|
// THE one, global instance
|
|
//
|
|
CInst g_inst;
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CInst::PerProcessInit()
|
|
//
|
|
// Zero it out.
|
|
//
|
|
|
|
void
|
|
CInst::PerProcessInit( HINSTANCE hinst )
|
|
{
|
|
m_hinst = hinst;
|
|
|
|
#ifdef MINIMAL_ISAPI
|
|
m_hfDummy = CreateFileW( L"c:\\temp\\test2.txt", // filename
|
|
GENERIC_READ, // dwAccess
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, // lpSecurityAttributes
|
|
OPEN_EXISTING, // creation flags
|
|
FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_SEQUENTIAL_SCAN |
|
|
FILE_FLAG_OVERLAPPED, // attributes
|
|
NULL ); // tenplate
|
|
#endif // MINIMAL_ISAPI
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CInst::GetInstData()
|
|
//
|
|
// Get the instance data for this ECB.
|
|
// Handoff this call to our InstDataCache.
|
|
//
|
|
|
|
CInstData&
|
|
CInst::GetInstData( const IEcb& ecb )
|
|
{
|
|
return CInstDataCache::GetInstData( ecb );
|
|
}
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CDAVExt::FInitializeDll()
|
|
//
|
|
// Your standard DLL entrypoint.
|
|
//
|
|
|
|
BOOL
|
|
CDAVExt::FInitializeDll( HINSTANCE hinst,
|
|
DWORD dwReason )
|
|
{
|
|
BOOL fInitialized = TRUE;
|
|
|
|
switch ( dwReason )
|
|
{
|
|
case DLL_THREAD_ATTACH:
|
|
case DLL_THREAD_DETACH:
|
|
|
|
Assert(FALSE);
|
|
break;
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
{
|
|
|
|
//
|
|
// Do per process initialization (and implicit initialization of
|
|
// the first thread). The try/catch block just allows us to
|
|
// clean up neatly if anything at all goes wrong.
|
|
//
|
|
try
|
|
{
|
|
g_inst.PerProcessInit( hinst );
|
|
}
|
|
catch ( CDAVException& )
|
|
{
|
|
DebugTrace( "CDAVExt::FInitializeDll() - Caught exception in per-process initialization\n" );
|
|
fInitialized = FALSE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
{
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
TrapSz( "FInitializeDll called for unknown reason\n" );
|
|
fInitialized = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return fInitialized;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CDAVExt::FVersion()
|
|
//
|
|
BOOL
|
|
CDAVExt::FVersion ( HSE_VERSION_INFO * pver )
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
//
|
|
// Init .INI file tagged debug traces
|
|
//
|
|
InitDavprsTraces();
|
|
|
|
// Init ECB logging -- DBG only
|
|
//
|
|
#ifdef DBG
|
|
if ( DEBUG_TRACE_TEST(ECBLogging) )
|
|
InitECBLogging();
|
|
#endif
|
|
|
|
// Instatiate the virtual root cache
|
|
// We must do that before we initialise the metabase as this cache will listen
|
|
// to the metabase notifications that are registered when metabase is created.
|
|
// So if CChildVRCache is not there we may notify the object that does not
|
|
// exist and crash while doing that.
|
|
//
|
|
CChildVRCache::CreateInstance();
|
|
|
|
// Init the metabase
|
|
//
|
|
if ( !FMDInitialize() )
|
|
goto ret;
|
|
|
|
// Instatiate the instance cache
|
|
//
|
|
CInstDataCache::CreateInstance();
|
|
|
|
// Create the language ID cache
|
|
//
|
|
CLangIDCache::CreateInstance();
|
|
|
|
if ( !CLangIDCache::FInitialize() )
|
|
goto ret;
|
|
|
|
// Instantiate the global registry-based mime map
|
|
//
|
|
if ( !FInitRegMimeMap() )
|
|
goto ret;
|
|
|
|
fSuccess = TRUE;
|
|
|
|
ret:
|
|
return fSuccess;
|
|
}
|
|
|
|
#ifndef MINIMAL_ISAPI
|
|
#else // defined(MINIMAL_ISAPI)
|
|
static VOID WINAPI
|
|
IOCompleteNoOp( EXTENSION_CONTROL_BLOCK * pecb,
|
|
PVOID pvContext,
|
|
DWORD cbIO,
|
|
DWORD dwLastError )
|
|
{
|
|
//
|
|
// Done with the session. This must be done from inside
|
|
// of the async callback because INETINFO crashes in
|
|
// INFOCOMM.DLL if you try to put it immediately after
|
|
// the SSF::HSE_REQ_TRANSMIT_FILE and the client sends
|
|
// a huge pile of requests before waiting for a response.
|
|
//
|
|
pecb->ServerSupportFunction (pecb->ConnID,
|
|
HSE_REQ_DONE_WITH_SESSION |
|
|
(pvContext ? HSE_STATUS_SUCCESS_AND_KEEP_CONN : 0),
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
void
|
|
CheckKeepAlive( LPEXTENSION_CONTROL_BLOCK pecb, DWORD * pdwKeepAlive )
|
|
{
|
|
pecb->ServerSupportFunction (pecb->ConnID,
|
|
HSE_REQ_IS_KEEP_CONN,
|
|
pdwKeepAlive,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
void
|
|
SendHeaders( LPEXTENSION_CONTROL_BLOCK pecb )
|
|
{
|
|
HSE_SEND_HEADER_EX_INFO hseSendHeaderExInfo;
|
|
|
|
static CHAR rgchStatus[] = "200 OK";
|
|
|
|
hseSendHeaderExInfo.pszStatus = rgchStatus;
|
|
hseSendHeaderExInfo.cchStatus = sizeof(rgchStatus) - 1;
|
|
|
|
hseSendHeaderExInfo.pszHeader = NULL;
|
|
hseSendHeaderExInfo.cchHeader = 0;
|
|
|
|
hseSendHeaderExInfo.fKeepConn = TRUE;
|
|
|
|
pecb->ServerSupportFunction (pecb->ConnID,
|
|
HSE_REQ_SEND_RESPONSE_HEADER_EX,
|
|
&hseSendHeaderExInfo,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
void
|
|
SendResponse( LPEXTENSION_CONTROL_BLOCK pecb, DWORD dwKeepAlive )
|
|
{
|
|
HSE_TF_INFO hseTFInfo;
|
|
|
|
ZeroMemory(&hseTFInfo, sizeof(HSE_TF_INFO));
|
|
|
|
//
|
|
// If we're going to close the connection anyway, might
|
|
// as well send the headers along with everything else now.
|
|
//
|
|
if ( !dwKeepAlive )
|
|
{
|
|
static CHAR rgchHeaders[] =
|
|
"HTTP/1.1 200 OK\r\n"
|
|
"Content-Type: text/plain\r\n"
|
|
"Connection: close\r\n"
|
|
"\r\n";
|
|
|
|
hseTFInfo.pHead = rgchHeaders;
|
|
hseTFInfo.HeadLength = sizeof(rgchHeaders) - 1;
|
|
}
|
|
|
|
hseTFInfo.pfnHseIO = IOCompleteNoOp;
|
|
hseTFInfo.pContext = (PVOID)(dwKeepAlive);
|
|
hseTFInfo.dwFlags = HSE_IO_ASYNC |
|
|
(dwKeepAlive ? 0 : HSE_IO_DISCONNECT_AFTER_SEND);
|
|
hseTFInfo.BytesToWrite = 0;
|
|
hseTFInfo.hFile = g_inst.m_hfDummy;
|
|
|
|
pecb->ServerSupportFunction (pecb->ConnID,
|
|
HSE_REQ_TRANSMIT_FILE,
|
|
&hseTFInfo,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
DWORD
|
|
CDAVExt::DwMain( LPEXTENSION_CONTROL_BLOCK pecb,
|
|
BOOL fUseRawUrlMappings /* = FALSE */ )
|
|
{
|
|
DWORD dwKeepAlive;
|
|
|
|
//
|
|
// Determine whether to keep the connection open
|
|
//
|
|
CheckKeepAlive( pecb, &dwKeepAlive );
|
|
|
|
//
|
|
// If keep alive is set, we *MUST* send the headers using
|
|
// HSE_REQ_SEND_RESPONSE_HEADERS_EX (which is always synchronous)
|
|
// because it's the only way that allows us to tell IIS to
|
|
// keep the connection open.
|
|
//
|
|
if ( dwKeepAlive )
|
|
SendHeaders( pecb );
|
|
|
|
//
|
|
// Transmit the dummy file
|
|
//
|
|
SendResponse( pecb, dwKeepAlive );
|
|
|
|
return HSE_STATUS_PENDING;
|
|
}
|
|
#endif // defined(MINIMAL_ISAPI)
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
//
|
|
// CDAVExt::FTerminate()
|
|
//
|
|
// Terminates (deinitializes) the common portions of this DAV ISAPI
|
|
//
|
|
// Returns:
|
|
// TRUE if the DAV ISAPI application can be unloaded now
|
|
// FALSE otherwise
|
|
//
|
|
BOOL
|
|
CDAVExt::FTerminate()
|
|
{
|
|
// Tear down the global registry-based mimemap
|
|
//
|
|
DeinitRegMimeMap();
|
|
|
|
// Tear down the XML Atom cache
|
|
//
|
|
CXAtomCache::DeinitIfUsed();
|
|
|
|
// Delete the language ID cache
|
|
//
|
|
CLangIDCache::DestroyInstance();
|
|
|
|
// Tear down the instance data cache
|
|
//
|
|
CInstDataCache::DestroyInstance();
|
|
|
|
//
|
|
// Deinit the metabase
|
|
//
|
|
MDDeinitialize();
|
|
|
|
// Tear down the child vroot cache
|
|
// We must do that after metabase is uninitialized and metabase notifications
|
|
// are shut down, as this cache listens to the metabase notifications.
|
|
// So if CChildVRCache is not there we may notify the object that does not
|
|
// exist and crash while doing that.
|
|
//
|
|
CChildVRCache::DestroyInstance();
|
|
|
|
// Deinit ECB logging
|
|
//
|
|
#ifdef DBG
|
|
if ( DEBUG_TRACE_TEST(ECBLogging) )
|
|
DeinitECBLogging();
|
|
#endif
|
|
|
|
// Due to the fact that COM threads may still be siting in the pur code
|
|
// even they are done modifying our data, and there is no way we can
|
|
// push them out (synchronization would need to happen outside of our
|
|
// dll-s) - we will sleep for 5 seconds, hoping tha they will leave us alone.
|
|
//
|
|
Sleep(5000);
|
|
|
|
//
|
|
// We can always shut down (for now...)
|
|
//
|
|
return TRUE;
|
|
}
|