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.

3527 lines
81 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ssinc.cxx
  5. Abstract:
  6. This module contains the server side include processing code. We
  7. aim for support as specified by iis\spec\ssi.doc. The code is based
  8. on existing SSI support done in iis\svcs\w3\server\ssinc.cxx.
  9. Author:
  10. Ming Lu (MingLu) 10-Apr-2000
  11. --*/
  12. #include "precomp.hxx"
  13. //
  14. // Globals
  15. //
  16. UINT g_MonthToDayCount[] = {
  17. 0,
  18. 31,
  19. 31 + 28,
  20. 31 + 28 + 31,
  21. 31 + 28 + 31 + 30,
  22. 31 + 28 + 31 + 30 + 31,
  23. 31 + 28 + 31 + 30 + 31 + 30,
  24. 31 + 28 + 31 + 30 + 31 + 30 + 31,
  25. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31,
  26. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
  27. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
  28. 31 + 28 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30,
  29. } ;
  30. //
  31. // Prototypes
  32. //
  33. extern "C" {
  34. BOOL
  35. WINAPI
  36. DLLEntry(
  37. HINSTANCE hDll,
  38. DWORD dwReason,
  39. LPVOID lpvReserved
  40. );
  41. }
  42. class SSI_ELEMENT_LIST;
  43. VOID
  44. InitializeSSIGlobals( VOID );
  45. //
  46. // Global Data
  47. //
  48. DECLARE_DEBUG_PRINTS_OBJECT()
  49. DECLARE_DEBUG_VARIABLE();
  50. //
  51. // This is the list of supported commands
  52. //
  53. struct _SSI_CMD_MAP
  54. {
  55. CHAR * pszCommand;
  56. DWORD cchCommand;
  57. SSI_COMMANDS ssiCmd;
  58. }
  59. SSICmdMap[] =
  60. {
  61. "#include ", 9, SSI_CMD_INCLUDE,
  62. "#echo ", 6, SSI_CMD_ECHO,
  63. "#fsize ", 7, SSI_CMD_FSIZE,
  64. "#flastmod ",10, SSI_CMD_FLASTMOD,
  65. "#config ", 8, SSI_CMD_CONFIG,
  66. "#exec ", 6, SSI_CMD_EXEC,
  67. NULL, 0, SSI_CMD_UNKNOWN
  68. };
  69. //
  70. // This is the list of supported tags
  71. //
  72. struct _SSI_TAG_MAP
  73. {
  74. CHAR * pszTag;
  75. DWORD cchTag;
  76. SSI_TAGS ssiTag;
  77. }
  78. SSITagMap[] =
  79. {
  80. "var", 3, SSI_TAG_VAR,
  81. "file", 4, SSI_TAG_FILE,
  82. "virtual", 7, SSI_TAG_VIRTUAL,
  83. "errmsg", 6, SSI_TAG_ERRMSG,
  84. "timefmt", 7, SSI_TAG_TIMEFMT,
  85. "sizefmt", 7, SSI_TAG_SIZEFMT,
  86. "cmd", 3, SSI_TAG_CMD,
  87. "cgi", 3, SSI_TAG_CGI,
  88. "isa", 3, SSI_TAG_ISA,
  89. NULL, 0, SSI_TAG_UNKNOWN
  90. };
  91. //
  92. // This is a list of #ECHO variables not supported by ISAPI
  93. //
  94. struct _SSI_VAR_MAP
  95. {
  96. CHAR * pszMap;
  97. DWORD cchMap;
  98. SSI_VARS ssiMap;
  99. }
  100. SSIVarMap[] =
  101. {
  102. "DOCUMENT_NAME", 13, SSI_VAR_DOCUMENT_NAME,
  103. "DOCUMENT_URI", 12, SSI_VAR_DOCUMENT_URI,
  104. "QUERY_STRING_UNESCAPED", 22, SSI_VAR_QUERY_STRING_UNESCAPED,
  105. "DATE_LOCAL", 10, SSI_VAR_DATE_LOCAL,
  106. "DATE_GMT", 8, SSI_VAR_DATE_GMT,
  107. "LAST_MODIFIED", 13, SSI_VAR_LAST_MODIFIED,
  108. NULL, 0, SSI_VAR_UNKNOWN
  109. };
  110. //
  111. // #EXEC CMD is BAD. Disable it by default
  112. //
  113. BOOL fEnableCmdDirective = FALSE;
  114. //
  115. // Pointer to file cache
  116. //
  117. W3_FILE_INFO_CACHE * g_pFileCache = NULL;
  118. //
  119. // Class Definitions
  120. //
  121. // class SSI_FILE
  122. //
  123. // File structure. All high level functions should use this
  124. // structure instead of dealing with handle specifics themselves.
  125. class SSI_FILE
  126. {
  127. private:
  128. STRU _strFilename;
  129. W3_FILE_INFO * _hHandle;
  130. HANDLE _hMapHandle;
  131. PVOID _pvMappedBase;
  132. BOOL _fValid;
  133. BOOL _fCloseOnDestroy;
  134. //
  135. // Track the current number of open handles for this file.
  136. //
  137. DWORD _cRefCount;
  138. CRITICAL_SECTION _csRef;
  139. public:
  140. SSI_FILE(
  141. IN STRU * pstrFilename,
  142. IN W3_FILE_INFO * pOpenFile
  143. ) : _hHandle ( pOpenFile ),
  144. _hMapHandle ( NULL ),
  145. _pvMappedBase ( NULL ),
  146. _fValid ( FALSE ),
  147. _cRefCount ( 0),
  148. _fCloseOnDestroy( FALSE )
  149. {
  150. InitializeCriticalSection( &_csRef );
  151. if ( FAILED( _strFilename.Copy( pstrFilename->QueryStr() ) ) )
  152. {
  153. return;
  154. }
  155. _fValid = TRUE;
  156. }
  157. SSI_FILE(
  158. IN STRU * pstrFilename,
  159. IN HANDLE hUser
  160. ) : _hHandle ( NULL ),
  161. _hMapHandle ( NULL ),
  162. _pvMappedBase ( NULL ),
  163. _fValid ( FALSE ),
  164. _cRefCount ( 0),
  165. _fCloseOnDestroy( TRUE )
  166. {
  167. FILE_CACHE_USER fileUser;
  168. HRESULT hr;
  169. InitializeCriticalSection( &_csRef );
  170. if ( FAILED( _strFilename.Copy( pstrFilename->QueryStr() ) ) )
  171. {
  172. return;
  173. }
  174. fileUser._hToken = hUser;
  175. hr = g_pFileCache->GetFileInfo( _strFilename,
  176. NULL,
  177. &fileUser,
  178. TRUE,
  179. &_hHandle );
  180. if ( FAILED( hr ) )
  181. {
  182. return;
  183. }
  184. _fValid = TRUE;
  185. }
  186. ~SSI_FILE()
  187. {
  188. if ( _fCloseOnDestroy )
  189. {
  190. if ( _hHandle )
  191. {
  192. _hHandle->DereferenceCacheEntry();
  193. }
  194. }
  195. DeleteCriticalSection( &_csRef );
  196. }
  197. VOID
  198. Lock(
  199. VOID
  200. )
  201. {
  202. EnterCriticalSection( &_csRef );
  203. }
  204. VOID
  205. UnLock(
  206. VOID
  207. )
  208. {
  209. LeaveCriticalSection( &_csRef );
  210. }
  211. BOOL
  212. IsValid(
  213. VOID
  214. ) const
  215. {
  216. return _fValid;
  217. }
  218. PSECURITY_DESCRIPTOR
  219. GetSecDesc(
  220. VOID
  221. ) const
  222. {
  223. return _hHandle->QuerySecDesc();
  224. }
  225. BOOL
  226. SSICreateFileMapping(
  227. VOID
  228. )
  229. /*++
  230. Creates a mapping to a file
  231. --*/
  232. {
  233. HANDLE hHandle;
  234. if ( _hHandle->QueryFileBuffer() )
  235. {
  236. return TRUE;
  237. }
  238. hHandle = _hHandle->QueryFileHandle();
  239. if ( _hMapHandle != NULL )
  240. {
  241. if ( !SSICloseMapHandle() )
  242. {
  243. return FALSE;
  244. }
  245. }
  246. _hMapHandle = ::CreateFileMapping( hHandle,
  247. NULL,
  248. PAGE_READONLY,
  249. 0,
  250. 0,
  251. NULL );
  252. if ( _hMapHandle == NULL )
  253. {
  254. DBGPRINTF(( DBG_CONTEXT,
  255. "CreateFileMapping failed with %d\n",
  256. GetLastError() ));
  257. }
  258. return _hMapHandle != NULL;
  259. }
  260. BOOL
  261. SSICloseMapHandle(
  262. VOID
  263. )
  264. /*++
  265. Closes mapping to a file
  266. --*/
  267. {
  268. if ( _hMapHandle != NULL )
  269. {
  270. ::CloseHandle( _hMapHandle );
  271. _hMapHandle = NULL;
  272. }
  273. return TRUE;
  274. }
  275. BOOL
  276. SSIMapViewOfFile(
  277. VOID
  278. )
  279. /*++
  280. Maps file to address
  281. --*/
  282. {
  283. if ( _hHandle->QueryFileBuffer() )
  284. {
  285. _pvMappedBase = _hHandle->QueryFileBuffer();
  286. return TRUE;
  287. }
  288. if ( _pvMappedBase != NULL )
  289. {
  290. if ( !SSIUnmapViewOfFile() )
  291. {
  292. return FALSE;
  293. }
  294. }
  295. _pvMappedBase = ::MapViewOfFile( _hMapHandle,
  296. FILE_MAP_READ,
  297. 0,
  298. 0,
  299. 0 );
  300. if ( _pvMappedBase == NULL )
  301. {
  302. DBGPRINTF(( DBG_CONTEXT,
  303. "MapViewOfFile() failed with %d\n",
  304. GetLastError() ));
  305. }
  306. return _pvMappedBase != NULL;
  307. }
  308. BOOL
  309. SSIUnmapViewOfFile(
  310. VOID
  311. )
  312. /*++
  313. Unmaps file
  314. --*/
  315. {
  316. if ( !_hHandle->QueryFileBuffer() && _pvMappedBase != NULL )
  317. {
  318. ::UnmapViewOfFile( _pvMappedBase );
  319. _pvMappedBase = NULL;
  320. }
  321. return TRUE;
  322. }
  323. DWORD
  324. SSIGetFileAttributes(
  325. VOID
  326. )
  327. /*++
  328. Gets the attributes of a file
  329. --*/
  330. {
  331. return _hHandle->QueryAttributes();
  332. }
  333. BOOL
  334. SSIGetFileSize(
  335. OUT DWORD * pdwLowWord,
  336. OUT DWORD * pdwHighWord
  337. )
  338. /*++
  339. Gets the size of the file.
  340. --*/
  341. {
  342. LARGE_INTEGER liSize;
  343. _hHandle->QuerySize( &liSize );
  344. *pdwLowWord = liSize.LowPart;
  345. *pdwHighWord = liSize.HighPart;
  346. return TRUE;
  347. }
  348. BOOL
  349. SSIGetLastModTime(
  350. OUT FILETIME * ftTime
  351. )
  352. /*++
  353. Gets the Last modification time of a file.
  354. --*/
  355. {
  356. _hHandle->QueryLastWriteTime( ftTime );
  357. return TRUE;
  358. }
  359. PVOID
  360. GetMappedBase(
  361. VOID
  362. )
  363. {
  364. return _pvMappedBase;
  365. }
  366. STRU &
  367. GetFilename(
  368. VOID
  369. )
  370. {
  371. return _strFilename;
  372. }
  373. };
  374. // Class SSI_ELEMENT_ITEM
  375. //
  376. // Represents a SSI command or block of static text in the document
  377. class SSI_ELEMENT_ITEM
  378. {
  379. private:
  380. DWORD _Signature;
  381. SSI_COMMANDS _ssiCmd;
  382. SSI_TAGS _ssiTag;
  383. STRA * _pstrTagValue;
  384. DWORD _cbBegin; // Only used for Byte range command
  385. DWORD _cbLength; // Only used for Byte range command
  386. public:
  387. LIST_ENTRY _ListEntry;
  388. SSI_ELEMENT_ITEM( VOID )
  389. : _ssiCmd ( SSI_CMD_UNKNOWN ),
  390. _ssiTag ( SSI_TAG_UNKNOWN ),
  391. _Signature( SIGNATURE_SEI ),
  392. _pstrTagValue( NULL )
  393. {
  394. _ListEntry.Flink = NULL;
  395. }
  396. ~SSI_ELEMENT_ITEM()
  397. {
  398. if ( _pstrTagValue != NULL )
  399. {
  400. delete _pstrTagValue;
  401. }
  402. DBG_ASSERT( _ListEntry.Flink == NULL );
  403. _Signature = SIGNATURE_SEI_FREE;
  404. }
  405. VOID
  406. SetByteRange(
  407. IN DWORD cbBegin,
  408. IN DWORD cbLength
  409. )
  410. {
  411. _ssiCmd = SSI_CMD_BYTERANGE;
  412. _cbBegin = cbBegin;
  413. _cbLength = cbLength;
  414. }
  415. BOOL
  416. SetCommand(
  417. IN SSI_COMMANDS ssiCmd,
  418. IN SSI_TAGS ssiTag,
  419. IN CHAR * achTag
  420. )
  421. {
  422. _ssiCmd = ssiCmd;
  423. _ssiTag = ssiTag;
  424. _pstrTagValue = new STRA();
  425. if( _pstrTagValue == NULL )
  426. {
  427. return FALSE;
  428. }
  429. if( FAILED( _pstrTagValue->Copy( achTag ) ) )
  430. {
  431. return FALSE;
  432. }
  433. return TRUE;
  434. }
  435. SSI_COMMANDS
  436. QueryCommand(
  437. VOID
  438. ) const
  439. {
  440. return _ssiCmd;
  441. }
  442. SSI_TAGS
  443. QueryTag(
  444. VOID
  445. ) const
  446. {
  447. return _ssiTag;
  448. }
  449. STRA *
  450. QueryTagValue(
  451. VOID
  452. ) const
  453. {
  454. return _pstrTagValue;
  455. }
  456. BOOL
  457. CheckSignature(
  458. VOID
  459. ) const
  460. {
  461. return _Signature == SIGNATURE_SEI;
  462. }
  463. DWORD
  464. QueryBegin(
  465. VOID
  466. ) const
  467. {
  468. return _cbBegin;
  469. }
  470. DWORD
  471. QueryLength(
  472. VOID
  473. ) const
  474. {
  475. return _cbLength;
  476. }
  477. };
  478. // Class SSI_ELEMENT_LIST
  479. //
  480. // This object sits as a cache blob under a file to be processed as a
  481. // server side include. It represents an interpreted list of data
  482. // elements that make up the file itself.
  483. //
  484. class SSI_ELEMENT_LIST : public ASSOCIATED_FILE_OBJECT
  485. {
  486. private:
  487. DWORD _Signature;
  488. LIST_ENTRY _ListHead;
  489. //
  490. // These are for tracking the memory mapped file
  491. //
  492. DWORD _cRefCount;
  493. CRITICAL_SECTION _csRef;
  494. //
  495. // Provides the utilities needed to open/manipulate files
  496. //
  497. SSI_FILE * _pssiFile;
  498. //
  499. // Name of URL. Used to resolve FILE="xxx" filenames
  500. //
  501. STRU _strURL;
  502. public:
  503. SSI_ELEMENT_LIST()
  504. : _Signature ( SIGNATURE_SEL ),
  505. _pssiFile( NULL ),
  506. _cRefCount( 0 )
  507. {
  508. InitializeListHead( &_ListHead );
  509. INITIALIZE_CRITICAL_SECTION( &_csRef );
  510. }
  511. ~SSI_ELEMENT_LIST()
  512. {
  513. SSI_ELEMENT_ITEM * pSEI;
  514. while ( !IsListEmpty( &_ListHead ))
  515. {
  516. pSEI = CONTAINING_RECORD( _ListHead.Flink,
  517. SSI_ELEMENT_ITEM,
  518. _ListEntry );
  519. RemoveEntryList( &pSEI->_ListEntry );
  520. pSEI->_ListEntry.Flink = NULL;
  521. delete pSEI;
  522. }
  523. UnMap();
  524. if( _pssiFile != NULL )
  525. {
  526. delete _pssiFile;
  527. }
  528. DeleteCriticalSection( &_csRef );
  529. _Signature = SIGNATURE_SEL_FREE;
  530. }
  531. VOID
  532. Cleanup(
  533. VOID
  534. )
  535. {
  536. delete this;
  537. }
  538. LIST_ENTRY *
  539. QueryListHead(
  540. VOID
  541. )
  542. {
  543. return &_ListHead;
  544. };
  545. BOOL
  546. AppendByteRange(
  547. IN DWORD cbStart,
  548. IN DWORD cbLength
  549. )
  550. {
  551. SSI_ELEMENT_ITEM * pSEI;
  552. pSEI = new SSI_ELEMENT_ITEM;
  553. if ( !pSEI )
  554. {
  555. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  556. return FALSE;
  557. }
  558. pSEI->SetByteRange( cbStart,
  559. cbLength );
  560. AppendItem( pSEI );
  561. return TRUE;
  562. }
  563. BOOL
  564. AppendCommand(
  565. IN SSI_COMMANDS ssiCmd,
  566. IN SSI_TAGS ssiTag,
  567. IN CHAR * pszTag
  568. )
  569. {
  570. SSI_ELEMENT_ITEM * pSEI;
  571. pSEI = new SSI_ELEMENT_ITEM;
  572. if ( !pSEI )
  573. {
  574. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  575. return FALSE;
  576. }
  577. if ( !pSEI->SetCommand( ssiCmd,
  578. ssiTag,
  579. pszTag ))
  580. {
  581. return FALSE;
  582. }
  583. AppendItem( pSEI );
  584. return TRUE;
  585. }
  586. VOID
  587. AppendItem(
  588. IN SSI_ELEMENT_ITEM * pSEI
  589. )
  590. {
  591. InsertTailList( &_ListHead,
  592. &pSEI->_ListEntry );
  593. }
  594. CHAR * QueryData(
  595. VOID
  596. ) const
  597. {
  598. return ( CHAR * ) _pssiFile->GetMappedBase();
  599. }
  600. PSECURITY_DESCRIPTOR
  601. QuerySecDesc(
  602. VOID
  603. )
  604. {
  605. return _pssiFile->GetSecDesc();
  606. }
  607. BOOL
  608. CheckSignature(
  609. VOID
  610. ) const
  611. {
  612. return _Signature == SIGNATURE_SEL;
  613. }
  614. VOID
  615. Lock(
  616. VOID
  617. )
  618. {
  619. EnterCriticalSection( &_csRef );
  620. }
  621. VOID
  622. UnLock(
  623. VOID
  624. )
  625. {
  626. LeaveCriticalSection( &_csRef );
  627. }
  628. BOOL
  629. UnMap(
  630. VOID
  631. )
  632. {
  633. Lock();
  634. if ( _cRefCount && !--_cRefCount )
  635. {
  636. DBG_REQUIRE( _pssiFile->SSIUnmapViewOfFile() );
  637. DBG_REQUIRE( _pssiFile->SSICloseMapHandle() );
  638. }
  639. UnLock();
  640. return TRUE;
  641. }
  642. BOOL
  643. Map(
  644. VOID
  645. )
  646. {
  647. Lock();
  648. if ( _cRefCount++ == 0 )
  649. {
  650. if ( !_pssiFile->SSICreateFileMapping() )
  651. {
  652. UnLock();
  653. return FALSE;
  654. }
  655. if ( !_pssiFile->SSIMapViewOfFile() )
  656. {
  657. UnMap();
  658. UnLock();
  659. return FALSE;
  660. }
  661. }
  662. UnLock();
  663. return TRUE;
  664. }
  665. VOID
  666. SetFile(
  667. IN SSI_FILE * pssiFile
  668. )
  669. {
  670. _pssiFile = pssiFile;
  671. }
  672. SSI_FILE *
  673. GetFile(
  674. VOID
  675. )
  676. {
  677. return _pssiFile;
  678. }
  679. HRESULT
  680. SetURL(
  681. IN STRU * pstrURL
  682. )
  683. {
  684. return _strURL.Copy( pstrURL->QueryStr() );
  685. }
  686. static
  687. BOOL
  688. SSIFreeContextRoutine(
  689. VOID * pvContext
  690. )
  691. {
  692. DBG_ASSERT( ( ( SSI_ELEMENT_LIST * ) pvContext) -> CheckSignature() );
  693. delete ( SSI_ELEMENT_LIST * ) pvContext;
  694. return TRUE;
  695. }
  696. };
  697. //
  698. // SSI_REQUEST methods implementation
  699. //
  700. //static
  701. ALLOC_CACHE_HANDLER * SSI_REQUEST::sm_pachSSIRequests = NULL;
  702. SSI_REQUEST::SSI_REQUEST( EXTENSION_CONTROL_BLOCK * pECB )
  703. : _pECB( pECB ),
  704. _fBaseFile( TRUE ),
  705. _fValid( FALSE ),
  706. _pchErrorBuff ( NULL )
  707. /*++
  708. Routine Description:
  709. Constructor
  710. --*/
  711. {
  712. DBG_ASSERT( _pECB != NULL );
  713. STACK_BUFFER (buffTemp, 512);
  714. DWORD cbSize = buffTemp.QuerySize();
  715. if (!_pECB->GetServerVariable(_pECB->ConnID,
  716. "UNICODE_URL",
  717. buffTemp.QueryPtr(),
  718. &cbSize))
  719. {
  720. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
  721. !buffTemp.Resize(cbSize))
  722. {
  723. return;
  724. }
  725. //
  726. // Now, we should have enough buffer, try again
  727. //
  728. if (!_pECB->GetServerVariable(_pECB->ConnID,
  729. "UNICODE_URL",
  730. buffTemp.QueryPtr(),
  731. &cbSize))
  732. {
  733. return;
  734. }
  735. }
  736. if (FAILED(_strURL.Copy( (LPWSTR)buffTemp.QueryPtr() )))
  737. {
  738. return;
  739. }
  740. cbSize = buffTemp.QuerySize();
  741. if (!_pECB->GetServerVariable(_pECB->ConnID,
  742. "UNICODE_SCRIPT_TRANSLATED",
  743. buffTemp.QueryPtr(),
  744. &cbSize))
  745. {
  746. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
  747. !buffTemp.Resize(cbSize))
  748. {
  749. return;
  750. }
  751. //
  752. // Now, we should have enough buffer, try again
  753. //
  754. if (!_pECB->GetServerVariable(_pECB->ConnID,
  755. "UNICODE_SCRIPT_TRANSLATED",
  756. buffTemp.QueryPtr(),
  757. &cbSize))
  758. {
  759. return;
  760. }
  761. }
  762. if (FAILED(_strFilename.Copy( (LPWSTR)buffTemp.QueryPtr() )))
  763. {
  764. return;
  765. }
  766. if ( !_pECB->ServerSupportFunction(
  767. _pECB->ConnID,
  768. HSE_REQ_GET_IMPERSONATION_TOKEN,
  769. &_hUser,
  770. NULL,
  771. NULL ) )
  772. {
  773. return;
  774. }
  775. _pSIF = new SSI_INCLUDE_FILE ( this, _strFilename, _strURL, NULL );
  776. if ( _pSIF == NULL || !_pSIF->IsValid() )
  777. {
  778. return;
  779. }
  780. if( !_IOBuffer.Resize(MAX_PATH) )
  781. {
  782. return;
  783. }
  784. if( FAILED( _IOString.Resize(MAX_PATH) ) )
  785. {
  786. return;
  787. }
  788. _fValid = TRUE;
  789. }
  790. SSI_REQUEST::~SSI_REQUEST()
  791. /*++
  792. Routine Description:
  793. Destructor
  794. --*/
  795. {
  796. if ( _pSIF != NULL )
  797. {
  798. //
  799. // There should be no nested stm files
  800. // State Machine was supposed to complete and cleanup child SSI_INCLUDE_FILES
  801. // (also in the case of error)
  802. //
  803. DBG_ASSERT( _pSIF->GetParent() == NULL );
  804. delete _pSIF;
  805. }
  806. if ( _pchErrorBuff != NULL )
  807. {
  808. ::LocalFree( ( VOID * )_pchErrorBuff );
  809. }
  810. }
  811. HRESULT
  812. SSI_REQUEST::SSISendError(
  813. IN DWORD dwMessageID,
  814. IN LPSTR apszParms[]
  815. )
  816. /*++
  817. Routine Description:
  818. Send an SSI error
  819. Arguments:
  820. dwMessageId - Message ID
  821. apszParms - Array of parameters
  822. Return Value:
  823. HRESULT (if couldn't find a custom error, this will fail)
  824. --*/
  825. {
  826. DWORD cbSent;
  827. if ( *( ( CHAR * )_strUserMessage.QueryStr() ) != '\0' )
  828. {
  829. //
  830. // user specified message with #CONFIG ERRMSG=
  831. //
  832. return WriteToClient( _strUserMessage.QueryStr(),
  833. _strUserMessage.QueryCCH(),
  834. &cbSent );
  835. }
  836. else
  837. {
  838. DWORD cch;
  839. HRESULT hr = E_FAIL;
  840. CHAR chTemp1 = '\0';
  841. CHAR chTemp2 = '\0';
  842. if( _pchErrorBuff )
  843. {
  844. ::LocalFree( ( VOID * )_pchErrorBuff );
  845. _pchErrorBuff = NULL;
  846. }
  847. //
  848. // Lame. I need to validate the parameters for being <1024
  849. // otherwise FormatMessage uses SEH to determine when to resize and
  850. // this will cause debuggers to break on the 1st change exception
  851. //
  852. if ( apszParms[ 0 ] != NULL &&
  853. strlen( apszParms[ 0 ] ) > SSI_MAX_FORMAT_LEN )
  854. {
  855. chTemp1 = apszParms[ 0 ][ SSI_MAX_FORMAT_LEN ];
  856. apszParms[ 0 ][ SSI_MAX_FORMAT_LEN ] = '\0';
  857. }
  858. if ( apszParms[ 1 ] != NULL &&
  859. strlen( apszParms[ 1 ] ) > SSI_MAX_FORMAT_LEN )
  860. {
  861. chTemp2 = apszParms[ 1 ][ SSI_MAX_FORMAT_LEN ];
  862. apszParms[ 1 ][ SSI_MAX_FORMAT_LEN ] = '\0';
  863. }
  864. cch = ::FormatMessageA( FORMAT_MESSAGE_ARGUMENT_ARRAY |
  865. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  866. FORMAT_MESSAGE_FROM_HMODULE,
  867. GetModuleHandle( SSI_DLL_NAME ),
  868. dwMessageID,
  869. 0,
  870. ( LPSTR ) &_pchErrorBuff,
  871. 0,
  872. ( va_list *) apszParms );
  873. if ( chTemp1 != '\0' )
  874. {
  875. apszParms[ 0 ][ SSI_MAX_FORMAT_LEN ] = chTemp1;
  876. }
  877. if ( chTemp2 != '\0' )
  878. {
  879. apszParms[ 1 ][ SSI_MAX_FORMAT_LEN ] = chTemp2;
  880. }
  881. if( cch != 0 )
  882. {
  883. //
  884. // WriteToClient will execute asynchronously so do not
  885. // free _pchErrorBuffer before I/O completion
  886. //
  887. hr = WriteToClient( _pchErrorBuff,
  888. cch,
  889. &cbSent );
  890. return hr;
  891. }
  892. else
  893. {
  894. return HRESULT_FROM_WIN32(GetLastError());
  895. }
  896. }
  897. }
  898. HRESULT
  899. SSI_REQUEST::SendCustomError(
  900. HSE_CUSTOM_ERROR_INFO * pCustomErrorInfo
  901. )
  902. /*++
  903. Routine Description:
  904. Try to have IIS send custom error on our behalf
  905. Arguments:
  906. pCustomErrorInfo - Describes custom error
  907. Return Value:
  908. HRESULT (if couldn't find a custom error, this will fail)
  909. --*/
  910. {
  911. BOOL fRet;
  912. fRet = _pECB->ServerSupportFunction( _pECB->ConnID,
  913. HSE_REQ_SEND_CUSTOM_ERROR,
  914. pCustomErrorInfo,
  915. NULL,
  916. NULL );
  917. if ( !fRet )
  918. {
  919. return HRESULT_FROM_WIN32( GetLastError() );
  920. }
  921. else
  922. {
  923. return NO_ERROR;
  924. }
  925. }
  926. HRESULT
  927. SSI_REQUEST::DoFLastMod(
  928. IN STRU * pstrFilename,
  929. IN STRA * pstrTimeFmt,
  930. IN SSI_ELEMENT_LIST * pList
  931. )
  932. /*++
  933. Routine Description:
  934. Send the LastModTime of file to HTML stream
  935. Arguments:
  936. pstrFilename - Filename
  937. pstrTimeFmt - Format of time -> follows strftime() convention
  938. Return Value:
  939. HRESULT
  940. --*/
  941. {
  942. FILETIME ftTime;
  943. FILETIME ftLocalTime;
  944. SYSTEMTIME sysLocal;
  945. if ( ( NULL == pList ) ||
  946. wcscmp( pstrFilename->QueryStr(),
  947. ( pList->GetFile()->GetFilename().QueryStr() ) ) )
  948. {
  949. SSI_FILE ssiFile( pstrFilename, GetUserToken() );
  950. if ( !ssiFile.IsValid() ||
  951. ( !ssiFile.SSIGetLastModTime( &ftTime ))
  952. )
  953. {
  954. return E_FAIL;
  955. }
  956. }
  957. else
  958. {
  959. pList->GetFile()->SSIGetLastModTime( &ftTime );
  960. }
  961. if ( ( !FileTimeToLocalFileTime( &ftTime, &ftLocalTime ) ) ||
  962. ( !FileTimeToSystemTime( &ftLocalTime, &sysLocal ) ) )
  963. {
  964. return E_FAIL;
  965. }
  966. return SendDate( &sysLocal,
  967. pstrTimeFmt );
  968. }
  969. HRESULT
  970. SSI_REQUEST::SendDate(
  971. IN SYSTEMTIME * psysTime,
  972. IN STRA * pstrTimeFmt
  973. )
  974. /*++
  975. Routine Description:
  976. Sends a SYSTEMTIME in appropriate format to HTML stream
  977. Arguments:
  978. psysTime - SYSTEMTIME containing time to send
  979. pstrTimeFmt - Format of time (follows strftime() convention)
  980. fCalcDays - TRUE if days since the beginning of the year should be
  981. calculated
  982. Return Value:
  983. HRESULT
  984. --*/
  985. {
  986. struct tm tm;
  987. // Convert SYSTEMTIME to 'struct tm'
  988. tm.tm_sec = psysTime->wSecond;
  989. tm.tm_min = psysTime->wMinute;
  990. tm.tm_hour = psysTime->wHour;
  991. tm.tm_mday = psysTime->wDay;
  992. tm.tm_mon = psysTime->wMonth - 1;
  993. tm.tm_year = psysTime->wYear - 1900;
  994. tm.tm_wday = psysTime->wDayOfWeek;
  995. tm.tm_yday = g_MonthToDayCount[ tm.tm_mon ] + tm.tm_mday - 1;
  996. //
  997. // Adjust for leap year - note that we do not handle 2100
  998. //
  999. if ( ( tm.tm_mon ) > 1 && !( psysTime->wYear & 3 ) )
  1000. {
  1001. ++tm.tm_yday;
  1002. }
  1003. tm.tm_isdst = -1; // Daylight savings time flag - have crt compute
  1004. _cbTimeBufferLen = strftime( _achTimeBuffer,
  1005. SSI_MAX_TIME_SIZE + 1,
  1006. ( CHAR * )pstrTimeFmt->QueryStr(),
  1007. &tm );
  1008. if ( _cbTimeBufferLen == 0 )
  1009. {
  1010. return E_FAIL;
  1011. }
  1012. return WriteToClient( _achTimeBuffer,
  1013. _cbTimeBufferLen,
  1014. &_cbTimeBufferLen );
  1015. }
  1016. HRESULT
  1017. SSI_REQUEST::LookupVirtualRoot( IN WCHAR * pszVirtual,
  1018. OUT STRU * pstrPhysical,
  1019. IN DWORD dwAccess )
  1020. /*++
  1021. Routine Description:
  1022. Lookup the given virtual path. Optionally ensure that its access
  1023. flags are valid for the require request.
  1024. Arguments:
  1025. pszVirtual = Virtual path to lookup
  1026. pstrPhysical = Contains the physical path
  1027. dwAccess = Access flags required for a valid request
  1028. Return Value:
  1029. HRESULT
  1030. --*/
  1031. {
  1032. HSE_URL_MAPEX_INFO URLMap;
  1033. DWORD dwMask;
  1034. STACK_STRA (strURL, 128);
  1035. HRESULT hr = E_FAIL;
  1036. //
  1037. // ServerSupportFunction doesn't accept unicode strings. Convert
  1038. //
  1039. if ( FAILED(hr = strURL.CopyW(pszVirtual)))
  1040. {
  1041. return hr;
  1042. }
  1043. if ( !_pECB->ServerSupportFunction( _pECB->ConnID,
  1044. HSE_REQ_MAP_URL_TO_PATH_EX,
  1045. strURL.QueryStr(),
  1046. NULL,
  1047. (PDWORD) &URLMap ) )
  1048. {
  1049. return HRESULT_FROM_WIN32(GetLastError());
  1050. }
  1051. dwMask = URLMap.dwFlags;
  1052. if ( dwAccess & HSE_URL_FLAGS_READ )
  1053. {
  1054. //
  1055. // BUGBUG-MING: Add IsSecurePort()
  1056. //
  1057. /*
  1058. if ( !( dwMask & HSE_URL_FLAGS_READ ) ||
  1059. ( ( dwMask & HSE_URL_FLAGS_SSL ) &&
  1060. !_pReq->IsSecurePort() ) )
  1061. */
  1062. if ( !( dwMask & HSE_URL_FLAGS_READ ) ||
  1063. ( dwMask & HSE_URL_FLAGS_SSL ) )
  1064. {
  1065. return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  1066. }
  1067. }
  1068. if( FAILED( pstrPhysical->CopyA( URLMap.lpszPath ) ) )
  1069. {
  1070. return HRESULT_FROM_WIN32(GetLastError());
  1071. }
  1072. return NO_ERROR;
  1073. }
  1074. HRESULT
  1075. SSI_REQUEST::DoEchoISAPIVariable(
  1076. IN STRA * pstrVariable
  1077. )
  1078. /*++
  1079. Routine Description:
  1080. Get ISAPI variable and if successful, send it to HTML stream
  1081. Arguments:
  1082. pstrVariable - Variable
  1083. Return Value:
  1084. HRESULT
  1085. --*/
  1086. {
  1087. HRESULT hr = E_FAIL;
  1088. if ( FAILED( hr = GetVariable( ( CHAR * )pstrVariable->QueryStr(),
  1089. &_IOBuffer ) ) )
  1090. {
  1091. return hr;
  1092. }
  1093. return WriteToClient( _IOBuffer.QueryPtr(),
  1094. strlen( ( CHAR * )_IOBuffer.QueryPtr() ),
  1095. &_cbIOLen );
  1096. }
  1097. HRESULT
  1098. SSI_REQUEST::DoEchoDateLocal(
  1099. IN STRA * pstrTimeFmt
  1100. )
  1101. /*++
  1102. Routine Description:
  1103. Sends local time (#ECHO VAR="DATE_LOCAL")
  1104. Arguments:
  1105. pstrTimefmt - Format of time (follows strftime() convention)
  1106. Return Value:
  1107. HRESULT
  1108. --*/
  1109. {
  1110. SYSTEMTIME sysTime;
  1111. ::GetLocalTime( &sysTime );
  1112. return SendDate( &sysTime,
  1113. pstrTimeFmt );
  1114. }
  1115. HRESULT
  1116. SSI_REQUEST::DoEchoDateGMT(
  1117. IN STRA * pstrTimeFmt
  1118. )
  1119. /*++
  1120. Routine Description:
  1121. Sends GMT time (#ECHO VAR="DATE_GMT")
  1122. Arguments:
  1123. pstrTimefmt - Format of time (follows strftime() convention)
  1124. Return Value:
  1125. HRESULT
  1126. --*/
  1127. {
  1128. SYSTEMTIME sysTime;
  1129. ::GetSystemTime( &sysTime );
  1130. return SendDate( &sysTime,
  1131. pstrTimeFmt );
  1132. }
  1133. HRESULT
  1134. SSI_REQUEST::DoEchoDocumentName(
  1135. IN STRU * pstrFilename
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. Sends filename of current SSI document (#ECHO VAR="DOCUMENT_NAME")
  1140. Arguments:
  1141. pstrFilename - filename to print
  1142. Return Value:
  1143. HRESULT
  1144. --*/
  1145. {
  1146. HRESULT hr = E_FAIL;
  1147. if ( FAILED( hr = (_IOString.CopyW(pstrFilename->QueryStr() ) ) ) )
  1148. {
  1149. return hr;
  1150. }
  1151. return WriteToClient( _IOString.QueryStr(),
  1152. _IOString.QueryCCH(),
  1153. &_cbIOLen);
  1154. }
  1155. HRESULT
  1156. SSI_REQUEST::DoEchoDocumentURI(
  1157. IN STRU * pstrURL
  1158. )
  1159. /*++
  1160. Routine Description:
  1161. Sends URL of current SSI document (#ECHO VAR="DOCUMENT_URI")
  1162. Arguments:
  1163. pstrURL - URL to print
  1164. Return Value:
  1165. HRESULT
  1166. --*/
  1167. {
  1168. HRESULT hr = E_FAIL;
  1169. if ( FAILED( hr = _IOString.CopyW(pstrURL->QueryStr() ) ) )
  1170. {
  1171. return hr;
  1172. }
  1173. return WriteToClient( _IOString.QueryStr(),
  1174. _IOString.QueryCCH(),
  1175. &_cbIOLen );
  1176. }
  1177. HRESULT
  1178. SSI_REQUEST::DoEchoQueryStringUnescaped(
  1179. VOID
  1180. )
  1181. /*++
  1182. Routine Description:
  1183. Sends unescaped querystring to HTML stream (#ECHO VAR="QUERY_STRING_UNESCAPED")
  1184. Arguments:
  1185. none
  1186. Return Value:
  1187. HRESULT
  1188. --*/
  1189. {
  1190. HRESULT hr = E_FAIL;
  1191. if ( FAILED( hr = _IOString.Copy( _pECB->lpszQueryString ) ) )
  1192. {
  1193. return hr;
  1194. }
  1195. if ( FAILED( hr = _IOString.Unescape()) )
  1196. {
  1197. return hr;
  1198. }
  1199. return WriteToClient( _IOString.QueryStr(),
  1200. _IOString.QueryCCH(),
  1201. &_cbIOLen );
  1202. }
  1203. HRESULT
  1204. SSI_REQUEST::DoEchoLastModified(
  1205. IN STRU * pstrFilename,
  1206. IN STRA * pstrTimeFmt,
  1207. IN SSI_ELEMENT_LIST * pList
  1208. )
  1209. /*++
  1210. Routine Description:
  1211. Sends LastModTime of current document (#ECHO VAR="LAST_MODIFIED")
  1212. Arguments:
  1213. pstrFilename - Filename of current SSI document
  1214. pstrTimeFmt - Time format (follows strftime() convention)
  1215. Return Value:
  1216. HRESULT
  1217. --*/
  1218. {
  1219. return DoFLastMod( pstrFilename,
  1220. pstrTimeFmt,
  1221. pList);
  1222. }
  1223. HRESULT
  1224. SSI_REQUEST::DoFSize(
  1225. IN STRU * pstrFilename,
  1226. IN BOOL bSizeFmtBytes,
  1227. IN SSI_ELEMENT_LIST * pList
  1228. )
  1229. /*++
  1230. Routine Description:
  1231. Sends file size of file to HTML stream
  1232. Arguments:
  1233. pstrfilename - Filename
  1234. bSizeFmtBytes - TRUE if count is in Bytes, FALSE if in KBytes
  1235. Return Value:
  1236. HRESULT
  1237. --*/
  1238. {
  1239. BOOL bRet;
  1240. DWORD cbSizeLow;
  1241. DWORD cbSizeHigh;
  1242. WCHAR achInputNumber[ SSI_MAX_NUMBER_STRING + 1 ];
  1243. WCHAR achOutputNumber[ SSI_MAX_NUMBER_STRING + 1 ];
  1244. NUMBERFMT nfNumberFormat;
  1245. int iOutputSize;
  1246. DWORD dwActualLen;
  1247. HRESULT hr = E_FAIL;
  1248. if ( ( NULL == pList ) ||
  1249. wcscmp( pstrFilename->QueryStr(),
  1250. ( pList->GetFile()->GetFilename().QueryStr() ) ) )
  1251. {
  1252. SSI_FILE ssiFile( pstrFilename, GetUserToken() );
  1253. if ( !ssiFile.IsValid() ||
  1254. ( !ssiFile.SSIGetFileSize( &cbSizeLow,
  1255. &cbSizeHigh ) )
  1256. )
  1257. {
  1258. return E_FAIL;
  1259. }
  1260. }
  1261. else
  1262. {
  1263. if (!pList->GetFile()->SSIGetFileSize( &cbSizeLow,
  1264. &cbSizeHigh ) )
  1265. {
  1266. return E_FAIL;
  1267. }
  1268. }
  1269. if ( cbSizeHigh )
  1270. {
  1271. //BUGBUG-jaro: do we ignore extra large files intentionaly?
  1272. return E_FAIL;
  1273. }
  1274. if ( !bSizeFmtBytes )
  1275. {
  1276. // express in terms of KB
  1277. cbSizeLow /= 1000;
  1278. }
  1279. nfNumberFormat.NumDigits = 0;
  1280. nfNumberFormat.LeadingZero = 0;
  1281. nfNumberFormat.Grouping = 3;
  1282. nfNumberFormat.lpThousandSep = L",";
  1283. nfNumberFormat.lpDecimalSep = L".";
  1284. nfNumberFormat.NegativeOrder = 2;
  1285. _snwprintf( achInputNumber,
  1286. SSI_MAX_NUMBER_STRING + 1,
  1287. L"%ld",
  1288. cbSizeLow );
  1289. iOutputSize = GetNumberFormat( LOCALE_SYSTEM_DEFAULT,
  1290. 0,
  1291. achInputNumber,
  1292. &nfNumberFormat,
  1293. achOutputNumber,
  1294. SSI_MAX_NUMBER_STRING + 1 );
  1295. if ( !iOutputSize )
  1296. {
  1297. return HRESULT_FROM_WIN32(GetLastError());
  1298. }
  1299. //
  1300. // Do not count trailing '\0'
  1301. //
  1302. iOutputSize--;
  1303. //
  1304. // Convert from Unicode before sending to client
  1305. //
  1306. if ( FAILED( hr = _IOString.CopyW(achOutputNumber) ) )
  1307. {
  1308. return hr;
  1309. }
  1310. return WriteToClient( _IOString.QueryStr(),
  1311. iOutputSize,
  1312. &_cbIOLen );
  1313. }
  1314. HRESULT
  1315. SSI_REQUEST::PrepareSSI(
  1316. VOID
  1317. )
  1318. /*++
  1319. Routine Description:
  1320. Prepare esential data structures
  1321. Arguments:
  1322. none
  1323. Return Value:
  1324. HRESULT
  1325. --*/
  1326. {
  1327. return _pSIF->Prepare();
  1328. }
  1329. HRESULT
  1330. SSI_REQUEST::DoWork(
  1331. DWORD dwError
  1332. )
  1333. /*++
  1334. Routine Description:
  1335. This is the top level routine for retrieving a server side include
  1336. file.
  1337. Arguments:
  1338. dwError - error of the last asynchronous operation (the one received by completion routine)
  1339. Return Value:
  1340. HRESULT
  1341. --*/
  1342. {
  1343. HRESULT hr = E_FAIL;
  1344. DBG_ASSERT ( _pSIF != NULL );
  1345. while( _pSIF != NULL )
  1346. {
  1347. //
  1348. // In the case that dwError != NO_ERROR
  1349. // _pSIF->DoWork() may be called multiple times to unwind state machine
  1350. // We will pass the same dwError in the case of multiple calls
  1351. // since that error is the primary reason why processing of this request
  1352. // must finish
  1353. //
  1354. hr = _pSIF->DoWork(dwError);
  1355. if ( hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING) )
  1356. {
  1357. //
  1358. // If there is pending IO return to caller
  1359. //
  1360. return hr;
  1361. }
  1362. else
  1363. {
  1364. //
  1365. // Either SSI_INCLUDE_FILE processing completed
  1366. // or there is nested include
  1367. //
  1368. // In the case of error this block is used to unwind state machine
  1369. //
  1370. if ( _pSIF->IsCompleted() )
  1371. {
  1372. //
  1373. // SSI_INCLUDE_FILE processing completed
  1374. // Cleanup and if there is parent SSI_INCLUDE_FILE continue with that one
  1375. //
  1376. SSI_INCLUDE_FILE * pParent = _pSIF->GetParent();
  1377. delete _pSIF;
  1378. _pSIF = pParent;
  1379. }
  1380. else
  1381. {
  1382. //
  1383. // Current SSI_INCLUDE_FILE _pSIF hasn't been completed yet. Continue
  1384. //
  1385. }
  1386. }
  1387. }
  1388. return hr;
  1389. }
  1390. //static
  1391. VOID WINAPI
  1392. SSI_REQUEST::HseIoCompletion(
  1393. IN EXTENSION_CONTROL_BLOCK * pECB,
  1394. IN PVOID pContext,
  1395. IN DWORD cbIO,
  1396. IN DWORD dwError
  1397. )
  1398. /*++
  1399. Routine Description:
  1400. This is the callback function for handling completions of asynchronous IO.
  1401. This function performs necessary cleanup and resubmits additional IO
  1402. (if required).
  1403. Arguments:
  1404. pecb pointer to ECB containing parameters related to the request.
  1405. pContext context information supplied with the asynchronous IO call.
  1406. cbIO count of bytes of IO in the last call.
  1407. dwError Error if any, for the last IO operation.
  1408. Return Value:
  1409. None.
  1410. --*/
  1411. {
  1412. SSI_REQUEST * pRequest = (SSI_REQUEST *) pContext;
  1413. HRESULT hr = E_FAIL;
  1414. //
  1415. // Continue processing SSI file
  1416. //
  1417. hr = pRequest->DoWork(dwError);
  1418. if ( hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING) )
  1419. {
  1420. //
  1421. // pending IO operation
  1422. //
  1423. return;
  1424. }
  1425. //
  1426. // Processing of current SSI request completed
  1427. // Do Cleanup
  1428. //
  1429. delete pRequest;
  1430. //
  1431. // Notify IIS that we are done with processing
  1432. //
  1433. pECB->ServerSupportFunction( pECB->ConnID,
  1434. HSE_REQ_DONE_WITH_SESSION,
  1435. NULL,
  1436. NULL,
  1437. NULL);
  1438. return;
  1439. }
  1440. //
  1441. // SSI_INCLUDE_FILE methods implementation
  1442. //
  1443. //static
  1444. ALLOC_CACHE_HANDLER * SSI_INCLUDE_FILE::sm_pachSSI_IncludeFiles = NULL;
  1445. SSI_INCLUDE_FILE::~SSI_INCLUDE_FILE( VOID )
  1446. /*++
  1447. Routine Description:
  1448. Destructor
  1449. --*/
  1450. {
  1451. if ( !_fSELCached && _pSEL )
  1452. {
  1453. delete _pSEL;
  1454. _pSEL = NULL;
  1455. }
  1456. if ( _pOpenFile )
  1457. {
  1458. _pOpenFile->DereferenceCacheEntry();
  1459. _pOpenFile = NULL;
  1460. }
  1461. }
  1462. HRESULT
  1463. SSI_INCLUDE_FILE::Prepare( VOID )
  1464. /*++
  1465. Routine Description:
  1466. This method builds the Server Side Include Element List the first
  1467. time a .stm file is sent. Subsequently, the element list is
  1468. checked out from the associated cache blob.
  1469. Note: The HTTP headers have already been sent at this point so for
  1470. any subsequent non-catastrophic errors, we have to insert them into
  1471. the output stream.
  1472. Arguments:
  1473. Return Value:
  1474. HRESULT
  1475. --*/
  1476. {
  1477. HRESULT hr = E_FAIL;
  1478. DWORD dwError;
  1479. LPSTR apszParms[ 2 ] = { NULL, NULL };
  1480. CHAR pszNumBuf[ SSI_MAX_NUMBER_STRING ];
  1481. FILE_CACHE_USER fileUser;
  1482. HSE_CUSTOM_ERROR_INFO customErrorInfo;
  1483. DBG_ASSERT( _State == SIF_STATE_INITIALIZED );
  1484. DBG_ASSERT( _pRequest != NULL );
  1485. fileUser._hToken = _pRequest->GetUserToken();
  1486. hr = g_pFileCache->GetFileInfo( _strFilename,
  1487. NULL,
  1488. &fileUser,
  1489. TRUE,
  1490. &_pOpenFile );
  1491. if ( FAILED( hr ) )
  1492. {
  1493. goto failed;
  1494. }
  1495. //
  1496. // The source file is in the cache. Check whether we have
  1497. // associated a SSI_ELEMENT_LIST with it.
  1498. //
  1499. _fFileCached = _pOpenFile->QueryFileBuffer() != NULL;
  1500. _pSEL = ( SSI_ELEMENT_LIST * )_pOpenFile->QueryAssociatedObject();
  1501. if ( _pSEL )
  1502. {
  1503. _fSELCached = TRUE;
  1504. }
  1505. else
  1506. {
  1507. //
  1508. // build SSI_ELEMENT_LIST _pSEL
  1509. //
  1510. hr = BuildSEL();
  1511. if ( FAILED( hr ) )
  1512. {
  1513. goto failed;
  1514. }
  1515. }
  1516. //
  1517. // Only bother to cache SEL if the file is cached
  1518. //
  1519. if ( !_fSELCached && _fFileCached )
  1520. {
  1521. if ( !_pOpenFile->SetAssociatedObject( _pSEL ) )
  1522. {
  1523. delete _pSEL;
  1524. _pSEL = (SSI_ELEMENT_LIST*) _pOpenFile->QueryAssociatedObject();
  1525. if ( !_pSEL )
  1526. {
  1527. DBG_ASSERT( FALSE );
  1528. hr = E_FAIL;
  1529. goto failed;
  1530. }
  1531. else
  1532. {
  1533. _fSELCached = TRUE;
  1534. }
  1535. }
  1536. else
  1537. {
  1538. _fSELCached = TRUE;
  1539. }
  1540. }
  1541. //
  1542. // adjust State
  1543. //
  1544. SetState( SIF_STATE_READY );
  1545. //
  1546. // If we got this far and this is the base file, we can send the
  1547. // 200 OK
  1548. //
  1549. if ( IsBaseFile() )
  1550. {
  1551. return _pRequest->SendResponseHeader( NULL,
  1552. SSI_HEADER );
  1553. }
  1554. else
  1555. {
  1556. return NO_ERROR;
  1557. }
  1558. failed:
  1559. dwError = WIN32_FROM_HRESULT(hr);
  1560. if ( IsBaseFile() )
  1561. {
  1562. //
  1563. // First try to have IIS send custom error
  1564. //
  1565. switch( dwError )
  1566. {
  1567. case ERROR_ACCESS_DENIED:
  1568. customErrorInfo.pszStatus = "401 Access Denied";
  1569. customErrorInfo.uHttpSubError = MD_ERROR_SUB401_LOGON_ACL;
  1570. customErrorInfo.fAsync = FALSE;
  1571. hr = _pRequest->SendCustomError( &customErrorInfo );
  1572. break;
  1573. case ERROR_FILE_NOT_FOUND:
  1574. case ERROR_PATH_NOT_FOUND:
  1575. customErrorInfo.pszStatus = "404 Object Not Found";
  1576. customErrorInfo.uHttpSubError = 0;
  1577. customErrorInfo.fAsync = FALSE;
  1578. hr = _pRequest->SendCustomError( &customErrorInfo );
  1579. break;
  1580. default:
  1581. hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  1582. }
  1583. //
  1584. // If IIS could not send custom error, then send our own legacy
  1585. // error response
  1586. //
  1587. if ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) )
  1588. {
  1589. switch( dwError )
  1590. {
  1591. case ERROR_ACCESS_DENIED:
  1592. _pRequest->SendResponseHeader( SSI_ACCESS_DENIED,
  1593. SSI_HEADER
  1594. "<body><h1>"
  1595. SSI_ACCESS_DENIED
  1596. "</h1></body>" );
  1597. break;
  1598. case ERROR_FILE_NOT_FOUND:
  1599. case ERROR_PATH_NOT_FOUND:
  1600. _pRequest->SendResponseHeader( SSI_OBJECT_NOT_FOUND,
  1601. SSI_HEADER
  1602. "<body><h1>"
  1603. SSI_OBJECT_NOT_FOUND
  1604. "</h1></body>" );
  1605. break;
  1606. default:
  1607. STACK_STRA (strURL, 128);
  1608. if (FAILED( hr = strURL.CopyW(_strURL.QueryStr())))
  1609. {
  1610. break;
  1611. }
  1612. _pRequest->SendResponseHeader( NULL,
  1613. SSI_HEADER );
  1614. _ultoa( dwError, pszNumBuf, 10 );
  1615. apszParms[ 0 ] = strURL.QueryStr();
  1616. apszParms[ 1 ] = pszNumBuf;
  1617. hr = _pRequest->SSISendError( SSINCMSG_ERROR_HANDLING_FILE,
  1618. apszParms );
  1619. }
  1620. }
  1621. }
  1622. else
  1623. {
  1624. STACK_STRA (strURL, 128);
  1625. if (SUCCEEDED( hr = strURL.CopyW(_strURL.QueryStr())))
  1626. {
  1627. _ultoa( dwError, pszNumBuf, 10 );
  1628. apszParms[ 0 ] = strURL.QueryStr();
  1629. apszParms[ 1 ] = pszNumBuf;
  1630. hr = _pRequest->SSISendError( SSINCMSG_ERROR_HANDLING_FILE,
  1631. apszParms );
  1632. }
  1633. }
  1634. //
  1635. // In the case of error set state to Completed
  1636. //
  1637. SetState( SIF_STATE_COMPLETED );
  1638. return ( ( FAILED(hr) ) ? hr : E_FAIL);
  1639. }
  1640. HRESULT
  1641. SSI_INCLUDE_FILE::BuildSEL( VOID )
  1642. /*++
  1643. Routine Description:
  1644. This method opens and parses the specified server side include file and
  1645. builds SSI_ELEMENT_LIST (SEL)
  1646. Note: The HTTP headers have already been sent at this point so for any
  1647. subsequent non-catastrophic errors, we have to insert them into the output
  1648. stream.
  1649. We keep the file open but that's ok because if a change dir notification
  1650. occurs, the cache blob will get decached at which point we will close
  1651. all of our open handles.
  1652. Arguments:
  1653. Return Value:
  1654. HRESULT
  1655. --*/
  1656. {
  1657. SSI_FILE * pssiFile = NULL;
  1658. SSI_ELEMENT_LIST * pSEL = NULL;
  1659. CHAR * pchBeginRange = NULL;
  1660. CHAR * pchFilePos = NULL;
  1661. CHAR * pchBeginFile = NULL;
  1662. CHAR * pchEOF = NULL;
  1663. DWORD cbSizeLow, cbSizeHigh;
  1664. HRESULT hr = E_FAIL;
  1665. //
  1666. // Create the element list
  1667. //
  1668. _pSEL = new SSI_ELEMENT_LIST;
  1669. if ( _pSEL == NULL )
  1670. {
  1671. hr = E_FAIL;
  1672. goto failed;
  1673. }
  1674. //
  1675. // Set the URL (to be used in calculating FILE="xxx" paths
  1676. //
  1677. _pSEL->SetURL( &_strURL );
  1678. //
  1679. // Open the file
  1680. //
  1681. pssiFile = new SSI_FILE( &_strFilename, _pOpenFile );
  1682. if ( pssiFile == NULL || !pssiFile->IsValid() )
  1683. {
  1684. if (pssiFile)
  1685. {
  1686. delete pssiFile;
  1687. pssiFile = NULL;
  1688. }
  1689. hr = E_FAIL;
  1690. goto failed;
  1691. }
  1692. _pSEL->SetFile( pssiFile );
  1693. //
  1694. // Make sure a parent doesn't try and include a directory
  1695. //
  1696. if ( pssiFile->SSIGetFileAttributes() & FILE_ATTRIBUTE_DIRECTORY )
  1697. {
  1698. hr = E_FAIL;
  1699. goto failed;
  1700. }
  1701. if ( !pssiFile->SSIGetFileSize( &cbSizeLow, &cbSizeHigh ) )
  1702. {
  1703. hr = E_FAIL;
  1704. goto failed;
  1705. }
  1706. if ( cbSizeHigh )
  1707. {
  1708. hr = HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  1709. goto failed;
  1710. }
  1711. //
  1712. // Create a file mapping, we shouldn't need to impersonate as we already
  1713. // have the file open
  1714. //
  1715. if ( !_pSEL->Map() )
  1716. {
  1717. hr = E_FAIL;
  1718. goto failed;
  1719. }
  1720. pchFilePos = pchBeginFile = pchBeginRange = _pSEL->QueryData();
  1721. pchEOF = pchFilePos + cbSizeLow;
  1722. //
  1723. // Scan for "<!--" or "<%"
  1724. //
  1725. while ( TRUE )
  1726. {
  1727. while ( pchFilePos < pchEOF && *pchFilePos != '<' )
  1728. {
  1729. pchFilePos++;
  1730. }
  1731. if ( pchFilePos + 4 >= pchEOF )
  1732. {
  1733. break;
  1734. }
  1735. //
  1736. // Is this one of our tags?
  1737. //
  1738. if ( pchFilePos[1] == '%' ||
  1739. !strncmp( pchFilePos, "<!--", 4 ))
  1740. {
  1741. CHAR * pchBeginTag = pchFilePos;
  1742. SSI_COMMANDS CommandType;
  1743. SSI_TAGS TagType;
  1744. CHAR achTagString[ SSI_MAX_PATH + 1 ];
  1745. BOOL fValidTag;
  1746. //
  1747. // Get the tag info. The file position will be advanced to the
  1748. // first character after the tag
  1749. //
  1750. if ( !ParseSSITag( &pchFilePos,
  1751. pchEOF,
  1752. &fValidTag,
  1753. &CommandType,
  1754. &TagType,
  1755. achTagString ) )
  1756. {
  1757. break;
  1758. }
  1759. //
  1760. // If it's a tag we don't recognize then ignore it
  1761. //
  1762. if ( !fValidTag )
  1763. {
  1764. pchFilePos++;
  1765. continue;
  1766. }
  1767. //
  1768. // Add the data up to the tag as a byte range
  1769. //
  1770. if ( pchBeginRange != pchBeginTag )
  1771. {
  1772. if ( !_pSEL->AppendByteRange(
  1773. DIFF(pchBeginRange - pchBeginFile),
  1774. DIFF(pchBeginTag - pchBeginRange) ) )
  1775. {
  1776. hr = E_FAIL;
  1777. goto failed;
  1778. }
  1779. }
  1780. pchBeginRange = pchFilePos;
  1781. //
  1782. // Add the tag
  1783. //
  1784. if ( !_pSEL->AppendCommand( CommandType,
  1785. TagType,
  1786. achTagString ))
  1787. {
  1788. hr = E_FAIL;
  1789. goto failed;
  1790. }
  1791. }
  1792. else
  1793. {
  1794. //
  1795. // Not one of our tags, skip the openning angle bracket
  1796. //
  1797. pchFilePos++;
  1798. }
  1799. }
  1800. //
  1801. // Tack on the last byte range
  1802. //
  1803. if ( pchFilePos > pchBeginRange )
  1804. {
  1805. if ( !_pSEL->AppendByteRange( DIFF(pchBeginRange - pchBeginFile),
  1806. DIFF(pchFilePos - pchBeginRange) ))
  1807. {
  1808. hr = E_FAIL;
  1809. goto failed;
  1810. }
  1811. }
  1812. return NO_ERROR;
  1813. failed:
  1814. if ( _pSEL != NULL )
  1815. {
  1816. //
  1817. // also deletes pssiFile if SetFile has been called.
  1818. //
  1819. delete _pSEL;
  1820. _pSEL = NULL;
  1821. }
  1822. return hr;
  1823. }
  1824. //static
  1825. BOOL
  1826. SSI_INCLUDE_FILE::ParseSSITag(
  1827. IN OUT CHAR * * ppchFilePos,
  1828. IN CHAR * pchEOF,
  1829. OUT BOOL * pfValidTag,
  1830. OUT SSI_COMMANDS * pCommandType,
  1831. OUT SSI_TAGS * pTagType,
  1832. OUT CHAR * pszTagString
  1833. )
  1834. /*++
  1835. Routine Description:
  1836. This function picks apart an NCSA style server side include
  1837. expression
  1838. The general form of a server side include directive is:
  1839. <[!-- or %]#[command] [tag]="[value]"[-- or %]>
  1840. For example:
  1841. <!--#include file="myfile.txt"-->
  1842. <%#echo var="HTTP_USER_AGENT"%>
  1843. <!--#fsize virtual="/dir/bar.htm"-->
  1844. For valid commands and tags see \iis\specs\ssi.doc
  1845. Arguments:
  1846. ppchFilePos - Pointer to first character of tag on way in, pointer
  1847. to first character after tag on way out if the tag is valid
  1848. pchEOF - Points to first byte beyond the end of the file
  1849. pfValidTag - Set to TRUE if this is a tag we support and all of the
  1850. parameters have been supplied
  1851. pCommandType - Receives SSI command
  1852. pTagType - Receives SSI tag
  1853. pszTagString - Receives value of pTagType. Must be > SSI_MAX_PATH.
  1854. Return Value:
  1855. TRUE if no errors occurred.
  1856. --*/
  1857. {
  1858. CHAR * pchFilePos = *ppchFilePos;
  1859. CHAR * pchEOT;
  1860. CHAR * pchEndQuote;
  1861. DWORD i;
  1862. DWORD cbToCopy;
  1863. DWORD cbJumpLen = 0;
  1864. BOOL fNewStyle; // <% format
  1865. DBG_ASSERT( *pchFilePos == '<' );
  1866. //
  1867. // Assume this is bad tag
  1868. //
  1869. *pfValidTag = FALSE;
  1870. if ( !strncmp( pchFilePos, "<!--", 4 ) )
  1871. {
  1872. fNewStyle = FALSE;
  1873. }
  1874. else if ( !strncmp( pchFilePos, "<%", 2 ) )
  1875. {
  1876. fNewStyle = TRUE;
  1877. }
  1878. else
  1879. {
  1880. return TRUE;
  1881. }
  1882. //
  1883. // Find the closing comment token (either --> or %>). The reason
  1884. // why we shouldn't simply look for a > is because we want to allow
  1885. // the user to embed HTML <tags> in the directive
  1886. // (ex. <!--#CONFIG ERRMSG="<B>ERROR!!!</B>-->)
  1887. //
  1888. pchEOT = strstr( pchFilePos, fNewStyle ? "%>" : "-->" );
  1889. if ( !pchEOT )
  1890. {
  1891. return FALSE;
  1892. }
  1893. cbJumpLen = fNewStyle ? 2 : 3;
  1894. //
  1895. // Find the '#' that prefixes the command
  1896. //
  1897. pchFilePos = SSISkipTo( pchFilePos, '#', pchEOT );
  1898. if ( !pchFilePos )
  1899. {
  1900. //
  1901. // No command, bail for this tag
  1902. //
  1903. // CODEWORK - Check for if expression here
  1904. //
  1905. return TRUE;
  1906. }
  1907. //
  1908. // Lookup the command
  1909. //
  1910. i = 0;
  1911. while ( SSICmdMap[i].pszCommand )
  1912. {
  1913. if ( *SSICmdMap[i].pszCommand == towlower( *pchFilePos ) &&
  1914. !_strnicmp( SSICmdMap[i].pszCommand,
  1915. pchFilePos,
  1916. SSICmdMap[i].cchCommand ))
  1917. {
  1918. *pCommandType = SSICmdMap[i].ssiCmd;
  1919. //
  1920. // Note the space after the command is included in
  1921. // cchCommand
  1922. //
  1923. pchFilePos += SSICmdMap[i].cchCommand;
  1924. goto FoundCommand;
  1925. }
  1926. i++;
  1927. }
  1928. //
  1929. // Unrecognized command, bail
  1930. //
  1931. return TRUE;
  1932. FoundCommand:
  1933. //
  1934. // Next, find the tag name
  1935. //
  1936. pchFilePos = SSISkipWhite( pchFilePos, pchEOT );
  1937. if ( !pchFilePos )
  1938. return TRUE;
  1939. i = 0;
  1940. while ( SSITagMap[i].pszTag )
  1941. {
  1942. if ( *SSITagMap[i].pszTag == tolower( *pchFilePos ) &&
  1943. !_strnicmp( SSITagMap[i].pszTag,
  1944. pchFilePos,
  1945. SSITagMap[i].cchTag ))
  1946. {
  1947. *pTagType = SSITagMap[i].ssiTag;
  1948. pchFilePos += SSITagMap[i].cchTag;
  1949. goto FoundTag;
  1950. }
  1951. i++;
  1952. }
  1953. //
  1954. // Tag not found, bail
  1955. //
  1956. return TRUE;
  1957. FoundTag:
  1958. //
  1959. // Skip to the quoted tag value, then find the close quote
  1960. //
  1961. pchFilePos = SSISkipTo( pchFilePos, '"', pchEOT );
  1962. if ( !pchFilePos )
  1963. return TRUE;
  1964. pchEndQuote = SSISkipTo( ++pchFilePos, '"', pchEOT );
  1965. if ( !pchEndQuote )
  1966. return TRUE;
  1967. cbToCopy = min( DIFF( pchEndQuote - pchFilePos ), SSI_MAX_PATH );
  1968. memcpy( pszTagString,
  1969. pchFilePos,
  1970. cbToCopy );
  1971. pszTagString[ cbToCopy ] = '\0';
  1972. *pfValidTag = TRUE;
  1973. *ppchFilePos = pchEOT + cbJumpLen;
  1974. return TRUE;
  1975. }
  1976. //static
  1977. CHAR *
  1978. SSI_INCLUDE_FILE::SSISkipTo(
  1979. IN CHAR * pchFilePos,
  1980. IN CHAR ch,
  1981. IN CHAR * pchEOF
  1982. )
  1983. {
  1984. return ( CHAR * ) memchr( pchFilePos,
  1985. ch,
  1986. DIFF( pchEOF - pchFilePos ) );
  1987. }
  1988. //static
  1989. CHAR *
  1990. SSI_INCLUDE_FILE::SSISkipWhite(
  1991. IN CHAR * pchFilePos,
  1992. IN CHAR * pchEOF
  1993. )
  1994. {
  1995. while ( pchFilePos < pchEOF )
  1996. {
  1997. if ( !SAFEIsSpace( *pchFilePos ) )
  1998. return pchFilePos;
  1999. pchFilePos++;
  2000. }
  2001. return NULL;
  2002. }
  2003. HRESULT
  2004. SSI_INCLUDE_FILE::DoWork(
  2005. DWORD dwError
  2006. )
  2007. /*++
  2008. Routine Description:
  2009. This method walks the element list sending the appropriate chunks of
  2010. data
  2011. Arguments:
  2012. dwError - error of the last asynchronous operation
  2013. Return Value:
  2014. HRESULT
  2015. --*/
  2016. {
  2017. HSE_EXEC_URL_STATUS ExecUrlStatus;
  2018. SSI_ELEMENT_ITEM * pSEI;
  2019. DWORD dwID;
  2020. LPSTR apszParms[ 2 ] = { NULL, NULL };
  2021. CHAR achNumberBuffer[ SSI_MAX_NUMBER_STRING ];
  2022. HRESULT hr = E_FAIL;
  2023. DBG_ASSERT( _pRequest != NULL );
  2024. if ( dwError != NO_ERROR )
  2025. {
  2026. //
  2027. // Last asynchronous operation failed
  2028. // only in the state: SIF_STATE_EXEC_CHILD_PENDING we will proceed if error occured
  2029. //
  2030. if ( _State != SIF_STATE_EXEC_CHILD_PENDING )
  2031. {
  2032. //
  2033. // Completion error means that we are forced to finish processing
  2034. //
  2035. SetState( SIF_STATE_COMPLETED );
  2036. }
  2037. }
  2038. while( _State != SIF_STATE_COMPLETED )
  2039. {
  2040. switch( _State )
  2041. {
  2042. case SIF_STATE_INITIALIZED:
  2043. //
  2044. // Prepare data structures when called for the first time
  2045. // and send initial headers or errors
  2046. //
  2047. hr = Prepare();
  2048. if( FAILED( hr ) )
  2049. {
  2050. return hr;
  2051. }
  2052. break;
  2053. case SIF_STATE_READY:
  2054. //
  2055. // Auxiliary state to flag that all the necessary date structures
  2056. // were prepared but actual processing hasn't started yet.
  2057. // Switch to PROCESSING state
  2058. //
  2059. SetState( SIF_STATE_PROCESSING );
  2060. break;
  2061. case SIF_STATE_PROCESSING:
  2062. //
  2063. // There are few cases when Process returns
  2064. // a) request completed
  2065. // b) pending operation
  2066. // c) child include file to be processed
  2067. //
  2068. // any any case return back to caller
  2069. //
  2070. hr = Process();
  2071. return hr;
  2072. case SIF_STATE_INCLUDE_CHILD_PENDING:
  2073. //
  2074. // Child include completed. Restore processing of current include file
  2075. //
  2076. SetState( SIF_STATE_PROCESSING );
  2077. break;
  2078. case SIF_STATE_EXEC_CHILD_PENDING:
  2079. //
  2080. // We were able to spawn child request. Get the status
  2081. //
  2082. pSEI = CONTAINING_RECORD( _pCurrentEntry, SSI_ELEMENT_ITEM, _ListEntry );
  2083. if( _pRequest->GetECB()->ServerSupportFunction(
  2084. _pRequest->GetECB()->ConnID,
  2085. HSE_REQ_GET_EXEC_URL_STATUS,
  2086. &ExecUrlStatus,
  2087. NULL,
  2088. NULL
  2089. ) )
  2090. {
  2091. if ( ExecUrlStatus.uHttpStatusCode >= 400 )
  2092. {
  2093. switch( ExecUrlStatus.uHttpStatusCode )
  2094. {
  2095. case 403:
  2096. dwID = SSINCMSG_NO_EXECUTE_PERMISSION;
  2097. break;
  2098. default:
  2099. dwID = SSINCMSG_CANT_EXEC_CGI_REPORT_HTTP_STATUS;
  2100. break;
  2101. }
  2102. _itoa( ExecUrlStatus.uHttpStatusCode, achNumberBuffer, 10 );
  2103. apszParms[ 0 ] = ( CHAR* )pSEI->QueryTagValue()->QueryStr();
  2104. apszParms[ 1 ] = achNumberBuffer;
  2105. }
  2106. else
  2107. {
  2108. dwID = 0;
  2109. }
  2110. }
  2111. else
  2112. {
  2113. _ultoa( GetLastError(), achNumberBuffer, 10 );
  2114. apszParms[ 0 ] = ( CHAR * )pSEI->QueryTagValue()->QueryStr();
  2115. apszParms[ 1 ] = achNumberBuffer;
  2116. dwID = SSINCMSG_CANT_EXEC_CGI;
  2117. }
  2118. //
  2119. // EXEC_URL completed. Adjust State back to PROCESSING
  2120. //
  2121. SetState( SIF_STATE_PROCESSING );
  2122. if ( dwID != 0 )
  2123. {
  2124. hr = _pRequest->SSISendError( dwID, apszParms );
  2125. if ( FAILED (hr) )
  2126. {
  2127. //
  2128. // This doesn't mean necessarily fatal error
  2129. // ERROR_IO_PENDING was likely returned
  2130. // so we have to simply return and wait for completion
  2131. //
  2132. return hr;
  2133. }
  2134. }
  2135. break;
  2136. default:
  2137. //
  2138. // Unexpected State
  2139. //
  2140. DBG_ASSERT( _State > SIF_STATE_UNINITIALIZED && _State < SIF_STATE_UNKNOWN );
  2141. return E_FAIL;
  2142. } // switch( _State )
  2143. }
  2144. return NO_ERROR;
  2145. }
  2146. HRESULT
  2147. SSI_INCLUDE_FILE::Process(
  2148. VOID
  2149. )
  2150. /*++
  2151. Routine Description:
  2152. This method walks the element list sending the appropriate chunks of
  2153. data
  2154. Arguments:
  2155. Return Value:
  2156. HRESULT
  2157. --*/
  2158. {
  2159. DWORD cbSent;
  2160. STACK_STRU( strPath, MAX_PATH);
  2161. SSI_ELEMENT_ITEM * pSEI;
  2162. HSE_EXEC_URL_STATUS ExecUrlStatus;
  2163. DWORD dwID;
  2164. LPSTR apszParms[ 2 ];
  2165. CHAR achNumberBuffer[ SSI_MAX_NUMBER_STRING ];
  2166. HRESULT hr = E_FAIL;
  2167. DBG_ASSERT( _pRequest != NULL );
  2168. if( _pCurrentEntry == NULL )
  2169. {
  2170. _pCurrentEntry = _pSEL->QueryListHead();
  2171. }
  2172. //
  2173. // Move CurrentEntry pointer to next element
  2174. //
  2175. _pCurrentEntry = _pCurrentEntry->Flink;
  2176. //
  2177. // Loop through each element and take the appropriate action
  2178. //
  2179. while( _pCurrentEntry != _pSEL->QueryListHead() )
  2180. {
  2181. DBG_ASSERT( _State == SIF_STATE_PROCESSING );
  2182. pSEI = CONTAINING_RECORD( _pCurrentEntry, SSI_ELEMENT_ITEM, _ListEntry );
  2183. DBG_ASSERT( pSEI->CheckSignature() );
  2184. dwID = 0;
  2185. switch ( pSEI->QueryCommand() )
  2186. {
  2187. case SSI_CMD_BYTERANGE:
  2188. if ( FAILED( hr = _pRequest->WriteToClient(
  2189. _pSEL->QueryData() + pSEI->QueryBegin(),
  2190. pSEI->QueryLength(),
  2191. &cbSent ) ) )
  2192. {
  2193. //
  2194. // This doesn't mean necessarily fatal error
  2195. // ERROR_IO_PENDING was likely returned
  2196. // so we have to simply return and wait for completion
  2197. //
  2198. return hr;
  2199. }
  2200. break;
  2201. case SSI_CMD_INCLUDE:
  2202. switch ( pSEI->QueryTag() )
  2203. {
  2204. case SSI_TAG_FILE:
  2205. case SSI_TAG_VIRTUAL:
  2206. {
  2207. STACK_STRU( strFullURL, MAX_PATH );
  2208. if ( FAILED ( hr = GetFullPath( pSEI,
  2209. &strPath,
  2210. HSE_URL_FLAGS_READ,
  2211. &_strURL,
  2212. &strFullURL ) ) )
  2213. {
  2214. _ultoa( WIN32_FROM_HRESULT(hr), achNumberBuffer, 10 );
  2215. apszParms[ 0 ] = ( CHAR * )pSEI->QueryTagValue()->
  2216. QueryStr();
  2217. apszParms[ 1 ] = achNumberBuffer;
  2218. dwID = SSINCMSG_ERROR_HANDLING_FILE;
  2219. break;
  2220. }
  2221. if ( IsRecursiveInclude( strPath ) )
  2222. {
  2223. apszParms[ 0 ] = ( CHAR * )pSEI->QueryTagValue()->
  2224. QueryStr();
  2225. apszParms[ 1 ] = NULL;
  2226. dwID = SSINCMSG_ERROR_RECURSIVE_INCLUDE;
  2227. break;
  2228. }
  2229. //
  2230. // Nested STM include
  2231. //
  2232. SSI_INCLUDE_FILE * pChild = new SSI_INCLUDE_FILE( _pRequest, strPath, strFullURL, this );
  2233. if ( pChild == NULL || !pChild->IsValid() )
  2234. {
  2235. _ultoa( WIN32_FROM_HRESULT(ERROR_OUTOFMEMORY), achNumberBuffer, 10 );
  2236. apszParms[ 0 ] = ( CHAR * )pSEI->QueryTagValue()->
  2237. QueryStr();
  2238. apszParms[ 1 ] = achNumberBuffer;
  2239. dwID = SSINCMSG_ERROR_HANDLING_FILE;
  2240. break;
  2241. }
  2242. _pRequest->SetCurrentIncludeFile( pChild );
  2243. SetState( SIF_STATE_INCLUDE_CHILD_PENDING );
  2244. //
  2245. // Return back to SSI_REQUEST (_pRequest)
  2246. // SSI_REQUEST will start executing it just added SSI_INCLUDE_FILE (pChild)
  2247. //
  2248. // This way recursive function calls that were used in the previous
  2249. // implementation can be avoided (to makes possible to implement
  2250. // asynchronous processing)
  2251. //
  2252. return NO_ERROR;
  2253. }
  2254. default:
  2255. dwID = SSINCMSG_INVALID_TAG;
  2256. }
  2257. break;
  2258. case SSI_CMD_FLASTMOD:
  2259. switch( pSEI->QueryTag() )
  2260. {
  2261. case SSI_TAG_FILE:
  2262. case SSI_TAG_VIRTUAL:
  2263. if ( FAILED( hr = GetFullPath( pSEI,
  2264. &strPath,
  2265. 0,
  2266. &_strURL ) ) ||
  2267. FAILED( hr = _pRequest->DoFLastMod( &strPath,
  2268. &_strTimeFmt,
  2269. _pSEL ) ) )
  2270. {
  2271. if ( hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING ) )
  2272. {
  2273. return hr;
  2274. }
  2275. _ultoa( WIN32_FROM_HRESULT(hr), achNumberBuffer, 10 );
  2276. apszParms[ 0 ] = ( CHAR * )pSEI->QueryTagValue()->
  2277. QueryStr();
  2278. apszParms[ 1 ] = achNumberBuffer;
  2279. dwID = SSINCMSG_CANT_DO_FLASTMOD;
  2280. }
  2281. break;
  2282. default:
  2283. dwID = SSINCMSG_INVALID_TAG;
  2284. }
  2285. break;
  2286. case SSI_CMD_CONFIG:
  2287. switch( pSEI->QueryTag() )
  2288. {
  2289. case SSI_TAG_ERRMSG:
  2290. if ( !_pRequest->SetUserErrorMessage(
  2291. pSEI->QueryTagValue() ) )
  2292. {
  2293. dwID = SSINCMSG_INVALID_TAG;
  2294. }
  2295. break;
  2296. case SSI_TAG_TIMEFMT:
  2297. if ( FAILED( _strTimeFmt.Resize(
  2298. pSEI->QueryTagValue()->QueryCCH() ) ) )
  2299. {
  2300. dwID = SSINCMSG_INVALID_TAG;
  2301. }
  2302. if ( FAILED( hr = _strTimeFmt.Copy( pSEI->QueryTagValue()->QueryStr() ) ) )
  2303. {
  2304. return hr;
  2305. }
  2306. break;
  2307. case SSI_TAG_SIZEFMT:
  2308. if ( _strnicmp( SSI_DEF_BYTES,
  2309. ( CHAR * )pSEI->QueryTagValue()->QueryStr(),
  2310. SSI_DEF_BYTES_LEN ) == 0 )
  2311. {
  2312. _fSizeFmtBytes = TRUE;
  2313. }
  2314. else if ( _strnicmp( SSI_DEF_ABBREV,
  2315. ( CHAR * )pSEI->QueryTagValue()->QueryStr(),
  2316. SSI_DEF_ABBREV_LEN ) == 0 )
  2317. {
  2318. _fSizeFmtBytes = FALSE;
  2319. }
  2320. else
  2321. {
  2322. dwID = SSINCMSG_INVALID_TAG;
  2323. }
  2324. break;
  2325. default:
  2326. dwID = SSINCMSG_INVALID_TAG;
  2327. }
  2328. break;
  2329. case SSI_CMD_FSIZE:
  2330. switch( pSEI->QueryTag() )
  2331. {
  2332. case SSI_TAG_FILE:
  2333. case SSI_TAG_VIRTUAL:
  2334. if ( FAILED ( hr = GetFullPath( pSEI,
  2335. &strPath,
  2336. 0,
  2337. &_strURL ) ) ||
  2338. FAILED ( hr = _pRequest->DoFSize( &strPath,
  2339. _fSizeFmtBytes,
  2340. _pSEL) ) )
  2341. {
  2342. if ( hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING ) )
  2343. {
  2344. return hr;
  2345. }
  2346. _ultoa( WIN32_FROM_HRESULT(hr), achNumberBuffer, 10 );
  2347. apszParms[ 0 ] = ( CHAR * )pSEI->QueryTagValue()->
  2348. QueryStr();
  2349. apszParms[ 1 ] = achNumberBuffer;
  2350. dwID = SSINCMSG_CANT_DO_FSIZE;
  2351. }
  2352. break;
  2353. default:
  2354. dwID = SSINCMSG_INVALID_TAG;
  2355. }
  2356. break;
  2357. case SSI_CMD_ECHO:
  2358. if ( pSEI->QueryTag() == SSI_TAG_VAR )
  2359. {
  2360. // First let ISAPI try to evaluate variable.
  2361. hr = _pRequest->DoEchoISAPIVariable(
  2362. pSEI->QueryTagValue() );
  2363. if ( hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING ) )
  2364. {
  2365. return hr;
  2366. }
  2367. if ( SUCCEEDED (hr ) )
  2368. {
  2369. break;
  2370. }
  2371. else
  2372. {
  2373. DWORD dwVar;
  2374. HRESULT hrEcho = E_FAIL;
  2375. // if ISAPI couldn't resolve var, try internal list
  2376. if ( !FindInternalVariable( pSEI->QueryTagValue(),
  2377. &dwVar ) )
  2378. {
  2379. apszParms[ 0 ] = ( CHAR * )pSEI->QueryTagValue()->
  2380. QueryStr();
  2381. apszParms[ 1 ] = NULL;
  2382. dwID = SSINCMSG_CANT_FIND_VARIABLE;
  2383. }
  2384. else
  2385. {
  2386. switch( dwVar )
  2387. {
  2388. case SSI_VAR_DOCUMENT_NAME:
  2389. hrEcho = _pRequest->DoEchoDocumentName(
  2390. &_pSEL->GetFile()->GetFilename() );
  2391. break;
  2392. case SSI_VAR_DOCUMENT_URI:
  2393. hrEcho = _pRequest->DoEchoDocumentURI(
  2394. &_strURL );
  2395. break;
  2396. case SSI_VAR_QUERY_STRING_UNESCAPED:
  2397. hrEcho = _pRequest->DoEchoQueryStringUnescaped();
  2398. break;
  2399. case SSI_VAR_DATE_LOCAL:
  2400. hrEcho = _pRequest->DoEchoDateLocal(
  2401. &_strTimeFmt );
  2402. break;
  2403. case SSI_VAR_DATE_GMT:
  2404. hrEcho = _pRequest->DoEchoDateGMT(
  2405. &_strTimeFmt );
  2406. break;
  2407. case SSI_VAR_LAST_MODIFIED:
  2408. hrEcho = _pRequest->DoEchoLastModified(
  2409. &_pSEL->GetFile()->GetFilename(),
  2410. &_strTimeFmt,
  2411. _pSEL );
  2412. break;
  2413. default:
  2414. apszParms[ 0 ] = ( CHAR * )pSEI->
  2415. QueryTagValue()->QueryStr();
  2416. apszParms[ 1 ] = NULL;
  2417. dwID = SSINCMSG_CANT_FIND_VARIABLE;
  2418. }
  2419. if ( hrEcho == HRESULT_FROM_WIN32(ERROR_IO_PENDING ) )
  2420. {
  2421. return hrEcho;
  2422. }
  2423. if ( FAILED ( hrEcho ) )
  2424. {
  2425. apszParms[ 0 ] = ( CHAR * )pSEI->
  2426. QueryTagValue()->QueryStr();
  2427. apszParms[ 1 ] = NULL;
  2428. dwID = SSINCMSG_CANT_EVALUATE_VARIABLE;
  2429. }
  2430. }
  2431. }
  2432. }
  2433. else
  2434. {
  2435. dwID = SSINCMSG_INVALID_TAG;
  2436. }
  2437. break;
  2438. case SSI_CMD_EXEC:
  2439. {
  2440. SSI_EXEC_TYPE ssiExecType = SSI_EXEC_UNKNOWN;
  2441. if ( _pRequest->IsExecDisabled() )
  2442. {
  2443. dwID = SSINCMSG_EXEC_DISABLED;
  2444. }
  2445. else if ( pSEI->QueryTag() == SSI_TAG_CMD )
  2446. {
  2447. if ( !fEnableCmdDirective )
  2448. {
  2449. dwID = SSINCMSG_CMD_NOT_ENABLED;
  2450. }
  2451. else
  2452. {
  2453. ssiExecType = SSI_EXEC_CMD;
  2454. }
  2455. }
  2456. else if ( pSEI->QueryTag() == SSI_TAG_CGI )
  2457. {
  2458. ssiExecType = SSI_EXEC_CGI;
  2459. }
  2460. else if ( pSEI->QueryTag() == SSI_TAG_ISA )
  2461. {
  2462. ssiExecType = SSI_EXEC_ISA;
  2463. }
  2464. else
  2465. {
  2466. dwID = SSINCMSG_INVALID_TAG;
  2467. }
  2468. if ( ssiExecType != SSI_EXEC_UNKNOWN )
  2469. {
  2470. BOOL fOk = FALSE;
  2471. ZeroMemory( &_ExecUrlInfo, sizeof( _ExecUrlInfo ) );
  2472. //
  2473. // Make asynchronous Child Execute
  2474. //
  2475. _ExecUrlInfo.dwExecUrlFlags = HSE_EXEC_URL_NO_HEADERS |
  2476. HSE_EXEC_URL_ASYNC |
  2477. HSE_EXEC_URL_IGNORE_APPPOOL |
  2478. HSE_EXEC_URL_DISABLE_CUSTOM_ERROR |
  2479. HSE_EXEC_URL_IGNORE_VALIDATION_AND_RANGE;
  2480. if ( ssiExecType == SSI_EXEC_CMD )
  2481. {
  2482. _ExecUrlInfo.dwExecUrlFlags |= HSE_EXEC_URL_SSI_CMD;
  2483. }
  2484. _ExecUrlInfo.pszUrl = (LPSTR) pSEI->QueryTagValue()->QueryStr();
  2485. DBG_ASSERT( _ExecUrlInfo.pszUrl != NULL );
  2486. //
  2487. // Avoid execution of empty URL
  2488. //
  2489. SetState( SIF_STATE_EXEC_CHILD_PENDING );
  2490. if ( _ExecUrlInfo.pszUrl[0] != '\0' )
  2491. {
  2492. fOk = _pRequest->GetECB()->ServerSupportFunction(
  2493. _pRequest->GetECB()->ConnID,
  2494. HSE_REQ_EXEC_URL,
  2495. &_ExecUrlInfo,
  2496. NULL,
  2497. NULL
  2498. );
  2499. }
  2500. if ( !fOk )
  2501. {
  2502. SetState( SIF_STATE_PROCESSING );
  2503. _ultoa( GetLastError(), achNumberBuffer, 10 );
  2504. apszParms[ 0 ] = ( CHAR * )pSEI->QueryTagValue()->QueryStr();
  2505. apszParms[ 1 ] = achNumberBuffer;
  2506. dwID = SSINCMSG_CANT_EXEC_CGI;
  2507. }
  2508. else
  2509. {
  2510. return HRESULT_FROM_WIN32( ERROR_IO_PENDING );
  2511. }
  2512. }
  2513. break;
  2514. }
  2515. default:
  2516. dwID = SSINCMSG_NOT_SUPPORTED;
  2517. break;
  2518. }
  2519. if ( dwID )
  2520. {
  2521. hr = _pRequest->SSISendError( dwID, apszParms );
  2522. if ( FAILED (hr) )
  2523. {
  2524. //
  2525. // This doesn't mean necessarily fatal error
  2526. // ERROR_IO_PENDING was likely returned
  2527. // so we have to simply return and wait for completion
  2528. //
  2529. return hr;
  2530. }
  2531. }
  2532. //
  2533. // Move to next element of SSI_ELEMENT_LIST
  2534. //
  2535. _pCurrentEntry = _pCurrentEntry->Flink;
  2536. }
  2537. //
  2538. // End of the list has been reached
  2539. // It means that processing of the current SSI_INCLUDE_FILE has completed
  2540. //
  2541. SetState( SIF_STATE_COMPLETED );
  2542. return NO_ERROR;
  2543. }
  2544. HRESULT
  2545. SSI_INCLUDE_FILE::GetFullPath(
  2546. IN SSI_ELEMENT_ITEM * pSEI,
  2547. OUT STRU * pstrPath,
  2548. IN DWORD dwPermission,
  2549. IN STRU * pstrCurrentURL,
  2550. OUT STRU * pstrURL
  2551. )
  2552. /*++
  2553. Routine Description:
  2554. Used to resolve FILE= and VIRTUAL= references. Fills in the physical
  2555. path of such file references and optionally checks the permissions
  2556. of the virtual directory.
  2557. Arguments:
  2558. pSEI - Element item ( either FILE or VIRTUAL )
  2559. pstrPath - Filled in with physical path of file
  2560. dwPermission - Contains permissions that the virtual
  2561. path must satisfy. For example HSE_URL_FLAGS_READ.
  2562. If 0, then no permissions are checked
  2563. pstrCurrentURL - Current .STM URL being parsed
  2564. pstrURL - Full URL filled in here (may be NULL if only pstrPath is to be retrieved)
  2565. Return Value:
  2566. HRESULT
  2567. --*/
  2568. {
  2569. WCHAR * pszValue;
  2570. STRU strValue;
  2571. DWORD dwMask;
  2572. DWORD cbBufLen;
  2573. WCHAR achPath[ SSI_MAX_PATH + 1 ];
  2574. HRESULT hr = E_FAIL;
  2575. //
  2576. // We recalc the virtual root each time in case the root
  2577. // to directory mapping has changed
  2578. //
  2579. if ( FAILED( hr = strValue.CopyA( pSEI->QueryTagValue()->QueryStr() ) ) )
  2580. {
  2581. return hr;
  2582. }
  2583. pszValue = strValue.QueryStr();
  2584. if ( *pszValue == L'/' )
  2585. {
  2586. wcscpy( achPath, pszValue );
  2587. }
  2588. else if ( ( int )pSEI->QueryTag() == ( int )SSI_TAG_FILE )
  2589. {
  2590. wcscpy( achPath, pstrCurrentURL->QueryStr() );
  2591. LPWSTR pL = achPath + wcslen( achPath );
  2592. while ( pL > achPath && pL[ -1 ] != L'/' )
  2593. {
  2594. --pL;
  2595. }
  2596. if ( pL == achPath )
  2597. {
  2598. *pL++ = L'/';
  2599. }
  2600. wcscpy( pL, pszValue );
  2601. }
  2602. else
  2603. {
  2604. achPath[ 0 ] = L'/';
  2605. wcscpy( achPath + 1, pszValue );
  2606. }
  2607. //
  2608. // First canonicalize the URL to be #included
  2609. //
  2610. // BUGBUG-MING
  2611. //CanonURL( achPath, g_fIsDBCS );
  2612. //
  2613. // Map to a physical directory
  2614. //
  2615. if ( FAILED( hr =_pRequest->LookupVirtualRoot( achPath,
  2616. pstrPath,
  2617. dwPermission ) ) )
  2618. {
  2619. return hr;
  2620. }
  2621. if( pstrURL == NULL )
  2622. {
  2623. return NO_ERROR;
  2624. }
  2625. if( FAILED( hr = pstrURL->Copy( achPath ) ) )
  2626. {
  2627. return hr;
  2628. }
  2629. return NO_ERROR;
  2630. }
  2631. //static
  2632. BOOL
  2633. SSI_INCLUDE_FILE::FindInternalVariable(
  2634. IN STRA * pstrVariable,
  2635. OUT PDWORD pdwID
  2636. )
  2637. /*++
  2638. Routine Description:
  2639. Lookup internal list of SSI variables that aren't supported by ISAPI.
  2640. These include "DOCUMENT_NAME", "DATE_LOCAL", etc.
  2641. Arguments:
  2642. pstrVariable - Variable to check
  2643. pdwID - Variable ID (or SSI_VAR_UNKNOWN if not found)
  2644. Return Value:
  2645. TRUE on success, FALSE on failure
  2646. --*/
  2647. {
  2648. DWORD dwCounter = 0;
  2649. while ( ( SSIVarMap[ dwCounter ].pszMap != NULL ) &&
  2650. _strnicmp( SSIVarMap[ dwCounter ].pszMap,
  2651. ( CHAR * )pstrVariable->QueryStr(),
  2652. SSIVarMap[ dwCounter ].cchMap ) )
  2653. {
  2654. dwCounter++;
  2655. }
  2656. if ( SSIVarMap[ dwCounter ].pszMap != NULL )
  2657. {
  2658. *pdwID = SSIVarMap[ dwCounter ].ssiMap;
  2659. return TRUE;
  2660. }
  2661. else
  2662. {
  2663. *pdwID = SSI_VAR_UNKNOWN;
  2664. return FALSE;
  2665. }
  2666. }
  2667. VOID
  2668. InitializeSSIGlobals( VOID )
  2669. /*++
  2670. Routine Description:
  2671. Initialize global variables
  2672. Return Value:
  2673. none
  2674. --*/
  2675. {
  2676. HKEY hKeyParam;
  2677. DWORD dwType;
  2678. DWORD nBytes;
  2679. DWORD dwValue;
  2680. DWORD err;
  2681. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2682. W3_PARAMETERS_KEY,
  2683. 0,
  2684. KEY_READ,
  2685. &hKeyParam ) == NO_ERROR )
  2686. {
  2687. nBytes = sizeof( dwValue );
  2688. err = RegQueryValueExA( hKeyParam,
  2689. "SSIEnableCmdDirective",
  2690. NULL,
  2691. &dwType,
  2692. ( LPBYTE )&dwValue,
  2693. &nBytes
  2694. );
  2695. if ( ( err == ERROR_SUCCESS ) && ( dwType == REG_DWORD ) )
  2696. {
  2697. fEnableCmdDirective = !!dwValue;
  2698. }
  2699. RegCloseKey( hKeyParam );
  2700. }
  2701. }
  2702. //
  2703. // ISAPI DLL Required Entry Points
  2704. //
  2705. DWORD
  2706. WINAPI
  2707. HttpExtensionProc(
  2708. EXTENSION_CONTROL_BLOCK * pecb
  2709. )
  2710. {
  2711. BOOL fRet;
  2712. HRESULT hr = E_FAIL;
  2713. SSI_REQUEST * pssiReq = new SSI_REQUEST(pecb);
  2714. if( pssiReq == NULL || !pssiReq->IsValid())
  2715. {
  2716. goto failed;
  2717. }
  2718. if ( !pecb->ServerSupportFunction( pecb->ConnID,
  2719. HSE_REQ_IO_COMPLETION,
  2720. SSI_REQUEST::HseIoCompletion,
  2721. 0,
  2722. (LPDWORD ) pssiReq)
  2723. )
  2724. {
  2725. goto failed;
  2726. }
  2727. hr = pssiReq->DoWork();
  2728. if ( hr == HRESULT_FROM_WIN32(ERROR_IO_PENDING) )
  2729. {
  2730. //
  2731. // No Cleanup, there is pending IO request.
  2732. // completion routine is responsible perform proper cleanup
  2733. //
  2734. return HSE_STATUS_PENDING;
  2735. }
  2736. if ( SUCCEEDED( hr ) )
  2737. {
  2738. //
  2739. // This request is completed. Do Cleanup before returning
  2740. //
  2741. delete pssiReq;
  2742. return HSE_STATUS_SUCCESS;
  2743. }
  2744. failed:
  2745. {
  2746. LPCSTR apsz[ 1 ];
  2747. DWORD cch;
  2748. LPSTR pchBuff;
  2749. CHAR chTemp = '\0';
  2750. apsz[ 0 ] = pecb->lpszPathInfo;
  2751. //
  2752. // Since FormatMessage() is lame and actually uses SEH and an
  2753. // AV to determine when to resize its buffers, we have to truncate
  2754. // the URL here. Otherwise, on a machine with a UM debugger attached
  2755. // , we will break on the 1st chance exception (unless debugger is
  2756. // configured to ignore these exceptions which isn't the case.
  2757. //
  2758. if ( strlen( pecb->lpszPathInfo ) > SSI_MAX_FORMAT_LEN )
  2759. {
  2760. chTemp = pecb->lpszPathInfo[ SSI_MAX_FORMAT_LEN ];
  2761. pecb->lpszPathInfo[ SSI_MAX_FORMAT_LEN ] = '\0';
  2762. }
  2763. cch = ::FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  2764. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  2765. FORMAT_MESSAGE_FROM_HMODULE,
  2766. GetModuleHandle( SSI_DLL_NAME ),
  2767. SSINCMSG_LOG_ERROR,
  2768. 0,
  2769. ( LPSTR ) &pchBuff,
  2770. 0,
  2771. ( va_list *) apsz );
  2772. if ( chTemp != '\0' )
  2773. {
  2774. pecb->lpszPathInfo[ SSI_MAX_FORMAT_LEN ] = chTemp;
  2775. }
  2776. if( cch )
  2777. {
  2778. strncpy( pecb->lpszLogData,
  2779. pchBuff,
  2780. (cch>HSE_LOG_BUFFER_LEN)?HSE_LOG_BUFFER_LEN:cch );
  2781. pecb->lpszLogData[HSE_LOG_BUFFER_LEN-1] = 0;
  2782. ::LocalFree( ( VOID * )pchBuff );
  2783. }
  2784. //
  2785. // This request is completed. Do Cleanup before returning
  2786. //
  2787. delete pssiReq;
  2788. return HSE_STATUS_ERROR;
  2789. }
  2790. }
  2791. BOOL
  2792. WINAPI
  2793. GetExtensionVersion(
  2794. HSE_VERSION_INFO * pver
  2795. )
  2796. {
  2797. pver->dwExtensionVersion = MAKELONG( 0, 1 );
  2798. strcpy( pver->lpszExtensionDesc,
  2799. "Server Side Include Extension DLL" );
  2800. //
  2801. // Get the cache instance for W3CORE.DLL
  2802. //
  2803. g_pFileCache = W3_FILE_INFO_CACHE::GetFileCache();
  2804. if ( g_pFileCache == NULL )
  2805. {
  2806. return FALSE;
  2807. }
  2808. if ( FAILED( SSI_REQUEST::Initialize() ) )
  2809. {
  2810. return FALSE;
  2811. }
  2812. if ( FAILED( SSI_INCLUDE_FILE::Initialize() ) )
  2813. {
  2814. SSI_REQUEST::Terminate();
  2815. return FALSE;
  2816. }
  2817. return TRUE;
  2818. }
  2819. BOOL
  2820. WINAPI
  2821. TerminateExtension(
  2822. DWORD dwFlags
  2823. )
  2824. {
  2825. SSI_REQUEST::Terminate();
  2826. SSI_INCLUDE_FILE::Terminate();
  2827. W3CacheFlushAllCaches();
  2828. return TRUE;
  2829. }
  2830. BOOL
  2831. WINAPI
  2832. DLLEntry(
  2833. HINSTANCE hDll,
  2834. DWORD dwReason,
  2835. LPVOID lpvReserved
  2836. )
  2837. {
  2838. switch ( dwReason )
  2839. {
  2840. case DLL_PROCESS_ATTACH:
  2841. CREATE_DEBUG_PRINT_OBJECT( "ssinc" );
  2842. DisableThreadLibraryCalls( hDll );
  2843. InitializeSSIGlobals();
  2844. break;
  2845. case DLL_PROCESS_DETACH:
  2846. DELETE_DEBUG_PRINT_OBJECT();
  2847. break;
  2848. default:
  2849. break;
  2850. }
  2851. return TRUE;
  2852. }