Source code of Windows XP (NT5)
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.

1041 lines
34 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000.
  5. //
  6. // File: webhits.cxx
  7. //
  8. // History: 05-20-96 t-matts Created
  9. // 03-03-97 dlee Converted to isapi
  10. //
  11. // Contents: This is the main() for the hit-highliting feature. The
  12. // CGI environment variables are read, yielding the filename
  13. // and the textual form of the restriction. The textual form
  14. // is then converted to internal form. The document is then
  15. // scanned for hits, and the positions contained in those
  16. // hits are sorted. Finally, HTML tags are inserted in the order
  17. // in which the distinct positions appear in the document, to
  18. // allow the user to navigate.
  19. //
  20. //--------------------------------------------------------------------------
  21. #include<pch.cxx>
  22. #pragma hdrstop
  23. #include <cidebug.hxx>
  24. #include <codepage.hxx>
  25. #include <ciregkey.hxx>
  26. #include <regacc.hxx>
  27. #include <cpid.hxx>
  28. #include <dblink.hxx>
  29. #include <imprsnat.hxx>
  30. #include <regevent.hxx>
  31. #include <dynstack.hxx>
  32. #include <cimbmgr.hxx>
  33. #include "webhits.hxx"
  34. #include "webdbg.hxx"
  35. #include "whmsg.h"
  36. #include "linkhits.hxx"
  37. #define _DECL_DLLMAIN 1
  38. DECLARE_INFOLEVEL (web);
  39. DECLARE_INFOLEVEL (ci);
  40. const int ERROR_MESSAGE_SIZE=512;
  41. BOOL g_fShutdown = TRUE;
  42. LONG g_cThreads = 0;
  43. CWebhitsInfo * g_pWebhitsInfo = 0;
  44. void OutputErrorMessage( CWebServer & webServer,
  45. CLanguageInfo & LanguageInfo,
  46. DWORD dwMsgId,
  47. WCHAR const * pwcIdqPPath,
  48. WCHAR const * pwcIdqVPath,
  49. WCHAR const * pwcHtwPPath,
  50. WCHAR const * pwcHtwVPath,
  51. WCHAR const * pwcWebhitsPPath,
  52. WCHAR const * pwcWebhitsVPath,
  53. WCHAR const * pwszDefaultMsg = 0,
  54. WCHAR const * pwszFileName = 0,
  55. ULONG ulFileLine = 0 );
  56. //+---------------------------------------------------------------------------
  57. //
  58. // Function: GetVPathInfo
  59. //
  60. // Synopsis: Convers a vpath to a ppath
  61. //
  62. // Arguments: [webServer] -- Used for the translation
  63. // [pwcVPath] -- VPath to translate
  64. // [dwAccessMask] -- Access required for file, or 0 for none
  65. // [dwFlags] -- Returns vpath flags (HSE_URL_FLAGS_*)
  66. //
  67. // Returns: pointer to PPath allocated on the heap.
  68. //
  69. // History: 3-04-97 dlee Created
  70. //
  71. //----------------------------------------------------------------------------
  72. WCHAR * GetVPathInfo(
  73. CWebServer & webServer,
  74. WCHAR const * pwcVPath,
  75. DWORD dwAccessMask,
  76. DWORD & dwFlags )
  77. {
  78. WCHAR *pwc = 0;
  79. TRY
  80. {
  81. WCHAR awcPPath[MAX_PATH];
  82. dwFlags = webServer.GetPhysicalPath( pwcVPath,
  83. awcPPath,
  84. sizeof awcPPath / sizeof WCHAR,
  85. dwAccessMask );
  86. if ( ( 0 == wcsstr( awcPPath, L"../" ) ) &&
  87. ( 0 == wcsstr( awcPPath, L"..\\" ) ) )
  88. {
  89. ULONG cwc = wcslen( awcPPath ) + 1;
  90. pwc = new WCHAR[ cwc ];
  91. RtlCopyMemory( pwc, awcPPath, cwc * sizeof WCHAR );
  92. }
  93. }
  94. CATCH( CException, e )
  95. {
  96. // returning 0 is sufficient
  97. }
  98. END_CATCH
  99. return pwc;
  100. } //GetVPathInfo
  101. //+---------------------------------------------------------------------------
  102. //
  103. // Function: GetWebhitsVPathInfo
  104. //
  105. // Synopsis: Converts vpaths to ppaths for the query, template, and
  106. // webhits files.
  107. //
  108. // Arguments: [vars] -- Source of vpaths, sink of ppaths
  109. // [webServer] -- Used for the translations
  110. //
  111. // History: 9-06-96 srikants Created
  112. //
  113. //----------------------------------------------------------------------------
  114. void GetWebhitsVPathInfo(
  115. CGetEnvVars & vars,
  116. CWebServer & webServer )
  117. {
  118. // Translate the path of the query (idq) file if one is given.
  119. DWORD dwFlags;
  120. if ( vars.GetQueryFileVPath() )
  121. {
  122. WCHAR * pwc = GetVPathInfo( webServer,
  123. vars.GetQueryFileVPath(),
  124. 0,
  125. dwFlags );
  126. if ( 0 == pwc )
  127. THROW( CWTXException( MSG_WEBHITS_IDQ_NOT_FOUND,
  128. vars.GetQueryFileVPath(),
  129. 0 ) );
  130. vars.AcceptQueryFilePPath( pwc, dwFlags );
  131. webDebugOut(( DEB_ITRACE, "Query file '%ws'\n", pwc ));
  132. }
  133. // Translate the path of the template (htw) file if one is given.
  134. if ( vars.GetTemplateFileVPath() )
  135. {
  136. WCHAR * pwc = GetVPathInfo( webServer,
  137. vars.GetTemplateFileVPath(),
  138. 0,
  139. dwFlags );
  140. if ( 0 == pwc )
  141. THROW( CWTXException( MSG_WEBHITS_NO_SUCH_TEMPLATE,
  142. vars.GetTemplateFileVPath(),
  143. 0 ) );
  144. vars.AcceptTemplateFilePPath( pwc, dwFlags );
  145. webDebugOut(( DEB_ITRACE, "Template file '%ws'\n", pwc ));
  146. }
  147. // Translate the path of the WebHits file being displayed. Read access
  148. // is required for this file.
  149. if ( vars.GetWebHitsFileVPath() )
  150. {
  151. WCHAR * pwc = GetVPathInfo( webServer,
  152. vars.GetWebHitsFileVPath(),
  153. HSE_URL_FLAGS_READ,
  154. dwFlags );
  155. if ( 0 == pwc )
  156. THROW( CException(MSG_WEBHITS_PATH_INVALID) );
  157. vars.AcceptWebHitsFilePPath( pwc, dwFlags );
  158. webDebugOut(( DEB_ITRACE, "WebHits file '%ws'\n", pwc ));
  159. }
  160. else
  161. {
  162. THROW( CException(MSG_WEBHITS_PATH_INVALID) );
  163. }
  164. } //GetWebhitsVPathInfo
  165. //+---------------------------------------------------------------------------
  166. //
  167. // Function: ProcessWebRequest
  168. //
  169. // Synopsis: Main driver method for webhits.
  170. //
  171. // Arguments: [webServer] -- web server to use
  172. //
  173. // History: 9-04-96 srikants Created
  174. //
  175. //----------------------------------------------------------------------------
  176. DWORD ProcessWebRequest( CWebServer & webServer )
  177. {
  178. DWORD hse = HSE_STATUS_SUCCESS;
  179. //
  180. // Initialize the locale and codepage.
  181. //
  182. LCID lcid = GetLCID( webServer );
  183. ULONG urlCodePage = GetBrowserCodepage( webServer, lcid );
  184. CLanguageInfo langInfo;
  185. //
  186. // Set the client and output locale info to be the same as
  187. // the client info. If a different value is set
  188. // via CiLocale, it will be changed when the querystring is parsed.
  189. //
  190. langInfo.SetUrlLangInfo( urlCodePage, lcid );
  191. langInfo.SetRestrictionLangInfo( urlCodePage, lcid );
  192. CURLUnescaper unescaper( langInfo.GetUrlCodePage() );
  193. CCollectVar varRetriever( unescaper, webServer );
  194. XArray<WCHAR> xwszQueryFile;
  195. WCHAR awcWebhitsPPath[ MAX_PATH ];
  196. WCHAR awcWebhitsVPath[ MAX_PATH ];
  197. WCHAR awcIdqPPath[ MAX_PATH ];
  198. WCHAR awcIdqVPath[ MAX_PATH ];
  199. WCHAR awcHtwPPath[ MAX_PATH ];
  200. WCHAR awcHtwVPath[ MAX_PATH ];
  201. WCHAR const * pwcWebhitsPPath = 0;
  202. WCHAR const * pwcWebhitsVPath = 0;
  203. WCHAR const * pwcIdqPPath = 0;
  204. WCHAR const * pwcIdqVPath = 0;
  205. WCHAR const * pwcHtwPPath = 0;
  206. WCHAR const * pwcHtwVPath = 0;
  207. TRY
  208. {
  209. //
  210. // Refresh the registry values if necessary
  211. //
  212. g_pWebhitsInfo->Refresh();
  213. //
  214. // Are there too many threads doing webhits?
  215. //
  216. if ( g_cThreads > (LONG) g_pWebhitsInfo->GetMaxRunningWebhits() )
  217. {
  218. webDebugOut(( DEB_WARN,
  219. "%d instances of webhits running\n",
  220. g_cThreads ));
  221. THROW( CException( MSG_WEBHITS_TOO_MANY_COPIES ) );
  222. }
  223. //
  224. // Retrieve the necessary environment variables.
  225. //
  226. CGetEnvVars variables( webServer,
  227. langInfo,
  228. varRetriever,
  229. unescaper );
  230. if (variables.GetQueryFileVPath())
  231. {
  232. xwszQueryFile.Init( wcslen(variables.GetQueryFileVPath())+1 );
  233. wcscpy( xwszQueryFile.GetPointer(), variables.GetQueryFileVPath() );
  234. }
  235. GetWebhitsVPathInfo( variables, webServer );
  236. //
  237. // construct Property List with static properties
  238. //
  239. XInterface<CEmptyPropertyList> xlist;
  240. //
  241. // If an idq file was specified, then parse the [NAMES] section of
  242. // that file to obtain custom properties
  243. //
  244. if ( variables.GetQueryFilePPath() )
  245. {
  246. Win4Assert( wcslen( variables.GetQueryFilePPath() ) < MAX_PATH );
  247. wcscpy( awcIdqPPath, variables.GetQueryFilePPath() );
  248. pwcIdqPPath = awcIdqPPath;
  249. Win4Assert( wcslen( variables.GetQueryFileVPath() ) < MAX_PATH );
  250. wcscpy( awcIdqVPath, variables.GetQueryFileVPath() );
  251. pwcIdqVPath = awcIdqVPath;
  252. xlist.Set( new CLocalGlobalPropertyList( GetGlobalStaticPropertyList(),
  253. TRUE,
  254. variables.GetQueryFilePPath(),
  255. langInfo.GetUrlCodePage()) );
  256. ULONG iLine;
  257. WCHAR * pwszFile;
  258. SCODE sc = ((CLocalGlobalPropertyList *)xlist.GetPointer())->CheckError( iLine, &pwszFile );
  259. if (FAILED(sc))
  260. THROW(CException(sc));
  261. }
  262. else
  263. xlist.Set(GetGlobalStaticPropertyList());
  264. //
  265. // If a template file is specified, it should be parsed.
  266. //
  267. XPtr<CWebhitsTemplate> xTemplate;
  268. if ( variables.GetTemplateFileVPath() )
  269. {
  270. Win4Assert( wcslen( variables.GetTemplateFilePPath() ) < MAX_PATH );
  271. wcscpy( awcHtwPPath, variables.GetTemplateFilePPath() );
  272. pwcHtwPPath = awcHtwPPath;
  273. Win4Assert( wcslen( variables.GetTemplateFileVPath() ) < MAX_PATH );
  274. wcscpy( awcHtwVPath, variables.GetTemplateFileVPath() );
  275. pwcHtwVPath = awcHtwVPath;
  276. CWebhitsTemplate * pTemplate =
  277. new CWebhitsTemplate( variables,
  278. langInfo.GetOutputCodePage() );
  279. xTemplate.Set( pTemplate );
  280. }
  281. //
  282. // convert textual query into CDbRestriction
  283. //
  284. CInternalQuery query( variables, xlist.GetReference(), langInfo.GetQueryLCID() );
  285. Win4Assert( wcslen( variables.GetWebHitsFilePPath() ) < MAX_PATH );
  286. wcscpy( awcWebhitsPPath, variables.GetWebHitsFilePPath() );
  287. pwcWebhitsPPath = awcWebhitsPPath;
  288. Win4Assert( wcslen( variables.GetWebHitsFileVPath() ) < MAX_PATH );
  289. wcscpy( awcWebhitsVPath, variables.GetWebHitsFileVPath() );
  290. pwcWebhitsVPath = awcWebhitsVPath;
  291. //
  292. // Verify a consistent SSL-setting for .htw and webhits files.
  293. // This fixes the problem where the webhits file requires SSL,
  294. // but the template file doesn't, since a port can't change its
  295. // SSL setting on the fly. A work-around would be to do a redirect
  296. // to a bogus .htw file in the same virtual directory as the
  297. // webhits file to force SSL, but that seemed overkill.
  298. //
  299. if ( variables.GetTemplateFileVPath() )
  300. {
  301. //
  302. // This is a complete list of SSL-related flags.
  303. //
  304. const DWORD dwSSL = HSE_URL_FLAGS_SSL |
  305. HSE_URL_FLAGS_NEGO_CERT |
  306. HSE_URL_FLAGS_REQUIRE_CERT |
  307. HSE_URL_FLAGS_MAP_CERT |
  308. HSE_URL_FLAGS_SSL128;
  309. DWORD dwTemplate = ( variables.GetTemplateFileFlags() & dwSSL );
  310. DWORD dwWebHits = ( variables.GetWebHitsFileFlags() & dwSSL );
  311. if ( ( dwTemplate != dwWebHits ) &&
  312. ( 0 != dwWebHits ) )
  313. {
  314. webDebugOut(( DEB_WARN,
  315. "SSL mismatch template: 0x%x, webhits: 0x%x\n",
  316. dwTemplate, dwWebHits ));
  317. THROW( CException( MSG_WEBHITS_INCONSISTENT_SSL ) );
  318. }
  319. }
  320. //
  321. // Impersonate if the file being webhit is remote
  322. //
  323. CImpersonateRemoteAccess imp( 0 );
  324. if ( CImpersonateRemoteAccess::IsNetPath( pwcWebhitsPPath ) )
  325. {
  326. CImpersonationTokenCache * pCache = g_pWebhitsInfo->GetTokenCache( webServer );
  327. imp.SetTokenCache( pCache );
  328. // Flip the slashes -- the token cache expects backslashes...
  329. unsigned cwc = wcslen( pwcWebhitsVPath );
  330. Win4Assert( cwc < MAX_PATH );
  331. WCHAR awcTempVPath[ MAX_PATH ];
  332. for ( unsigned c = 0; c < cwc; c++ )
  333. {
  334. if ( L'/' == pwcWebhitsVPath[c] )
  335. awcTempVPath[c] = L'\\';
  336. else
  337. awcTempVPath[c] = pwcWebhitsVPath[c];
  338. }
  339. awcTempVPath[ cwc ] = 0;
  340. //
  341. // If impersonation fails, try rescanning the metabase.
  342. // There may have been an update to vroot info.
  343. // Note that revocation may take a long time as a result.
  344. // It's really unlikely we'll have to reinit very often
  345. // unless the server is misconfigured.
  346. //
  347. if ( !imp.ImpersonateIfNoThrow( pwcWebhitsPPath, awcTempVPath ) )
  348. {
  349. pCache->ReInitializeIISScopes();
  350. imp.ImpersonateIf( pwcWebhitsPPath, awcTempVPath );
  351. }
  352. }
  353. //
  354. // construct framework for highlighting, and highlight hits
  355. //
  356. query.CreateISearch( pwcWebhitsPPath );
  357. //
  358. // two cases - either summary or full hit-highlighting
  359. //
  360. CReleasableLock lock( g_pWebhitsInfo->GetNonThreadedFilterMutex(),
  361. FALSE );
  362. if (variables.GetHiliteType() == CGetEnvVars::SUMMARY)
  363. {
  364. XPtr<CDocument> xDoc( new CDocument(
  365. (WCHAR*) pwcWebhitsPPath,
  366. CLinkQueryHits::BOGUS_RANK,
  367. query.GetISearchRef(),
  368. g_pWebhitsInfo->GetMaxWebhitsCpuTime(),
  369. lock,
  370. xlist.GetReference(),
  371. g_pWebhitsInfo->GetDisplayScript() ) );
  372. PHttpOutput httpOutput( webServer, langInfo );
  373. httpOutput.Init( &variables, xTemplate.GetPointer() );
  374. HitIter iterator;
  375. iterator.Init( xDoc.GetPointer() );
  376. httpOutput.OutputHTMLHeader();
  377. if ( variables.IsFixedFont() )
  378. httpOutput.OutputPreformattedTag();
  379. CExtractHits hitExtractor( xDoc.GetReference(),
  380. iterator,
  381. httpOutput );
  382. httpOutput.OutputHTMLFooter();
  383. }
  384. else
  385. {
  386. PHttpFullOutput httpOutput( webServer, langInfo );
  387. httpOutput.Init(&variables, xTemplate.GetPointer());
  388. XPtr<CLinkQueryHits> xLQH( new CLinkQueryHits(
  389. query,
  390. variables,
  391. httpOutput,
  392. g_pWebhitsInfo->GetMaxWebhitsCpuTime(),
  393. lock,
  394. xlist.GetReference(),
  395. g_pWebhitsInfo->GetDisplayScript() ) );
  396. httpOutput.OutputHTMLHeader();
  397. xLQH->InsertLinks();
  398. httpOutput.OutputHTMLFooter();
  399. }
  400. }
  401. CATCH( CPListException, ple )
  402. {
  403. WCHAR wcTempBuffer[ERROR_MESSAGE_SIZE];
  404. wsprintf( wcTempBuffer,
  405. L"Property list parsing query file %ls failed with error 0x%X\n",
  406. xwszQueryFile.GetPointer(),
  407. ple.GetPListError() );
  408. OutputErrorMessage( webServer,
  409. langInfo,
  410. ple.GetPListError(),
  411. pwcIdqPPath,
  412. pwcIdqVPath,
  413. pwcHtwPPath,
  414. pwcHtwVPath,
  415. pwcWebhitsPPath,
  416. pwcWebhitsVPath,
  417. wcTempBuffer,
  418. xwszQueryFile.GetPointer(),
  419. ple.GetLine() );
  420. }
  421. AND_CATCH( CWTXException, we )
  422. {
  423. WCHAR wcTempBuffer[ERROR_MESSAGE_SIZE];
  424. wsprintf( wcTempBuffer,
  425. L"Parsing template file %ls failed with error 0x%X\n",
  426. we.GetFileName(),
  427. we.GetErrorCode() );
  428. OutputErrorMessage( webServer,
  429. langInfo,
  430. we.GetErrorCode(),
  431. pwcIdqPPath,
  432. pwcIdqVPath,
  433. pwcHtwPPath,
  434. pwcHtwVPath,
  435. pwcWebhitsPPath,
  436. pwcWebhitsVPath,
  437. wcTempBuffer,
  438. we.GetFileName(),
  439. we.GetLineNumber() );
  440. }
  441. AND_CATCH( CParserException, pe )
  442. {
  443. WCHAR wcTempBuffer[ERROR_MESSAGE_SIZE];
  444. wsprintf( wcTempBuffer,
  445. L"Parsing of QUERY_STRING failed with error 0x%X\n",
  446. pe.GetErrorCode() );
  447. OutputErrorMessage( webServer,
  448. langInfo,
  449. pe.GetParseError(),
  450. pwcIdqPPath,
  451. pwcIdqVPath,
  452. pwcHtwPPath,
  453. pwcHtwVPath,
  454. pwcWebhitsPPath,
  455. pwcWebhitsVPath,
  456. wcTempBuffer );
  457. }
  458. AND_CATCH( CException,e )
  459. {
  460. OutputErrorMessage( webServer,
  461. langInfo,
  462. e.GetErrorCode(),
  463. pwcIdqPPath,
  464. pwcIdqVPath,
  465. pwcHtwPPath,
  466. pwcHtwVPath,
  467. pwcWebhitsPPath,
  468. pwcWebhitsVPath );
  469. }
  470. END_CATCH
  471. return hse;
  472. } //ProcessWebRequest
  473. //+---------------------------------------------------------------------------
  474. //
  475. // Function: OutputErrorMessage
  476. //
  477. // Synopsis: Outputs an error message based on the msg id given. It first
  478. // looks up for the error in webhits.dll, query.dll, then in
  479. // kernel32.dll.
  480. // If no message is found, it then uses the default message.
  481. //
  482. // Arguments: [dwMsgId] - Message id
  483. // [pwszDefaultMsg] - Pointer to the default message. Will be
  484. // used if there is no pre-formatted message.
  485. // [pwszFileName] - File name to be printed prior to the error
  486. // message. Will not be printed if null.
  487. // [ulFileLine] - File line number. Not printed if zero.
  488. //
  489. // History: 9-04-96 srikants Created
  490. //
  491. //----------------------------------------------------------------------------
  492. void OutputErrorMessage( CWebServer & webServer,
  493. CLanguageInfo & langInfo,
  494. DWORD dwMsgId,
  495. WCHAR const * pwcIdqPPath,
  496. WCHAR const * pwcIdqVPath,
  497. WCHAR const * pwcHtwPPath,
  498. WCHAR const * pwcHtwVPath,
  499. WCHAR const * pwcWebhitsPPath,
  500. WCHAR const * pwcWebhitsVPath,
  501. WCHAR const * pwszDefaultMsg,
  502. WCHAR const * pwszFileName,
  503. ULONG ulFileLine )
  504. {
  505. CImpersonateSystem system;
  506. //
  507. // If the error was the result of an access denied problem, then simply
  508. // return a 401 error to the browser if the path allows authentication
  509. //
  510. // Generate the Win32 error code by removing the facility code (7) and
  511. // the error bit.
  512. //
  513. if ( (STATUS_ACCESS_DENIED == dwMsgId) ||
  514. (STATUS_NETWORK_ACCESS_DENIED == dwMsgId) ||
  515. (HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) == dwMsgId) ||
  516. (HRESULT_FROM_WIN32( ERROR_INVALID_ACCESS ) == dwMsgId) ||
  517. (HRESULT_FROM_WIN32( ERROR_NETWORK_ACCESS_DENIED ) == dwMsgId) )
  518. {
  519. WCHAR const * pwcVPath = 0;
  520. WCHAR const * pwcPPath = 0;
  521. if ( 0 != pwcWebhitsVPath )
  522. {
  523. pwcPPath = pwcWebhitsPPath;
  524. pwcVPath = pwcWebhitsVPath;
  525. }
  526. else if ( 0 != pwcHtwVPath )
  527. {
  528. pwcPPath = pwcHtwPPath;
  529. pwcVPath = pwcHtwVPath;
  530. }
  531. else
  532. {
  533. pwcPPath = pwcIdqPPath;
  534. pwcVPath = pwcIdqVPath;
  535. }
  536. Win4Assert( 0 != pwcPPath );
  537. Win4Assert( 0 != pwcVPath );
  538. webDebugOut(( DEB_ITRACE, "error P and V paths: '%ws', '%ws'\n",
  539. pwcPPath, pwcVPath ));
  540. CMetaDataMgr mdMgr( FALSE, W3VRoot, webServer.GetServerInstance() );
  541. ULONG Authorization = mdMgr.GetVPathAuthorization( pwcVPath );
  542. webDebugOut(( DEB_ITRACE, "authorization: 0x%x\n", Authorization ));
  543. // If the virtual directory doesn't support just anonymous,
  544. // this is not a remote physical path, try to authenticate.
  545. if ( 0 != Authorization &&
  546. MD_AUTH_ANONYMOUS != Authorization &&
  547. !CImpersonateRemoteAccess::IsNetPath( pwcPPath ) )
  548. {
  549. webDebugOut(( DEB_WARN,
  550. "mapping 0x%x to 401 access denied\n",
  551. dwMsgId ));
  552. webServer.WriteHeader( 0, "401 Access denied" );
  553. const char * pcAccessDenied = "Access is denied.";
  554. webServer.WriteClient( (BYTE *) pcAccessDenied,
  555. strlen( pcAccessDenied ) );
  556. return;
  557. }
  558. }
  559. WCHAR awcTempBuffer[ERROR_MESSAGE_SIZE];
  560. WCHAR * pwszErrorMessage = awcTempBuffer;
  561. ULONG cchAvailMessage = ERROR_MESSAGE_SIZE;
  562. //
  563. // Don't pass a specific lang id to FormatMessage since it will
  564. // fail if there's no message in that language. Instead set
  565. // the thread locale, which will get FormatMessage to use a search
  566. // algorithm to find a message of the appropriate language or
  567. // use a reasonable fallback msg if there's none.
  568. //
  569. LCID SaveLCID = GetThreadLocale();
  570. SetThreadLocale( langInfo.GetQueryLCID() );
  571. if (pwszFileName != 0)
  572. {
  573. //
  574. // These are errors encountered while parsing the [names] section
  575. //
  576. DWORD_PTR args [] = {
  577. (DWORD_PTR) pwszFileName,
  578. (DWORD_PTR) ulFileLine,
  579. };
  580. NTSTATUS MsgNum = MSG_WEBHITS_FILE_MESSAGE;
  581. if ( 0 != ulFileLine )
  582. MsgNum = MSG_WEBHITS_FILE_LINE_MESSAGE;
  583. ULONG cchMsg = FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
  584. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  585. GetModuleHandle(L"webhits.dll"),
  586. MsgNum,
  587. 0,
  588. pwszErrorMessage,
  589. cchAvailMessage,
  590. (va_list *) args );
  591. pwszErrorMessage += cchMsg;
  592. cchAvailMessage -= cchMsg;
  593. }
  594. if ( !FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
  595. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  596. GetModuleHandle(L"webhits.dll"),
  597. dwMsgId,
  598. 0,
  599. pwszErrorMessage,
  600. cchAvailMessage,
  601. 0 ) &&
  602. !FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
  603. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  604. GetModuleHandle(L"Query.dll"),
  605. dwMsgId,
  606. 0,
  607. pwszErrorMessage,
  608. cchAvailMessage,
  609. 0 ) &&
  610. !FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
  611. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  612. GetModuleHandle(L"kernel32.dll"),
  613. dwMsgId,
  614. 0,
  615. pwszErrorMessage,
  616. cchAvailMessage,
  617. 0 ) &&
  618. !FormatMessage( FORMAT_MESSAGE_FROM_HMODULE |
  619. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  620. GetModuleHandle(L"kernel32.dll"),
  621. HRESULT_CODE(dwMsgId),
  622. 0,
  623. pwszErrorMessage,
  624. cchAvailMessage,
  625. 0 ) )
  626. {
  627. DWORD dwError = GetLastError();
  628. webDebugOut(( DEB_ERROR, "Format Message failed with error 0x%X\n",
  629. dwError ));
  630. if ( !pwszDefaultMsg )
  631. {
  632. wsprintf( pwszErrorMessage,
  633. L"Error 0x%X occurred while running webhits \n",
  634. dwMsgId );
  635. }
  636. else
  637. {
  638. Win4Assert( wcslen( pwszDefaultMsg ) < cchAvailMessage );
  639. wsprintf( pwszErrorMessage, L"%ws\n", pwszDefaultMsg );
  640. }
  641. }
  642. SetThreadLocale(SaveLCID);
  643. PHttpOutput httpOutput( webServer, langInfo );
  644. httpOutput.OutputErrorHeader();
  645. httpOutput.OutputErrorMessage( awcTempBuffer, wcslen(awcTempBuffer) );
  646. httpOutput.OutputHTMLFooter();
  647. } //OutputErrorMessage
  648. //+---------------------------------------------------------------------------
  649. //
  650. // Function: GetExtensionVersion - public
  651. //
  652. // Synposis: Returns extension info to the server. This is called before
  653. // HttpExtensionProc is called, and it is called in System
  654. // context, so any initialization that requires this context
  655. // must be handled here.
  656. //
  657. // Arguments: [pVer] - where the info goes
  658. //
  659. // History: 96-Apr-15 dlee Added header
  660. //
  661. //----------------------------------------------------------------------------
  662. BOOL WINAPI GetExtensionVersion(
  663. HSE_VERSION_INFO * pVer )
  664. {
  665. BOOL fOK = TRUE;
  666. TRANSLATE_EXCEPTIONS;
  667. TRY
  668. {
  669. Win4Assert( g_fShutdown );
  670. Win4Assert( 0 == g_pWebhitsInfo );
  671. pVer->dwExtensionVersion = MAKELONG( 0, 3 );
  672. strcpy( pVer->lpszExtensionDesc, "Indexing Service webhits extension" );
  673. g_pWebhitsInfo = new CWebhitsInfo();
  674. g_fShutdown = FALSE;
  675. }
  676. CATCH( CException, e )
  677. {
  678. fOK = FALSE;
  679. webDebugOut(( DEB_WARN,
  680. "GetExtensionVersion failed 0x%x\n",
  681. e.GetErrorCode() ));
  682. }
  683. END_CATCH
  684. UNTRANSLATE_EXCEPTIONS;
  685. return fOK;
  686. } //GetExtensionVersion
  687. //+---------------------------------------------------------------------------
  688. //
  689. // Function: TerminateExtension, public
  690. //
  691. // Synposis: Called by IIS during shutdown
  692. //
  693. // History: 3-Mar-97 dlee Created
  694. //
  695. //----------------------------------------------------------------------------
  696. BOOL WINAPI TerminateExtension(
  697. DWORD dwFlags )
  698. {
  699. TRANSLATE_EXCEPTIONS;
  700. BOOL fOK = FALSE;
  701. if ( dwFlags & HSE_TERM_MUST_UNLOAD )
  702. {
  703. TRY
  704. {
  705. Win4Assert( !g_fShutdown );
  706. g_fShutdown = TRUE;
  707. webDebugOut(( DEB_WARN,
  708. "Mandatory extension unload. Shutting down webhits.\n" ));
  709. // wait for all the isapi request threads to finish
  710. while ( 0 != g_cThreads )
  711. Sleep( 50 );
  712. delete g_pWebhitsInfo;
  713. g_pWebhitsInfo = 0;
  714. CIShutdown();
  715. }
  716. CATCH( CException, e )
  717. {
  718. // ignore
  719. }
  720. END_CATCH
  721. fOK = TRUE;
  722. }
  723. webDebugOut(( DEB_WARN,
  724. "webhits extension unload: 0x%x. Flags = 0x%x\n",
  725. fOK, dwFlags ));
  726. UNTRANSLATE_EXCEPTIONS;
  727. return fOK;
  728. } //TerminateExtension
  729. //+---------------------------------------------------------------------------
  730. //
  731. // Function: HttpExtensionProc, public
  732. //
  733. // Synposis: Handles a request from the web server
  734. //
  735. // Arguments: [pEcb] -- block from the server
  736. //
  737. // History: 3-Mar-97 dlee Created
  738. //
  739. //----------------------------------------------------------------------------
  740. DWORD WINAPI HttpExtensionProc(
  741. EXTENSION_CONTROL_BLOCK * pEcb )
  742. {
  743. if ( g_fShutdown )
  744. {
  745. pEcb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
  746. return HSE_STATUS_ERROR;
  747. }
  748. InterlockedIncrement( & g_cThreads );
  749. CWebServer webServer( pEcb );
  750. DWORD hseStatus = HSE_STATUS_ERROR;
  751. webServer.SetHttpStatus( HTTP_STATUS_OK );
  752. TRANSLATE_EXCEPTIONS;
  753. TRY
  754. {
  755. XCom xcom;
  756. hseStatus = ProcessWebRequest( webServer );
  757. }
  758. CATCH( CException, e )
  759. {
  760. hseStatus = HSE_STATUS_ERROR;
  761. webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
  762. }
  763. END_CATCH
  764. UNTRANSLATE_EXCEPTIONS;
  765. Win4Assert( HSE_STATUS_PENDING != hseStatus );
  766. InterlockedDecrement( & g_cThreads );
  767. return hseStatus;
  768. } //HttpExtensionProc
  769. //+---------------------------------------------------------------------------
  770. //
  771. // Method: CWebhitsInfo::CWebhitsInfo, public
  772. //
  773. // Synposis: Constructs a webhits info object
  774. //
  775. // History: 18-Aug-97 dlee Created
  776. //
  777. //----------------------------------------------------------------------------
  778. CWebhitsInfo::CWebhitsInfo() :
  779. _regChangeEvent( wcsRegAdminTree )
  780. {
  781. ReadRegValues();
  782. } //CWebhitsInfo
  783. //+---------------------------------------------------------------------------
  784. //
  785. // Method: CWebhitsInfo::Refresh, public
  786. //
  787. // Synposis: Checks to see if the registry has changed and refreshes it
  788. //
  789. // History: 18-Aug-97 dlee Created
  790. //
  791. //----------------------------------------------------------------------------
  792. void CWebhitsInfo::Refresh()
  793. {
  794. CLock lock( _mutex );
  795. ULONG res = WaitForSingleObject( _regChangeEvent.GetEventHandle(), 0 );
  796. if ( WAIT_OBJECT_0 == res )
  797. {
  798. ReadRegValues();
  799. _regChangeEvent.Reset();
  800. }
  801. } //Refresh
  802. //+---------------------------------------------------------------------------
  803. //
  804. // Method: CWebhitsInfo::ReadRegValues
  805. //
  806. // Synposis: Reads webhits registry info
  807. //
  808. // History: 18-Aug-97 dlee Created
  809. //
  810. //----------------------------------------------------------------------------
  811. void CWebhitsInfo::ReadRegValues()
  812. {
  813. CRegAccess reg( RTL_REGISTRY_CONTROL, wcsRegAdmin );
  814. const ULONG CI_RUNNING_WEBHITS_DEFAULT = 20;
  815. const ULONG CI_RUNNING_WEBHITS_MIN = 1;
  816. const ULONG CI_RUNNING_WEBHITS_MAX = 200;
  817. ULONG ul = reg.Read( wcsMaxRunningWebhits, CI_RUNNING_WEBHITS_DEFAULT );
  818. _cMaxRunningWebhits = Range( ul, CI_RUNNING_WEBHITS_MIN, CI_RUNNING_WEBHITS_MAX );
  819. const ULONG CI_WEBHITS_DISPLAY_SCRIPT_DEFAULT = DISPLAY_SCRIPT_KNOWN_FILTER;
  820. const ULONG CI_WEBHITS_DISPLAY_SCRIPT_MIN = 0;
  821. const ULONG CI_WEBHITS_DISPLAY_SCRIPT_MAX = 2;
  822. ul = reg.Read( wcsWebhitsDisplayScript, CI_WEBHITS_DISPLAY_SCRIPT_DEFAULT );
  823. _ulDisplayScript = Range( ul, CI_WEBHITS_DISPLAY_SCRIPT_MIN, CI_WEBHITS_DISPLAY_SCRIPT_MAX );
  824. const ULONG CI_WEBHITS_TIMEOUT_DEFAULT = 30;
  825. const ULONG CI_WEBHITS_TIMEOUT_MIN = 5;
  826. const ULONG CI_WEBHITS_TIMEOUT_MAX = 7200;
  827. ul = reg.Read( wcsMaxWebhitsCpuTime, CI_WEBHITS_TIMEOUT_DEFAULT );
  828. _cmsMaxWebhitsCpuTime = Range( ul, CI_WEBHITS_TIMEOUT_MIN, CI_WEBHITS_TIMEOUT_MAX );
  829. } //ReadRegValues
  830. //+---------------------------------------------------------------------------
  831. //
  832. // Method: GetTokenCache, public
  833. //
  834. // Synposis: Retrieves the appropriate token cache for the web server
  835. //
  836. // Arguments: [webServer] -- The web server instance
  837. //
  838. // History: 18-Aug-97 dlee Created
  839. //
  840. //----------------------------------------------------------------------------
  841. CImpersonationTokenCache * CWebhitsInfo::GetTokenCache(
  842. CWebServer & webServer )
  843. {
  844. //
  845. // Get the server instance of this ISAPI request
  846. //
  847. ULONG ulInstance = webServer.GetServerInstance();
  848. //
  849. // Look for a token cache for this server instance
  850. //
  851. CLock lock( _mutex );
  852. for ( unsigned x = 0; x < _aTokenCache.Count(); x++ )
  853. {
  854. Win4Assert( 0 != _aTokenCache[ x ] );
  855. if ( _aTokenCache[ x ]->GetW3Instance() == ulInstance )
  856. return _aTokenCache[ x ];
  857. }
  858. //
  859. // Not found, so create a new token cache
  860. //
  861. CImpersonateSystem system;
  862. XPtr<CImpersonationTokenCache> xCache( new CImpersonationTokenCache( L"" ) );
  863. xCache->Initialize( L"webhits", // arbitrary name of token cache
  864. TRUE, // w3svc
  865. FALSE, // not nntp
  866. FALSE, // not imap
  867. ulInstance, // virtual server instance number
  868. 0, // no nntp vserver instance
  869. 0 ); // no imap vserver instance
  870. _aTokenCache[ _aTokenCache.Count() ] = xCache.GetPointer();
  871. return xCache.Acquire();
  872. } //GetTokenCache