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.

5052 lines
127 KiB

  1. /*++
  2. Copyright (c) 1995-1997 Microsoft Corporation
  3. Module Name :
  4. wamreq.cxx
  5. Abstract:
  6. This module implements the WAM_REQUEST object
  7. Author:
  8. David Kaplan ( DaveK ) 26-Feb-1997
  9. Environment:
  10. User Mode - Win32
  11. Project:
  12. W3 services DLL
  13. --*/
  14. /************************************************************
  15. * Include Headers
  16. ************************************************************/
  17. #include <w3p.hxx>
  18. #include "wamreq.hxx"
  19. #include "iwr_i.c"
  20. #include "WrcStIds.hxx" // wamreq core string id's
  21. #include "WrcFixed.hxx"
  22. #include "WamExec.hxx"
  23. #include "lonsi.hxx" // IISDuplicateHandleEx
  24. #include <tokenacl.hxx>
  25. #include <malloc.h>
  26. /*******************************************
  27. * *
  28. * WAM_REQUEST allocation cache *
  29. * *
  30. * *
  31. *******************************************/
  32. ALLOC_CACHE_HANDLER * WAM_REQUEST::sm_pachWamRequest;
  33. # define WAM_REQUEST_CACHE_THRESHOLD (400) // UNDONE: Empirically vary
  34. #if DBG
  35. extern PTRACE_LOG g_pDbgCCRefTraceLog;
  36. PTRACE_LOG WAM_REQUEST::sm_pDbgRefTraceLog;
  37. #endif
  38. DWORD WAM_REQUEST::sm_dwRequestID;
  39. inline BOOL
  40. DupTokenWithSameImpersonationLevel
  41. (
  42. HANDLE hExistingToken,
  43. DWORD dwDesiredAccess,
  44. TOKEN_TYPE TokenType,
  45. PHANDLE phNewToken
  46. )
  47. /*++
  48. Routine Description:
  49. Duplicate an impersionation token using the same ImpersonationLevel.
  50. Arguments:
  51. hExistingToken - a handle to a valid impersionation token
  52. dwDesiredAccess - the access level to the new token (see DuplicateTokenEx)
  53. phNewToken - ptr to the new token handle, client must CloseHandle.
  54. Return Value:
  55. Return value of DuplicateTokenEx
  56. --*/
  57. {
  58. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  59. DWORD dwBytesReturned;
  60. if( !GetTokenInformation( hExistingToken,
  61. TokenImpersonationLevel,
  62. &ImpersonationLevel,
  63. sizeof(ImpersonationLevel),
  64. &dwBytesReturned
  65. ) )
  66. {
  67. DBGERROR(( DBG_CONTEXT,
  68. "GetTokenInformation - failed to get TokenImpersonationLevel "
  69. "LastError=%d, using SecurityImpersonation\n",
  70. GetLastError()
  71. ));
  72. ImpersonationLevel = SecurityImpersonation;
  73. }
  74. return DuplicateTokenEx( hExistingToken,
  75. dwDesiredAccess,
  76. NULL,
  77. ImpersonationLevel,
  78. TokenType,
  79. phNewToken
  80. );
  81. }
  82. BOOL IsStringTerminated( LPCSTR lpSz, DWORD cchMax )
  83. /*++
  84. Routine Description:
  85. This function verifies that the range of memory specified by the
  86. input parameters can be read by the calling process and that
  87. the string is zero-terminated.
  88. Note that since Win32 is a pre-emptive multi-tasking environment,
  89. the results of this test are only meaningful if the other threads in
  90. the process do not manipulate the range of memory being tested by
  91. this call. Even after a pointer validation, an application should
  92. use the structured exception handling capabilities present in the
  93. system to gaurd access through pointers that it does not control.
  94. Arguments:
  95. lpsz - Supplies the base address of the memory that is to be checked
  96. for read access and termination.
  97. cchMax - Supplies the length in bytes to be checked (including terminator).
  98. Return Value:
  99. TRUE - All bytes in the specified range are readable and the string is
  100. zero-terminated (or NULL pointer)
  101. FALSE - Either memory is not readable or there is no zero terminator.
  102. --*/
  103. {
  104. BOOL fSuccess = TRUE;
  105. DWORD i;
  106. //
  107. // We consider NULL pointer to be terminated
  108. //
  109. if( lpSz == NULL || cchMax == 0) {
  110. return TRUE;
  111. }
  112. //
  113. // Any non-NULL pointer we interrogate
  114. //
  115. __try {
  116. for( i = 0; i < cchMax && lpSz[i]; i++ ) {
  117. }
  118. return (i < cchMax);
  119. } __except( EXCEPTION_EXECUTE_HANDLER ) {
  120. return FALSE;
  121. }
  122. return TRUE;
  123. }
  124. /*******************************************
  125. * *
  126. * Local WAM_REQUEST methods *
  127. * *
  128. * *
  129. *******************************************/
  130. /*---------------------------------------------------------------------*
  131. WAM_REQUEST::WAM_REQUEST
  132. Constructor.
  133. Arguments:
  134. None
  135. Return Value:
  136. None
  137. */
  138. WAM_REQUEST::WAM_REQUEST(
  139. HTTP_REQUEST * pHttpRequest
  140. , EXEC_DESCRIPTOR * pExec
  141. , CWamInfo * pWamInfo
  142. )
  143. :
  144. m_dwSignature ( WAM_REQUEST_SIGNATURE )
  145. , m_pHttpRequest ( pHttpRequest )
  146. , m_pWamInfo ( pWamInfo )
  147. , m_dwWamVersion ( 0 )
  148. , m_pWamExecInfo ( NULL )
  149. , m_pExec ( pExec )
  150. , m_cRefs ( 0 )
  151. , m_hFileTfi ( INVALID_HANDLE_VALUE )
  152. , m_fWriteHeaders ( TRUE )
  153. , m_fFinishWamRequest ( FALSE )
  154. , m_pUnkFTM (NULL)
  155. , m_pszStatusTfi (NULL)
  156. , m_pszTailTfi (NULL)
  157. , m_pszHeadTfi (NULL)
  158. , m_fExpectCleanup (FALSE)
  159. , m_fPrepCleanupCalled (FALSE)
  160. , m_fCleanupCalled (FALSE)
  161. , m_pbAsyncReadOopBuffer(NULL)
  162. {
  163. DBG_ASSERT( m_pHttpRequest );
  164. DBG_ASSERT( m_pExec );
  165. DBG_ASSERT( m_pWamInfo );
  166. //
  167. // init list pointers
  168. //
  169. InitializeListHead(&m_leOOP);
  170. //
  171. // bind to our httpreq
  172. //
  173. BindHttpRequest();
  174. #if DBG
  175. //
  176. // produce precise request ID for debbuging/perf work
  177. //
  178. m_dwRequestID = InterlockedIncrement( (LONG *) &sm_dwRequestID );
  179. #else
  180. //
  181. // we can live with approximately correct result
  182. // (we don't want to pay the price of InterlockedIncrement)
  183. //
  184. m_dwRequestID = sm_dwRequestID++;
  185. #endif
  186. }
  187. /*---------------------------------------------------------------------*
  188. WAM_REQUEST::~WAM_REQUEST
  189. Destructor.
  190. Arguments:
  191. None
  192. Return Value:
  193. None
  194. */
  195. WAM_REQUEST::~WAM_REQUEST(
  196. )
  197. {
  198. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  199. //
  200. // If waminfo is oop, then this call removes this from the active
  201. // list of wamreqests.
  202. //
  203. m_pWamInfo->LeaveOOPZone(this, TRUE);
  204. m_pWamInfo->Dereference();
  205. //
  206. // if not a child request, take cleanup actions
  207. //
  208. // NOTE we don't take cleanup actions on a child request
  209. // because these actions are inherently 'connection-oriented',
  210. // i.e. they should only be done once per client connection
  211. // (for example, could result in disconnecting the client, etc)
  212. //
  213. if( DoCleanupOnDestroy() && !IsChild() )
  214. {
  215. //
  216. // Write log record.
  217. //
  218. m_pHttpRequest->WriteLogRecord();
  219. //
  220. // We must later call FinishWamRequest() from destructor
  221. // if we are in non-error state - set m_fFinishWamRequest
  222. // to tell us if we need to do this.
  223. //
  224. // See bug 109159.
  225. //
  226. // NOTE only here (and NOT in PrepCleanupWamRequest), do we
  227. // potentially set flag true. This is because mainline thread,
  228. // which only calls PrepCleanupWamRequest, has its own restart
  229. // logic, hence should never call FinishWamRequest().
  230. //
  231. m_fFinishWamRequest = (m_pHttpRequest->QueryIOStatus() == NO_ERROR);
  232. IF_DEBUG( ERROR ) {
  233. if ( !m_fFinishWamRequest ){
  234. DBGPRINTF((
  235. DBG_CONTEXT
  236. , "WAM_REQUEST[%p]::CleanupWamRequest "
  237. "async i/o failed "
  238. "m_pHttpRequest[%p] "
  239. "pClientConn[%p] "
  240. "m_pHttpRequest->QueryIOStatus()(%d) "
  241. "\n"
  242. , this
  243. , m_pHttpRequest
  244. , m_pHttpRequest->QueryClientConn()
  245. , m_pHttpRequest->QueryIOStatus()
  246. ));
  247. }
  248. }
  249. }
  250. //
  251. // ********* THREAD RACE ALERT ************************************
  252. //
  253. // We do our final cleanup in this EXACT order:
  254. //
  255. // 1) unbind that which must be unbound before we can finish
  256. // (i.e. that which would cause a race on the httpreq)
  257. //
  258. // 2) if required, finish the request
  259. //
  260. // 3) unbind that which was required to finish the request
  261. //
  262. // ********* ANY OTHER USE VOIDS WARRANTY *************************
  263. //
  264. UnbindBeforeFinish();
  265. if ( m_fFinishWamRequest ) {
  266. FinishWamRequest();
  267. }
  268. UnbindAfterFinish();
  269. //
  270. // Close file handle used for TransmitFile ops
  271. // NOTE normally, handle will be closed (and invalid) by now.
  272. // We do one last check to cover potential error cases.
  273. //
  274. if ( m_hFileTfi != INVALID_HANDLE_VALUE ) {
  275. DBG_ASSERT( !(m_pWamInfo->FInProcess()) );
  276. CloseHandle( m_hFileTfi );
  277. m_hFileTfi = INVALID_HANDLE_VALUE;
  278. }
  279. //
  280. // Ditto for TFI strings (if any)
  281. //
  282. if ( m_pszStatusTfi != NULL )
  283. {
  284. LocalFree( m_pszStatusTfi );
  285. m_pszStatusTfi = NULL;
  286. }
  287. if ( m_pszTailTfi != NULL )
  288. {
  289. LocalFree( m_pszTailTfi );
  290. m_pszTailTfi = NULL;
  291. }
  292. if ( m_pszHeadTfi != NULL )
  293. {
  294. LocalFree( m_pszHeadTfi );
  295. m_pszHeadTfi = NULL;
  296. }
  297. //
  298. // At last possible moment, right before we free the memory,
  299. // set various object state that is useful for debugging
  300. //
  301. // set this object's signature to its 'free' value
  302. m_dwSignature = WAM_REQUEST_SIGNATURE_FREE;
  303. #if DBG
  304. // write thread id into second dword of this object's memory
  305. // (alloc cache stores next-ptr in 1st dword, so we use 2nd slot)
  306. *( (DWORD *)this + 1 ) = GetCurrentThreadId();
  307. #endif
  308. if (m_pUnkFTM != NULL)
  309. {
  310. m_pUnkFTM->Release();
  311. }
  312. m_leOOP.Flink = NULL;
  313. m_leOOP.Blink = NULL;
  314. }
  315. /*---------------------------------------------------------------------*
  316. WAM_REQUEST::InitWamRequest
  317. Initializes WAM_REQUEST object.
  318. Arguments:
  319. Return Value:
  320. HRESULT
  321. */
  322. HRESULT
  323. WAM_REQUEST::InitWamRequest(
  324. const STR * pstrPath
  325. )
  326. {
  327. HRESULT hr;
  328. hr = CoCreateFreeThreadedMarshaler(this, &m_pUnkFTM);
  329. if ( FAILED(hr) ) {
  330. return hr;
  331. }
  332. //
  333. // copy dll path and path-trans
  334. //
  335. if( !m_strISADllPath.Copy( *pstrPath ) ) {
  336. return HresultFromBool( FALSE );
  337. }
  338. if( !SetPathTrans() ) {
  339. return HresultFromBool( FALSE );
  340. }
  341. DBG_ASSERT( m_pHttpRequest );
  342. if( !m_pHttpRequest->GetInfo(
  343. "HTTP_USER_AGENT",
  344. &m_strUserAgent
  345. ) )
  346. {
  347. m_strUserAgent.Reset();
  348. }
  349. if( !m_pHttpRequest->GetInfo(
  350. "HTTP_COOKIE",
  351. &m_strCookie
  352. ) )
  353. {
  354. m_strCookie.Reset();
  355. }
  356. // build the ExpireHeader
  357. LPSTR lpszExpires = NULL;
  358. CHAR achTime[128];
  359. // obtain a pointer to the MetaData object
  360. PW3_METADATA pMetaData = m_pHttpRequest->QueryMetaData();
  361. ASSERT(pMetaData);
  362. // switch on the mode. One of STATIC or DYNAMIC
  363. switch(pMetaData->QueryExpireMode()) {
  364. // if STATIC, the ExpireHeader is already built up
  365. case EXPIRE_MODE_STATIC :
  366. lpszExpires = m_pHttpRequest->QueryExpireHeader();
  367. break;
  368. // if DYNAMIC, then the ExpireHeader must be built here.
  369. // The MetaData has the ExpireDelta which is added to the
  370. // current time and built up into a full Expires header.
  371. case EXPIRE_MODE_DYNAMIC :
  372. DWORD dwDelta = pMetaData->QueryExpireDelta();
  373. SYSTEMTIME SysTime;
  374. char *p = achTime;
  375. ::IISGetCurrentTimeAsSystemTime( &SysTime );
  376. strcpy(p, "Expires: ");
  377. p += (sizeof("Expires: ") - 1);
  378. // if SystemTimeToGMTEx fails, silently fail leaving
  379. // lpszExpires as NULL
  380. if ( ::SystemTimeToGMTEx( SysTime,
  381. p,
  382. sizeof(achTime),
  383. dwDelta ))
  384. {
  385. lpszExpires = achTime;
  386. p += strlen(p);
  387. strcpy(p, "\r\n");
  388. }
  389. break;
  390. }
  391. if( lpszExpires ) {
  392. m_strExpires.Copy( lpszExpires );
  393. } else {
  394. m_strExpires.Reset();
  395. }
  396. return NOERROR;
  397. }
  398. /*---------------------------------------------------------------------*
  399. WAM_REQUEST::BindHttpRequest
  400. "Binds" this wamreq to its associated httpreq and refs the httpreq.
  401. Bind ==
  402. 1) ref httpreq
  403. 2) set this wamreq's pointer into httpreq
  404. 3) increment httpreq stats counter
  405. NOTE we invert this function in two phases, with UnbindBeforeFinish
  406. and UnbindAfterFinish.
  407. Arguments:
  408. None
  409. Return Value:
  410. None
  411. */
  412. VOID
  413. WAM_REQUEST::BindHttpRequest(
  414. )
  415. {
  416. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  417. DBG_ASSERT( m_pHttpRequest );
  418. DBG_ASSERT( m_pExec );
  419. //
  420. // set httpreq's wamreq ptr to this wamreq
  421. // and ref httpreq (which actually refs client-conn)
  422. //
  423. // NOTE we set wamreq ptr first so that it will show
  424. // up in client-conn's ref trace log.
  425. //
  426. DBG_ASSERT( m_pHttpRequest->QueryWamRequest() == NULL );
  427. m_pHttpRequest->SetWamRequest( this );
  428. m_pHttpRequest->Reference();
  429. //
  430. // Increment stats counter.
  431. //
  432. m_pHttpRequest->QueryW3StatsObj()->IncrBGIRequests();
  433. //
  434. // The child request completion event is set in Unbind().
  435. // Here in Bind() the fact that we got this far means that
  436. // Unbind() will get executed, and thus we mark the child
  437. // compeletion as 'must wait for'.
  438. //
  439. if (IsChild()) {
  440. m_pExec->SetMustWaitForChildEvent();
  441. }
  442. } // WAM_REQUEST::BindHttpRequest
  443. /*-----------------------------------------------------------------------------*
  444. WAM_REQUEST::UnbindBeforeFinish
  445. "Unbinds" the parts of the httpreq and its embedded exec descriptor
  446. which ***MUST*** be done before attempting to finish the request.
  447. NOTE include in this function any operation which would cause a race
  448. on the httpreq if we did it after another thread gets the httpreq.
  449. Arguments:
  450. None
  451. Returns:
  452. None
  453. */
  454. VOID
  455. WAM_REQUEST::UnbindBeforeFinish(
  456. )
  457. {
  458. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  459. DBG_ASSERT( m_pHttpRequest != NULL );
  460. DBG_ASSERT( m_pExec != NULL );
  461. //
  462. // null out the wamreq ptr stored in httpreq,
  463. //
  464. DBG_ASSERT( m_pHttpRequest->QueryWamRequest() == this );
  465. m_pHttpRequest->SetWamRequest( NULL );
  466. return;
  467. } // WAM_REQUEST::UnbindBeforeFinish()
  468. /*---------------------------------------------------------------------*
  469. WAM_REQUEST::UnbindAfterFinish
  470. "Unbinds" the parts of the httpreq and its embedded exec descriptor
  471. which are required to finish the request, and which hence
  472. may not be done until after attempting to finish the request.
  473. NOTE ***DO NOT*** include in this function any operation which
  474. would cause a race on the httpreq if we did it after another thread
  475. gets the httpreq.
  476. Arguments:
  477. None
  478. Return Value:
  479. None
  480. */
  481. VOID
  482. WAM_REQUEST::UnbindAfterFinish(
  483. )
  484. {
  485. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  486. DBG_ASSERT( m_pHttpRequest != NULL );
  487. //
  488. // Decrement stats counter.
  489. //
  490. m_pHttpRequest->QueryW3StatsObj()->DecrCurrentBGIRequests();
  491. //
  492. // If this is a child request, set its event,
  493. // which allows parent request to continue processing
  494. //
  495. if ( IsChild() ) {
  496. m_pExec->SetChildEvent();
  497. }
  498. //
  499. // Now that we are done with exec, null out our ptr
  500. //
  501. m_pExec = NULL;
  502. DBG_ASSERT( m_pWamInfo != NULL );
  503. //
  504. // If this is a crashed oop request, disconnect
  505. //
  506. // NOTE crashed ==> current wam version differs from
  507. // the one we cached in this wamreq when it was created
  508. //
  509. if ( m_pWamInfo->FInProcess() == FALSE ) {
  510. if ( ((CWamInfoOutProc *)m_pWamInfo)
  511. ->GetWamVersion() != m_dwWamVersion ) {
  512. //
  513. // NOTE this is safe even if we have already called Disconnect()
  514. // because Disconnect() no-ops if it was already called
  515. //
  516. m_pHttpRequest->Disconnect(
  517. 0
  518. , NO_ERROR
  519. , TRUE // fShutdown
  520. );
  521. }
  522. }
  523. //
  524. // Now that we are done with httpreq, deref it and null out our ptr
  525. //
  526. DereferenceConn( m_pHttpRequest->QueryClientConn() );
  527. m_pHttpRequest = NULL;
  528. } // WAM_REQUEST::UnbindAfterFinish
  529. VOID
  530. WAM_REQUEST::DisconnectOnServerError(
  531. DWORD dwHTHeader,
  532. DWORD dwError
  533. )
  534. {
  535. m_pHttpRequest->Disconnect(dwHTHeader, dwError);
  536. }
  537. /*---------------------------------------------------------------------*
  538. WAM_REQUEST::FinishWamRequest
  539. Description:
  540. Finishes this wam request - should only be call from destructor,
  541. and only if cleanup was done by isapi callback thread.
  542. ANY OTHER USE VOIDS WARRANTY.
  543. Arguments:
  544. None
  545. Returns:
  546. Nothing
  547. */
  548. VOID
  549. WAM_REQUEST::FinishWamRequest(
  550. )
  551. {
  552. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  553. DBG_ASSERT( m_pHttpRequest );
  554. BOOL fDoAgain = FALSE; // do we need to post completion status?
  555. if ( !m_pHttpRequest->IsKeepConnSet() ) {
  556. //
  557. // If keep-alive is not set, disconnect.
  558. //
  559. m_pHttpRequest->Disconnect( 0, NO_ERROR, TRUE );
  560. } else {
  561. //
  562. // If keep-alive is set, start up a new session
  563. //
  564. if ( !m_pHttpRequest->QueryClientConn()->OnSessionStartup(
  565. &fDoAgain ) ) {
  566. //
  567. // Disconnect with error if startup failed
  568. //
  569. m_pHttpRequest->Disconnect(
  570. HT_SERVER_ERROR
  571. , GetLastError()
  572. , TRUE
  573. );
  574. }
  575. }
  576. //
  577. // If OnSessionStartup returned do-again TRUE,
  578. // post completion status.
  579. //
  580. if ( fDoAgain ) {
  581. if ( !m_pHttpRequest->QueryClientConn()->PostCompletionStatus(
  582. m_pHttpRequest->QueryBytesWritten() ) ) {
  583. //
  584. // Disconnect with error if post failed
  585. //
  586. m_pHttpRequest->Disconnect(
  587. HT_SERVER_ERROR
  588. , GetLastError()
  589. , TRUE
  590. );
  591. }
  592. }
  593. return;
  594. } // WAM_REQUEST::FinishWamRequest()
  595. /*-----------------------------------------------------------------------------*
  596. WAM_REQUEST::QueryInterface
  597. COM implementation
  598. Arguments:
  599. The usual ones.
  600. Returns:
  601. HRESULT
  602. */
  603. HRESULT
  604. WAM_REQUEST::QueryInterface
  605. (
  606. REFIID riid,
  607. void __RPC_FAR *__RPC_FAR *ppvObject
  608. )
  609. {
  610. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  611. DBG_ASSERT( ppvObject );
  612. *ppvObject = NULL;
  613. IF_DEBUG( IID )
  614. {
  615. DBGPRINTF(( DBG_CONTEXT,
  616. "WAM_REQUEST::QueryInterface looking for ... ( " GUID_FORMAT " )\n",
  617. GUID_EXPAND( &riid) ));
  618. }
  619. if( riid == IID_IWamRequest )
  620. {
  621. *ppvObject = static_cast<IWamRequest *>( this );
  622. }
  623. else if ( riid == IID_IMarshal )
  624. {
  625. if (m_pUnkFTM == NULL)
  626. {
  627. DBG_ASSERT(FALSE);
  628. return E_NOINTERFACE;
  629. }
  630. else
  631. {
  632. return m_pUnkFTM->QueryInterface(riid, ppvObject);
  633. }
  634. }
  635. else if( riid == IID_IUnknown )
  636. {
  637. *ppvObject = static_cast<IWamRequest *>( this );
  638. }
  639. else if (m_pUnkFTM != NULL)
  640. {
  641. return m_pUnkFTM->QueryInterface(riid, ppvObject);
  642. }
  643. else
  644. {
  645. return E_NOINTERFACE;
  646. }
  647. DBG_ASSERT( *ppvObject );
  648. ((IUnknown *)*ppvObject)->AddRef();
  649. IF_DEBUG( IID )
  650. {
  651. DBGPRINTF(( DBG_CONTEXT,
  652. "WAM_REQUEST::QueryInterface found ( " GUID_FORMAT ", %p )\n",
  653. GUID_EXPAND( &riid),
  654. *ppvObject ));
  655. }
  656. return NOERROR;
  657. }
  658. /*---------------------------------------------------------------------*
  659. Support for debug ref trace logging
  660. */
  661. #define WR_LOG_REF_COUNT( cRefs ) \
  662. \
  663. if( sm_pDbgRefTraceLog != NULL ) { \
  664. \
  665. WriteRefTraceLogEx( \
  666. sm_pDbgRefTraceLog \
  667. , cRefs \
  668. , (PVOID) this \
  669. , m_pHttpRequest \
  670. , m_pExec \
  671. , m_pHttpRequest \
  672. ? m_pHttpRequest->QueryClientConn() \
  673. : NULL \
  674. ); \
  675. } \
  676. #define WR_SHARED_LOG_REF_COUNT( cRefs ) \
  677. \
  678. SHARED_LOG_REF_COUNT( \
  679. cRefs \
  680. , m_pHttpRequest \
  681. ? m_pHttpRequest->QueryClientConn() \
  682. : NULL \
  683. , m_pHttpRequest \
  684. , this \
  685. , m_pHttpRequest \
  686. ? m_pHttpRequest->QueryState() \
  687. : NULL \
  688. ); \
  689. /*---------------------------------------------------------------------*
  690. WAM_REQUEST::AddRef
  691. Addrefs wamreq
  692. Arguments:
  693. None
  694. Returns:
  695. Refcount
  696. */
  697. ULONG
  698. WAM_REQUEST::AddRef( )
  699. {
  700. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  701. IF_DEBUG( BGI ) {
  702. DBGPRINTF((
  703. DBG_CONTEXT
  704. , "WAM_REQUEST(%p) AddRef: %d -> %d\n"
  705. , this
  706. , m_cRefs
  707. , m_cRefs + 1
  708. ));
  709. }
  710. LONG cRefs = InterlockedIncrement( &m_cRefs );
  711. #if DBG
  712. //
  713. // Write to both wamreq trace log and shared trace log
  714. //
  715. WR_LOG_REF_COUNT( cRefs );
  716. WR_SHARED_LOG_REF_COUNT( cRefs );
  717. #endif
  718. return cRefs;
  719. }
  720. /*---------------------------------------------------------------------*
  721. WAM_REQUEST::Release
  722. Releases wamreq
  723. Arguments:
  724. None
  725. Returns:
  726. Refcount
  727. */
  728. ULONG
  729. WAM_REQUEST::Release( )
  730. {
  731. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  732. IF_DEBUG( BGI ) {
  733. DBGPRINTF((
  734. DBG_CONTEXT
  735. , "WAM_REQUEST(%p) Release: %d -> %d\n"
  736. , this
  737. , m_cRefs
  738. , m_cRefs - 1
  739. ));
  740. }
  741. #if DBG
  742. LONG cRefsAfter = m_cRefs - 1;
  743. //
  744. // Write to both wamreq trace log and shared trace log
  745. //
  746. // NOTE write the trace log BEFORE the decrement operation :(
  747. // If we write it after the decrement, we will run into potential
  748. // race conditions in this object getting freed up accidentally
  749. // by another thread
  750. //
  751. // NOTE we write ref count AFTER decrement happens
  752. //
  753. WR_LOG_REF_COUNT( cRefsAfter );
  754. WR_SHARED_LOG_REF_COUNT( cRefsAfter );
  755. #endif
  756. LONG cRefs = InterlockedDecrement( &m_cRefs );
  757. if( cRefs == 0 ) {
  758. IF_DEBUG( BGI ) {
  759. DBGPRINTF((
  760. DBG_CONTEXT
  761. , "WAM_REQUEST(%p) dying when ref = %d.\n"
  762. , this
  763. , cRefs
  764. ));
  765. }
  766. delete this;
  767. return 0;
  768. }
  769. return cRefs;
  770. }
  771. /*---------------------------------------------------------------------*
  772. // Interlocked Increment only if non zero
  773. //
  774. // Returns 0 or value after increment
  775. //
  776. */
  777. LONG
  778. WAM_REQUEST::InterlockedNonZeroAddRef(VOID)
  779. {
  780. while (TRUE)
  781. {
  782. LONG l = m_cRefs;
  783. if (l == 0)
  784. {
  785. return 0;
  786. }
  787. if (g_pfnInterlockedCompareExchange(&m_cRefs, l+1, l) == l)
  788. {
  789. return l+1;
  790. }
  791. }
  792. }
  793. /*---------------------------------------------------------------------*
  794. WAM_REQUEST::WriteLogInfo
  795. Writes information to the IIS log.
  796. Arguments:
  797. None
  798. Returns:
  799. None
  800. */
  801. BOOL
  802. WAM_REQUEST::WriteLogInfo(
  803. CHAR * szLogMessage
  804. , DWORD dwLogHttpResponse
  805. , DWORD dwLogWinError
  806. )
  807. {
  808. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  809. if ( m_pHttpRequest == NULL ) {
  810. return FALSE;
  811. }
  812. if ( !m_pHttpRequest->AppendLogParameter( szLogMessage ) ) {
  813. return FALSE;
  814. }
  815. m_pHttpRequest->SetLogStatus( dwLogHttpResponse,dwLogWinError );
  816. return m_pHttpRequest->WriteLogRecord();
  817. } // WAM_REQUEST::WriteLogInfo()
  818. /*-----------------------------------------------------------------------------*
  819. NOTE on PrepCleanupWamRequest and CleanupWamRequest:
  820. Our cleanup policy depends on whether the request gets cleaned up by
  821. the mainline thread or the isapi callback thread.
  822. If the mainline thread does cleanup, it calls PrepCleanupWamRequest
  823. and relies on its higher-level callers (DoWork et al) to handle the
  824. remaining cleanup tasks.
  825. If the isapi callback thread does cleanup, it calls CleanupWamRequest,
  826. which in turn calls PrepCleanupWamRequest, and does all cleanup tasks
  827. itself. (In this case, of course, there are no higher-level callers
  828. to rely upon).
  829. */
  830. /*-----------------------------------------------------------------------------*
  831. WAM_REQUEST::PrepCleanupWamRequest
  832. Description:
  833. Preps for CleanupWamRequest
  834. Arguments:
  835. Below
  836. Returns:
  837. HRESULT
  838. */
  839. HRESULT
  840. WAM_REQUEST::PrepCleanupWamRequest(
  841. unsigned char * szLogData // log data buffer
  842. , DWORD cbLogData // size of log data buffer
  843. , DWORD dwHttpStatusCode // HTTP Status code from ecb
  844. , DWORD dwIsaKeepConn // keep/close/no-change connection?
  845. )
  846. {
  847. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  848. DBG_ASSERT( m_pHttpRequest );
  849. DBG_ASSERT( m_pExec );
  850. DBG_ASSERT( m_fFinishWamRequest == FALSE );
  851. m_fPrepCleanupCalled = TRUE;
  852. //
  853. // Append log info to logfile parameters and set log status
  854. //
  855. // UNDONE This is a little bit bogus, we're not translating
  856. // the win32 error code based on the HTTP status code
  857. //
  858. //
  859. // String should be zero-terminated (#157805)
  860. //
  861. if( IsStringTerminated( (LPCSTR) szLogData, cbLogData ) ) {
  862. m_pHttpRequest->AppendLogParameter( (char*) szLogData );
  863. }
  864. m_pHttpRequest->SetLogStatus( dwHttpStatusCode, NO_ERROR );
  865. /*
  866. Keep-conn logic works like this:
  867. If ISA asked us NOT to keep-conn, or if this is an old ISA
  868. (which implicitly assumed we would close the connection)
  869. set client keep-conn false.
  870. Else, leave client keep-conn unchanged.
  871. NOTE: At the end of the day we want the connection kept open
  872. if and only if BOTH the client and the ISA said to keep it open;
  873. and, the connection will be kept open or closed based on the
  874. state of the client's keep-conn flag when cleanup runs later on.
  875. This function accomplishes the goal as follows (Yes == keep-conn):
  876. Client ISA This function End result
  877. ------ --- ------------- ----------
  878. Yes Yes Does nothing Connection will be kept open
  879. Yes No Sets client flag false Connection will be closed
  880. No Yes Does nothing Connection will be closed
  881. No No Sets client flag false Connection will be closed
  882. */
  883. if ( dwIsaKeepConn == KEEPCONN_FALSE
  884. || dwIsaKeepConn == KEEPCONN_OLD_ISAPI ) {
  885. SetKeepConn( FALSE );
  886. }
  887. return NOERROR;
  888. } // WAM_REQUEST::PrepCleanupWamRequest
  889. /*---------------------------------------------------------------------*
  890. WAM_REQUEST::CleanupWamRequest
  891. Description:
  892. Cleans up wamreq.
  893. NOTE this function replaces cleanup code which in IIS 3.0
  894. resided in ServerSupportFunction and should be called
  895. ONLY from ServerSupportFunction on isapi callback thread.
  896. See comments in PrepCleanupWamRequest for more details.
  897. ANY OTHER USE VOIDS WARRANTY.
  898. [When mainline thread does cleanup, it happens elsewhere.]
  899. Arguments:
  900. Below
  901. Returns:
  902. HRESULT
  903. */
  904. HRESULT
  905. WAM_REQUEST::CleanupWamRequest(
  906. unsigned char * szLogData // log data buffer
  907. , DWORD cbLogData // size of log data buffer
  908. , DWORD dwHttpStatusCode // HTTP Status code from ecb
  909. , DWORD dwIsaKeepConn // keep/close/no-change connection?
  910. )
  911. {
  912. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  913. DBG_ASSERT( m_pHttpRequest );
  914. DBG_ASSERT( m_pExec );
  915. #if CC_REF_TRACKING
  916. //
  917. // log to our various ref logs
  918. //
  919. // NOTE negative indicates no change to ref count
  920. //
  921. #if DBG
  922. WR_LOG_REF_COUNT( -m_cRefs );
  923. WR_SHARED_LOG_REF_COUNT( -m_cRefs );
  924. #endif // DBG
  925. //
  926. // log to local (per-object) CLIENT_CONN log
  927. //
  928. LogRefCountCCLocal(
  929. - m_cRefs
  930. , m_pHttpRequest
  931. ? m_pHttpRequest->QueryClientConn()
  932. : NULL
  933. , m_pHttpRequest
  934. , this
  935. , m_pHttpRequest
  936. ? m_pHttpRequest->QueryState()
  937. : NULL
  938. );
  939. #endif // CC_REF_TRACKING
  940. m_fCleanupCalled = TRUE;
  941. PrepCleanupWamRequest(
  942. szLogData
  943. , cbLogData
  944. , dwHttpStatusCode
  945. , dwIsaKeepConn
  946. );
  947. return NOERROR;
  948. } // WAM_REQUEST::CleanupWamRequest
  949. /*-----------------------------------------------------------------------------*
  950. WAM_REQUEST::IsChild
  951. Is this a child request?
  952. Arguments:
  953. None
  954. Returns:
  955. BOOL
  956. */
  957. BOOL
  958. WAM_REQUEST::IsChild( VOID ) const
  959. {
  960. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  961. return m_pExec && m_pExec->IsChild();
  962. }
  963. /*-----------------------------------------------------------------------------*
  964. WAM_REQUEST::QueryExecMetaData
  965. Metadata pointer from m_pExec member
  966. Arguments:
  967. None
  968. Returns:
  969. PW3_METADATA
  970. */
  971. PW3_METADATA
  972. WAM_REQUEST::QueryExecMetaData( VOID ) const
  973. {
  974. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  975. return m_pExec ? m_pExec->QueryMetaData() : NULL;
  976. }
  977. /*-----------------------------------------------------------------------------*
  978. WAM_REQUEST::SetPathTrans
  979. Sets path-trans member
  980. Arguments:
  981. None
  982. Returns:
  983. BOOL
  984. */
  985. BOOL
  986. WAM_REQUEST::SetPathTrans( )
  987. {
  988. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  989. DBG_ASSERT( m_pHttpRequest );
  990. DBG_ASSERT( m_pExec );
  991. DBG_ASSERT( m_pExec->_pstrPathInfo );
  992. DBG_ASSERT( m_pExec->_pstrPathInfo->QueryStr() );
  993. //
  994. // If path-info is identical to the URL, as will be the case when script
  995. // mapping is used (i.e. the image name is not in the URL),
  996. // then path-tran is simply physical path, verbatim.
  997. // Else we need to get path-tran from vroot lookup.
  998. //
  999. DWORD cchURL = m_pHttpRequest->QueryURLStr().QueryCCH();
  1000. if( ( m_pExec->_pstrPathInfo->QueryCCH() == cchURL )
  1001. && !memcmp( m_pExec->_pstrPathInfo->QueryStr(),
  1002. m_pHttpRequest->QueryURLStr().QueryStr(), cchURL ) )
  1003. {
  1004. if( !m_strPathTrans.Copy( m_pHttpRequest->QueryPhysicalPathStr() ) )
  1005. {
  1006. DBGPRINTF((
  1007. DBG_CONTEXT
  1008. , "WAM_REQUEST[%p]::SetPathTrans failed "
  1009. "due to STR::Copy failure\n"
  1010. , this
  1011. ));
  1012. return FALSE;
  1013. }
  1014. }
  1015. else
  1016. {
  1017. //
  1018. // ISAPI Specifies that the pathTrans will contain the
  1019. // Path xlated for the path specified in 'PathInfo'
  1020. // Do the Virtual Root Lookup now.
  1021. //
  1022. // NOTE since we are passing in metadata ptrs,
  1023. // callee will not free, so we need to do this ourselves
  1024. // (we free in destructor)
  1025. //
  1026. if( !m_pHttpRequest->
  1027. LookupVirtualRoot( &m_strPathTrans,
  1028. m_pExec->_pstrPathInfo->QueryStr(),
  1029. m_pExec->_pstrPathInfo->QueryCCH(),
  1030. NULL,
  1031. NULL,
  1032. NULL,
  1033. NULL,
  1034. FALSE,
  1035. &m_pExec->_pPathInfoMetaData,
  1036. &m_pExec->_pPathInfoURIBlob ) )
  1037. {
  1038. DBGPRINTF((
  1039. DBG_CONTEXT
  1040. , "WAM_REQUEST[%p]::SetPathTrans failed "
  1041. "due to LookupVirtualRoot failure\n"
  1042. , this
  1043. ));
  1044. return FALSE;
  1045. }
  1046. }
  1047. return TRUE;
  1048. } // WAM_REQUEST::SetPathTrans()
  1049. /*-----------------------------------------------------------------------------*
  1050. WAM_REQUEST::CbWrcStrings
  1051. Returns count of bytes required for wamreq core strings
  1052. Arguments:
  1053. None
  1054. Returns:
  1055. Count of bytes required for wamreq core strings, including null-terminators
  1056. */
  1057. DWORD
  1058. WAM_REQUEST::CbWrcStrings
  1059. (
  1060. BOOL fInProcess
  1061. )
  1062. {
  1063. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1064. DBG_ASSERT( m_pExec );
  1065. DBG_ASSERT( m_pHttpRequest );
  1066. /* sync WRC_STRINGS */
  1067. DWORD cbRet = 1 + m_pExec->_pstrPathInfo->QueryCCH()
  1068. + 1 + m_strPathTrans.QueryCCH()
  1069. + 1 + m_pHttpRequest->QueryMethodStr().QueryCCH()
  1070. + 1 + m_pHttpRequest->QueryContentTypeStr().QueryCCH()
  1071. + 1 + m_pHttpRequest->QueryURLStr().QueryCCH()
  1072. + 1 + m_strISADllPath.QueryCCH()
  1073. + 1 + m_pExec->_pstrURLParams->QueryCCH()
  1074. + 1 + m_pHttpRequest->GetWAMMetaData()->QueryAppPath()->QueryCCH()
  1075. + 1 + m_strUserAgent.QueryCCH()
  1076. + 1 + m_strCookie.QueryCCH()
  1077. + 1 + m_strExpires.QueryCCH()
  1078. ;
  1079. /* sync WRC_STRINGS */
  1080. if( !fInProcess )
  1081. {
  1082. // if out-of-proc, allow for entity body in buffer
  1083. // NOTE no null terminator
  1084. cbRet += m_pHttpRequest->QueryEntityBodyCB();
  1085. }
  1086. return cbRet;
  1087. }
  1088. DWORD
  1089. WAM_REQUEST::CbCachedSVStrings(
  1090. IN SV_CACHE_LIST::BUFFER_ITEM * pCacheItems,
  1091. IN DWORD cItems
  1092. )
  1093. {
  1094. DWORD dwTotalBytesRequired = 0;
  1095. for( DWORD i = 0; i < cItems; ++i )
  1096. {
  1097. //
  1098. // We store the number of characters required for each string
  1099. // in dwOffset before we get the actual values. Once the values
  1100. // are retrieved, dwOffset contains the offset into the value
  1101. // buffer or an error code that should be returned to the client.
  1102. //
  1103. LPDWORD pcchRequired = &(pCacheItems[i].dwOffset);
  1104. DWORD svid = pCacheItems[i].svid;
  1105. LPCSTR pszVariableName =
  1106. g_pWamDictator->QueryServerVariableMap().FindName(svid);
  1107. BOOL fSuccess = m_pHttpRequest->GetInfoForName( pszVariableName,
  1108. NULL,
  1109. pcchRequired
  1110. );
  1111. if( !fSuccess )
  1112. {
  1113. // This is really all debug code. Should remove...
  1114. // But it will probably all optimize away.
  1115. DWORD dwError = GetLastError();
  1116. if( dwError != ERROR_INSUFFICIENT_BUFFER )
  1117. {
  1118. // This will happen for HTTP_ variables that were
  1119. // not sent by the client, not a problem. We'll
  1120. // handle in WAM_REQUEST::GetCachedSVStrings
  1121. DBG_ASSERT( *pcchRequired == 0 );
  1122. }
  1123. else
  1124. {
  1125. // Normal case
  1126. DBG_ASSERT( *pcchRequired > 0 );
  1127. }
  1128. }
  1129. dwTotalBytesRequired += *pcchRequired;
  1130. }
  1131. return dwTotalBytesRequired;
  1132. }
  1133. HRESULT
  1134. WAM_REQUEST::GetCachedSVStrings(
  1135. IN OUT unsigned char * pbServerVariables,
  1136. IN DWORD cchAvailable,
  1137. IN SV_CACHE_LIST::BUFFER_ITEM * pCacheItems,
  1138. IN DWORD cCacheItems
  1139. )
  1140. {
  1141. DBG_ASSERT( pbServerVariables );
  1142. DBG_ASSERT( pCacheItems );
  1143. HRESULT hr = NOERROR;
  1144. DWORD cchRemainingBuffer;
  1145. DWORD cchValue;
  1146. DWORD dwOffset = 0;
  1147. for( DWORD i = 0; i < cCacheItems; ++i )
  1148. {
  1149. DWORD svid = pCacheItems[i].svid;
  1150. LPCSTR pszVariableName =
  1151. g_pWamDictator->QueryServerVariableMap().FindName(svid);
  1152. // Test <= because the last server variable may be one that
  1153. // produces an error. In that case cchRemainingBuffer will
  1154. // be 0 which will still generate the correct result.
  1155. if( dwOffset <= cchAvailable )
  1156. {
  1157. cchRemainingBuffer = cchAvailable - dwOffset;
  1158. cchValue = pCacheItems[i].dwOffset;
  1159. DBG_ASSERT( cchRemainingBuffer >= cchValue );
  1160. if( m_pHttpRequest->GetInfoForName( pszVariableName,
  1161. (LPSTR)pbServerVariables + dwOffset,
  1162. &cchValue
  1163. ) )
  1164. {
  1165. pCacheItems[i].dwOffset = dwOffset;
  1166. dwOffset += cchValue;
  1167. // Buffer over run.
  1168. DBG_ASSERT( dwOffset <= cchAvailable );
  1169. }
  1170. else
  1171. {
  1172. DWORD dwError = GetLastError();
  1173. DBG_ASSERT( dwError != ERROR_SUCCESS );
  1174. switch( dwError )
  1175. {
  1176. // Could collapse these into two cases...
  1177. case ERROR_INVALID_INDEX:
  1178. //
  1179. // This is expected if the server variable
  1180. // is unknown. This should only happen
  1181. // for HTTP_ server variables that were not
  1182. // sent by the client. Set the error, so we
  1183. // can return this to the client
  1184. //
  1185. pCacheItems[i].dwOffset = HRESULT_FROM_WIN32(dwError);
  1186. break;
  1187. case ERROR_INSUFFICIENT_BUFFER:
  1188. //
  1189. // This shouldn't happen.
  1190. // Mark this as not cached.
  1191. //
  1192. DBG_ASSERT(FALSE);
  1193. pCacheItems[i].dwOffset = SV_DATA_INVALID_OFFSET;
  1194. break;
  1195. case ERROR_NO_DATA:
  1196. //
  1197. // According to the documentation, but not the code,
  1198. // we can return this value.
  1199. //
  1200. pCacheItems[i].dwOffset = HRESULT_FROM_WIN32(dwError);
  1201. break;
  1202. case ERROR_INVALID_PARAMETER:
  1203. default:
  1204. //
  1205. // Anything else is bogus.
  1206. //
  1207. DBG_ASSERT(FALSE);
  1208. pCacheItems[i].dwOffset = SV_DATA_INVALID_OFFSET;
  1209. break;
  1210. }
  1211. DBGPRINTF(( DBG_CONTEXT,
  1212. "WAM_REQUEST[%p]::GetCachedSVStrings - Failed on "
  1213. "m_pHttpRequest->GetInfoForName( %s, ,%d ) : %08x\n",
  1214. this,
  1215. pszVariableName,
  1216. cchValue,
  1217. dwError
  1218. ));
  1219. }
  1220. }
  1221. else
  1222. {
  1223. // This should never happen
  1224. DBGPRINTF(( DBG_CONTEXT,
  1225. "WAM_REQUEST[%p]::GetCachedSVStrings() - "
  1226. "Insufficient buffer - cchAvailable(%d) dwOffset(%d)\n",
  1227. this,
  1228. cchAvailable,
  1229. dwOffset
  1230. ));
  1231. DBG_ASSERT(FALSE);
  1232. }
  1233. }
  1234. return hr;
  1235. }
  1236. /*---------------------------------------------------------------------*
  1237. WAM_REQUEST::ProcessAsyncGatewayIO
  1238. Processes async i/o for a pending wam request
  1239. Arguments:
  1240. dwStatus - i/o status
  1241. cbWritten - count of byte written
  1242. Returns:
  1243. HRESULT
  1244. */
  1245. HRESULT
  1246. WAM_REQUEST::ProcessAsyncGatewayIO(
  1247. DWORD dwStatus
  1248. , DWORD cbWritten
  1249. )
  1250. {
  1251. HRESULT hr = NOERROR;
  1252. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1253. DBG_ASSERT( m_cRefs > 0);
  1254. DBG_ASSERT( m_pHttpRequest );
  1255. IF_DEBUG( WAM_ISA_CALLS ) {
  1256. DBGPRINTF((
  1257. DBG_CONTEXT,
  1258. "WAM_REQUEST[%p]::ProcessAsyncGatewayIO\n"
  1259. , this
  1260. ));
  1261. }
  1262. DBG_ASSERT( m_pWamExecInfo );
  1263. if( !m_fAsyncWrite && m_pHttpRequest->IsChunked() && cbWritten ) {
  1264. //
  1265. // decode chunked data
  1266. //
  1267. DWORD cbToDecode = cbWritten;
  1268. if( m_pHttpRequest->DecodeChunkedBytes( m_pAsyncReadBuffer, &cbWritten ) ) {
  1269. if( cbWritten == 0 ) {
  1270. if( !m_pHttpRequest->IsChunkedReadComplete() ) {
  1271. //
  1272. // All the bytes we've read were headers or footers.
  1273. // We need to restart reading...
  1274. //
  1275. m_pHttpRequest->SetState(
  1276. HTR_GATEWAY_ASYNC_IO,
  1277. m_pHttpRequest->QueryLogHttpResponse(),
  1278. m_pHttpRequest->QueryLogWinError() );
  1279. if( m_pHttpRequest->ReadFile(
  1280. m_pAsyncReadBuffer
  1281. , m_dwAsyncReadBufferSize
  1282. , NULL
  1283. , IO_FLAG_ASYNC
  1284. ) )
  1285. {
  1286. //
  1287. // Successfuly restarted reading.
  1288. //
  1289. return NOERROR;
  1290. } else {
  1291. //
  1292. // Failed to restart reading -- undo the state change
  1293. //
  1294. m_pHttpRequest->SetState(
  1295. HTR_DOVERB,
  1296. m_pHttpRequest->QueryLogHttpResponse(),
  1297. ERROR_INVALID_PARAMETER
  1298. );
  1299. DBGPRINTF((
  1300. DBG_CONTEXT,
  1301. "WAM_REQUEST[%p]::Failed to restart reading\n", this
  1302. ));
  1303. }
  1304. }
  1305. }
  1306. } else {
  1307. //
  1308. // Error decoding chunked data.
  1309. //
  1310. m_pHttpRequest->SetState(
  1311. HTR_DOVERB,
  1312. m_pHttpRequest->QueryLogHttpResponse(),
  1313. ERROR_INVALID_PARAMETER
  1314. );
  1315. dwStatus = ERROR_INVALID_PARAMETER;
  1316. }
  1317. }
  1318. //
  1319. // If this is a read, let HTTP_REQUEST know how much we read for
  1320. // logging purposes.
  1321. //
  1322. if( !m_fAsyncWrite && dwStatus == STATUS_SUCCESS )
  1323. {
  1324. m_pHttpRequest->AddTotalEntityBodyCB( cbWritten );
  1325. }
  1326. //
  1327. // If we used file handle for async i/o, close it now.
  1328. //
  1329. if ( m_hFileTfi != INVALID_HANDLE_VALUE ) {
  1330. DBG_ASSERT( !(m_pWamInfo->FInProcess()) );
  1331. CloseHandle( m_hFileTfi );
  1332. m_hFileTfi = INVALID_HANDLE_VALUE;
  1333. }
  1334. //
  1335. // Free TFI strings (if any)
  1336. //
  1337. if ( m_pszStatusTfi != NULL )
  1338. {
  1339. LocalFree( m_pszStatusTfi );
  1340. m_pszStatusTfi = NULL;
  1341. }
  1342. if ( m_pszTailTfi != NULL )
  1343. {
  1344. LocalFree( m_pszTailTfi );
  1345. m_pszTailTfi = NULL;
  1346. }
  1347. if ( m_pszHeadTfi != NULL )
  1348. {
  1349. LocalFree( m_pszHeadTfi );
  1350. m_pszHeadTfi = NULL;
  1351. }
  1352. if( m_pbAsyncReadOopBuffer != NULL )
  1353. {
  1354. // Doing an out of process async read
  1355. DBG_ASSERT( !m_fAsyncWrite );
  1356. // Save a local copy of the read buffer before making callback.
  1357. // ISAPI may queue another async read.
  1358. LPBYTE pbTemp = m_pbAsyncReadOopBuffer;
  1359. m_pbAsyncReadOopBuffer = NULL;
  1360. hr = m_pWamInfo->ProcessAsyncIO(
  1361. this,
  1362. #ifdef _WIN64
  1363. (UINT64) m_pWamExecInfo,
  1364. #else
  1365. (ULONG_PTR) m_pWamExecInfo,
  1366. #endif
  1367. dwStatus,
  1368. cbWritten,
  1369. pbTemp
  1370. );
  1371. LocalFree( pbTemp );
  1372. }
  1373. else
  1374. {
  1375. hr = m_pWamInfo->ProcessAsyncIO(
  1376. this,
  1377. #ifdef _WIN64
  1378. (UINT64) m_pWamExecInfo,
  1379. #else
  1380. (ULONG_PTR) m_pWamExecInfo,
  1381. #endif
  1382. dwStatus,
  1383. cbWritten );
  1384. }
  1385. //
  1386. // Deref upon completing async i/o operation.
  1387. //
  1388. // NOTE balances ref which must precede any async i/o operation.
  1389. //
  1390. // NOTE this ref/deref scheme fixes 97842, wherein inetinfo crashed
  1391. // after oop isapi submited async readcli and then crashed
  1392. //
  1393. Release();
  1394. return hr;
  1395. }
  1396. /*-----------------------------------------------------------------------------*
  1397. WAM_REQUEST::SetDeniedFlags
  1398. Cover function
  1399. */
  1400. VOID
  1401. WAM_REQUEST::SetDeniedFlags
  1402. (
  1403. DWORD dwDeniedFlags
  1404. )
  1405. {
  1406. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1407. m_pHttpRequest->SetDeniedFlags( dwDeniedFlags );
  1408. }
  1409. /*---------------------------------------------------------------------*
  1410. WAM_REQUEST::SendEntireResponseFast
  1411. Description:
  1412. Sends an entire response (headers and body) as fast as possible
  1413. by calling WSASend.
  1414. Arguments:
  1415. pHseResponseInfo - custom struct, see iisext.x
  1416. Returns:
  1417. HRESULT
  1418. */
  1419. HRESULT
  1420. WAM_REQUEST::SendEntireResponseFast(
  1421. HSE_SEND_ENTIRE_RESPONSE_INFO * pHseResponseInfo
  1422. )
  1423. {
  1424. HRESULT hrRet = NOERROR;
  1425. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1426. //
  1427. // write status and header into buffer, but suppress actual send
  1428. // (by first setting m_fWriteHeaders = FALSE)
  1429. //
  1430. // NOTE it is semi-hokey to use a member BOOL for this
  1431. // instead of passing an arg, but it saves cluttering the idl file
  1432. //
  1433. m_fWriteHeaders = FALSE;
  1434. if ( FAILED( hrRet =
  1435. SendHeader(
  1436. (unsigned char *) pHseResponseInfo->HeaderInfo.pszStatus
  1437. , pHseResponseInfo->HeaderInfo.cchStatus
  1438. , (unsigned char *) pHseResponseInfo->HeaderInfo.pszHeader
  1439. , pHseResponseInfo->HeaderInfo.cchHeader
  1440. , pHseResponseInfo->HeaderInfo.fKeepConn
  1441. ) ) ) {
  1442. return hrRet;
  1443. }
  1444. m_fWriteHeaders = TRUE;
  1445. //
  1446. // NOTE: Caller must have allocated N+1 buffers
  1447. // and filled buffers 1 through N with its data buffers.
  1448. // We now fill the extra buffer (buffer 0) with header info,
  1449. // generated by above SendHeader call.
  1450. //
  1451. // NOTE we assert that empty array slot is 0'ed out.
  1452. // This is valid as long as this api stays private
  1453. // and all of its callers comply.
  1454. //
  1455. DBG_ASSERT( pHseResponseInfo->rgWsaBuf[0].len == 0 );
  1456. DBG_ASSERT( pHseResponseInfo->rgWsaBuf[0].buf == NULL );
  1457. pHseResponseInfo->rgWsaBuf[0].len = m_pHttpRequest->QueryRespBufCB();
  1458. pHseResponseInfo->rgWsaBuf[0].buf = m_pHttpRequest->QueryRespBufPtr();
  1459. //
  1460. // write wsa-buffer array:
  1461. //
  1462. return HresultFromBool(
  1463. m_pHttpRequest->SyncWsaSend(
  1464. pHseResponseInfo->rgWsaBuf
  1465. , pHseResponseInfo->cWsaBuf
  1466. , &pHseResponseInfo->cbWritten
  1467. ) );
  1468. } // WAM_REQUEST::SendEntireResponseFast()
  1469. /*---------------------------------------------------------------------*
  1470. WAM_REQUEST::SendEntireResponseNormal
  1471. Description:
  1472. Sends an entire response (headers and body) by surface mail.
  1473. Arguments:
  1474. pHseResponseInfo - custom struct, see iisext.x
  1475. Returns:
  1476. HRESULT
  1477. */
  1478. HRESULT
  1479. WAM_REQUEST::SendEntireResponseNormal(
  1480. HSE_SEND_ENTIRE_RESPONSE_INFO * pHseResponseInfo
  1481. )
  1482. {
  1483. HRESULT hrRet = NOERROR;
  1484. DWORD cbWritten = 0;
  1485. UINT i;
  1486. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1487. //
  1488. // init bytes-written count to 0 - we keep a running tally below
  1489. //
  1490. pHseResponseInfo->cbWritten = 0;
  1491. //
  1492. // send headers
  1493. //
  1494. // UNDONE need to get bytes-written back from SendHeader
  1495. //
  1496. DBG_ASSERT( m_fWriteHeaders );
  1497. if ( FAILED( hrRet =
  1498. SendHeader(
  1499. (unsigned char *) pHseResponseInfo->HeaderInfo.pszStatus
  1500. , pHseResponseInfo->HeaderInfo.cchStatus
  1501. , (unsigned char *) pHseResponseInfo->HeaderInfo.pszHeader
  1502. , pHseResponseInfo->HeaderInfo.cchHeader
  1503. , pHseResponseInfo->HeaderInfo.fKeepConn
  1504. /* , &cbWritten */
  1505. ) ) ) {
  1506. goto LExit;
  1507. }
  1508. pHseResponseInfo->cbWritten += cbWritten;
  1509. //
  1510. // Send body (data buffers)
  1511. //
  1512. // NOTE: Caller must have allocated N+1 buffers
  1513. // and filled buffers 1 through N with its data buffers.
  1514. // We ignore buffer 0 (unused in this case) and send
  1515. // each data buffer by normal means.
  1516. //
  1517. for ( i = 1; i < pHseResponseInfo->cWsaBuf; i++ ) {
  1518. if ( FAILED( hrRet =
  1519. SyncWriteClient(
  1520. pHseResponseInfo->rgWsaBuf[i].len
  1521. , (unsigned char *) pHseResponseInfo->rgWsaBuf[i].buf
  1522. , &cbWritten,
  1523. 0
  1524. ) ) ) {
  1525. goto LExit;
  1526. }
  1527. pHseResponseInfo->cbWritten += cbWritten;
  1528. }
  1529. LExit:
  1530. return hrRet;
  1531. } // WAM_REQUEST::SendEntireResponseNormal()
  1532. /*******************************************
  1533. * *
  1534. * IWamRequest interface methods *
  1535. * *
  1536. * *
  1537. *******************************************/
  1538. /*-----------------------------------------------------------------------------*
  1539. Support for WAM_REQUEST::GetCoreState
  1540. */
  1541. /*-----------------------------------------------------------------------------*
  1542. HGetOopImpersonationToken
  1543. Description
  1544. Dup the handle for use in the hWam process.
  1545. NOTE the WAM must release the handle after it is done with it.
  1546. Arguments
  1547. HANDLE hImpersonationToken - the impersonation token in this process
  1548. HANDLE hWam - handle to wam process
  1549. HANDLE *phOopImpersonationToken - Returned handle for use in the remote
  1550. process
  1551. Returns
  1552. HRESULT
  1553. */
  1554. HRESULT
  1555. HGetOopImpersonationToken(
  1556. IN HANDLE hImpersonationToken,
  1557. IN HANDLE hWam,
  1558. OUT HANDLE *phOopImpersonationToken
  1559. )
  1560. {
  1561. HANDLE hImpTokInChildProcessAddressSpace = NULL;
  1562. HANDLE hDuplicateToken = NULL;
  1563. HRESULT hr = NOERROR;
  1564. BOOL fSuccess;
  1565. DBG_ASSERT( hImpersonationToken != (HANDLE)0 );
  1566. DBG_ASSERT( phOopImpersonationToken );
  1567. *phOopImpersonationToken = NULL;
  1568. do
  1569. {
  1570. fSuccess =
  1571. DupTokenWithSameImpersonationLevel( hImpersonationToken,
  1572. TOKEN_ALL_ACCESS,
  1573. TokenImpersonation,
  1574. &hDuplicateToken
  1575. );
  1576. if( !fSuccess )
  1577. {
  1578. DBGPRINTF((DBG_CONTEXT,"Error %d on DuplicateTokenEx\n",
  1579. GetLastError()
  1580. ));
  1581. hr = HRESULT_FROM_WIN32(GetLastError());
  1582. break;
  1583. }
  1584. hr = GrantAllAccessToToken( hDuplicateToken );
  1585. if( FAILED(hr) )
  1586. {
  1587. DBGPRINTF((DBG_CONTEXT,"Error %08x on GrantAllAccessToToken\n",
  1588. hr
  1589. ));
  1590. DBG_ASSERT( SUCCEEDED(hr) );
  1591. break;
  1592. }
  1593. fSuccess = DuplicateHandle(
  1594. g_pWamDictator->HW3SvcProcess(), // Handle of W3Svc process
  1595. hDuplicateToken, // Handle to duplicate to remote process
  1596. hWam, // Handle of Wam process
  1597. &hImpTokInChildProcessAddressSpace, // Handle to token in remote process
  1598. 0, // ignored when DUPLICATE_SAME_ACCESS is passed
  1599. FALSE, // inheritance flag
  1600. DUPLICATE_SAME_ACCESS // duplicate same access permissions as original
  1601. );
  1602. if( !fSuccess )
  1603. {
  1604. DBGPRINTF((DBG_CONTEXT,"Error %d on DuplicateHandle\n",
  1605. GetLastError()
  1606. ));
  1607. hr = HRESULT_FROM_WIN32(GetLastError());
  1608. break;
  1609. }
  1610. } while( FALSE );
  1611. if( hDuplicateToken )
  1612. {
  1613. CloseHandle( hDuplicateToken );
  1614. }
  1615. *phOopImpersonationToken = hImpTokInChildProcessAddressSpace;
  1616. return hr;
  1617. }
  1618. #define APPEND_WRC_STRING( iString, pstr ) \
  1619. DBG_ASSERT( pbWrcData ); \
  1620. DBG_ASSERT( iString < WRC_C_STRINGS ); \
  1621. DBG_ASSERT( (pstr) ); \
  1622. cch = rgcchWrcStrings[ iString ] = (pstr)->QueryCCH(); \
  1623. CopyMemory( pchCur, (pstr)->QueryStr(), cch+1 ); \
  1624. rgcbWrcOffsets[ iString ] = DIFF(pchCur - pbWrcData); \
  1625. pchCur += cch+1;
  1626. /*-----------------------------------------------------------------------------*
  1627. WAM_REQUEST::GetCoreState
  1628. Fills a caller-supplied buffer with wamreq core strings
  1629. Arguments:
  1630. See below
  1631. Returns:
  1632. HRESULT
  1633. */
  1634. STDMETHODIMP
  1635. WAM_REQUEST::GetCoreState(
  1636. DWORD cbWrcData // size of wamreq core data buffer
  1637. , unsigned char * pbWrcData // ptr to address of wamreq core data buffer
  1638. , DWORD cbWRCF // size of wamreq core fixed-length struct
  1639. , unsigned char * pbWRCF // ptr to address of struct - WAM_REQ_CORE_FIXED
  1640. )
  1641. {
  1642. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1643. IF_DEBUG( WAM_ISA_CALLS ) {
  1644. DBGPRINTF((
  1645. DBG_CONTEXT
  1646. , "WAM_REQUEST[%p]::GetCoreState\n"
  1647. , this
  1648. ));
  1649. }
  1650. DBG_ASSERT( pbWrcData );
  1651. DBG_ASSERT( pbWRCF );
  1652. DBG_ASSERT( m_pExec );
  1653. DBG_ASSERT( m_pHttpRequest );
  1654. BOOL fInProcess = m_pWamInfo->FInProcess();
  1655. WAM_REQ_CORE_FIXED * pWamReqCoreFixed = reinterpret_cast< WAM_REQ_CORE_FIXED * >( pbWRCF );
  1656. //
  1657. // make sure the buffers are large enough (#157823)
  1658. //
  1659. if( cbWrcData < ( WRC_CB_FIXED_ARRAYS + CbWrcStrings( fInProcess ) )
  1660. || cbWRCF < sizeof( WAM_REQ_CORE_FIXED) )
  1661. {
  1662. return ERROR_INVALID_PARAMETER;
  1663. }
  1664. /********************************************
  1665. * Get variable-length (string) data
  1666. *
  1667. */
  1668. /*
  1669. Init string offsets array and string lengths array
  1670. NOTE offsets to strings are stored at start of data buffer
  1671. NOTE string lengths are stored immediately after offsets in data buffer
  1672. sync WRC_DATA_LAYOUT
  1673. */
  1674. DWORD * rgcbWrcOffsets = (DWORD *) pbWrcData;
  1675. DWORD * rgcchWrcStrings = ((DWORD *) pbWrcData) + WRC_C_STRINGS;
  1676. // Init current copy ptr to start of strings section of buffer
  1677. // sync WRC_DATA_LAYOUT
  1678. unsigned char * pchCur = pbWrcData + WRC_CB_FIXED_ARRAYS;
  1679. /* sync WRC_STRINGS */
  1680. // NOTE append order MUST match WRC_I_ index order
  1681. DWORD cch = 0;
  1682. APPEND_WRC_STRING( WRC_I_PATHINFO, m_pExec->_pstrPathInfo )
  1683. APPEND_WRC_STRING( WRC_I_PATHTRANS, &m_strPathTrans )
  1684. APPEND_WRC_STRING( WRC_I_METHOD, (STR *) &m_pHttpRequest->QueryMethodStr() )
  1685. APPEND_WRC_STRING( WRC_I_CONTENTTYPE, (STR *) &m_pHttpRequest->QueryContentTypeStr() )
  1686. APPEND_WRC_STRING( WRC_I_URL, (STR *) &m_pHttpRequest->QueryURLStr() )
  1687. APPEND_WRC_STRING( WRC_I_ISADLLPATH, &m_strISADllPath )
  1688. APPEND_WRC_STRING( WRC_I_QUERY, m_pExec->_pstrURLParams )
  1689. APPEND_WRC_STRING( WRC_I_APPLMDPATH, m_pHttpRequest->GetWAMMetaData()->QueryAppPath() )
  1690. APPEND_WRC_STRING( WRC_I_USERAGENT, &m_strUserAgent )
  1691. APPEND_WRC_STRING( WRC_I_COOKIE, &m_strCookie )
  1692. APPEND_WRC_STRING( WRC_I_EXPIRES, &m_strExpires )
  1693. /********************************************
  1694. * Get fixed-length data
  1695. *
  1696. */
  1697. pWamReqCoreFixed->m_fAnonymous = m_pHttpRequest->IsAnonymous();
  1698. pWamReqCoreFixed->m_cbEntityBody = m_pHttpRequest->QueryEntityBodyCB();
  1699. pWamReqCoreFixed->m_cbClientContent = m_pHttpRequest->QueryClientContentLength();
  1700. pWamReqCoreFixed->m_fCacheISAPIApps = m_pHttpRequest->QueryMetaData()->QueryCacheISAPIApps();
  1701. pWamReqCoreFixed->m_dwChildExecFlags = m_pExec->_dwExecFlags;
  1702. pWamReqCoreFixed->m_dwHttpVersion = (m_pHttpRequest->QueryVersionMajor() << 16) |
  1703. m_pHttpRequest->QueryVersionMinor();
  1704. pWamReqCoreFixed->m_dwInstanceId = m_pHttpRequest->QueryW3Instance()->QueryInstanceId();
  1705. /********************************************
  1706. * Get oop-dependent stuff
  1707. *
  1708. */
  1709. if( fInProcess ) {
  1710. //
  1711. // In-Proc: return the handle we already have
  1712. //
  1713. pWamReqCoreFixed->m_hUserToken = m_pExec->QueryImpersonationHandle();
  1714. } else {
  1715. //
  1716. // Out-Proc: duplicate and return a process-valid handle
  1717. // from the handle we already have
  1718. //
  1719. HRESULT hrTemp = HGetOopImpersonationToken(
  1720. m_pExec->QueryImpersonationHandle(),
  1721. m_pWamInfo->HWamProcess(),
  1722. &(pWamReqCoreFixed->m_hUserToken)
  1723. );
  1724. if( FAILED(hrTemp) )
  1725. {
  1726. DBGPRINTF(( DBG_CONTEXT,
  1727. "WAM_REQUEST[%p] HGetOopImpersonationToken() FAILED hr=%08x",
  1728. this,
  1729. hrTemp
  1730. ));
  1731. return hrTemp;
  1732. }
  1733. //
  1734. // Out-Proc: append entity body to end of strings
  1735. //
  1736. // NOTE must do this here because it depends on
  1737. // pWamReqCoreFixed->m_cbEntityBody, which we fill above
  1738. //
  1739. DWORD cb = pWamReqCoreFixed->m_cbEntityBody;
  1740. rgcchWrcStrings[ WRC_I_ENTITYBODY ] = cb;
  1741. //
  1742. // copy entity body into buffer
  1743. // NOTE no null terminator
  1744. //
  1745. CopyMemory( pchCur, m_pHttpRequest->QueryEntityBody(), cb );
  1746. //
  1747. // set the offset from start of strings buffer to string we copied
  1748. /* sync WRC_DATA_LAYOUT */
  1749. //
  1750. rgcbWrcOffsets[ WRC_I_ENTITYBODY ] = DIFF(pchCur - pbWrcData);
  1751. }
  1752. return NOERROR;
  1753. } // WAM_REQUEST::GetCoreState
  1754. /*-----------------------------------------------------------------------------*
  1755. WAM_REQUEST::QueryEntityBody
  1756. Description
  1757. Cover function
  1758. Arguments
  1759. Returns
  1760. HRESULT
  1761. */
  1762. STDMETHODIMP
  1763. WAM_REQUEST::QueryEntityBody
  1764. (
  1765. unsigned char ** ppbEntityBody
  1766. )
  1767. {
  1768. IF_DEBUG( WAM_ISA_CALLS ) {
  1769. DBGPRINTF(( DBG_CONTEXT,
  1770. "WAM_REQUEST[%p]::QueryEntityBody\n"
  1771. ,
  1772. this
  1773. ));
  1774. }
  1775. *ppbEntityBody = m_pHttpRequest->QueryEntityBody();
  1776. return NOERROR;
  1777. }
  1778. /*-----------------------------------------------------------------------------*
  1779. WAM_REQUEST::SetKeepConn
  1780. Cover function
  1781. */
  1782. STDMETHODIMP
  1783. WAM_REQUEST::SetKeepConn( int fKeepConn )
  1784. {
  1785. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1786. IF_DEBUG( WAM_ISA_CALLS ) {
  1787. DBGPRINTF(( DBG_CONTEXT,
  1788. "WAM_REQUEST[%p]::SetKeepConn\n"
  1789. ,
  1790. this
  1791. ));
  1792. }
  1793. m_pHttpRequest->SetKeepConn( fKeepConn );
  1794. return NOERROR;
  1795. }
  1796. /*-----------------------------------------------------------------------------*
  1797. WAM_REQUEST::IsKeepConnSet
  1798. Cover function
  1799. */
  1800. STDMETHODIMP
  1801. WAM_REQUEST::IsKeepConnSet
  1802. (
  1803. BOOL * pfKeepConn
  1804. )
  1805. {
  1806. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1807. IF_DEBUG( WAM_ISA_CALLS ) {
  1808. DBGPRINTF(( DBG_CONTEXT,
  1809. "WAM_REQUEST[%p]::IsKeepConnSet\n"
  1810. ,
  1811. this
  1812. ));
  1813. }
  1814. *pfKeepConn = m_pHttpRequest->IsKeepConnSet();
  1815. return NOERROR;
  1816. }
  1817. /*-----------------------------------------------------------------------------*
  1818. WAM_REQUEST::GetInfoForName
  1819. */
  1820. STDMETHODIMP
  1821. WAM_REQUEST::GetInfoForName
  1822. (
  1823. const unsigned char * szVarName,
  1824. unsigned char * pchBuffer,
  1825. DWORD cchBuffer,
  1826. DWORD * pcchRequired
  1827. )
  1828. {
  1829. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1830. IF_DEBUG( WAM_ISA_CALLS ) {
  1831. DBGPRINTF(( DBG_CONTEXT,
  1832. "WAM_REQUEST[%p]::GetInfoForName(%s)\n",
  1833. this,
  1834. szVarName
  1835. ));
  1836. }
  1837. BOOL fReturn = FALSE;
  1838. DBG_ASSERT( m_pWamInfo );
  1839. m_pWamInfo->NotifyGetInfoForName( (LPCSTR)szVarName );
  1840. //
  1841. // set required buffer size to actual incoming size
  1842. // and do the look-up
  1843. //
  1844. *pcchRequired = cchBuffer;
  1845. fReturn = m_pHttpRequest->GetInfoForName( (const CHAR *) szVarName,
  1846. (CHAR *) pchBuffer,
  1847. pcchRequired );
  1848. //
  1849. // bail if buffer too small
  1850. //
  1851. if ( *pcchRequired > cchBuffer ) {
  1852. return ( HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) );
  1853. }
  1854. return HresultFromBool( fReturn );
  1855. } // WAM_REQUEST::GetInfoForName()
  1856. /*-----------------------------------------------------------------------------*
  1857. WAM_REQUEST::AppendLogParameter
  1858. Cover function
  1859. */
  1860. STDMETHODIMP
  1861. WAM_REQUEST::AppendLogParameter
  1862. (
  1863. unsigned char * pszParam
  1864. )
  1865. {
  1866. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1867. IF_DEBUG( WAM_ISA_CALLS ) {
  1868. DBGPRINTF(( DBG_CONTEXT,
  1869. "WAM_REQUEST[%p]::AppendLogParameter\n"
  1870. ,
  1871. this
  1872. ));
  1873. }
  1874. return HresultFromBool( m_pHttpRequest->AppendLogParameter(
  1875. (CHAR *) pszParam ) );
  1876. }
  1877. /*-----------------------------------------------------------------------------*
  1878. WAM_REQUEST::LookupVirtualRoot
  1879. Returns path-translated of a URL.
  1880. Arguments
  1881. pchBuffer - [in, out] contains URL coming in, path-tran going out
  1882. cchBuffer - [in] size of buffer
  1883. pcchRequired - [out] required size for path-tran
  1884. Returns:
  1885. HRESULT
  1886. */
  1887. STDMETHODIMP
  1888. WAM_REQUEST::LookupVirtualRoot
  1889. (
  1890. unsigned char * pchBuffer,
  1891. DWORD cchBuffer,
  1892. DWORD * pcchRequired
  1893. )
  1894. {
  1895. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1896. IF_DEBUG( WAM_ISA_CALLS ) {
  1897. DBGPRINTF(( DBG_CONTEXT,
  1898. "WAM_REQUEST[%p]::LookupVirtualRoot\n"
  1899. ,
  1900. this
  1901. ));
  1902. }
  1903. CanonURL((char *)pchBuffer, g_pInetSvc->IsSystemDBCS());
  1904. // NOTE we pass buffer as both source and dest
  1905. return LookupVirtualRootEx( pchBuffer,
  1906. pchBuffer,
  1907. cchBuffer,
  1908. pcchRequired,
  1909. NULL,
  1910. NULL,
  1911. NULL );
  1912. }
  1913. /*-----------------------------------------------------------------------------*
  1914. WAM_REQUEST::LookupVirtualRootEx
  1915. Returns path-translated of a URL plus additional info
  1916. Arguments
  1917. szURL - [in] URL string
  1918. pchBuffer - [out] buffer for returned path-tran
  1919. cchBuffer - [in] size of path-tran buffer as passed
  1920. pcchRequired - [out] required size for path-tran buffer
  1921. pcchMatchingPath- [out] number of matching chars in phys path - NULL to ignore
  1922. pcchMatchingURL - [out] number of matching chars in URL - pass NULL to ignore
  1923. pdwFlags - [out] vroot attribute flags - pass NULL to ignore
  1924. Returns:
  1925. HRESULT
  1926. */
  1927. STDMETHODIMP
  1928. WAM_REQUEST::LookupVirtualRootEx
  1929. (
  1930. unsigned char * szURL,
  1931. unsigned char * pchBuffer,
  1932. DWORD cchBuffer,
  1933. DWORD * pcchRequired,
  1934. DWORD * pcchMatchingPath,
  1935. DWORD * pcchMatchingURL,
  1936. DWORD * pdwFlags
  1937. )
  1938. {
  1939. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  1940. IF_DEBUG( WAM_ISA_CALLS ) {
  1941. DBGPRINTF(( DBG_CONTEXT,
  1942. "WAM_REQUEST[%p]::LookupVirtualRootEx\n"
  1943. ,
  1944. this
  1945. ));
  1946. }
  1947. DBG_ASSERT( szURL );
  1948. DBG_ASSERT( pchBuffer );
  1949. DBG_ASSERT( pcchRequired );
  1950. STACK_STR( strPathTran, MAX_PATH);
  1951. BOOL fReturn = FALSE;
  1952. fReturn = ( m_pHttpRequest->LookupVirtualRoot(
  1953. &strPathTran,
  1954. (const char *) szURL,
  1955. strlen((const char *) szURL),
  1956. pcchMatchingPath, // pcchDirRoot,
  1957. pcchMatchingURL, // pcchVRoot,
  1958. pdwFlags, // pdwMask,
  1959. NULL, // BOOL * pfFinished,
  1960. FALSE, // BOOL fGetAcl,
  1961. NULL, // PW3_METADATA * ppMetaData,
  1962. NULL // PW3_URI_INFO * ppURIBlob
  1963. ) );
  1964. if ( fReturn )
  1965. {
  1966. //
  1967. // Include one byte for the null terminator
  1968. //
  1969. *pcchRequired = strPathTran.QueryCB() + 1;
  1970. if ( *pcchRequired <= cchBuffer )
  1971. {
  1972. // we have enough room in buffer so copy the str
  1973. CopyMemory( pchBuffer, strPathTran.QueryStr(), *pcchRequired );
  1974. }
  1975. else
  1976. {
  1977. //
  1978. // we don't have enough room in buffer
  1979. // in normal case, we fail
  1980. // in 'extended' case, we copy as much as buffer will hold
  1981. //
  1982. //
  1983. // CHEESE ALERT
  1984. // We check null-ness of the 'extended' dword ptrs
  1985. // to determine whether we are in 'extended' or normal case
  1986. // (cheaper than adding a BOOL to the interface)
  1987. //
  1988. // 'extended' <==> all ptrs are non-null
  1989. //
  1990. if ( !( pcchMatchingPath && pcchMatchingURL && pdwFlags ) )
  1991. {
  1992. // normal case - set error and bail
  1993. SetLastError( ERROR_INSUFFICIENT_BUFFER );
  1994. fReturn = FALSE;
  1995. }
  1996. else
  1997. {
  1998. // 'extended' case - copy as much as buffer will hold
  1999. DWORD cch = min( *pcchRequired, cchBuffer );
  2000. CopyMemory( pchBuffer, strPathTran.QueryStr(), cch );
  2001. pchBuffer[cch - 1] = '\0';
  2002. }
  2003. }
  2004. }
  2005. return HresultFromBool( fReturn );
  2006. } // WAM_REQUEST::LookupVirtualRootEx
  2007. /*-----------------------------------------------------------------------------*
  2008. WAM_REQUEST::GetVirtualPathToken
  2009. Returns an impersonation token for the specified virtual path.
  2010. WARNING: the token should be CloseHandle()d by caller.
  2011. Arguments
  2012. See below
  2013. Returns:
  2014. Nothing
  2015. */
  2016. STDMETHODIMP
  2017. WAM_REQUEST::GetVirtualPathToken(
  2018. IN unsigned char * szURL, // virtual root
  2019. #ifdef _WIN64
  2020. OUT UINT64 * phToken // points to token (handle) placeholder
  2021. #else
  2022. OUT ULONG_PTR * phToken // points to token (handle) placeholder
  2023. #endif
  2024. )
  2025. {
  2026. PW3_METADATA pMD = NULL;
  2027. BOOL fSuccess = FALSE;
  2028. STACK_STR( strPathTran, MAX_PATH);
  2029. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  2030. DBG_ASSERT( szURL );
  2031. DBG_ASSERT( phToken );
  2032. IF_DEBUG( WAM_ISA_CALLS ) {
  2033. DBGPRINTF(( DBG_CONTEXT,
  2034. "WAM_REQUEST[%p]::GetVirtualPathToken(%s)\n"
  2035. ,
  2036. this,
  2037. szURL
  2038. ));
  2039. }
  2040. //
  2041. // Get metabase data item pointer
  2042. //
  2043. fSuccess = m_pHttpRequest->LookupVirtualRoot(
  2044. &strPathTran,
  2045. (const char *) szURL,
  2046. strlen((const char *) szURL),
  2047. NULL,
  2048. NULL,
  2049. NULL,
  2050. NULL,
  2051. TRUE, // BOOL fGetAcl,
  2052. &pMD, // PW3_METADATA * ppMetaData,
  2053. NULL
  2054. );
  2055. if(fSuccess) {
  2056. //
  2057. // We know this virtual root. Even if it may not have a token, we
  2058. // could return TRUE to caller. Make sure they get a meaningful token.
  2059. //
  2060. *phToken = NULL;
  2061. //
  2062. // try to get access token for the specified URL
  2063. //
  2064. HANDLE hToken = pMD->QueryVrAccessToken();
  2065. //
  2066. // if we have it, make a duplicate. This is very expensive,
  2067. // but we want to preserve transparency of inproc/out-of-proc,
  2068. //
  2069. if(hToken)
  2070. {
  2071. // Client closes the handle we return
  2072. HANDLE hTokenLocalDuplicate = NULL;
  2073. fSuccess = DupTokenWithSameImpersonationLevel(
  2074. hToken,
  2075. MAXIMUM_ALLOWED,
  2076. TokenPrimary,
  2077. &hTokenLocalDuplicate
  2078. );
  2079. if( fSuccess )
  2080. {
  2081. if( m_pWamInfo->FInProcess() )
  2082. {
  2083. #ifdef _WIN64
  2084. *phToken = (UINT64)hTokenLocalDuplicate;
  2085. #else
  2086. *phToken = (ULONG_PTR)hTokenLocalDuplicate;
  2087. #endif
  2088. }
  2089. else
  2090. {
  2091. // In the oop case, duplicate the handle to the
  2092. // remote process.
  2093. HANDLE hTokenRemote = NULL;
  2094. fSuccess = DuplicateHandle(
  2095. g_pWamDictator->HW3SvcProcess(),
  2096. hTokenLocalDuplicate,
  2097. m_pWamInfo->HWamProcess(),
  2098. &hTokenRemote,
  2099. 0,
  2100. FALSE,
  2101. DUPLICATE_SAME_ACCESS
  2102. );
  2103. CloseHandle(hTokenLocalDuplicate);
  2104. #ifdef _WIN64
  2105. *phToken = (UINT64)hTokenRemote;
  2106. #else
  2107. *phToken = (ULONG_PTR)hTokenRemote;
  2108. #endif
  2109. }
  2110. }
  2111. }
  2112. }
  2113. return HresultFromBool( fSuccess );
  2114. }
  2115. /*-----------------------------------------------------------------------------*
  2116. WAM_REQUEST::GetPrivatePtr
  2117. Returns a 'private' ptr
  2118. WARNING only for knowledgeable IN-PROC callers (ssinc, httpodbc, et al)
  2119. Arguments
  2120. See below
  2121. Returns:
  2122. Nothing
  2123. */
  2124. STDMETHODIMP
  2125. WAM_REQUEST::GetPrivatePtr
  2126. (
  2127. DWORD dwHSERequest, // type of ServerSupportFunction request
  2128. unsigned char ** ppData // [out] returned ptr
  2129. )
  2130. {
  2131. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  2132. IF_DEBUG( WAM_ISA_CALLS ) {
  2133. DBGPRINTF(( DBG_CONTEXT,
  2134. "WAM_REQUEST[%p]::GetPrivatePtr\n"
  2135. ,
  2136. this
  2137. ));
  2138. }
  2139. switch( dwHSERequest ) {
  2140. case HSE_PRIV_REQ_TSVCINFO: {
  2141. *((PIIS_SERVICE *)*ppData) = g_pInetSvc;
  2142. break;
  2143. }
  2144. case HSE_PRIV_REQ_HTTP_REQUEST: {
  2145. *((HTTP_REQUEST **)*ppData) = m_pHttpRequest;
  2146. break;
  2147. }
  2148. case HSE_PRIV_REQ_VROOT_TABLE: {
  2149. //
  2150. // UNDONE we think no one uses this ???
  2151. // REMOVE this case if so
  2152. //
  2153. DBG_ASSERT( FALSE );
  2154. *ppData = NULL;
  2155. return HRESULT_FROM_WIN32( ERROR_INVALID_FUNCTION );
  2156. *((PIIS_VROOT_TABLE *)*ppData) =
  2157. m_pHttpRequest->QueryW3Instance()->QueryVrootTable();
  2158. break;
  2159. }
  2160. case HSE_PRIV_REQ_TSVC_CACHE: {
  2161. *((TSVC_CACHE **)*ppData) =
  2162. &m_pHttpRequest->QueryW3Instance()->GetTsvcCache();
  2163. break;
  2164. }
  2165. default: {
  2166. DBG_ASSERT( FALSE );
  2167. }
  2168. }
  2169. return NOERROR;
  2170. }
  2171. /*-----------------------------------------------------------------------------*
  2172. WAM_REQUEST::AsyncReadClientExt
  2173. This function exists simply to avoid cross-process calls.
  2174. Arguments:
  2175. NOTE pWamExecInfo is passed as DWORD to fool the marshaller.
  2176. We simply hold it in WAM_REQUEST::m_pWamExecInfo, do nothing with it,
  2177. then pass it back to wam on i/o completion callback.
  2178. Returns:
  2179. BOOL
  2180. */
  2181. STDMETHODIMP
  2182. WAM_REQUEST::AsyncReadClientExt(
  2183. #ifdef _WIN64
  2184. IN UINT64 pWamExecInfo
  2185. #else
  2186. IN ULONG_PTR pWamExecInfo
  2187. #endif
  2188. , OUT unsigned char * lpBuffer
  2189. , IN DWORD nBytesToRead
  2190. )
  2191. {
  2192. BOOL fReturn = FALSE;
  2193. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  2194. IF_DEBUG( WAM_ISA_CALLS ) {
  2195. DBGPRINTF(( DBG_CONTEXT,
  2196. "WAM_REQUEST[%p]::AsyncReadClientExt\n"
  2197. ,
  2198. this
  2199. ));
  2200. }
  2201. m_pWamExecInfo = (WAM_EXEC_INFO *) pWamExecInfo;
  2202. DBG_ASSERT( m_pWamExecInfo );
  2203. //
  2204. // If chunked read already complete, call notification routine
  2205. // and return success
  2206. //
  2207. if(m_pHttpRequest->IsChunked() && m_pHttpRequest->IsChunkedReadComplete()) {
  2208. #ifdef _WIN64
  2209. m_pWamInfo->ProcessAsyncIO( this, (UINT64) m_pWamExecInfo, 0, 0 );
  2210. #else
  2211. m_pWamInfo->ProcessAsyncIO( this, (ULONG_PTR) m_pWamExecInfo, 0, 0 );
  2212. #endif
  2213. return HresultFromBool( TRUE );
  2214. }
  2215. m_pHttpRequest->SetState( HTR_GATEWAY_ASYNC_IO, HT_DONT_LOG, NO_ERROR );
  2216. //
  2217. // Ref before starting async i/o operation
  2218. //
  2219. // NOTE this is balanced by deref in ProcessAsyncGatewayIO
  2220. //
  2221. AddRef();
  2222. //
  2223. // Save buffer pointer and size in case we need to
  2224. // restart chunk-encoded transfer
  2225. // (when the decoded data has 0 bytes)
  2226. //
  2227. m_pAsyncReadBuffer = lpBuffer;
  2228. m_dwAsyncReadBufferSize = nBytesToRead;
  2229. //
  2230. // Let the completion routine know that we do need to decode
  2231. //
  2232. m_fAsyncWrite = FALSE;
  2233. fReturn = m_pHttpRequest->ReadFile(
  2234. lpBuffer
  2235. , nBytesToRead
  2236. , NULL
  2237. , IO_FLAG_ASYNC
  2238. );
  2239. if ( !fReturn ) {
  2240. //
  2241. // Deref if async i/o operation failed (balances above ref)
  2242. //
  2243. Release();
  2244. m_pHttpRequest->SetState( HTR_DOVERB, HT_DONT_LOG, NO_ERROR );
  2245. }
  2246. return HresultFromBool( fReturn );
  2247. }
  2248. STDMETHODIMP
  2249. WAM_REQUEST::AsyncReadClientOop(
  2250. #ifdef _WIN64
  2251. IN UINT64 pWamExecInfo
  2252. #else
  2253. IN ULONG_PTR pWamExecInfo
  2254. #endif
  2255. , IN DWORD nBytesToRead
  2256. )
  2257. {
  2258. DBG_ASSERT( nBytesToRead > 0 );
  2259. IF_DEBUG( WAM_ISA_CALLS ) {
  2260. DBGPRINTF(( DBG_CONTEXT,
  2261. "WAM_REQUEST[%p]::AsyncReadClientOop\n"
  2262. ,
  2263. this
  2264. ));
  2265. }
  2266. m_pbAsyncReadOopBuffer = (LPBYTE)LocalAlloc( LPTR, nBytesToRead );
  2267. if( !m_pbAsyncReadOopBuffer )
  2268. {
  2269. return E_OUTOFMEMORY;
  2270. }
  2271. HRESULT hr = AsyncReadClientExt( pWamExecInfo, m_pbAsyncReadOopBuffer, nBytesToRead );
  2272. if( FAILED(hr) )
  2273. {
  2274. // If this call fails then the async callback should never be made.
  2275. DBG_ASSERT( m_pbAsyncReadOopBuffer );
  2276. LocalFree( m_pbAsyncReadOopBuffer );
  2277. m_pbAsyncReadOopBuffer = NULL;
  2278. }
  2279. return hr;
  2280. }
  2281. /*-----------------------------------------------------------------------------*
  2282. WAM_REQUEST::AsyncWriteClient
  2283. Arguments:
  2284. NOTE pWamExecInfo is passed as ULONG_PTR to fool the marshaller.
  2285. We simply hold it in WAM_REQUEST::m_pWamExecInfo, do nothing with it,
  2286. then pass it back to wam on i/o completion callback.
  2287. Returns:
  2288. HRESULT
  2289. */
  2290. STDMETHODIMP
  2291. WAM_REQUEST::AsyncWriteClient(
  2292. #ifdef _WIN64
  2293. UINT64 pWamExecInfo
  2294. #else
  2295. ULONG_PTR pWamExecInfo
  2296. #endif
  2297. , unsigned char * lpBuffer
  2298. , DWORD nBytesToWrite
  2299. , DWORD dwFlags
  2300. )
  2301. {
  2302. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  2303. IF_DEBUG( WAM_ISA_CALLS ) {
  2304. DBGPRINTF((
  2305. DBG_CONTEXT
  2306. , "WAM_REQUEST[%p]::AsyncWriteClient\n"
  2307. , this
  2308. ));
  2309. }
  2310. m_pHttpRequest->SetState(
  2311. HTR_GATEWAY_ASYNC_IO
  2312. , HT_DONT_LOG
  2313. , NO_ERROR
  2314. );
  2315. m_pWamExecInfo = (WAM_EXEC_INFO *) pWamExecInfo;
  2316. DBG_ASSERT( m_pWamExecInfo );
  2317. //
  2318. // Ref before starting async i/o operation
  2319. //
  2320. // NOTE this is balanced by deref in ProcessAsyncGatewayIO
  2321. //
  2322. AddRef();
  2323. //
  2324. // Mark the operation as "WRITE" so if we are in the process of
  2325. // decoding chunked upload, we won't attempt to decode on
  2326. // a completion of THIS async write
  2327. //
  2328. m_fAsyncWrite = TRUE;
  2329. //
  2330. // Strip off undefined flags
  2331. //
  2332. dwFlags &= IO_FLAG_NO_DELAY;
  2333. BOOL fReturn = m_pHttpRequest->WriteFile(
  2334. (LPVOID) lpBuffer
  2335. , nBytesToWrite
  2336. , NULL
  2337. , IO_FLAG_ASYNC | dwFlags
  2338. );
  2339. if ( !fReturn ) {
  2340. //
  2341. // Deref if async i/o operation failed (balances above ref)
  2342. //
  2343. Release();
  2344. m_pHttpRequest->SetState(
  2345. HTR_DOVERB
  2346. , HT_DONT_LOG
  2347. , NO_ERROR
  2348. );
  2349. }
  2350. return HresultFromBool( fReturn );
  2351. }
  2352. /*---------------------------------------------------------------------*
  2353. WAM_REQUEST::TransmitFileInProc
  2354. Interface to TransmitFile which works in-proc only
  2355. Arguments:
  2356. pWamExecInfo - ptr to this wamreq's wamexecinfo (in wam process)
  2357. pHseTfIn - ptr to transmit-file-info struct
  2358. NOTE pWamExecInfo is passed as ULONG_PTR to fool the marshaller.
  2359. We simply hold it in WAM_REQUEST::m_pWamExecInfo, do nothing with it,
  2360. then pass it back to wam on i/o completion callback.
  2361. Returns:
  2362. HRESULT
  2363. */
  2364. STDMETHODIMP
  2365. WAM_REQUEST::TransmitFileInProc(
  2366. #ifdef _WIN64
  2367. IN UINT64 pWamExecInfo
  2368. #else
  2369. IN ULONG_PTR pWamExecInfo
  2370. #endif
  2371. , IN unsigned char * pHseTfIn
  2372. )
  2373. {
  2374. HRESULT hrRet = NOERROR;
  2375. HSE_TF_INFO * pHseTfi = reinterpret_cast<HSE_TF_INFO *>(pHseTfIn);
  2376. DWORD dwFlags = IO_FLAG_ASYNC;
  2377. PVOID pHead = NULL;
  2378. DWORD cbHead = 0;
  2379. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  2380. IF_DEBUG( WAM_ISA_CALLS ) {
  2381. DBGPRINTF((
  2382. DBG_CONTEXT
  2383. , "WAM_REQUEST[%p]::TransmitFileInProc\n"
  2384. , this
  2385. ));
  2386. }
  2387. //
  2388. // Don't disconnect the socket after the transmit if we need
  2389. // to notify a filter about the end of a request
  2390. //
  2391. if ( !m_pHttpRequest->QueryFilter()->IsNotificationNeeded(
  2392. SF_NOTIFY_END_OF_REQUEST
  2393. , m_pHttpRequest->IsSecurePort()
  2394. )
  2395. && (pHseTfi->dwFlags & HSE_IO_DISCONNECT_AFTER_SEND) ) {
  2396. // suggests fast close & reuse of data socket
  2397. dwFlags |= (TF_DISCONNECT | TF_REUSE_SOCKET);
  2398. }
  2399. //
  2400. // Honor the HSE_IO_NODELAY flag. HTTP_REQ_BASE::WriteClient will
  2401. // handle this flag for WriteClient. Note: Both of these calls will
  2402. // have the effect of leaving the flag set or unset on the socket.
  2403. // This shouldn't really be an issue as it is not likely that the
  2404. // user would want same client connection to change settings.
  2405. //
  2406. AtqSetSocketOption( m_pHttpRequest->QueryClientConn()->QueryAtqContext(),
  2407. TCP_NODELAY,
  2408. (pHseTfi->dwFlags & HSE_IO_NODELAY) ? 1 : 0
  2409. );
  2410. //
  2411. // Check if ISAPI requests us to send headers
  2412. // If we need to send headers, we will call upon BuildHttpHeader()
  2413. // to construct a custom header for the client.
  2414. // It is the application's responsibility not to use
  2415. // HSE_REQ_SEND_RESOPNSE_HEADER if it chooses to use
  2416. // the header option HSE_IO_SEND_HEADERS.
  2417. //
  2418. if ( pHseTfi->dwFlags & HSE_IO_SEND_HEADERS) {
  2419. BOOL fFinished = FALSE;
  2420. //
  2421. // Format the header using the pszStatusCode and
  2422. // extra headers specified in pHseTfi->pHead.
  2423. //
  2424. if ( pHseTfi->pszStatusCode
  2425. && ( (!strncmp( (char *) pHseTfi->pszStatusCode, "401 ", sizeof("401 ")-1 ) ) ||
  2426. (!strncmp( (char *) pHseTfi->pszStatusCode, "407 ", sizeof("407 ")-1 ) ) )
  2427. ) {
  2428. m_pHttpRequest->SetDeniedFlags( SF_DENIED_APPLICATION );
  2429. m_pHttpRequest->SetAuthenticationRequested( TRUE );
  2430. }
  2431. //
  2432. // BuildHttpHeader doesn't provide the \r\n final terminator for
  2433. // the header block. If pHead contains nothing, then the response
  2434. // will be malformed.
  2435. //
  2436. if ( !m_pHttpRequest->BuildHttpHeader(
  2437. &fFinished
  2438. , (CHAR * ) pHseTfi->pszStatusCode
  2439. , (CHAR * ) pHseTfi->pHead
  2440. ) ) {
  2441. hrRet = E_FAIL; // UNDONE something besides E_FAIL???
  2442. goto LExit;
  2443. }
  2444. pHead = m_pHttpRequest->QueryRespBufPtr();
  2445. cbHead = m_pHttpRequest->QueryRespBufCB();
  2446. //
  2447. // Check if any filters are to be notified about the headers
  2448. //
  2449. if ( m_pHttpRequest->QueryFilter()->IsNotificationNeeded( SF_NOTIFY_SEND_RESPONSE,
  2450. m_pHttpRequest->IsSecurePort() ) )
  2451. {
  2452. BOOL fFinished = FALSE;
  2453. BOOL fAnyChanges = FALSE;
  2454. if ( !m_pHttpRequest->QueryFilter()->NotifySendHeaders( (const CHAR*) pHead,
  2455. &fFinished,
  2456. &fAnyChanges,
  2457. m_pHttpRequest->QueryRespBuf() ) )
  2458. {
  2459. hrRet = E_FAIL;
  2460. goto LExit;
  2461. }
  2462. pHead = m_pHttpRequest->QueryRespBufPtr();
  2463. cbHead = m_pHttpRequest->QueryRespBufCB();
  2464. }
  2465. } else {
  2466. pHead = pHseTfi->pHead;
  2467. cbHead = pHseTfi->HeadLength;
  2468. }
  2469. //
  2470. // Setup stage for and execute TransmitFile operation
  2471. //
  2472. //
  2473. // 1. Set Request state to be async IO from ISAPI client
  2474. // 2. Cache wamexec info ptr in member
  2475. // 3. Submit Async IOP
  2476. // 4. return to the ISAPI application
  2477. //
  2478. m_pHttpRequest->SetState(
  2479. HTR_GATEWAY_ASYNC_IO
  2480. , HT_DONT_LOG
  2481. , NO_ERROR
  2482. );
  2483. m_pWamExecInfo = (WAM_EXEC_INFO *) pWamExecInfo;
  2484. DBG_ASSERT( m_pWamExecInfo );
  2485. //
  2486. // Ref before starting async i/o operation
  2487. //
  2488. // NOTE this is balanced by deref in ProcessAsyncGatewayIO
  2489. //
  2490. AddRef();
  2491. //
  2492. // Mark the operation as "WRITE" so if we are in the process of
  2493. // decoding chunked upload, we won't attempt to decode on
  2494. // a completion of THIS async write
  2495. //
  2496. m_fAsyncWrite = TRUE;
  2497. hrRet = HresultFromBool( m_pHttpRequest->TransmitFile(
  2498. NULL,
  2499. pHseTfi->hFile
  2500. , pHseTfi->Offset
  2501. , pHseTfi->BytesToWrite
  2502. , dwFlags | IO_FLAG_NO_RECV
  2503. , (PVOID) pHead
  2504. , cbHead
  2505. , (PVOID) pHseTfi->pTail
  2506. , pHseTfi->TailLength
  2507. ) );
  2508. if ( FAILED( hrRet ) ) {
  2509. //
  2510. // Deref if async i/o operation failed (balances above ref)
  2511. //
  2512. Release();
  2513. m_pHttpRequest->SetState(
  2514. HTR_DOVERB
  2515. , HT_DONT_LOG
  2516. , NO_ERROR
  2517. );
  2518. }
  2519. LExit:
  2520. return hrRet;
  2521. } // WAM_REQUEST::TransmitFileInProc
  2522. /*---------------------------------------------------------------------*
  2523. WAM_REQUEST::TransmitFileOutProc
  2524. Interface to TransmitFile, recommended for out-of-proc only
  2525. (works in-proc, but is slower than TransmitFileInProc).
  2526. This function is a simple cover over TransmitFileInProc.
  2527. It does the following:
  2528. - dups the file handle into this process
  2529. - creates a local TransmitFile-info struct from the in-args
  2530. - calls TransmitFileInProc to do the real work
  2531. Arguments:
  2532. pWamExecInfo - ptr to this wamreq's wamexecinfo (in wam process)
  2533. other params - transmit-file-info struct, as individual args
  2534. NOTE pWamExecInfo is passed as DWORD to fool the marshaller.
  2535. We simply hold it in WAM_REQUEST::m_pWamExecInfo, do nothing with it,
  2536. then pass it back to wam on i/o completion callback.
  2537. Returns:
  2538. HRESULT
  2539. */
  2540. STDMETHODIMP
  2541. WAM_REQUEST::TransmitFileOutProc(
  2542. #ifdef _WIN64
  2543. IN UINT64 pWamExecInfo
  2544. , IN UINT64 hFile // file handle valid in WAM process
  2545. #else
  2546. IN ULONG_PTR pWamExecInfo
  2547. , IN ULONG_PTR hFile // file handle valid in WAM process
  2548. #endif
  2549. , IN unsigned char * pszStatusCode
  2550. , IN DWORD cbStatusCode
  2551. , IN DWORD BytesToWrite
  2552. , IN DWORD Offset
  2553. , IN unsigned char * pHead
  2554. , IN DWORD HeadLength
  2555. , IN unsigned char * pTail
  2556. , IN DWORD TailLength
  2557. , IN DWORD dwFlags
  2558. )
  2559. {
  2560. HSE_TF_INFO HseTfi; // TransmitFile-info struct
  2561. HRESULT hr;
  2562. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  2563. IF_DEBUG( WAM_ISA_CALLS ) {
  2564. DBGPRINTF((
  2565. DBG_CONTEXT
  2566. , "WAM_REQUEST[%p]::TransmitFileOutProc\n"
  2567. , this
  2568. ));
  2569. }
  2570. if( hFile != NULL )
  2571. {
  2572. //
  2573. // Dup file handle into member to keep it around
  2574. // throughout async i/o operation.
  2575. //
  2576. // NOTE we close file handle elsewhere, once we know
  2577. // it is no longer needed
  2578. //
  2579. // CONSIDER don't dup handle when not needed
  2580. // Is handle not needed when BytesToWrite > 0 ???
  2581. //
  2582. if ( !DuplicateHandle(
  2583. m_pWamInfo->HWamProcess() // source process handle
  2584. , (HANDLE) hFile // handle to duplicate
  2585. , g_pWamDictator->HW3SvcProcess() // target process handle
  2586. , &m_hFileTfi // ptr to duplicate handle
  2587. , 0 // dwDesiredAccess - ignored with DUPLICATE_SAME_ACCESS
  2588. , FALSE // non-inheritable
  2589. , DUPLICATE_SAME_ACCESS // optional actions
  2590. ) ) {
  2591. return HRESULT_FROM_WIN32( ERROR_INVALID_HANDLE );
  2592. }
  2593. DBG_ASSERT( m_hFileTfi != INVALID_HANDLE_VALUE );
  2594. }
  2595. else
  2596. {
  2597. // No file handle only the head and tail buffers will be
  2598. // sent.
  2599. DBG_ASSERT( BytesToWrite == 0 );
  2600. DBG_ASSERT( Offset == 0 );
  2601. }
  2602. //
  2603. // Copy in-args into TransmitFile-info struct,
  2604. // making sure that any custom heads and tails are zero-terminated
  2605. //
  2606. if( pszStatusCode != NULL ) {
  2607. if( cbStatusCode != 0 ) {
  2608. if( pszStatusCode[cbStatusCode - 1] != '\0') {
  2609. m_pszStatusTfi = (unsigned char *)
  2610. LocalAlloc( LMEM_FIXED, cbStatusCode + 1 );
  2611. if ( m_pszStatusTfi ) {
  2612. memcpy( m_pszStatusTfi, pszStatusCode, cbStatusCode );
  2613. m_pszStatusTfi[cbStatusCode] = '\0';
  2614. pszStatusCode = m_pszStatusTfi;
  2615. }
  2616. }
  2617. } else {
  2618. // there is a pointer, but 0 length -- sanitize it
  2619. pszStatusCode = (unsigned char *) "";
  2620. }
  2621. }
  2622. if( pHead != NULL ) {
  2623. if( HeadLength != 0 ) {
  2624. if ( pHead[HeadLength - 1] != '\0' ) {
  2625. m_pszHeadTfi = (unsigned char *)
  2626. LocalAlloc( LMEM_FIXED, HeadLength + 1 );
  2627. if( m_pszHeadTfi ) {
  2628. memcpy( m_pszHeadTfi, pHead, HeadLength );
  2629. m_pszHeadTfi[HeadLength] = '\0';
  2630. pHead = m_pszHeadTfi;
  2631. }
  2632. }
  2633. } else {
  2634. pHead = (unsigned char *) "";
  2635. }
  2636. }
  2637. if( pTail != NULL ) {
  2638. if ( TailLength != 0 ) {
  2639. if( pTail[TailLength - 1] != '\0') {
  2640. m_pszTailTfi = (unsigned char *)
  2641. LocalAlloc( LMEM_FIXED, TailLength + 1 );
  2642. if( m_pszTailTfi ) {
  2643. memcpy( m_pszTailTfi, pTail, TailLength );
  2644. m_pszTailTfi[TailLength] = '\0';
  2645. pTail = m_pszTailTfi;
  2646. }
  2647. }
  2648. } else {
  2649. pTail = (unsigned char *)"";
  2650. }
  2651. }
  2652. HseTfi.hFile = ( hFile ) ? (HANDLE) m_hFileTfi : NULL;
  2653. HseTfi.pszStatusCode = (const char *) pszStatusCode;
  2654. HseTfi.BytesToWrite = BytesToWrite;
  2655. HseTfi.Offset = Offset;
  2656. HseTfi.pHead = pHead;
  2657. HseTfi.HeadLength = HeadLength;
  2658. HseTfi.pTail = pTail;
  2659. HseTfi.TailLength = TailLength;
  2660. HseTfi.dwFlags = dwFlags;
  2661. //
  2662. // Invoke in-proc function to do the real work
  2663. //
  2664. hr = TransmitFileInProc(
  2665. pWamExecInfo
  2666. , (unsigned char *) &HseTfi
  2667. );
  2668. if ( FAILED( hr ) )
  2669. {
  2670. if( m_pszStatusTfi )
  2671. {
  2672. LocalFree( m_pszStatusTfi );
  2673. m_pszStatusTfi = NULL;
  2674. }
  2675. if( m_pszHeadTfi )
  2676. {
  2677. LocalFree( m_pszHeadTfi );
  2678. m_pszHeadTfi = NULL;
  2679. }
  2680. if( m_pszTailTfi )
  2681. {
  2682. LocalFree( m_pszTailTfi );
  2683. m_pszTailTfi = NULL;
  2684. }
  2685. }
  2686. return hr;
  2687. } // WAM_REQUEST::TransmitFileOutProc
  2688. /*-----------------------------------------------------------------------------*
  2689. WAM_REQUEST::SyncReadClient
  2690. Description:
  2691. This function is a wrapper for the sychronous read from the client.
  2692. It is separated from the async case because no async state changes
  2693. need to be done here => cleaner function
  2694. Arguments:
  2695. lpBuffer - pointer to buffer into which the contents have to be read-in
  2696. nBytesToRead - number of bytes the buffer can accomodate
  2697. pnBytesRead - pointer to location that will contain the # of bytes returned
  2698. Returns:
  2699. TRUE for success and FALSE for failure
  2700. */
  2701. STDMETHODIMP
  2702. WAM_REQUEST::SyncReadClient
  2703. (
  2704. unsigned char * lpBuffer, // LPVOID lpBuffer,
  2705. DWORD nBytesToRead,
  2706. DWORD * pnBytesRead
  2707. )
  2708. {
  2709. BOOL fSuccess;
  2710. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  2711. DBG_ASSERT( m_pHttpRequest->QueryClientConn()->CheckSignature() );
  2712. IF_DEBUG( WAM_ISA_CALLS ) {
  2713. DBGPRINTF(( DBG_CONTEXT, "WAM_REQUEST[%p]::"
  2714. "SyncReadClient( %p, %d, %p)\n",
  2715. this, lpBuffer, nBytesToRead, pnBytesRead));
  2716. }
  2717. retry:
  2718. //
  2719. // Handle the case when Chunked read was complete.
  2720. //
  2721. if( m_pHttpRequest->IsChunked() && m_pHttpRequest->IsChunkedReadComplete() ) {
  2722. *pnBytesRead = 0;
  2723. fSuccess = TRUE;
  2724. goto done;
  2725. }
  2726. fSuccess = m_pHttpRequest->ReadFile( lpBuffer,
  2727. nBytesToRead,
  2728. pnBytesRead,
  2729. IO_FLAG_SYNC );
  2730. if(fSuccess && m_pHttpRequest->IsChunked() && *pnBytesRead) {
  2731. //
  2732. // Decode read bytes
  2733. //
  2734. DWORD cbToDecode = *pnBytesRead;
  2735. if( m_pHttpRequest->DecodeChunkedBytes( lpBuffer, pnBytesRead ) ) {
  2736. DBGPRINTF(( DBG_CONTEXT, "WAM_REQUEST[%p]::"
  2737. "DecodeChunkedBytes got %d out of %d bytes\n",
  2738. this, *pnBytesRead, cbToDecode ));
  2739. if( *pnBytesRead == 0 && !m_pHttpRequest->IsChunkedReadComplete()) {
  2740. //
  2741. // We decoded zero bytes. This means that all bytes
  2742. // that we've read were chunk headers or footers.
  2743. //
  2744. // We can't return THAT to the caller, because it will
  2745. // think that we are done with reading.
  2746. //
  2747. // We'll have to initiate another read.
  2748. //
  2749. goto retry;
  2750. }
  2751. }
  2752. }
  2753. //
  2754. // Increment the count of request entity body bytes read. This
  2755. // is used in logging how many bytes the client sent, etc.
  2756. //
  2757. m_pHttpRequest->AddTotalEntityBodyCB( *pnBytesRead );
  2758. done:
  2759. return HresultFromBool( fSuccess );
  2760. } // WAM_REQUEST::SyncReadClient()
  2761. /*-----------------------------------------------------------------------------*
  2762. WAM_REQUEST::SyncWriteClient
  2763. Description:
  2764. This function is a wrapper for the sychronous write to the client.
  2765. It is separated from the async case because no async state changes
  2766. need to be done here => cleaner function
  2767. Arguments:
  2768. lpBuffer - pointer to buffer that has contents to be written out
  2769. nBytesToWrite - number of bytes to write to client
  2770. pnBytesWritten - pointer to number of bytes written to client
  2771. Returns:
  2772. TRUE for success and FALSE for failure
  2773. */
  2774. STDMETHODIMP
  2775. WAM_REQUEST::SyncWriteClient
  2776. (
  2777. DWORD nBytesToWrite,
  2778. unsigned char * lpBuffer, // LPVOID lpBuffer,
  2779. DWORD * pnBytesWritten,
  2780. DWORD dwFlags
  2781. )
  2782. {
  2783. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  2784. DBG_ASSERT( m_pHttpRequest->QueryClientConn()->CheckSignature() );
  2785. IF_DEBUG( WAM_ISA_CALLS ) {
  2786. DBGPRINTF(( DBG_CONTEXT, "WAM_REQUEST[%p]::"
  2787. "SyncWriteClient( %p, %d)\n",
  2788. this, lpBuffer, nBytesToWrite));
  2789. }
  2790. // strip off undefined flags
  2791. dwFlags &= IO_FLAG_NO_DELAY;
  2792. return HresultFromBool( m_pHttpRequest->WriteFile( lpBuffer,
  2793. nBytesToWrite,
  2794. pnBytesWritten,
  2795. IO_FLAG_SYNC | dwFlags ) );
  2796. } // WAM_REQUEST::SyncWriteClient()
  2797. /*---------------------------------------------------------------------*
  2798. WAM_REQUEST::SendHeader
  2799. Description:
  2800. Arguments:
  2801. szStatus - status string
  2802. cchStatus - length of status string
  2803. szHeader - header string
  2804. cchHeader - length of header string
  2805. dwIsaKeepConn - keep/close/no-change connection?
  2806. Returns:
  2807. HRESULT
  2808. */
  2809. STDMETHODIMP
  2810. WAM_REQUEST::SendHeader(
  2811. IN unsigned char * szStatus
  2812. , IN DWORD cchStatus
  2813. , IN unsigned char * szHeader
  2814. , IN DWORD cchHeader
  2815. , IN DWORD dwIsaKeepConn
  2816. )
  2817. {
  2818. HRESULT hrRet = NOERROR;
  2819. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  2820. //
  2821. // Make sure the strings are zero-terminated (#157805)
  2822. //
  2823. if( !IsStringTerminated( (LPCSTR) szStatus, cchStatus ) ||
  2824. !IsStringTerminated( (LPCSTR) szHeader, cchHeader ) )
  2825. {
  2826. return ERROR_INVALID_PARAMETER;
  2827. }
  2828. IF_DEBUG( WAM_ISA_CALLS ) {
  2829. DBGPRINTF((
  2830. DBG_CONTEXT
  2831. , "WAM_REQUEST[%p]::SendHeader( %s, %s)"
  2832. "\n"
  2833. , this
  2834. , szStatus
  2835. , szHeader
  2836. ));
  2837. DBGPRINTF(( DBG_CONTEXT,
  2838. "WAM_REQUEST::SendHeader: "
  2839. "Intended keep-conn = %d "
  2840. "\n"
  2841. , dwIsaKeepConn
  2842. ));
  2843. }
  2844. DBG_ASSERT( m_pExec );
  2845. DBG_ASSERT( m_pHttpRequest );
  2846. //
  2847. // If this is a child ISA, we may not want to send any headers
  2848. //
  2849. if ( m_pExec->NoHeaders() || m_pExec->RedirectOnly() ) {
  2850. DWORD cbSent;
  2851. BYTE * pbTextToSend;
  2852. //
  2853. // If no headers needed, just send everything past the
  2854. // "\r\n\r\n"
  2855. //
  2856. pbTextToSend = ScanForTerminator( (char *) szHeader );
  2857. pbTextToSend = ( pbTextToSend == NULL )
  2858. ? (BYTE * ) szHeader
  2859. : pbTextToSend;
  2860. cbSent = lstrlen( (CHAR*) pbTextToSend );
  2861. hrRet = SyncWriteClient( cbSent, pbTextToSend, &cbSent,
  2862. IO_FLAG_NO_DELAY );
  2863. goto LExit;
  2864. } else {
  2865. BOOL fFinished;
  2866. //
  2867. // If ISA specified a keep-conn change:
  2868. // Set request's keep-conn state to AND of ISA setting
  2869. // and client setting (which is request's current setting)
  2870. //
  2871. // NOTE this means that if ISA said KEEPCONN_TRUE or
  2872. // KEEPCONN_OLD_ISAPI we no-op.
  2873. //
  2874. // NOTE we do this before building headers to ensure
  2875. // correct keep-alive behavior.
  2876. //
  2877. if ( dwIsaKeepConn == KEEPCONN_FALSE
  2878. || dwIsaKeepConn == KEEPCONN_OLD_ISAPI ) {
  2879. m_pHttpRequest->SetKeepConn( FALSE );
  2880. }
  2881. IF_DEBUG( WAM_ISA_CALLS ) {
  2882. DBGPRINTF(( DBG_CONTEXT,
  2883. "WAM_REQUEST::SendHeader: "
  2884. "Actual keep-conn = %d "
  2885. "\n"
  2886. , m_pHttpRequest->IsKeepConnSet()
  2887. ));
  2888. }
  2889. //
  2890. // Build the typical server response headers for the extension DLL
  2891. //
  2892. if ( szStatus
  2893. && ( (!strncmp( (char *) szStatus, "401 ", sizeof("401 ")-1 ) ) ||
  2894. (!strncmp( (char *) szStatus, "407 ", sizeof("407 ")-1 ) ) )
  2895. ) {
  2896. m_pHttpRequest->SetDeniedFlags( SF_DENIED_APPLICATION );
  2897. m_pHttpRequest->SetAuthenticationRequested( TRUE );
  2898. }
  2899. if ( szHeader ) {
  2900. // NYI: Ugly cast of const char * to "char *"
  2901. m_pHttpRequest->CheckForBasicAuthenticationHeader(
  2902. (char * ) szHeader
  2903. );
  2904. }
  2905. // NYI: Ugly cast of const char * to "char *"
  2906. hrRet = HresultFromBool( m_pHttpRequest->SendHeader(
  2907. (char * ) szStatus
  2908. , (char * ) (( szHeader)
  2909. ? ( szHeader)
  2910. : (unsigned char * ) "\r\n")
  2911. , IO_FLAG_SYNC
  2912. , &fFinished
  2913. , 0 // dwOptions
  2914. , m_fWriteHeaders
  2915. ));
  2916. // NYI: I need to figure out what this fFinished was there for
  2917. // borrowed from ext\isplocal.cxx::ServerSupportFunction()
  2918. DBG_ASSERT( !fFinished );
  2919. }
  2920. LExit:
  2921. return hrRet;
  2922. } // WAM_REQUEST::SendHeader()
  2923. /*---------------------------------------------------------------------*
  2924. WAM_REQUEST::SendEntireResponse
  2925. Description:
  2926. Sends an entire response (headers and body).
  2927. NOTE this is a private api provided as a performance optimization
  2928. for ASP
  2929. NOTE Works only in-process.
  2930. [would be LOTS of work to support oop - must marshal all buffers]
  2931. Arguments:
  2932. pvHseResponseInfo - custom struct, see iisext.x
  2933. Returns:
  2934. HRESULT
  2935. */
  2936. STDMETHODIMP
  2937. WAM_REQUEST::SendEntireResponse(
  2938. unsigned char * pvHseResponseInfo // HSE_SEND_ENTIRE_RESPONSE_INFO *
  2939. )
  2940. {
  2941. HRESULT hrRet = NOERROR;
  2942. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  2943. //
  2944. // figure out whether we need to invoke filter(s) or not.
  2945. // we need to invoke filter(s) if either the raw-data-notify
  2946. // or headers-notify flag is set.
  2947. //
  2948. // if yes, we use normal code path to invoke filter(s).
  2949. //
  2950. // if no, we use fastpath.
  2951. //
  2952. // CONSIDER support filters in fastpath code as well
  2953. //
  2954. BOOL fMustUseFilter =
  2955. m_pHttpRequest->QueryFilter()->IsNotificationNeeded(
  2956. SF_NOTIFY_SEND_RAW_DATA | SF_NOTIFY_SEND_RESPONSE
  2957. , m_pHttpRequest->IsSecurePort()
  2958. );
  2959. if ( fMustUseFilter ) {
  2960. hrRet = SendEntireResponseNormal(
  2961. reinterpret_cast
  2962. <HSE_SEND_ENTIRE_RESPONSE_INFO *>
  2963. (pvHseResponseInfo)
  2964. );
  2965. } else {
  2966. hrRet = SendEntireResponseFast(
  2967. reinterpret_cast
  2968. <HSE_SEND_ENTIRE_RESPONSE_INFO *>
  2969. (pvHseResponseInfo)
  2970. );
  2971. }
  2972. return hrRet;
  2973. } // WAM_REQUEST::SendEntireResponse()
  2974. /*++
  2975. WAM_REQUEST::SendEntireResponseAndCleanup
  2976. Description:
  2977. This routine is designed to provide the same functionality as
  2978. the SendEntireResponse method for oop applications but will do
  2979. the CleanupWamRequest call, so that no additional RPC calls are
  2980. needed.
  2981. This will enable oop asp to send the request and cleanup in
  2982. a single RPC call. Currently oop asp requests use multiple
  2983. RPC calls that do synchronous IO:
  2984. 1. SendHeaders
  2985. 2. WriteClient * number of response buffers
  2986. 3. CleanupWamRequest
  2987. 4. Release
  2988. This interface will collapse this to two RPC calls.
  2989. Possible additional work:
  2990. 1. Do writes asyncronously.
  2991. 2. Use shared memory handles to pass the data.
  2992. Other Notes:
  2993. Possible ISAP race conditions. The _FirstThread synch
  2994. method was removed for ease of implementation on the
  2995. WAM side. This may need to be put into place and that
  2996. code reworked if there are regressions.
  2997. Figure out what paramter types make sense thoughout
  2998. the code path. Right now I'm constantly casting from
  2999. char * to unsigned char * and back. Ick.
  3000. Arguments:
  3001. Returns:
  3002. --*/
  3003. STDMETHODIMP
  3004. WAM_REQUEST::SendEntireResponseAndCleanup
  3005. (
  3006. IN unsigned char * szStatus
  3007. , IN DWORD cbStatus
  3008. , IN unsigned char * szHeader
  3009. , IN DWORD cbHeader
  3010. , IN OOP_RESPONSE_INFO * pOopResponseInfo
  3011. , IN unsigned char * szLogData
  3012. , IN DWORD cbLogData
  3013. , IN DWORD dwIsaKeepConn
  3014. , OUT BOOL * pfDisconnected
  3015. )
  3016. {
  3017. HRESULT hr = NOERROR;
  3018. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  3019. DBG_ASSERT( m_pHttpRequest->QueryClientConn()->CheckSignature() );
  3020. DBG_ASSERT( szStatus );
  3021. DBG_ASSERT( szHeader );
  3022. DBG_ASSERT( szLogData );
  3023. DBG_ASSERT( pOopResponseInfo );
  3024. DBG_ASSERT( pfDisconnected );
  3025. IF_DEBUG( WAM_ISA_CALLS ) {
  3026. DBGPRINTF(( DBG_CONTEXT,
  3027. "WAM_REQUEST[%p]::SendEntireResponseAndCleanup()\n"
  3028. "szStatus: %s; cbHeader: %x;\n",
  3029. this,
  3030. szStatus,
  3031. cbHeader
  3032. ));
  3033. }
  3034. // Assume that we will not do the cleanup inline
  3035. *pfDisconnected = FALSE;
  3036. //
  3037. // The most obvious thing to do with the send entire response
  3038. // for out of process is to repack the marshalled data into
  3039. // the format used by in the in process call and use that
  3040. // call.
  3041. //
  3042. HSE_SEND_ENTIRE_RESPONSE_INFO hseResponseInfo;
  3043. // populate struct with header info
  3044. hseResponseInfo.HeaderInfo.pszStatus = (LPCSTR)szStatus;
  3045. hseResponseInfo.HeaderInfo.cchStatus = cbStatus;
  3046. hseResponseInfo.HeaderInfo.pszHeader = (LPCSTR)szHeader;
  3047. hseResponseInfo.HeaderInfo.cchHeader = cbHeader;
  3048. hseResponseInfo.HeaderInfo.fKeepConn =
  3049. (dwIsaKeepConn == KEEPCONN_TRUE) ? TRUE : FALSE;
  3050. // populate the wsa buffers
  3051. hseResponseInfo.cWsaBuf = 1 + pOopResponseInfo->cBuffers;
  3052. hseResponseInfo.rgWsaBuf =
  3053. (WSABUF *)(_alloca(hseResponseInfo.cWsaBuf * sizeof(WSABUF)));
  3054. // first buffer is empty
  3055. hseResponseInfo.rgWsaBuf[0].len = 0;
  3056. hseResponseInfo.rgWsaBuf[0].buf = NULL;
  3057. for ( DWORD i = 0; i < pOopResponseInfo->cBuffers; i++ )
  3058. {
  3059. hseResponseInfo.rgWsaBuf[i+1].len = pOopResponseInfo->rgBuffers[i].cbBuffer;
  3060. hseResponseInfo.rgWsaBuf[i+1].buf = (LPSTR)pOopResponseInfo->rgBuffers[i].pbBuffer;
  3061. }
  3062. hr = SendEntireResponse( (LPBYTE)&hseResponseInfo );
  3063. if( SUCCEEDED(hr) )
  3064. {
  3065. *pfDisconnected = TRUE;
  3066. DWORD dwStatus = atol( (LPSTR)szStatus );
  3067. // We want to only do the cleanup on success and send back a failure
  3068. // indication to the WAM_EXEC_INFO this would allow normal
  3069. // termination in the event that the client is disconnected, etc.
  3070. HRESULT hrCleanup = CleanupWamRequest( szLogData,
  3071. cbLogData,
  3072. dwStatus,
  3073. dwIsaKeepConn
  3074. );
  3075. DBG_ASSERT(SUCCEEDED(hrCleanup));
  3076. }
  3077. return hr;
  3078. }
  3079. /*-----------------------------------------------------------------------------*
  3080. WAM_REQUEST::SendURLRedirectResponse
  3081. Descrption:
  3082. Send an URL redirect message to the browser client
  3083. Input:
  3084. pData - pointer to buffer that contains the location to
  3085. redirect the client to.
  3086. Return:
  3087. BOOL
  3088. */
  3089. STDMETHODIMP
  3090. WAM_REQUEST::SendURLRedirectResponse
  3091. (
  3092. unsigned char * pData
  3093. )
  3094. {
  3095. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  3096. IF_DEBUG( WAM_ISA_CALLS ) {
  3097. DBGPRINTF(( DBG_CONTEXT,
  3098. "WAM_REQUEST[%p]::SendURLRedirectResponse\n"
  3099. ,
  3100. this
  3101. ));
  3102. }
  3103. DBG_ASSERT( m_pExec );
  3104. DBG_ASSERT( m_pHttpRequest );
  3105. HRESULT hrRet = NOERROR;
  3106. if ( m_pExec->RedirectOnly() )
  3107. {
  3108. DWORD cbLen;
  3109. STACK_STR( strMessageString, 256 );
  3110. STACK_STR( strOutputString, 512 );
  3111. cbLen = LoadString( GetModuleHandle( W3_MODULE_NAME ),
  3112. IDS_URL_MOVED,
  3113. strMessageString.QueryStr(),
  3114. 256 );
  3115. if ( !cbLen )
  3116. {
  3117. hrRet = E_FAIL; // UNDONE can we be more explicit than E_FAIL
  3118. goto LExit;
  3119. }
  3120. // NYI: Check for overflows!
  3121. cbLen = wsprintf( strOutputString.QueryStr(),
  3122. strMessageString.QueryStr(),
  3123. (CHAR*) pData );
  3124. hrRet = SyncWriteClient(
  3125. cbLen,
  3126. (unsigned char *) strOutputString.QueryStr(),
  3127. &cbLen,
  3128. 0 );
  3129. }
  3130. else
  3131. {
  3132. hrRet = SendRedirectMessage( (unsigned char *) pData);
  3133. }
  3134. LExit:
  3135. return hrRet;
  3136. }
  3137. /*-----------------------------------------------------------------------------*
  3138. WAM_REQUEST::SendRedirectMessage
  3139. Description:
  3140. Arguments:
  3141. Returns:
  3142. */
  3143. STDMETHODIMP
  3144. WAM_REQUEST::SendRedirectMessage
  3145. (
  3146. unsigned char * szRedirect // LPCSTR pszRedirect
  3147. )
  3148. {
  3149. STACK_STR( strURL, 512);
  3150. DWORD cb;
  3151. BOOL fFinished = FALSE;
  3152. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  3153. IF_DEBUG( WAM_ISA_CALLS ) {
  3154. DBGPRINTF(( DBG_CONTEXT,
  3155. "WAM_REQUEST[%p]::SendRedirectMessage( %s)\n",
  3156. this, szRedirect));
  3157. }
  3158. //
  3159. // Construct a redirect message and send it synchronously
  3160. //
  3161. // UNDONE cleanup
  3162. if ( strURL.Copy( (LPCSTR) szRedirect ) &&
  3163. m_pHttpRequest->
  3164. BuildURLMovedResponse( m_pHttpRequest->QueryRespBuf(),
  3165. &strURL,
  3166. HT_REDIRECT ) &&
  3167. m_pHttpRequest->SendHeader( m_pHttpRequest->QueryRespBufPtr(),
  3168. m_pHttpRequest->QueryRespBufCB(),
  3169. IO_FLAG_SYNC,
  3170. &fFinished ) ) {
  3171. return NOERROR;
  3172. }
  3173. return E_FAIL; // UNDONE can we say more than E_FAIL?
  3174. } // WAM_REQUEST::SendRedirectMessage()
  3175. // UNDONE remove unused ???
  3176. /*-----------------------------------------------------------------------------*
  3177. WAM_REQUEST::GetSslCtxt
  3178. Description:
  3179. Arguments:
  3180. Returns:
  3181. */
  3182. STDMETHODIMP
  3183. WAM_REQUEST::GetSslCtxt
  3184. (
  3185. DWORD cbCtxtHandle,
  3186. unsigned char * pbCtxtHandle // PBYTE pbCtxtHandle
  3187. )
  3188. {
  3189. HRESULT hrRet = NOERROR; // UNDONE not reset anywhere???
  3190. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  3191. IF_DEBUG( WAM_ISA_CALLS ) {
  3192. DBGPRINTF(( DBG_CONTEXT, "WAM_REQUEST[%p]::GetSslCtxt( %d, %p)\n",
  3193. this, cbCtxtHandle, pbCtxtHandle));
  3194. }
  3195. //
  3196. // QuerySslCtxtHandle() returns a handle to certificate info.
  3197. // This handle will be copied to the caller if cert is available
  3198. // otherwise a NULL handle will be returned ( this is not considered
  3199. // an error)
  3200. //
  3201. if ( m_pHttpRequest->QueryAuthenticationObj()->QuerySslCtxtHandle() ) {
  3202. memcpy( pbCtxtHandle,
  3203. m_pHttpRequest->QueryAuthenticationObj()->QuerySslCtxtHandle(),
  3204. sizeof( CtxtHandle ));
  3205. } else {
  3206. // UNDONE: I need to send/set proper error code
  3207. memset( pbCtxtHandle, 0, sizeof( CtxtHandle ));
  3208. }
  3209. return hrRet;
  3210. } // WAM_REQUEST::GetSslCtxt()
  3211. /*-----------------------------------------------------------------------------*
  3212. WAM_REQUEST::GetClientCertInfoEx
  3213. Description:
  3214. Arguments:
  3215. Returns:
  3216. */
  3217. STDMETHODIMP
  3218. WAM_REQUEST::GetClientCertInfoEx
  3219. (
  3220. IN DWORD cbAllocated,
  3221. OUT DWORD * pdwCertEncodingType,
  3222. OUT unsigned char * pbCertEncoded,
  3223. OUT DWORD * pcbCertEncoded,
  3224. OUT DWORD * pdwCertificateFlags
  3225. )
  3226. {
  3227. HRESULT hrRet = NOERROR;
  3228. DBG_ASSERT( m_dwSignature == WAM_REQUEST_SIGNATURE );
  3229. IF_DEBUG( WAM_ISA_CALLS ) {
  3230. DBGPRINTF(( DBG_CONTEXT,
  3231. "WAM_REQUEST[%p]::GetClientCertInfoEx( %d, %p)\n",
  3232. this, cbAllocated, pbCertEncoded));
  3233. }
  3234. if ( !m_pHttpRequest->QueryAuthenticationObj()->GetClientCertBlob(
  3235. cbAllocated,
  3236. pdwCertEncodingType,
  3237. pbCertEncoded,
  3238. pcbCertEncoded,
  3239. pdwCertificateFlags ) ) {
  3240. //
  3241. // if get call failed, return last error (set by callee)
  3242. //
  3243. hrRet = HRESULT_FROM_WIN32( GetLastError() );
  3244. }
  3245. return hrRet;
  3246. } // WAM_REQUEST::GetClientCertInfoEx()
  3247. /*-----------------------------------------------------------------------------*
  3248. WAM_REQUEST::GetSspiInfo
  3249. Description:
  3250. Arguments:
  3251. Returns:
  3252. */
  3253. STDMETHODIMP
  3254. WAM_REQUEST::GetSspiInfo
  3255. (
  3256. DWORD cbCtxtHandle,
  3257. unsigned char * pbCtxtHandle, // PBYTE pbCtxtHandle
  3258. DWORD cbCredHandle,
  3259. unsigned char * pbCredHandle // PBYTE pbCredHandle
  3260. )
  3261. {
  3262. HRESULT hrRet = NOERROR;
  3263. IF_DEBUG( WAM_ISA_CALLS ) {
  3264. DBGPRINTF(( DBG_CONTEXT,
  3265. "WAM_REQUEST[%p]::GetSspiInfo( %d, %p, %d, %d)\n",
  3266. this, cbCtxtHandle, pbCtxtHandle,
  3267. cbCredHandle, pbCredHandle));
  3268. }
  3269. if ( m_pHttpRequest->IsClearTextPassword() ) {
  3270. hrRet = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  3271. goto LExit;
  3272. }
  3273. DBG_ASSERT( cbCtxtHandle == sizeof( CtxtHandle));
  3274. if ( m_pHttpRequest->QueryAuthenticationObj()->QueryCtxtHandle() ) {
  3275. memcpy( pbCtxtHandle,
  3276. m_pHttpRequest->QueryAuthenticationObj()->QueryCtxtHandle(),
  3277. sizeof( CtxtHandle ));
  3278. } else {
  3279. memset( pbCtxtHandle, 0, sizeof( CtxtHandle ));
  3280. }
  3281. DBG_ASSERT( cbCredHandle == sizeof( CredHandle));
  3282. if ( m_pHttpRequest->QueryAuthenticationObj()->QueryCredHandle() ) {
  3283. memcpy( pbCredHandle,
  3284. m_pHttpRequest->QueryAuthenticationObj()->QueryCredHandle(),
  3285. sizeof( CredHandle ));
  3286. } else {
  3287. memset( pbCredHandle, 0, sizeof( CredHandle ));
  3288. }
  3289. LExit:
  3290. return hrRet;
  3291. } // WAM_REQUEST::GetSspiInfo()
  3292. /*-----------------------------------------------------------------------------*
  3293. WAM_REQUEST::RequestAbortiveClose
  3294. Cover function
  3295. */
  3296. STDMETHODIMP
  3297. WAM_REQUEST::RequestAbortiveClose( VOID )
  3298. {
  3299. IF_DEBUG( WAM_ISA_CALLS ) {
  3300. DBGPRINTF(( DBG_CONTEXT,
  3301. "WAM_REQUEST[%p]::RequestAbortiveClose\n"
  3302. ,
  3303. this
  3304. ));
  3305. }
  3306. return HresultFromBool( m_pHttpRequest->RequestAbortiveClose() );
  3307. }
  3308. /*-----------------------------------------------------------------------------*
  3309. WAM_REQUEST::CloseConnection
  3310. */
  3311. STDMETHODIMP
  3312. WAM_REQUEST::CloseConnection( VOID )
  3313. {
  3314. IF_DEBUG( WAM_ISA_CALLS ) {
  3315. DBGPRINTF(( DBG_CONTEXT,
  3316. "WAM_REQUEST[%p]::CloseConnection\n",
  3317. this
  3318. ));
  3319. }
  3320. return HresultFromBool( m_pHttpRequest->CloseConnection() );
  3321. }
  3322. /*-----------------------------------------------------------------------------*
  3323. WAM_REQUEST::LogEvent
  3324. */
  3325. STDMETHODIMP
  3326. WAM_REQUEST::LogEvent( DWORD dwEventId, unsigned char * szText )
  3327. {
  3328. IF_DEBUG( WAM_ISA_CALLS ) {
  3329. DBGPRINTF(( DBG_CONTEXT,
  3330. szText ?
  3331. "WAM_REQUEST[%p]::LogEvent: %d %s\n" :
  3332. "WAM_REQUEST[%p]::LogEvent: %d\n",
  3333. this,
  3334. dwEventId,
  3335. szText
  3336. ));
  3337. }
  3338. //
  3339. // per KB Q129126, only SYSTEM can write to event log
  3340. // temporarily revert to self.
  3341. //
  3342. HANDLE hToken = 0;
  3343. OpenThreadToken( GetCurrentThread(), TOKEN_ALL_ACCESS, FALSE, &hToken );
  3344. //
  3345. // Drop to SYSTEM context, but only if we have user token to return to
  3346. //
  3347. if( hToken ) {
  3348. RevertToSelf( );
  3349. }
  3350. //
  3351. // We don't instantiate event log until needed - do it now
  3352. //
  3353. if( g_pWamEventLog == NULL ) {
  3354. g_pWamEventLog = new EVENT_LOG( "WAM" );
  3355. if( (g_pWamEventLog == NULL) || !g_pWamEventLog->Success() ) {
  3356. DWORD dwError = g_pWamEventLog ?
  3357. g_pWamEventLog->GetErrorCode() : ERROR_NOT_ENOUGH_MEMORY;
  3358. DBGPRINTF(( DBG_CONTEXT,
  3359. "Failure to init WAM event log (%d)\n",
  3360. dwError
  3361. ));
  3362. if(g_pWamEventLog) {
  3363. delete g_pWamEventLog;
  3364. g_pWamEventLog = NULL;
  3365. }
  3366. }
  3367. }
  3368. if( g_pWamEventLog != NULL ) {
  3369. //
  3370. // We let EVENT_LOG object handle any problems that may occur here
  3371. //
  3372. const CHAR * apsz[1];
  3373. apsz[0] = (const CHAR *)szText;
  3374. g_pWamEventLog->LogEvent( dwEventId, 1, apsz, 0 );
  3375. }
  3376. if( hToken ) {
  3377. SetThreadToken(NULL, hToken);
  3378. }
  3379. //
  3380. // There is really no point in returning any error from here --
  3381. // our callers have enough problems already
  3382. //
  3383. return HresultFromBool( TRUE );
  3384. }
  3385. /*-----------------------------------------------------------------------------*
  3386. WAM_REQUEST::SSIncExec
  3387. Descrption:
  3388. Executes SSInc #exec
  3389. Input:
  3390. szCommand - command
  3391. dwExecFlags - HSE_EXEC_???
  3392. pszVerb - verb
  3393. Return:
  3394. HRESULT
  3395. */
  3396. STDMETHODIMP
  3397. WAM_REQUEST::SSIncExec
  3398. (
  3399. unsigned char *szCommand,
  3400. DWORD dwExecFlags,
  3401. unsigned char *szVerb
  3402. )
  3403. {
  3404. HRESULT hrRet = NOERROR;
  3405. IF_DEBUG( WAM_ISA_CALLS ) {
  3406. DBGPRINTF(( DBG_CONTEXT,
  3407. "WAM_REQUEST[%p]::SSIncExec\n"
  3408. ,
  3409. this
  3410. ));
  3411. }
  3412. //
  3413. // Ref before child exec operation, in case child exec
  3414. // introduces an asynchronicity.
  3415. //
  3416. AddRef();
  3417. //
  3418. // temporarily reset the binding of the WAM_REQUEST to HTTP_REQUEST
  3419. // this will ensure that we do not tramp on rebinding a new WAM_REQUEST
  3420. // to the same HTTP_REQUEST
  3421. //
  3422. DBG_ASSERT( m_pHttpRequest->QueryWamRequest() == this );
  3423. m_pHttpRequest->SetWamRequest( NULL );
  3424. if ( dwExecFlags & HSE_EXEC_COMMAND ) {
  3425. hrRet = HresultFromBool( m_pHttpRequest->ExecuteChildCommand(
  3426. (char *)szCommand,
  3427. dwExecFlags ));
  3428. } else {
  3429. hrRet = HresultFromBool( m_pHttpRequest->ExecuteChildCGIBGI(
  3430. (char *)szCommand,
  3431. dwExecFlags,
  3432. (char *)szVerb ));
  3433. }
  3434. //
  3435. // Restore the binding back.
  3436. //
  3437. DBG_ASSERT( m_pHttpRequest->QueryWamRequest() == NULL );
  3438. m_pHttpRequest->SetWamRequest( this );
  3439. //
  3440. // Deref after child exec operation
  3441. //
  3442. Release();
  3443. return hrRet;
  3444. }
  3445. /*---------------------------------------------------------------------*
  3446. WAM_REQUEST::GetAspMDAllData
  3447. Descrption:
  3448. Private api for ASP that returns asp metadata in a buffer. Equivalent
  3449. of MD GetAllData.
  3450. Parameters:
  3451. Return:
  3452. HRESULT
  3453. */
  3454. STDMETHODIMP
  3455. WAM_REQUEST::GetAspMDAllData(
  3456. IN unsigned char * pszMDPath
  3457. , IN DWORD dwMDUserType
  3458. , IN DWORD dwDefaultBufferSize
  3459. , OUT unsigned char * pBuffer
  3460. , OUT DWORD * pdwRequiredBufferSize
  3461. , OUT DWORD * pdwNumDataEntries
  3462. )
  3463. {
  3464. HRESULT hr = NOERROR, hrT;
  3465. BOOL fT;
  3466. METADATA_GETALL_RECORD *pMDGetAllRec = (METADATA_GETALL_RECORD *)pBuffer;
  3467. DWORD dwDataSetNumber = 0;
  3468. IMDCOM* pMetabase = g_pWamDictator->PMetabase()->QueryPMDCOM();
  3469. METADATA_HANDLE hMetabase = NULL;
  3470. const DWORD dwMDDefaultTimeOut = 2000;
  3471. DBG_ASSERT(pMetabase != NULL);
  3472. IF_DEBUG( WAM_ISA_CALLS ) {
  3473. DBGPRINTF((
  3474. DBG_CONTEXT
  3475. , "WAM_REQUEST[%p]::GetAspMDAllData\n"
  3476. , this
  3477. ));
  3478. }
  3479. // Only allow the return of the data that ASP needs. Dont allow anything else
  3480. if (dwMDUserType != IIS_MD_UT_WAM && dwMDUserType != ASP_MD_UT_APP)
  3481. return(E_ACCESSDENIED);
  3482. // Open the metabase key
  3483. hr = pMetabase->ComMDOpenMetaObjectA(METADATA_MASTER_ROOT_HANDLE, pszMDPath,
  3484. METADATA_PERMISSION_READ, dwMDDefaultTimeOut, &hMetabase);
  3485. if (FAILED(hr)) {
  3486. DBGPRINTF((
  3487. DBG_CONTEXT
  3488. , "WAM_REQUEST[%p]::Metadata open failed %x\n"
  3489. , this
  3490. , hr
  3491. ));
  3492. return E_FAIL;
  3493. }
  3494. DBG_ASSERT( hMetabase );
  3495. hr = pMetabase->ComMDGetAllMetaDataW( hMetabase,
  3496. L"",
  3497. METADATA_INHERIT,
  3498. dwMDUserType,
  3499. ALL_METADATA,
  3500. pdwNumDataEntries,
  3501. &dwDataSetNumber,
  3502. dwDefaultBufferSize,
  3503. (unsigned char *)pBuffer,
  3504. pdwRequiredBufferSize
  3505. );
  3506. hrT = pMetabase->ComMDCloseMetaObject(hMetabase);
  3507. DBG_ASSERT(SUCCEEDED(hrT));
  3508. return hr;
  3509. } // WAM_REQUEST::GetAspMDAllData
  3510. /*---------------------------------------------------------------------*
  3511. WAM_REQUEST::GetAspMDData
  3512. Descrption:
  3513. Private api for ASP that returns asp metadata in a buffer. Equivalent
  3514. of MD GetAllData.
  3515. Parameters:
  3516. Return:
  3517. HRESULT
  3518. */
  3519. STDMETHODIMP
  3520. WAM_REQUEST::GetAspMDData(
  3521. IN unsigned char * pszMDPath
  3522. , IN DWORD dwMDIdentifier
  3523. , IN DWORD dwMDAttributes
  3524. , IN DWORD dwMDUserType
  3525. , IN DWORD dwMDDataType
  3526. , IN DWORD dwMDDataLen
  3527. , IN DWORD dwMDDataTag
  3528. , OUT unsigned char * pbMDData
  3529. , OUT DWORD * pdwRequiredBufferSize
  3530. )
  3531. {
  3532. HRESULT hr = NOERROR, hrT;
  3533. BOOL fT;
  3534. IMDCOM* pMetabase = g_pWamDictator->PMetabase()->QueryPMDCOM();
  3535. METADATA_HANDLE hMetabase = NULL;
  3536. const DWORD dwMDDefaultTimeOut = 2000;
  3537. METADATA_RECORD MDRec;
  3538. DBG_ASSERT(pMetabase != NULL);
  3539. IF_DEBUG( WAM_ISA_CALLS ) {
  3540. DBGPRINTF((
  3541. DBG_CONTEXT
  3542. , "WAM_REQUEST[%p]::GetAspMDData\n"
  3543. , this
  3544. ));
  3545. }
  3546. // Only allow the return of the data that ASP needs. Dont allow anything else
  3547. if (dwMDIdentifier != MD_SERVER_COMMENT && // used by ASP debugger
  3548. dwMDIdentifier != MD_APP_FRIENDLY_NAME && // used by ASP debugger
  3549. dwMDIdentifier != MD_APP_WAM_CLSID &&
  3550. dwMDIdentifier != MD_APP_ISOLATED)
  3551. return(E_ACCESSDENIED);
  3552. // Open the metabase key
  3553. hr = pMetabase->ComMDOpenMetaObjectA(METADATA_MASTER_ROOT_HANDLE, pszMDPath,
  3554. METADATA_PERMISSION_READ, dwMDDefaultTimeOut, &hMetabase);
  3555. if (FAILED(hr)) {
  3556. DBGPRINTF((
  3557. DBG_CONTEXT
  3558. , "WAM_REQUEST[%p]::Metadata open failed %x\n"
  3559. , this
  3560. , hr
  3561. ));
  3562. return E_FAIL;
  3563. }
  3564. DBG_ASSERT( hMetabase );
  3565. MDRec.dwMDIdentifier = dwMDIdentifier;
  3566. MDRec.dwMDAttributes = dwMDAttributes;
  3567. MDRec.dwMDUserType = dwMDUserType;
  3568. MDRec.dwMDDataType = dwMDDataType;
  3569. MDRec.dwMDDataLen = dwMDDataLen;
  3570. MDRec.pbMDData = pbMDData;
  3571. MDRec.dwMDDataTag = dwMDDataTag;
  3572. hr = pMetabase->ComMDGetMetaDataW( hMetabase,
  3573. L"",
  3574. &MDRec,
  3575. pdwRequiredBufferSize
  3576. );
  3577. hrT = pMetabase->ComMDCloseMetaObject(hMetabase);
  3578. DBG_ASSERT(SUCCEEDED(hrT));
  3579. return hr;
  3580. } // WAM_REQUEST::GetAspMDAllData
  3581. /*---------------------------------------------------------------------*
  3582. WAM_REQUEST::GetCustomError
  3583. Description:
  3584. Private API for ASP that returns custom error.
  3585. Parameters:
  3586. dwError error code
  3587. dwSubError sub error code
  3588. dwBufferSize supplied buffer size for URL/file
  3589. pbBuffer supplied buffer for URL/file
  3590. in case of file, mime type gets
  3591. concatinated to the file path
  3592. pdwRequiredBufferSize [out] required buffer size
  3593. pfIsFileError [out] flag: is file? (not URL)
  3594. Return:
  3595. HRESULT
  3596. */
  3597. STDMETHODIMP
  3598. WAM_REQUEST::GetCustomError
  3599. (
  3600. DWORD dwError,
  3601. DWORD dwSubError,
  3602. DWORD dwBufferSize,
  3603. unsigned char *pbBuffer,
  3604. DWORD *pdwRequiredBufferSize,
  3605. BOOL *pfIsFileError
  3606. )
  3607. {
  3608. HRESULT hr = NOERROR;
  3609. PCUSTOM_ERROR_ENTRY pceError;
  3610. DBG_ASSERT( m_pHttpRequest );
  3611. pceError = m_pHttpRequest->GetWAMMetaData()->LookupCustomError(
  3612. dwError,
  3613. dwSubError
  3614. );
  3615. if ( pceError) {
  3616. CHAR *szError = NULL; // URL or file
  3617. DWORD cchError = 0; // count of chars
  3618. STR strMimeType; // file mime type STR
  3619. CHAR *szMimeType = NULL; // file mime type CHAR*
  3620. DWORD cchMimeType = 0; // count of chars
  3621. if ( pceError->IsFileError()) {
  3622. *pfIsFileError = TRUE;
  3623. szError = pceError->QueryErrorFileName();
  3624. // get the mimetype
  3625. if ( SelectMimeMapping( &strMimeType,
  3626. szError,
  3627. m_pHttpRequest->GetWAMMetaData(),
  3628. MIMEMAP_MIME_TYPE)) {
  3629. szMimeType = strMimeType.QueryStr();
  3630. cchMimeType = strMimeType.QueryCCH();
  3631. }
  3632. // mime type is required -- no mime type = bad custom error
  3633. if ( NULL == szMimeType) {
  3634. szError = NULL;
  3635. }
  3636. }
  3637. else {
  3638. // URL
  3639. *pfIsFileError = FALSE;
  3640. szError = pceError->QueryErrorURL();
  3641. }
  3642. if ( szError) {
  3643. cchError = strlen( szError);
  3644. *pdwRequiredBufferSize = cchError + 1 + cchMimeType + 1;
  3645. if ( dwBufferSize >= *pdwRequiredBufferSize) {
  3646. memcpy( pbBuffer, szError, cchError+1);
  3647. if ( szMimeType) {
  3648. memcpy( pbBuffer+cchError+1, szMimeType, cchMimeType+1);
  3649. }
  3650. else {
  3651. pbBuffer[cchError+1] = '\0';
  3652. }
  3653. }
  3654. else {
  3655. // doesn't fit into supplied buffer
  3656. hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER);
  3657. }
  3658. }
  3659. else {
  3660. // malformed custom error
  3661. hr = E_FAIL;
  3662. }
  3663. }
  3664. else {
  3665. // custom error not found
  3666. hr = TYPE_E_ELEMENTNOTFOUND;
  3667. }
  3668. return hr;
  3669. } // WAM_REQUEST::GetCustomError
  3670. /*---------------------------------------------------------------------*
  3671. WAM_REQUEST::TestConnection
  3672. Description:
  3673. Private API for ASP that tests the IP connection to the client.
  3674. Parameters:
  3675. pfIsConnected [out] flag: is [probably] connected?
  3676. Return:
  3677. HRESULT
  3678. */
  3679. STDMETHODIMP
  3680. WAM_REQUEST::TestConnection(
  3681. BOOL *pfIsConnected
  3682. )
  3683. {
  3684. *pfIsConnected = m_pHttpRequest->TestConnection();
  3685. return NOERROR;
  3686. } // WAM_REQUEST::TestConnection
  3687. STDMETHODIMP
  3688. WAM_REQUEST::ExtensionTrigger(
  3689. unsigned char * pvContext,
  3690. DWORD dwTriggerType
  3691. )
  3692. /*++
  3693. Routine Description:
  3694. Invoke ISAPI filters waiting on SF_NOTIFY_EXTENSION_TRIGGER
  3695. Arguments:
  3696. pvContext - Trigger context pointer
  3697. dwTriggerType - Type of trigger
  3698. Returns:
  3699. HRESULT
  3700. --*/
  3701. {
  3702. BOOL fRet;
  3703. fRet = m_pHttpRequest->QueryFilter()->NotifyExtensionTriggerFilters(
  3704. (PVOID)pvContext,
  3705. dwTriggerType );
  3706. return HresultFromBool( fRet );
  3707. }
  3708. /************************************************************
  3709. * Static Member Functions of WAM_REQUEST
  3710. ************************************************************/
  3711. /*-----------------------------------------------------------------------------*
  3712. Support for WAM_REQUEST allocation cache
  3713. */
  3714. BOOL
  3715. WAM_REQUEST::InitClass( VOID)
  3716. {
  3717. ALLOC_CACHE_CONFIGURATION acConfig = { 1, WAM_REQUEST_CACHE_THRESHOLD,
  3718. sizeof(WAM_REQUEST)};
  3719. if ( NULL != sm_pachWamRequest) {
  3720. // already initialized
  3721. return ( TRUE);
  3722. }
  3723. sm_pachWamRequest = new ALLOC_CACHE_HANDLER( "WamRequest",
  3724. &acConfig);
  3725. #if DBG
  3726. sm_pDbgRefTraceLog = CreateRefTraceLog( C_REFTRACES_GLOBAL, 0 );
  3727. #endif
  3728. //
  3729. // Initialize class static request ID
  3730. //
  3731. sm_dwRequestID = 0;
  3732. return ( NULL != sm_pachWamRequest);
  3733. } // WAM_REQUEST::InitClass()
  3734. VOID
  3735. WAM_REQUEST::CleanupClass( VOID)
  3736. {
  3737. if ( NULL != sm_pachWamRequest) {
  3738. delete sm_pachWamRequest;
  3739. sm_pachWamRequest = NULL;
  3740. }
  3741. #if DBG
  3742. DestroyRefTraceLog( sm_pDbgRefTraceLog );
  3743. #endif
  3744. return;
  3745. } // WAM_REQUEST::CleanupClass()
  3746. void *
  3747. WAM_REQUEST::operator new( size_t s)
  3748. {
  3749. DBG_ASSERT( s == sizeof( WAM_REQUEST));
  3750. // allocate from allocation cache.
  3751. DBG_ASSERT( NULL != sm_pachWamRequest);
  3752. return (sm_pachWamRequest->Alloc());
  3753. } // WAM_REQUEST::operator new()
  3754. void
  3755. WAM_REQUEST::operator delete( void * pwr)
  3756. {
  3757. DBG_ASSERT( NULL != pwr);
  3758. // free to the allocation pool
  3759. DBG_ASSERT( NULL != sm_pachWamRequest);
  3760. DBG_REQUIRE( sm_pachWamRequest->Free(pwr));
  3761. return;
  3762. } // WAM_REQUEST::operator delete()
  3763. /************************ End of File ***********************/