Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

651 lines
16 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. Implementation of the ssinc ISAPI entrypoints.
  10. implementation of the custom error handling
  11. Author:
  12. Ming Lu (MingLu) 10-Apr-2000
  13. --*/
  14. #include "precomp.hxx"
  15. //
  16. // Prototypes
  17. //
  18. extern "C" {
  19. BOOL
  20. WINAPI
  21. DllMain(
  22. HINSTANCE hDll,
  23. DWORD dwReason,
  24. LPVOID lpvReserved
  25. );
  26. }
  27. //
  28. // Global Data
  29. //
  30. DECLARE_DEBUG_PRINTS_OBJECT();
  31. DECLARE_DEBUG_VARIABLE();
  32. //
  33. // utility functions
  34. //
  35. DWORD
  36. SsiFormatMessageA(
  37. IN DWORD dwMessageId,
  38. IN LPSTR apszParms[],
  39. OUT LPSTR * ppchErrorBuff
  40. )
  41. /*++
  42. Routine Description:
  43. FormatMessage wrapper
  44. Arguments:
  45. dwMessageId - message Id to format
  46. apszParms[] - parameters for message
  47. ppchErrorBuff - formatted message text (caller must free it calling LocalFree)
  48. Return Value:
  49. HRESULT
  50. --*/
  51. {
  52. DWORD cch;
  53. //
  54. // FormatMessage uses SEH to determine when to resize and
  55. // this will cause debuggers to break on the 1st change exception
  56. // All the parameters must be limited in max output size using format string
  57. // in the message eg %1!.30s!would limit output of the parameter to max size
  58. // of 30 characters
  59. cch = ::FormatMessageA( FORMAT_MESSAGE_ARGUMENT_ARRAY |
  60. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  61. FORMAT_MESSAGE_FROM_HMODULE,
  62. GetModuleHandle( IIS_RESOURCE_DLL_NAME ),
  63. dwMessageId,
  64. 0,
  65. ( LPSTR ) ppchErrorBuff, //see FormatMessage doc
  66. 0,
  67. ( va_list *) apszParms );
  68. return cch;
  69. }
  70. //
  71. // class that handles asynchronous sends of custom errors from
  72. // the master level
  73. //
  74. class SSI_CUSTOM_ERROR
  75. {
  76. public:
  77. SSI_CUSTOM_ERROR();
  78. HRESULT
  79. SSI_CUSTOM_ERROR::SendCustomError(
  80. EXTENSION_CONTROL_BLOCK * pecb,
  81. HRESULT hrErrorToReport
  82. );
  83. private:
  84. ~SSI_CUSTOM_ERROR();
  85. VOID
  86. SSI_CUSTOM_ERROR::SetVectorResponseData(
  87. IN PCHAR pszStatus,
  88. IN PCHAR pszHeaders,
  89. IN PCHAR pszResponse
  90. );
  91. static
  92. VOID WINAPI
  93. HseCustomErrorCompletion(
  94. IN EXTENSION_CONTROL_BLOCK * pECB,
  95. IN PVOID pContext,
  96. IN DWORD cbIO,
  97. IN DWORD dwError
  98. );
  99. HSE_CUSTOM_ERROR_INFO _CustomErrorInfo;
  100. HSE_RESPONSE_VECTOR _ResponseVector;
  101. HSE_VECTOR_ELEMENT _VectorElement;
  102. PCHAR _pszFormattedMessage;
  103. BOOL _fHeadRequest;
  104. };
  105. SSI_CUSTOM_ERROR::SSI_CUSTOM_ERROR()
  106. {
  107. ZeroMemory( &_ResponseVector, sizeof( _ResponseVector ) );
  108. ZeroMemory( &_VectorElement, sizeof( _VectorElement ) );
  109. _ResponseVector.lpElementArray = &_VectorElement;
  110. _ResponseVector.dwFlags = HSE_IO_ASYNC |
  111. HSE_IO_SEND_HEADERS |
  112. HSE_IO_DISCONNECT_AFTER_SEND;
  113. _ResponseVector.pszStatus = "";
  114. _ResponseVector.pszHeaders = "";
  115. _ResponseVector.nElementCount = 0;
  116. _pszFormattedMessage = NULL;
  117. _fHeadRequest = FALSE;
  118. }
  119. SSI_CUSTOM_ERROR::~SSI_CUSTOM_ERROR()
  120. {
  121. if ( _pszFormattedMessage != NULL )
  122. {
  123. LocalFree( _pszFormattedMessage );
  124. _pszFormattedMessage = NULL;
  125. }
  126. }
  127. VOID
  128. SSI_CUSTOM_ERROR::SetVectorResponseData(
  129. IN PCHAR pszStatus,
  130. IN PCHAR pszHeaders,
  131. IN PCHAR pszResponse )
  132. /*++
  133. Routine Description:
  134. if custom error couldn't be used then Vector send is used
  135. This function is used internally to setup VectorSend structures
  136. Arguments:
  137. pszStatus -
  138. pszHeaders -
  139. pszResponse - response body
  140. Return Value:
  141. HRESULT
  142. --*/
  143. {
  144. _ResponseVector.pszStatus = pszStatus;
  145. _ResponseVector.pszHeaders = pszHeaders;
  146. if ( !_fHeadRequest )
  147. {
  148. _VectorElement.ElementType = HSE_VECTOR_ELEMENT_TYPE_MEMORY_BUFFER;
  149. _VectorElement.pvContext = pszResponse;
  150. _VectorElement.cbSize = strlen( pszResponse );
  151. _ResponseVector.nElementCount = 1;
  152. }
  153. else
  154. {
  155. _ResponseVector.nElementCount = 0;
  156. }
  157. }
  158. //static
  159. VOID WINAPI
  160. SSI_CUSTOM_ERROR::HseCustomErrorCompletion(
  161. IN EXTENSION_CONTROL_BLOCK * pECB,
  162. IN PVOID pContext,
  163. IN DWORD /*cbIO*/,
  164. IN DWORD /*dwError*/
  165. )
  166. /*++
  167. Routine Description:
  168. completion routine (for async custom error send or vector send
  169. Arguments:
  170. Return Value:
  171. HRESULT
  172. --*/
  173. {
  174. DBG_ASSERT( pContext != NULL );
  175. SSI_CUSTOM_ERROR * pSsiCustomError =
  176. reinterpret_cast<SSI_CUSTOM_ERROR *> (pContext);
  177. delete pSsiCustomError;
  178. pSsiCustomError = NULL;
  179. //
  180. // Notify IIS that we are done with processing
  181. //
  182. pECB->ServerSupportFunction( pECB->ConnID,
  183. HSE_REQ_DONE_WITH_SESSION,
  184. NULL,
  185. NULL,
  186. NULL );
  187. return;
  188. }
  189. HRESULT
  190. SSI_CUSTOM_ERROR::SendCustomError(
  191. EXTENSION_CONTROL_BLOCK * pecb,
  192. HRESULT hrErrorToReport
  193. )
  194. /*++
  195. Routine Description:
  196. reports error hrErrorToReport either as custom error if possible or
  197. builds error response that gets send asynchronously using VectorSend
  198. Arguments:
  199. pecb
  200. hrErrorToReport - error to be reported
  201. Return Value:
  202. HRESULT
  203. --*/
  204. {
  205. HRESULT hr = E_FAIL;
  206. if ( !pecb->ServerSupportFunction( pecb->ConnID,
  207. HSE_REQ_IO_COMPLETION,
  208. SSI_CUSTOM_ERROR::HseCustomErrorCompletion,
  209. 0,
  210. (LPDWORD ) this ) )
  211. {
  212. hr = HRESULT_FROM_WIN32( GetLastError() );
  213. goto failed;
  214. }
  215. if ( _stricmp( pecb->lpszMethod, "HEAD" ) == 0 )
  216. {
  217. _fHeadRequest = TRUE;
  218. }
  219. DWORD dwError = WIN32_FROM_HRESULT( hrErrorToReport );
  220. _CustomErrorInfo.pszStatus = NULL;
  221. switch( dwError )
  222. {
  223. case ERROR_ACCESS_DENIED:
  224. _CustomErrorInfo.pszStatus = "401 Access Denied";
  225. _CustomErrorInfo.uHttpSubError = MD_ERROR_SUB401_LOGON_ACL;
  226. _CustomErrorInfo.fAsync = TRUE;
  227. break;
  228. case ERROR_FILE_NOT_FOUND:
  229. case ERROR_PATH_NOT_FOUND:
  230. case ERROR_INVALID_NAME:
  231. _CustomErrorInfo.pszStatus = "404 Object Not Found";
  232. _CustomErrorInfo.uHttpSubError = 0;
  233. _CustomErrorInfo.fAsync = TRUE;
  234. break;
  235. default:
  236. hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  237. }
  238. if ( _CustomErrorInfo.pszStatus != NULL )
  239. {
  240. BOOL fRet = pecb->ServerSupportFunction( pecb->ConnID,
  241. HSE_REQ_SEND_CUSTOM_ERROR,
  242. &_CustomErrorInfo,
  243. NULL,
  244. NULL );
  245. if ( !fRet )
  246. {
  247. hr = HRESULT_FROM_WIN32( GetLastError() );
  248. }
  249. else
  250. {
  251. hr = S_OK;
  252. }
  253. }
  254. //
  255. // Sending custom error failed, send our own error
  256. //
  257. if ( hr == HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) )
  258. {
  259. switch( dwError )
  260. {
  261. case ERROR_ACCESS_DENIED:
  262. SetVectorResponseData(
  263. SSI_ACCESS_DENIED,
  264. SSI_HEADER,
  265. "<body><h1>"
  266. SSI_ACCESS_DENIED
  267. "</h1></body>" );
  268. break;
  269. case ERROR_FILE_NOT_FOUND:
  270. case ERROR_PATH_NOT_FOUND:
  271. case ERROR_INVALID_NAME:
  272. SetVectorResponseData(
  273. SSI_OBJECT_NOT_FOUND,
  274. SSI_HEADER,
  275. "<body><h1>"
  276. SSI_OBJECT_NOT_FOUND
  277. "</h1></body>" );
  278. break;
  279. default:
  280. {
  281. STACK_BUFFER( buffTemp, ( SSI_DEFAULT_URL_SIZE + 1 ) * sizeof(WCHAR) );
  282. STACK_STRA( strURL, SSI_DEFAULT_URL_SIZE );
  283. DWORD cbSize = buffTemp.QuerySize();
  284. CHAR pszNumBuf[ SSI_MAX_NUMBER_STRING ];
  285. LPSTR apszParms[ 2 ] = { NULL, NULL };
  286. //
  287. // get the URL
  288. //
  289. if ( !pecb->GetServerVariable( pecb->ConnID,
  290. "UNICODE_URL",
  291. buffTemp.QueryPtr(),
  292. &cbSize ) )
  293. {
  294. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER ||
  295. !buffTemp.Resize(cbSize))
  296. {
  297. hr = HRESULT_FROM_WIN32( GetLastError() );
  298. goto failed;
  299. }
  300. //
  301. // Now, we should have enough buffer, try again
  302. //
  303. if ( !pecb->GetServerVariable( pecb->ConnID,
  304. "UNICODE_URL",
  305. buffTemp.QueryPtr(),
  306. &cbSize ) )
  307. {
  308. hr = HRESULT_FROM_WIN32( GetLastError() );
  309. goto failed;
  310. }
  311. }
  312. if (FAILED( hr = strURL.CopyW((LPWSTR)buffTemp.QueryPtr())))
  313. {
  314. break;
  315. }
  316. _ultoa( dwError, pszNumBuf, 10 );
  317. apszParms[ 0 ] = strURL.QueryStr();
  318. apszParms[ 1 ] = pszNumBuf;
  319. DWORD cch = SsiFormatMessageA (
  320. SSINCMSG_REQUEST_ERROR,
  321. apszParms,
  322. &_pszFormattedMessage
  323. );
  324. if ( cch == 0 )
  325. {
  326. return HRESULT_FROM_WIN32( GetLastError() );
  327. goto failed;
  328. }
  329. SetVectorResponseData( "", // means 200 OK
  330. SSI_HEADER,
  331. _pszFormattedMessage );
  332. } //end of default block
  333. }
  334. //
  335. // perform the Vector send
  336. //
  337. if ( !pecb->ServerSupportFunction(
  338. pecb->ConnID,
  339. HSE_REQ_VECTOR_SEND,
  340. &_ResponseVector,
  341. NULL,
  342. NULL) )
  343. {
  344. hr = HRESULT_FROM_WIN32( GetLastError() );
  345. goto failed;
  346. }
  347. }
  348. else if ( FAILED( hr ) )
  349. {
  350. goto failed;
  351. }
  352. return S_OK;
  353. failed:
  354. DBG_ASSERT( FAILED( hr ) );
  355. return hr;
  356. }
  357. //
  358. // ISAPI DLL Required Entry Points
  359. //
  360. DWORD
  361. WINAPI
  362. HttpExtensionProc(
  363. EXTENSION_CONTROL_BLOCK * pecb
  364. )
  365. {
  366. HRESULT hr = E_FAIL;
  367. HRESULT hrToReport = E_FAIL;
  368. BOOL fAsyncPending = FALSE;
  369. SSI_REQUEST * pssiReq = NULL;
  370. hrToReport = SSI_REQUEST::CreateInstance(
  371. pecb,
  372. &pssiReq );
  373. if( FAILED( hrToReport ) )
  374. {
  375. SSI_CUSTOM_ERROR * pSsiCustomError = new SSI_CUSTOM_ERROR;
  376. if ( pSsiCustomError == NULL )
  377. {
  378. hr = HRESULT_FROM_WIN32( ERROR_OUTOFMEMORY );
  379. goto failed;
  380. }
  381. //
  382. // in the case of success asynchronous custom error
  383. // send will be executed
  384. //
  385. hr = pSsiCustomError->SendCustomError(
  386. pecb,
  387. hrToReport );
  388. if ( FAILED ( hr ) )
  389. {
  390. goto failed;
  391. }
  392. else
  393. {
  394. //
  395. // No Cleanup, there is pending IO request.
  396. // completion routine is responsible perform proper cleanup
  397. //
  398. return HSE_STATUS_PENDING;
  399. }
  400. }
  401. DBG_ASSERT( pssiReq != NULL );
  402. //
  403. // Register completion callback since we will execute asynchronously
  404. //
  405. if ( !pecb->ServerSupportFunction( pecb->ConnID,
  406. HSE_REQ_IO_COMPLETION,
  407. SSI_REQUEST::HseIoCompletion,
  408. 0,
  409. (LPDWORD ) pssiReq )
  410. )
  411. {
  412. goto failed;
  413. }
  414. //
  415. // Continue processing SSI file
  416. //
  417. hr = pssiReq->DoWork( 0,
  418. &fAsyncPending );
  419. if ( SUCCEEDED(hr) )
  420. {
  421. if( fAsyncPending )
  422. {
  423. //
  424. // No Cleanup, there is pending IO request.
  425. // completion routine is responsible perform proper cleanup
  426. //
  427. return HSE_STATUS_PENDING;
  428. }
  429. else
  430. {
  431. //
  432. // This request is completed. Do Cleanup before returning
  433. //
  434. delete pssiReq;
  435. pssiReq = NULL;
  436. return HSE_STATUS_SUCCESS;
  437. }
  438. }
  439. failed:
  440. {
  441. LPCSTR apsz[ 1 ];
  442. DWORD cch;
  443. LPSTR pchBuff;
  444. apsz[ 0 ] = pecb->lpszPathInfo;
  445. cch = SsiFormatMessageA( SSINCMSG_LOG_ERROR,
  446. ( va_list *) apsz,
  447. &pchBuff );
  448. if( cch > 0 )
  449. {
  450. strncpy( pecb->lpszLogData,
  451. pchBuff,
  452. HSE_LOG_BUFFER_LEN );
  453. pecb->lpszLogData[ HSE_LOG_BUFFER_LEN - 1 ] = 0;
  454. ::LocalFree( ( VOID * )pchBuff );
  455. }
  456. //
  457. // This request is completed. Do Cleanup before returning
  458. //
  459. if ( pssiReq != NULL )
  460. {
  461. delete pssiReq;
  462. pssiReq = NULL;
  463. }
  464. return HSE_STATUS_ERROR;
  465. }
  466. }
  467. BOOL
  468. WINAPI
  469. GetExtensionVersion(
  470. HSE_VERSION_INFO * pver
  471. )
  472. {
  473. pver->dwExtensionVersion = MAKELONG( 0, 1 );
  474. strncpy( pver->lpszExtensionDesc,
  475. "Server Side Include Extension DLL",
  476. HSE_MAX_EXT_DLL_NAME_LEN );
  477. pver->lpszExtensionDesc[ HSE_MAX_EXT_DLL_NAME_LEN - 1 ] = '\0';
  478. if ( FAILED( SSI_REQUEST::InitializeGlobals() ) )
  479. {
  480. return FALSE;
  481. }
  482. if ( FAILED( SSI_INCLUDE_FILE::InitializeGlobals() ) )
  483. {
  484. SSI_REQUEST::TerminateGlobals();
  485. return FALSE;
  486. }
  487. if ( FAILED( SSI_FILE::InitializeGlobals() ) )
  488. {
  489. SSI_INCLUDE_FILE::TerminateGlobals();
  490. SSI_REQUEST::TerminateGlobals();
  491. return FALSE;
  492. }
  493. return TRUE;
  494. }
  495. BOOL
  496. WINAPI
  497. TerminateExtension(
  498. DWORD /* dwFlags */
  499. )
  500. {
  501. SSI_FILE::TerminateGlobals();
  502. SSI_INCLUDE_FILE::TerminateGlobals();
  503. SSI_REQUEST::TerminateGlobals();
  504. return TRUE;
  505. }
  506. BOOL
  507. WINAPI
  508. DllMain(
  509. HINSTANCE hDll,
  510. DWORD dwReason,
  511. LPVOID /*lpvReserved*/
  512. )
  513. {
  514. switch ( dwReason )
  515. {
  516. case DLL_PROCESS_ATTACH:
  517. CREATE_DEBUG_PRINT_OBJECT( "ssinc" );
  518. DisableThreadLibraryCalls( hDll );
  519. break;
  520. case DLL_PROCESS_DETACH:
  521. DELETE_DEBUG_PRINT_OBJECT();
  522. break;
  523. default:
  524. break;
  525. }
  526. return TRUE;
  527. }