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.

874 lines
18 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ssinc.hxx
  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\gateways\ssinc\ssinc.cxx.
  9. Author:
  10. Ming Lu (MingLu) 5-Apr-2000
  11. --*/
  12. #ifndef SSINC_HXX_INCLUDED
  13. #define SSINC_HXX_INCLUDED
  14. /************************************************************
  15. * Macros
  16. ************************************************************/
  17. //
  18. // General Constants
  19. //
  20. #define SSI_MAX_PATH 1024
  21. #define SSI_MAX_ERROR_MESSAGE 512
  22. #define SSI_MAX_TIME_SIZE 256
  23. #define SSI_MAX_NUMBER_STRING 32
  24. #define SSI_INIT_VARIABLE_OUTPUT_SIZE 64
  25. #define SSI_MAX_NESTED_INCLUDES 255
  26. #define SSI_MAX_FORMAT_LEN 1024
  27. #define SSI_HEADER "Content-Type: text/html\r\n\r\n"
  28. #define SSI_ACCESS_DENIED "401 Authentication Required"
  29. #define SSI_OBJECT_NOT_FOUND "404 Object Not Found"
  30. #define SSI_DLL_NAME L"ssinc.dll"
  31. //
  32. // Default values for #CONFIG options
  33. //
  34. #define SSI_DEF_ERRMSG ""
  35. #define SSI_DEF_ERRMSG_LEN sizeof( SSI_DEF_ERRMSG )
  36. #define SSI_MAX_ERRMSG 256
  37. #define SSI_DEF_TIMEFMT "%A %B %d %Y"
  38. #define SSI_DEF_TIMEFMT_LEN sizeof( SSI_DEF_TIMEFMT )
  39. #define SSI_MAX_TIMEFMT 256
  40. #define SSI_DEF_SIZEFMT FALSE
  41. //
  42. // Specific lvalues for #CONFIG SIZEFMT and #CONFIG CMDECHO
  43. //
  44. #define SSI_DEF_BYTES "bytes"
  45. #define SSI_DEF_BYTES_LEN sizeof( SSI_DEF_BYTES )
  46. #define SSI_DEF_ABBREV "abbrev"
  47. #define SSI_DEF_ABBREV_LEN sizeof( SSI_DEF_ABBREV )
  48. //
  49. // Other cache/signature constants
  50. //
  51. #define SIGNATURE_SEI 0x20494553
  52. #define SIGNATURE_SEL 0x204C4553
  53. #define SIGNATURE_SEI_FREE 0x66494553
  54. #define SIGNATURE_SEL_FREE 0x664C4553
  55. #define W3_PARAMETERS_KEY \
  56. L"System\\CurrentControlSet\\Services\\w3svc\\Parameters"
  57. //
  58. // These are available SSI commands
  59. //
  60. enum SSI_COMMANDS
  61. {
  62. SSI_CMD_INCLUDE = 0,
  63. SSI_CMD_ECHO,
  64. SSI_CMD_FSIZE, // File size of specified file
  65. SSI_CMD_FLASTMOD, // Last modified date of specified file
  66. SSI_CMD_CONFIG, // Configure options
  67. SSI_CMD_EXEC, // Execute CGI or CMD script
  68. SSI_CMD_BYTERANGE, // Custom commands, not defined by NCSA
  69. SSI_CMD_UNKNOWN
  70. };
  71. //
  72. // These tags are essentially subcommands for the various SSI_COMMAND
  73. // values
  74. //
  75. enum SSI_TAGS
  76. {
  77. SSI_TAG_FILE, // Used with include, fsize & flastmod
  78. SSI_TAG_VIRTUAL,
  79. SSI_TAG_VAR, // Used with echo
  80. SSI_TAG_CMD, // Used with Exec
  81. SSI_TAG_CGI,
  82. SSI_TAG_ISA,
  83. SSI_TAG_ERRMSG, // Used with Config
  84. SSI_TAG_TIMEFMT,
  85. SSI_TAG_SIZEFMT,
  86. SSI_TAG_UNKNOWN
  87. };
  88. //
  89. // Variables available to #ECHO VAR = "xxx" but not available in ISAPI
  90. //
  91. enum SSI_VARS
  92. {
  93. SSI_VAR_DOCUMENT_NAME = 0,
  94. SSI_VAR_DOCUMENT_URI,
  95. SSI_VAR_QUERY_STRING_UNESCAPED,
  96. SSI_VAR_DATE_LOCAL,
  97. SSI_VAR_DATE_GMT,
  98. SSI_VAR_LAST_MODIFIED,
  99. SSI_VAR_UNKNOWN
  100. };
  101. //
  102. // SSI Exec types
  103. //
  104. enum SSI_EXEC_TYPE
  105. {
  106. SSI_EXEC_CMD = 1,
  107. SSI_EXEC_CGI = 2,
  108. SSI_EXEC_ISA = 4,
  109. SSI_EXEC_UNKNOWN
  110. };
  111. //
  112. // States of asynchronous SSI_INCLUDE_FILE processing
  113. //
  114. enum SIF_STATE
  115. {
  116. SIF_STATE_UNINITIALIZED,
  117. SIF_STATE_INITIALIZED,
  118. SIF_STATE_READY,
  119. SIF_STATE_EXEC_CHILD_PENDING,
  120. SIF_STATE_INCLUDE_CHILD_PENDING,
  121. SIF_STATE_PROCESSING,
  122. SIF_STATE_COMPLETED,
  123. SIF_STATE_UNKNOWN
  124. };
  125. class SSI_INCLUDE_FILE;
  126. class SSI_ELEMENT_LIST;
  127. class SSI_ELEMENT_ITEM;
  128. /************************************************************
  129. * Structure and Class declarations
  130. ************************************************************/
  131. /*++
  132. class SSI_REQUEST
  133. Master structure for SSI request.
  134. Provides a "library" of utilities for use by higher level functions
  135. Hierarchy:
  136. SSI_REQUEST
  137. - SSI_INCLUDE_FILE
  138. - SSI_ELEMENT_LIST
  139. - SSI_ELEMENT_ITEM
  140. --*/
  141. class SSI_REQUEST
  142. {
  143. private:
  144. EXTENSION_CONTROL_BLOCK * _pECB;
  145. STRU _strFilename;
  146. STRU _strURL;
  147. STRA _strUserMessage;
  148. BOOL _fBaseFile;
  149. HANDLE _hUser;
  150. BOOL _fValid;
  151. // Current include file (multiple stm files may be nested)
  152. SSI_INCLUDE_FILE * _pSIF;
  153. // Buffers used for async writes must stay around
  154. LPSTR _pchErrorBuff;
  155. CHAR _achTimeBuffer[ SSI_MAX_TIME_SIZE + 1 ];
  156. DWORD _cbTimeBufferLen;
  157. BUFFER _IOBuffer;
  158. STRA _IOString;
  159. // buffer length variable (to be used for async I/O)
  160. DWORD _cbIOLen;
  161. // Handle to file cache
  162. W3_FILE_INFO_CACHE * _pFileCache;
  163. // Lookaside
  164. static ALLOC_CACHE_HANDLER * sm_pachSSIRequests;
  165. public:
  166. SSI_REQUEST( EXTENSION_CONTROL_BLOCK * pECB );
  167. ~SSI_REQUEST();
  168. VOID *
  169. operator new(
  170. size_t size
  171. )
  172. {
  173. DBG_ASSERT( size == sizeof( SSI_REQUEST ) );
  174. DBG_ASSERT( sm_pachSSIRequests != NULL );
  175. return sm_pachSSIRequests->Alloc();
  176. }
  177. VOID
  178. operator delete(
  179. VOID * pSSIRequest
  180. )
  181. {
  182. DBG_ASSERT( pSSIRequest != NULL );
  183. DBG_ASSERT( sm_pachSSIRequests != NULL );
  184. DBG_REQUIRE( sm_pachSSIRequests->Free( pSSIRequest ) );
  185. }
  186. static
  187. HRESULT
  188. Initialize(
  189. VOID
  190. )
  191. /*++
  192. Routine Description:
  193. Global initialization routine for SSI_REQUEST
  194. Arguments:
  195. None
  196. Return Value:
  197. HRESULT
  198. --*/
  199. {
  200. ALLOC_CACHE_CONFIGURATION acConfig;
  201. HRESULT hr = NO_ERROR;
  202. //
  203. // Setup allocation lookaside
  204. //
  205. acConfig.nConcurrency = 1;
  206. acConfig.nThreshold = 100;
  207. acConfig.cbSize = sizeof( SSI_REQUEST );
  208. DBG_ASSERT( sm_pachSSIRequests == NULL );
  209. sm_pachSSIRequests = new ALLOC_CACHE_HANDLER( "SSI_REQUEST",
  210. &acConfig );
  211. if ( sm_pachSSIRequests == NULL )
  212. {
  213. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  214. }
  215. return NO_ERROR;
  216. }
  217. static
  218. VOID
  219. Terminate(
  220. VOID
  221. )
  222. /*++
  223. Routine Description:
  224. Terminate SSI_REQUEST globals
  225. Arguments:
  226. None
  227. Return Value:
  228. None
  229. --*/
  230. {
  231. if ( sm_pachSSIRequests != NULL )
  232. {
  233. delete sm_pachSSIRequests;
  234. sm_pachSSIRequests = NULL;
  235. }
  236. }
  237. BOOL
  238. IsValid(
  239. VOID
  240. ) const
  241. {
  242. return _fValid;
  243. }
  244. BOOL
  245. SetCurrentIncludeFile(
  246. SSI_INCLUDE_FILE * pSIF
  247. )
  248. {
  249. _pSIF = pSIF;
  250. return TRUE;
  251. }
  252. EXTENSION_CONTROL_BLOCK *
  253. GetECB(
  254. VOID
  255. ) const
  256. {
  257. return _pECB;
  258. }
  259. HANDLE
  260. GetUserToken(
  261. VOID
  262. )
  263. {
  264. return _hUser;
  265. }
  266. HRESULT
  267. WriteToClient(
  268. IN PVOID pBuffer,
  269. IN DWORD dwBufLen,
  270. OUT PDWORD pdwActualLen
  271. )
  272. /*++
  273. Write to data to client through ISAPI.
  274. If sending a nulltermed string, dwBufLen should be strlen( pBuffer )
  275. --*/
  276. {
  277. BOOL fRet = FALSE;
  278. *pdwActualLen = dwBufLen;
  279. if ( dwBufLen == 0 )
  280. {
  281. //
  282. // If 0 bytes are sent asynchronously
  283. // there will be no completion callback
  284. //
  285. return NO_ERROR;
  286. }
  287. fRet = _pECB->WriteClient( _pECB->ConnID,
  288. pBuffer,
  289. pdwActualLen,
  290. HSE_IO_ASYNC );
  291. if ( fRet )
  292. {
  293. return HRESULT_FROM_WIN32(ERROR_IO_PENDING);
  294. }
  295. else
  296. {
  297. return HRESULT_FROM_WIN32(GetLastError());
  298. }
  299. }
  300. HRESULT
  301. SendResponseHeader(
  302. IN CHAR * pszMessage,
  303. IN CHAR * pszHeaders
  304. )
  305. /*++
  306. Send a response header to client through ISAPI
  307. --*/
  308. {
  309. BOOL fRet = FALSE;
  310. if( _pECB->ServerSupportFunction( _pECB->ConnID,
  311. HSE_REQ_SEND_RESPONSE_HEADER,
  312. pszMessage,
  313. NULL,
  314. ( DWORD * ) pszHeaders ) )
  315. {
  316. return NO_ERROR;
  317. }
  318. else
  319. {
  320. return HRESULT_FROM_WIN32(GetLastError());
  321. }
  322. }
  323. HRESULT
  324. GetVariable(
  325. IN LPSTR pszVariableName,
  326. OUT BUFFER * pbuffOutput
  327. )
  328. /*++
  329. Get an ISAPI variable
  330. --*/
  331. {
  332. DWORD dwBufLen = SSI_INIT_VARIABLE_OUTPUT_SIZE;
  333. BOOL fRet;
  334. BOOL fSecondTry = FALSE;
  335. TryAgain:
  336. if ( !pbuffOutput->Resize( dwBufLen ) )
  337. {
  338. return HRESULT_FROM_WIN32(GetLastError());
  339. }
  340. fRet = _pECB->GetServerVariable( _pECB->ConnID,
  341. pszVariableName,
  342. pbuffOutput->QueryPtr(),
  343. &dwBufLen );
  344. if ( fRet )
  345. {
  346. return NO_ERROR;
  347. }
  348. else if ( !fSecondTry &&
  349. GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  350. {
  351. fSecondTry = TRUE;
  352. goto TryAgain;
  353. }
  354. else
  355. {
  356. return HRESULT_FROM_WIN32(GetLastError());
  357. }
  358. }
  359. HRESULT
  360. SSISendError(
  361. IN DWORD dwMessageID,
  362. IN LPSTR apszParms[]
  363. );
  364. BOOL
  365. SetUserErrorMessage(
  366. IN STRA * pstrUserMessage
  367. )
  368. {
  369. if( FAILED ( _strUserMessage.Copy(*pstrUserMessage) ) )
  370. {
  371. return FALSE;
  372. }
  373. return TRUE;
  374. }
  375. //BUGBUG OTHER WAYS TO FIND OUT THE METABASE INFO
  376. BOOL
  377. IsExecDisabled(
  378. VOID
  379. ) const
  380. {
  381. //return _pReq->QueryMetaData()->SSIExecDisabled();
  382. return FALSE;
  383. }
  384. HRESULT
  385. SendCustomError(
  386. HSE_CUSTOM_ERROR_INFO * pCustomErrorInfo
  387. );
  388. HRESULT
  389. DoFLastMod(
  390. IN STRU *,
  391. IN STRA *,
  392. IN SSI_ELEMENT_LIST *
  393. );
  394. HRESULT
  395. DoFSize(
  396. IN STRU *,
  397. IN BOOL,
  398. IN SSI_ELEMENT_LIST *
  399. );
  400. HRESULT
  401. DoEchoISAPIVariable(
  402. IN STRA *
  403. );
  404. HRESULT
  405. DoEchoDocumentName(
  406. IN STRU *
  407. );
  408. HRESULT
  409. DoEchoDocumentURI(
  410. IN STRU *
  411. );
  412. HRESULT
  413. DoEchoQueryStringUnescaped(
  414. VOID
  415. );
  416. HRESULT
  417. DoEchoDateLocal(
  418. IN STRA *
  419. );
  420. HRESULT
  421. DoEchoDateGMT(
  422. IN STRA *
  423. );
  424. HRESULT
  425. DoEchoLastModified(
  426. IN STRU *,
  427. IN STRA *,
  428. IN SSI_ELEMENT_LIST *
  429. );
  430. HRESULT
  431. SendDate(
  432. IN SYSTEMTIME *,
  433. IN STRA *
  434. );
  435. HRESULT
  436. LookupVirtualRoot(
  437. IN WCHAR * pszVirtual,
  438. OUT STRU * pstrPhysical,
  439. IN DWORD dwAccess
  440. );
  441. HRESULT
  442. DoWork(
  443. DWORD dwError = NO_ERROR
  444. );
  445. HRESULT
  446. PrepareSSI(
  447. VOID
  448. );
  449. static
  450. VOID WINAPI
  451. HseIoCompletion(
  452. IN EXTENSION_CONTROL_BLOCK * pECB,
  453. IN PVOID pContext,
  454. IN DWORD cbIO,
  455. IN DWORD dwError
  456. );
  457. };
  458. /*++
  459. class SSI_INCLUDE_FILE
  460. STM file may include other files. Each include file is represented by SSI_INCLUDE_FILE
  461. --*/
  462. class SSI_INCLUDE_FILE
  463. {
  464. private:
  465. SSI_REQUEST * _pRequest;
  466. // _strFileName - File to send
  467. STRU _strFilename;
  468. // _strURL - URL (from root) of this file
  469. STRU _strURL;
  470. // pParent - Parent SSI include file
  471. SSI_INCLUDE_FILE * _pParent;
  472. SIF_STATE _State;
  473. SSI_ELEMENT_LIST * _pSEL;
  474. LIST_ENTRY * _pCurrentEntry;
  475. BOOL _fSELCached;
  476. BOOL _fFileCached;
  477. W3_FILE_INFO * _pOpenFile;
  478. // Asynchronous child execute info
  479. HSE_EXEC_URL_INFO _ExecUrlInfo;
  480. // Size and time formating info
  481. BOOL _fSizeFmtBytes;
  482. STRA _strTimeFmt;
  483. // Lookaside
  484. static ALLOC_CACHE_HANDLER * sm_pachSSI_IncludeFiles;
  485. public:
  486. SSI_INCLUDE_FILE(
  487. SSI_REQUEST * pRequest,
  488. STRU & strFilename,
  489. STRU & strURL,
  490. SSI_INCLUDE_FILE * pParent
  491. )
  492. : _pRequest( pRequest ),
  493. _pParent( pParent ),
  494. _pSEL( NULL ),
  495. _pCurrentEntry( NULL ),
  496. _fSELCached( FALSE ),
  497. _fFileCached( FALSE ),
  498. _pOpenFile( NULL ),
  499. _fSizeFmtBytes (SSI_DEF_SIZEFMT),
  500. _State( SIF_STATE_UNINITIALIZED )
  501. {
  502. if ( FAILED( _strFilename.Copy( strFilename ) ) )
  503. {
  504. return;
  505. }
  506. if ( FAILED( _strURL.Copy( strURL ) ) )
  507. {
  508. return;
  509. }
  510. if ( FAILED( _strTimeFmt.Resize( sizeof( SSI_DEF_TIMEFMT ) + 1 ) ) )
  511. {
  512. return;
  513. }
  514. strcpy( ( CHAR * )_strTimeFmt.QueryStr(), SSI_DEF_TIMEFMT );
  515. SetState( SIF_STATE_INITIALIZED );
  516. }
  517. ~SSI_INCLUDE_FILE( VOID );
  518. VOID *
  519. operator new(
  520. size_t size
  521. )
  522. {
  523. DBG_ASSERT( size == sizeof( SSI_INCLUDE_FILE ) );
  524. DBG_ASSERT( sm_pachSSI_IncludeFiles != NULL );
  525. return sm_pachSSI_IncludeFiles->Alloc();
  526. }
  527. VOID
  528. operator delete(
  529. VOID * pSSI_IncludeFile
  530. )
  531. {
  532. DBG_ASSERT( pSSI_IncludeFile != NULL );
  533. DBG_ASSERT( sm_pachSSI_IncludeFiles != NULL );
  534. DBG_REQUIRE( sm_pachSSI_IncludeFiles->Free( pSSI_IncludeFile ) );
  535. }
  536. static
  537. HRESULT
  538. Initialize(
  539. VOID
  540. )
  541. /*++
  542. Routine Description:
  543. Global initialization routine for SSI_REQUEST
  544. Arguments:
  545. None
  546. Return Value:
  547. HRESULT
  548. --*/
  549. {
  550. ALLOC_CACHE_CONFIGURATION acConfig;
  551. HRESULT hr = NO_ERROR;
  552. //
  553. // Setup allocation lookaside
  554. //
  555. acConfig.nConcurrency = 1;
  556. acConfig.nThreshold = 100;
  557. acConfig.cbSize = sizeof( SSI_INCLUDE_FILE );
  558. DBG_ASSERT( sm_pachSSI_IncludeFiles == NULL );
  559. sm_pachSSI_IncludeFiles = new ALLOC_CACHE_HANDLER( "SSI_INCLUDE_FILE",
  560. &acConfig );
  561. if ( sm_pachSSI_IncludeFiles == NULL )
  562. {
  563. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  564. }
  565. return NO_ERROR;
  566. }
  567. static
  568. VOID
  569. Terminate(
  570. VOID
  571. )
  572. /*++
  573. Routine Description:
  574. Terminate SSI_REQUEST globals
  575. Arguments:
  576. None
  577. Return Value:
  578. None
  579. --*/
  580. {
  581. if ( sm_pachSSI_IncludeFiles != NULL )
  582. {
  583. delete sm_pachSSI_IncludeFiles;
  584. sm_pachSSI_IncludeFiles = NULL;
  585. }
  586. }
  587. SSI_INCLUDE_FILE *
  588. GetParent( VOID )
  589. {
  590. return _pParent;
  591. }
  592. LIST_ENTRY *
  593. GetCurrentEntry( VOID )
  594. {
  595. return _pCurrentEntry;
  596. }
  597. BOOL IsCompleted( VOID )
  598. {
  599. return ( _State == SIF_STATE_COMPLETED );
  600. }
  601. BOOL IsValid( VOID )
  602. {
  603. return ( _State != SIF_STATE_UNINITIALIZED );
  604. }
  605. BOOL IsBaseFile( VOID )
  606. {
  607. return ( _pParent == NULL );
  608. }
  609. BOOL IsRecursiveInclude( IN STRU & strFilename )
  610. {
  611. if ( !_wcsicmp( strFilename.QueryStr(),
  612. _strFilename.QueryStr() ) )
  613. {
  614. return TRUE;
  615. }
  616. if ( !_pParent )
  617. {
  618. return FALSE;
  619. }
  620. else
  621. {
  622. return _pParent->IsRecursiveInclude( strFilename );
  623. }
  624. }
  625. VOID
  626. SetState(
  627. SIF_STATE State
  628. )
  629. {
  630. _State = State;
  631. }
  632. HRESULT
  633. Prepare(
  634. VOID
  635. );
  636. HRESULT
  637. BuildSEL(
  638. VOID
  639. );
  640. HRESULT
  641. Process(
  642. VOID
  643. );
  644. HRESULT
  645. DoWork(
  646. DWORD dwError = NO_ERROR
  647. );
  648. HRESULT
  649. GetFullPath(
  650. IN SSI_ELEMENT_ITEM * pSEI,
  651. OUT STRU * pstrPath,
  652. IN DWORD dwPermission,
  653. IN STRU * pstrCurrentURL,
  654. OUT STRU * pstrURL = NULL
  655. );
  656. static
  657. BOOL
  658. ParseSSITag(
  659. IN OUT CHAR * * ppchFilePos,
  660. IN CHAR * pchEOF,
  661. OUT BOOL * pfValidTag,
  662. OUT SSI_COMMANDS * pCommandType,
  663. OUT SSI_TAGS * pTagType,
  664. OUT CHAR * pszTagString
  665. );
  666. static
  667. CHAR *
  668. SSISkipTo(
  669. IN CHAR * pchFilePos,
  670. IN CHAR ch,
  671. IN CHAR * pchEOF
  672. );
  673. static
  674. CHAR *
  675. SSISkipWhite(
  676. IN CHAR * pchFilePos,
  677. IN CHAR * pchEOF
  678. );
  679. static
  680. BOOL
  681. FindInternalVariable(
  682. IN STRA * pstrVariable,
  683. OUT PDWORD pdwID
  684. );
  685. };
  686. #endif