// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // // APPMAIN.CPP // // DAV ISAPI DLL entrypoints, main routine, global instance management // // // Copyright 1986-1997 Microsoft Corporation, All Rights Reserved // #include <_davprs.h> #include // XML atom cache #include "instdata.h" #include #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; }