Leaked source code of windows server 2003
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.

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