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.

973 lines
30 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000.
  5. //
  6. // File: main.cxx
  7. //
  8. // Contents: External entry points for idq.dll.
  9. //
  10. // History: 96/Jan/3 DwightKr Created
  11. //
  12. //----------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <ntverp.h>
  16. #define IDQ_VERSION 3
  17. #define _DECL_DLLMAIN 1
  18. CTheGlobalIDQVariables * pTheGlobalIDQVariables = 0;
  19. DWORD g_cClients = 0;
  20. CRITICAL_SECTION g_csInitExclusive;
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Function: GetExtensionVersion - public
  24. //
  25. // Synposis: Returns extension info to the server. This is called before
  26. // HttpExtensionProc is called, and it is called in System
  27. // context, so any initialization that requires this context
  28. // must be handled here.
  29. //
  30. // Arguments: [pVer] - where the info goes
  31. //
  32. // History: 96-Apr-15 dlee Added header
  33. //
  34. // Notes: There may be multiple clients of this ISAPI app in one
  35. // process (eg W3Svc and NNTPSvc), so refcount the users.
  36. //
  37. //----------------------------------------------------------------------------
  38. BOOL WINAPI GetExtensionVersion( HSE_VERSION_INFO * pVer )
  39. {
  40. BOOL fSuccess = TRUE;
  41. EnterCriticalSection( &g_csInitExclusive );
  42. TRANSLATE_EXCEPTIONS;
  43. TRY
  44. {
  45. pVer->dwExtensionVersion = MAKELONG( 0, IDQ_VERSION );
  46. strcpy( pVer->lpszExtensionDesc, "Indexing Service extension" );
  47. if ( 0 == g_cClients )
  48. {
  49. Win4Assert( 0 == pTheGlobalIDQVariables );
  50. pTheGlobalIDQVariables = new CTheGlobalIDQVariables();
  51. LoadServerErrors();
  52. }
  53. g_cClients++;
  54. }
  55. CATCH( CException, e )
  56. {
  57. fSuccess = FALSE;
  58. ciGibDebugOut(( DEB_WARN, "GetExtensionVersion failed 0x%x\n",
  59. e.GetErrorCode() ));
  60. }
  61. END_CATCH
  62. UNTRANSLATE_EXCEPTIONS;
  63. LeaveCriticalSection( &g_csInitExclusive );
  64. return fSuccess;
  65. } //GetExtensionVersion
  66. //+---------------------------------------------------------------------------
  67. //
  68. // Function: TerminateExtension, public
  69. //
  70. // Synposis: Called by IIS during shutdown
  71. // History: 29-Apr-96 KyleP Created
  72. //
  73. //----------------------------------------------------------------------------
  74. BOOL WINAPI TerminateExtension( DWORD dwFlags )
  75. {
  76. EnterCriticalSection( &g_csInitExclusive );
  77. TRANSLATE_EXCEPTIONS;
  78. BOOL fOK = FALSE;
  79. if ( dwFlags & HSE_TERM_MUST_UNLOAD )
  80. {
  81. TRY
  82. {
  83. Win4Assert( 0 != g_cClients );
  84. g_cClients--;
  85. if ( 0 == g_cClients )
  86. {
  87. ciGibDebugOut(( DEB_WARN, "Mandatory extension unload. Shutting down CI.\n" ));
  88. TheWebQueryCache.Shutdown();
  89. TheWebPendingRequestQueue.Shutdown();
  90. //
  91. // Wait for all ISAPI threads to exit before shutting down CI
  92. //
  93. while ( TheWebResourceArbiter.GetThreadCount() > 0 )
  94. {
  95. ciGibDebugOut(( DEB_WARN, "TerminateExtension: waiting for ISAPI threads to complete\n" ));
  96. Sleep( 50 );
  97. }
  98. ciGibDebugOut(( DEB_WARN,
  99. "TerminatExtension, request count %d\n",
  100. TheWebQueryCache.ActiveRequestCount() ));
  101. // note: don't call CIShutdown here. There's no need
  102. // to, and it'll hose the impersonation token cache for
  103. // webhits.
  104. delete pTheGlobalIDQVariables;
  105. pTheGlobalIDQVariables = 0;
  106. }
  107. }
  108. CATCH( CException, e )
  109. {
  110. // ignore
  111. }
  112. END_CATCH
  113. fOK = TRUE;
  114. }
  115. ciGibDebugOut(( DEB_WARN, "Extension unload: 0x%x. Flags = 0x%x\n",
  116. fOK, dwFlags ));
  117. UNTRANSLATE_EXCEPTIONS;
  118. LeaveCriticalSection( &g_csInitExclusive );
  119. return fOK;
  120. } //TerminateExtension
  121. //+---------------------------------------------------------------------------
  122. //
  123. // Function: CreateQueryFromRequest, private
  124. //
  125. // Synposis: Issues a query from a request.
  126. //
  127. // Arguments: [outputFormat] -- returns the formatting info.
  128. // [localVars] -- returns the local variables.
  129. // [wcsIDQFile] -- returns the idq file name.
  130. // [webServer] -- web server for the request.
  131. // [eErrorClass] -- returns the error class
  132. // [status] -- returns the error code
  133. // [fPending] -- returns TRUE if the request is pending
  134. //
  135. // History: 96-Apr-15 dlee created from existing code
  136. //
  137. //----------------------------------------------------------------------------
  138. #if (CIDBG == 0)
  139. inline
  140. #endif
  141. CWQueryItem * CreateQueryFromRequest( XPtr<COutputFormat> & outputFormat,
  142. XPtr<CVariableSet> & localVars,
  143. WCHAR * wcsIDQFile,
  144. CWebServer & webServer,
  145. int & eErrorClass,
  146. NTSTATUS & status,
  147. BOOL & fPending )
  148. {
  149. //
  150. // NOTE: COutputFormat makes a **copy** of the web server. This
  151. // copy should be used exclusively from this point on. The
  152. // original web server will still be used by callers of this
  153. // routine in cases where we fail to create the copy.
  154. //
  155. outputFormat.Set( new COutputFormat( webServer ) );
  156. localVars.Set( new CVariableSet );
  157. CSecurityIdentity securityIdentity;
  158. XArray<WCHAR> xLocale;
  159. //
  160. // Update the original web server, in case we use it in a top-level
  161. // error path.
  162. //
  163. webServer = outputFormat.GetReference();
  164. LCID locale = GetBrowserLCID( outputFormat.GetReference() , xLocale );
  165. outputFormat->LoadNumberFormatInfo( locale, GetBrowserCodepage(outputFormat.GetReference(), locale) );
  166. localVars->AddExtensionControlBlock( outputFormat.GetReference() );
  167. ULONG cwc = MAX_PATH;
  168. BOOL fOK = outputFormat->GetCGI_PATH_TRANSLATED( wcsIDQFile, cwc );
  169. if ( !fOK )
  170. {
  171. wcsIDQFile[0] = 0;
  172. THROW( CIDQException( MSG_CI_IDQ_NOT_FOUND, 0 ) );
  173. }
  174. outputFormat->SetCodePage(outputFormat->CodePage());
  175. Win4Assert( fOK );
  176. if ( IsNetPath(wcsIDQFile) )
  177. {
  178. ciGibDebugOut(( DEB_ERROR, "Path for idq file (%ws) is a UNC name\n",
  179. wcsIDQFile ));
  180. THROW( CIDQException(MSG_CI_SCRIPTS_ON_REMOTE_UNC, 0) );
  181. }
  182. CWQueryItem *pItem = 0;
  183. //
  184. // Check to see whether this is an .IDQ or .IDA file.
  185. //
  186. static WCHAR const wszAdmin[] = L".IDA";
  187. static unsigned const ccAdmin = sizeof(wszAdmin)/sizeof(wszAdmin[0]) - 1;
  188. if ( cwc > ccAdmin && 0 == _wcsicmp( wszAdmin, wcsIDQFile + cwc - ccAdmin - 1 ) )
  189. {
  190. CVirtualString IDAResults;
  191. DoAdmin( wcsIDQFile,
  192. localVars.GetReference(),
  193. outputFormat.GetReference(),
  194. IDAResults );
  195. if ( outputFormat->WriteClient( IDAResults ) )
  196. outputFormat->SetHttpStatus( HTTP_STATUS_OK );
  197. else
  198. {
  199. eErrorClass = eWebServerWriteError;
  200. outputFormat->SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
  201. }
  202. }
  203. else
  204. {
  205. //
  206. // Atempt to find an existing query using this IDQ file, &
  207. // sequence number, based on the bookmark received.
  208. //
  209. fPending = FALSE;
  210. pItem = TheWebQueryCache.CreateOrFindQuery( wcsIDQFile,
  211. localVars,
  212. outputFormat,
  213. securityIdentity,
  214. fPending );
  215. if ( fPending )
  216. {
  217. Win4Assert( 0 == pItem );
  218. }
  219. else
  220. {
  221. TRY
  222. {
  223. Win4Assert( !pItem->IsCanonicalOutput() );
  224. CVirtualString queryResults( 16384 );
  225. //
  226. // Write the query results to a WCHAR string buffer
  227. // Initial virtual string size is in WCHARs
  228. //
  229. pItem->OutputQueryResults( localVars.GetReference(),
  230. outputFormat.GetReference(),
  231. queryResults );
  232. //
  233. // Send the query results to the browser
  234. //
  235. if ( outputFormat->WriteClient( queryResults ) )
  236. outputFormat->SetHttpStatus( HTTP_STATUS_OK );
  237. else
  238. {
  239. eErrorClass = eWebServerWriteError;
  240. outputFormat->SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
  241. }
  242. }
  243. CATCH( CException, e )
  244. {
  245. eErrorClass = eDefaultISAPIError;
  246. status = e.GetErrorCode();
  247. }
  248. END_CATCH
  249. }
  250. }
  251. return pItem;
  252. } //CreateQueryFromRequest
  253. //+---------------------------------------------------------------------------
  254. //
  255. // Function: ReportErrorNoThrow, public
  256. //
  257. // Synposis: Attempts to report an error condition and log the query
  258. //
  259. // Arguments: [localVars] -- local variables.
  260. // [eErrorClass] -- error class
  261. // [status] -- status code of faulure
  262. // [ulErrorLine] -- line # of the error
  263. // [wcsErrorFile] -- file associated with error
  264. // [outputFormat] -- formatting info.
  265. // [webServer] -- web server for the request.
  266. //
  267. // History: 96-Nov-25 dlee created from existing code, added TRY
  268. //
  269. //----------------------------------------------------------------------------
  270. void ReportErrorNoThrow(
  271. XPtr<CVariableSet> & localVars,
  272. int eErrorClass,
  273. NTSTATUS status,
  274. ULONG ulErrorLine,
  275. WCHAR const * wcsErrorFile,
  276. XPtr<COutputFormat> & outputFormat,
  277. CWebServer & webServer )
  278. {
  279. TRY
  280. {
  281. WCHAR * wcsRestriction = 0;
  282. //
  283. // Lookup the restriction, if one has been fully constructed.
  284. //
  285. if ( 0 != localVars.GetPointer() )
  286. {
  287. CVariable * pVarRestriction = localVars->Find(ISAPI_CI_RESTRICTION);
  288. if ( 0 != pVarRestriction )
  289. {
  290. ULONG cwcValue;
  291. wcsRestriction = pVarRestriction->GetStringValueRAW( outputFormat.GetReference(), cwcValue );
  292. }
  293. }
  294. //
  295. // Attempt to write out the error picture, if appropriate
  296. //
  297. CVirtualString vString;
  298. GetErrorPageNoThrow( eErrorClass,
  299. status,
  300. ulErrorLine,
  301. wcsErrorFile,
  302. localVars.GetPointer(),
  303. outputFormat.GetPointer(),
  304. outputFormat.GetPointer() ? outputFormat->GetLCID() : 0,
  305. webServer,
  306. vString );
  307. ciGibDebugOut(( DEB_IWARN, "WARNING: %ws\n", vString.Get() ));
  308. webServer.WriteClient( vString );
  309. Win4Assert( webServer.GetHttpStatus() >= HTTP_STATUS_FIRST );
  310. //
  311. // Log the restriction in the failed query. It may not have
  312. // been logged yet since we may have thrown before it was
  313. // logged in the query execution path.
  314. //
  315. // if ( 0 != wcsRestriction )
  316. // webServer.WriteLogData( wcsRestriction );
  317. }
  318. CATCH( CException, e )
  319. {
  320. // ignore -- not enough memory to output an error message
  321. }
  322. END_CATCH
  323. } //ReportErrorNoThrow
  324. //+---------------------------------------------------------------------------
  325. //
  326. // Function: ReportErrorNoThrow, public
  327. //
  328. // Synposis: Attempts to report an error condition and log the query
  329. //
  330. // Arguments: [localVars] -- local variables.
  331. // [scError] -- error code
  332. // [pwszErrorMessage] -- Description provided by Ole-DB error svc.
  333. // [outputFormat] -- formatting info.
  334. // [webServer] -- web server for the request.
  335. //
  336. // History: 97-May-08 KrishnaN created from existing ReportErrorNoThrow
  337. //
  338. //----------------------------------------------------------------------------
  339. void ReportErrorNoThrow(
  340. XPtr<CVariableSet> & localVars,
  341. int eErrorClass,
  342. SCODE scError,
  343. WCHAR const * pwszErrorMessage,
  344. XPtr<COutputFormat> & outputFormat,
  345. CWebServer & webServer )
  346. {
  347. TRY
  348. {
  349. WCHAR * wcsRestriction = 0;
  350. //
  351. // Lookup the restriction, if one has been fully constructed.
  352. //
  353. if ( 0 != localVars.GetPointer() )
  354. {
  355. CVariable * pVarRestriction = localVars->Find(ISAPI_CI_RESTRICTION);
  356. if ( 0 != pVarRestriction )
  357. {
  358. ULONG cwcValue;
  359. wcsRestriction = pVarRestriction->GetStringValueRAW( outputFormat.GetReference(), cwcValue );
  360. }
  361. }
  362. //
  363. // Attempt to write out the error picture, if appropriate
  364. //
  365. CVirtualString vString;
  366. GetErrorPageNoThrow(eErrorClass,
  367. scError,
  368. pwszErrorMessage,
  369. localVars.GetPointer(),
  370. outputFormat.GetPointer(),
  371. outputFormat.GetPointer() ? outputFormat->GetLCID() : 0,
  372. webServer,
  373. vString );
  374. ciGibDebugOut(( DEB_IWARN, "WARNING: %ws\n", vString.Get() ));
  375. webServer.WriteClient( vString );
  376. Win4Assert( webServer.GetHttpStatus() >= HTTP_STATUS_FIRST );
  377. //
  378. // Log the restriction in the failed query. It may not have
  379. // been logged yet since we may have thrown before it was
  380. // logged in the query execution path.
  381. //
  382. // if ( 0 != wcsRestriction )
  383. // webServer.WriteLogData( wcsRestriction );
  384. }
  385. CATCH( CException, e )
  386. {
  387. // ignore -- not enough memory to output an error message
  388. }
  389. END_CATCH
  390. } //ReportErrorNoThrow
  391. //+---------------------------------------------------------------------------
  392. //
  393. // Function: ProcessWebRequest, public
  394. //
  395. // Synposis: Issues a query from a request.
  396. //
  397. // Arguments: [webServer] -- web server for the request.
  398. //
  399. // Returns: The HSE_STATUS code.
  400. //
  401. // History: 96-Apr-15 dlee created from existing code
  402. // 98-Sep-16 KLam Checks for valid method
  403. //
  404. //----------------------------------------------------------------------------
  405. DWORD ProcessWebRequest(
  406. CWebServer & webServer )
  407. {
  408. Win4Assert( HTTP_STATUS_ACCEPTED == webServer.GetHttpStatus() );
  409. WCHAR wcsIDQFile[MAX_PATH];
  410. wcsIDQFile[0] = 0;
  411. CWQueryItem *pItem = 0;
  412. XPtr<COutputFormat> outputFormat;
  413. XPtr<CVariableSet> localVars;
  414. NTSTATUS status = STATUS_SUCCESS; // Error code from query
  415. ULONG ulErrorLine; // Line # in IDQ file error occured
  416. int eErrorClass; // Type of error, IDQ, HTX, parse, ...
  417. WCHAR const * wcsErrorFile = 0; // Name of file containing error
  418. BOOL fPending = FALSE;
  419. //
  420. // Set the following flag to TRUE if we encounter an error
  421. // whose description is already available.
  422. //
  423. BOOL fReportErrorWithDescription = FALSE;
  424. BSTR bstrErrorDescription = 0;
  425. //
  426. // Make sure we have a valid method
  427. //
  428. if ( strcmp ( webServer.GetMethod(), "HEAD" ) == 0 )
  429. {
  430. //
  431. // Do not need to execute the query if the client only wants the head
  432. //
  433. if ( webServer.WriteHeader() )
  434. webServer.SetHttpStatus ( HTTP_STATUS_OK );
  435. else
  436. {
  437. eErrorClass = eWebServerWriteError;
  438. webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
  439. return HSE_STATUS_ERROR;
  440. }
  441. return HSE_STATUS_SUCCESS;
  442. }
  443. // Only support GET and POST for queries
  444. else if ( strcmp( webServer.GetMethod(), "GET" ) != 0
  445. && strcmp ( webServer.GetMethod(), "POST" ) != 0 )
  446. {
  447. // HTTP 1.1 Spec determines value of header status string
  448. if ( webServer.WriteHeader( NULL, "501 Not Implemented" ) )
  449. webServer.SetHttpStatus ( HTTP_STATUS_NOT_SUPPORTED );
  450. else
  451. {
  452. eErrorClass = eWebServerWriteError;
  453. webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
  454. }
  455. return HSE_STATUS_ERROR;
  456. }
  457. else
  458. {
  459. TRY
  460. {
  461. pItem = CreateQueryFromRequest( outputFormat,
  462. localVars,
  463. wcsIDQFile,
  464. webServer,
  465. eErrorClass,
  466. status,
  467. fPending );
  468. }
  469. CATCH( CPListException, e )
  470. {
  471. status = e.GetPListError();
  472. ulErrorLine = e.GetLine();
  473. eErrorClass = eIDQPlistError;
  474. wcsErrorFile = wcsIDQFile;
  475. Win4Assert( STATUS_SUCCESS != status );
  476. }
  477. AND_CATCH( CIDQException, e )
  478. {
  479. status = e.GetErrorCode();
  480. ulErrorLine = e.GetErrorIndex();
  481. eErrorClass = eIDQParseError;
  482. wcsErrorFile = wcsIDQFile;
  483. Win4Assert( STATUS_SUCCESS != status );
  484. }
  485. AND_CATCH( CHTXException, e )
  486. {
  487. status = e.GetErrorCode();
  488. ulErrorLine = e.GetErrorIndex();
  489. eErrorClass = eHTXParseError;
  490. wcsErrorFile = e.GetHTXFileName();
  491. //
  492. // copy the error file name; it's stored on the stack below
  493. // this function.
  494. //
  495. ULONG cchFileName = min( wcslen(wcsErrorFile) + 1, MAX_PATH );
  496. Win4Assert(cchFileName < MAX_PATH);
  497. RtlCopyMemory( wcsIDQFile,
  498. wcsErrorFile,
  499. sizeof(WCHAR) * cchFileName );
  500. wcsIDQFile[MAX_PATH-1] = 0;
  501. wcsErrorFile = wcsIDQFile;
  502. Win4Assert( STATUS_SUCCESS != status );
  503. }
  504. AND_CATCH( CParserException, e )
  505. {
  506. status = e.GetParseError();
  507. ulErrorLine = 0;
  508. eErrorClass = eRestrictionParseError;
  509. wcsErrorFile = wcsIDQFile;
  510. Win4Assert( STATUS_SUCCESS != status );
  511. }
  512. AND_CATCH( CPostedOleDBException, e )
  513. {
  514. //
  515. // When the execution error was detected, the Ole DB error
  516. // info was retrieved and stored in the exception object.
  517. // We retrieve that here and compose the error message.
  518. //
  519. status = e.GetErrorCode();
  520. eErrorClass = e.GetErrorClass();
  521. Win4Assert( STATUS_SUCCESS != status );
  522. XInterface <IErrorInfo> xErrorInfo(e.AcquireErrorInfo());
  523. if (xErrorInfo.GetPointer())
  524. xErrorInfo->GetDescription(&bstrErrorDescription);
  525. if (bstrErrorDescription)
  526. fReportErrorWithDescription = TRUE;
  527. else
  528. {
  529. // NO description. Follow the normal path.
  530. ulErrorLine = 0;
  531. wcsErrorFile = wcsIDQFile;
  532. }
  533. }
  534. AND_CATCH( CException, e )
  535. {
  536. status = e.GetErrorCode();
  537. ulErrorLine = 0;
  538. eErrorClass = eDefaultISAPIError;
  539. wcsErrorFile = wcsIDQFile;
  540. Win4Assert( STATUS_SUCCESS != status );
  541. }
  542. END_CATCH
  543. }
  544. TRY
  545. {
  546. if ( STATUS_SUCCESS != status )
  547. {
  548. fPending = FALSE;
  549. // the request failed, but we're returning an error message,
  550. // so indicate that everything is ok.
  551. webServer.SetHttpStatus( HTTP_STATUS_OK );
  552. if (fReportErrorWithDescription)
  553. {
  554. Win4Assert(bstrErrorDescription);
  555. ReportErrorNoThrow(localVars,
  556. eErrorClass,
  557. status,
  558. (WCHAR const *)bstrErrorDescription,
  559. outputFormat,
  560. webServer );
  561. SysFreeString(bstrErrorDescription);
  562. }
  563. else
  564. {
  565. Win4Assert(0 == bstrErrorDescription);
  566. ReportErrorNoThrow( localVars,
  567. eErrorClass,
  568. status,
  569. ulErrorLine,
  570. wcsErrorFile,
  571. outputFormat,
  572. webServer );
  573. }
  574. if ( 0 != pItem )
  575. pItem->Zombify();
  576. }
  577. TheWebQueryCache.Release( pItem );
  578. }
  579. CATCH( CException, e )
  580. {
  581. ciGibDebugOut(( DEB_ERROR, "ProcessWebRequest Error 0x%X\n", e.GetErrorCode() ));
  582. Win4Assert( e.GetErrorCode() != STATUS_ACCESS_VIOLATION );
  583. }
  584. END_CATCH
  585. #if CIDBG == 1
  586. //
  587. // If fPending is TRUE, the http status of the ecb can't be trusted,
  588. // because the request may have asynchronously completed by now:
  589. //
  590. if ( !fPending )
  591. {
  592. DWORD dwHttpStatus = webServer.GetHttpStatus();
  593. Win4Assert( HTTP_STATUS_ACCEPTED != dwHttpStatus );
  594. Win4Assert( HTTP_STATUS_OK == dwHttpStatus ||
  595. HTTP_STATUS_SERVER_ERROR == dwHttpStatus ||
  596. HTTP_STATUS_DENIED == dwHttpStatus ||
  597. HTTP_STATUS_SERVICE_UNAVAIL == dwHttpStatus );
  598. }
  599. #endif // CIDBG == 1
  600. if ( fPending )
  601. return HSE_STATUS_PENDING;
  602. return HSE_STATUS_SUCCESS;
  603. } //ProcessWebRequest
  604. //+---------------------------------------------------------------------------
  605. //
  606. // Function: HttpExtensionProc, public
  607. //
  608. // Synposis: Handles a request from the web server
  609. //
  610. // Arguments: [pEcb] -- block from the server
  611. //
  612. // History: 96-Apr-15 dlee created header
  613. //
  614. //----------------------------------------------------------------------------
  615. DWORD WINAPI HttpExtensionProc( EXTENSION_CONTROL_BLOCK *pEcb )
  616. {
  617. if ( 0 == pTheGlobalIDQVariables || fTheActiveXSearchShutdown )
  618. {
  619. ciGibDebugOut(( DEB_GIB_REQUEST,
  620. "Indexing Service being shutdown\n" ));
  621. pEcb->dwHttpStatusCode = HTTP_STATUS_SERVICE_UNAVAIL;
  622. return HSE_STATUS_ERROR;
  623. }
  624. CIncomingThread incoming( TheWebResourceArbiter );
  625. TheWebQueryCache.IncrementActiveRequests();
  626. CWebServer webServer( pEcb );
  627. DWORD hseStatus = HSE_STATUS_ERROR;
  628. webServer.SetHttpStatus( HTTP_STATUS_ACCEPTED );
  629. TRANSLATE_EXCEPTIONS;
  630. TRY
  631. {
  632. if ( TheWebResourceArbiter.IsSystemBusy() )
  633. {
  634. if ( TheWebQueryCache.AddToPendingRequestQueue( pEcb ) )
  635. {
  636. ciGibDebugOut(( DEB_GIB_REQUEST, "Server busy, queueing request\n" ));
  637. hseStatus = HSE_STATUS_PENDING;
  638. TheWebQueryCache.Wakeup();
  639. TheWebQueryCache.UpdatePendingRequestCount();
  640. }
  641. else
  642. {
  643. TheWebQueryCache.IncrementRejectedRequests();
  644. ciGibDebugOut(( DEB_GIB_REQUEST,
  645. "Server too busy, failing request!!!\n" ));
  646. ReturnServerError( HTTP_STATUS_SERVICE_UNAVAIL, webServer );
  647. hseStatus = HSE_STATUS_SUCCESS;
  648. }
  649. }
  650. else
  651. {
  652. ciGibDebugOut(( DEB_GIB_REQUEST, "Server not busy, processing request\n" ));
  653. hseStatus = ProcessWebRequest( webServer );
  654. }
  655. }
  656. CATCH( CException, e )
  657. {
  658. hseStatus = HSE_STATUS_ERROR;
  659. }
  660. END_CATCH
  661. UNTRANSLATE_EXCEPTIONS;
  662. if ( HSE_STATUS_PENDING != hseStatus )
  663. {
  664. TheWebQueryCache.DecrementActiveRequests();
  665. ciGibDebugOut(( DEB_GIB_REQUEST,
  666. "Falling out of isapi proc, active: %d\n",
  667. TheWebQueryCache.ActiveRequestCount() ));
  668. Win4Assert( webServer.GetHttpStatus() >= HTTP_STATUS_FIRST &&
  669. webServer.GetHttpStatus() <= HTTP_STATUS_LAST );
  670. if ( ( webServer.GetHttpStatus() < HTTP_STATUS_FIRST ) ||
  671. ( webServer.GetHttpStatus() > HTTP_STATUS_LAST ) )
  672. {
  673. ciGibDebugOut(( DEB_WARN,
  674. "non-pending hse %d ECB %08x status invalid: %d\n",
  675. hseStatus,
  676. pEcb,
  677. webServer.GetHttpStatus() ));
  678. webServer.SetHttpStatus( HTTP_STATUS_SERVER_ERROR );
  679. }
  680. }
  681. else
  682. {
  683. //
  684. // The pending request may have asynchronously completed by now,
  685. // so nothing can be asserted about the http status except that it
  686. // is a valid http status code, which retrieving the status does.
  687. //
  688. #if CIDBG == 1
  689. webServer.GetHttpStatus();
  690. #endif
  691. }
  692. ciGibDebugOut(( DEB_ITRACE, "httpExtensionProc: hse %d, http %d\n",
  693. hseStatus, webServer.GetHttpStatus() ));
  694. return hseStatus;
  695. } //HttpExtensionProc
  696. //+---------------------------------------------------------------------------
  697. //
  698. // Method: CWebPendingQueue::CWebPendingQueue, public
  699. //
  700. // Synposis: Constructs the pending request queue
  701. //
  702. // History: 96-Apr-15 dlee created
  703. //
  704. //----------------------------------------------------------------------------
  705. CWebPendingQueue::CWebPendingQueue()
  706. : TFifoCircularQueue<CWebPendingItem>
  707. ( TheIDQRegParams.GetISRequestQueueSize() ),
  708. _ulSignature( LONGSIG( 'p', 'e', 'n', 'd' ) )
  709. {
  710. } //CWebPendingQueue
  711. //+---------------------------------------------------------------------------
  712. //
  713. // Method: CWebResourceArbiter::CWebResourceArbiter, public
  714. //
  715. // Synposis: Constructs the web resource arbiter
  716. //
  717. // History: 96-Apr-15 dlee created
  718. //
  719. //----------------------------------------------------------------------------
  720. CWebResourceArbiter::CWebResourceArbiter() :
  721. _ulSignature( LONGSIG( 'a', 'r', 'b', 'i' ) ),
  722. _cThreads( 0 )
  723. {
  724. ULONG factor = TheIDQRegParams.GetISRequestThresholdFactor();
  725. Win4Assert( 0 != factor );
  726. SYSTEM_INFO si;
  727. GetSystemInfo( &si );
  728. _maxThreads = si.dwNumberOfProcessors * factor;
  729. Win4Assert( _maxThreads >= (LONG) factor );
  730. _maxPendingQueries = TheIDQRegParams.GetMaxActiveQueryThreads() *
  731. factor;
  732. } //CWebResourceArbiter
  733. //+---------------------------------------------------------------------------
  734. //
  735. // Method: CWebResourceArbiter::IsSystemBusy, public
  736. //
  737. // Synposis: Determines if the system is too busy to process a request.
  738. //
  739. // Returns: TRUE if the request should be queued or rejected, FALSE
  740. // if the system is free enough to handle it.
  741. //
  742. // History: 96-Apr-15 dlee created
  743. //
  744. //----------------------------------------------------------------------------
  745. BOOL CWebResourceArbiter::IsSystemBusy()
  746. {
  747. return ( _cThreads > _maxThreads ) ||
  748. ( TheWebQueryCache.PendingQueryCount() >= _maxPendingQueries );
  749. } //IsSystemBusy
  750. //+---------------------------------------------------------------------------
  751. //
  752. // Function: DllMain
  753. //
  754. // Synopsis: Called from C-Runtime on process/thread attach/detach
  755. //
  756. // Arguments: [hInstance] -- Module handle
  757. // [dwReason] -- Reason for being called
  758. // [lpReserved] --
  759. //
  760. // History: 23-Apr-97 dlee Created
  761. //
  762. //----------------------------------------------------------------------------
  763. #if CIDBG == 1
  764. #define VER_CIDEBUG "chk"
  765. #else // CIDBG == 1
  766. #define VER_CIDEBUG "fre"
  767. #endif // CIDBG == 1
  768. #if IDQ_VERSION == 3
  769. #define VER_PROJECT "query"
  770. #else // IDQ_VERSION != 3
  771. #define VER_PROJECT "indexsrv"
  772. #endif // IDQ_VERSION == 3
  773. #define MAKELITERALSTRING( s, lit ) s #lit
  774. #define MAKELITERAL( s, lit ) MAKELITERALSTRING( s, lit )
  775. #define VERSION_STRING MAKELITERAL("Indexing Service ", IDQ_VERSION) \
  776. "(" VER_PROJECT ") " VER_CIDEBUG \
  777. MAKELITERAL(" built by ", BUILD_USERNAME) \
  778. MAKELITERAL(" with ", VER_PRODUCTBUILD) \
  779. " on " __DATE__ " at " __TIME__
  780. char g_ciBuild[ ] = VERSION_STRING;
  781. BOOL WINAPI DllMain(
  782. HANDLE hInstance,
  783. DWORD dwReason,
  784. void * lpReserved )
  785. {
  786. BOOL fRetval = TRUE;
  787. TRANSLATE_EXCEPTIONS;
  788. TRY
  789. {
  790. switch ( dwReason )
  791. {
  792. case DLL_PROCESS_ATTACH:
  793. {
  794. DisableThreadLibraryCalls( (HINSTANCE) hInstance );
  795. InitializeCriticalSection( &g_csInitExclusive );
  796. break;
  797. }
  798. case DLL_PROCESS_DETACH:
  799. {
  800. DeleteCriticalSection( &g_csInitExclusive );
  801. break;
  802. }
  803. }
  804. }
  805. CATCH( CException, e )
  806. {
  807. // About the only thing this could be is STATUS_NO_MEMORY which
  808. // can be thrown by InitializeCriticalSection.
  809. ciGibDebugOut(( DEB_ERROR,
  810. "IDQ: Exception %#x in DllMain\n",
  811. e.GetErrorCode()));
  812. #if CIDBG == 1 // for debugging NTRAID 340297
  813. if (e.GetErrorCode() == STATUS_NO_MEMORY)
  814. DbgPrint( "IDQ: STATUS_NO_MEMORY exception in DllMain\n");
  815. else
  816. DbgPrint( "IDQ: ??? Exception in DllMain\n");
  817. #endif // CIDBG == 1
  818. fRetval = FALSE;
  819. }
  820. END_CATCH
  821. UNTRANSLATE_EXCEPTIONS;
  822. return fRetval;
  823. } //DllMain