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

3527 lines
86 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name :
  4. isapi_request.cxx
  5. Abstract:
  6. IIS+ IIsapiCore implementation.
  7. Author:
  8. Wade Hilmo (wadeh) 29-Aug-2000
  9. Project:
  10. w3core.dll
  11. --*/
  12. #include "precomp.hxx"
  13. #include "isapi_request.hxx"
  14. #include "iisapicore_i.c"
  15. #include "isapi_handler.h"
  16. #include "stringau.hxx"
  17. #define ISAPI_REQUEST_CACHE_THRESHOLD (400) // Value lifted from IIS 5
  18. #define SZ_FAILED_OOP_REQUEST_LOG_MESSAGE \
  19. "Out-of-process+ISAPI+extension+request+failed."
  20. ALLOC_CACHE_HANDLER * ISAPI_REQUEST::sm_pachIsapiRequest;
  21. PTRACE_LOG ISAPI_REQUEST::sm_pTraceLog;
  22. HRESULT
  23. SendEntityBodyAndLogDataHelper(
  24. W3_CONTEXT *pW3Context,
  25. ULATQ_CONTEXT pContext,
  26. BOOL fAsync,
  27. DWORD dwFlags,
  28. USHORT cChunks,
  29. HTTP_DATA_CHUNK * pChunks,
  30. DWORD *pcbSent
  31. );
  32. BOOL
  33. ISAPI_REQUEST::InitClass( VOID )
  34. /*++
  35. Routine Description:
  36. Acache initialization function
  37. Arguments:
  38. None
  39. Return Value:
  40. TRUE on success, FALSE on error
  41. --*/
  42. {
  43. ALLOC_CACHE_CONFIGURATION acConfig = { 1, ISAPI_REQUEST_CACHE_THRESHOLD,
  44. sizeof( ISAPI_REQUEST ) };
  45. if ( NULL != sm_pachIsapiRequest) {
  46. // already initialized
  47. return ( TRUE);
  48. }
  49. sm_pachIsapiRequest = new ALLOC_CACHE_HANDLER( "IsapiRequest",
  50. &acConfig);
  51. #if DBG
  52. sm_pTraceLog = CreateRefTraceLog( 2000, 0 );
  53. #else
  54. sm_pTraceLog = NULL;
  55. #endif
  56. return ( NULL != sm_pachIsapiRequest);
  57. }
  58. VOID
  59. ISAPI_REQUEST::CleanupClass( VOID )
  60. /*++
  61. Routine Description:
  62. Acache cleanup function
  63. Arguments:
  64. None
  65. Return Value:
  66. None
  67. --*/
  68. {
  69. if ( sm_pTraceLog != NULL )
  70. {
  71. DestroyRefTraceLog( sm_pTraceLog );
  72. sm_pTraceLog = NULL;
  73. }
  74. if ( NULL != sm_pachIsapiRequest)
  75. {
  76. delete sm_pachIsapiRequest;
  77. sm_pachIsapiRequest = NULL;
  78. }
  79. return;
  80. }
  81. HRESULT
  82. ISAPI_REQUEST::Create(
  83. VOID
  84. )
  85. /*++
  86. Routine Description:
  87. Creates a newly allocated ISAPI_REQUEST object. This
  88. function does initialization tasks which wouldn't be
  89. appropriate in the constructor due to potential failure
  90. during initialization.
  91. Arguments:
  92. None
  93. Return Value:
  94. HRESULT
  95. --*/
  96. {
  97. HRESULT hr = NOERROR;
  98. DBG_ASSERT( CheckSignature() );
  99. DBG_ASSERT( _pW3Context );
  100. IF_DEBUG( ISAPI )
  101. {
  102. DBGPRINTF((
  103. DBG_CONTEXT,
  104. "Creating ISAPI_REQUEST %p, W3Context=%p, Handler=%p.\r\n",
  105. this,
  106. _pW3Context,
  107. _pW3Context->QueryHandler()
  108. ));
  109. }
  110. if ( _fIsOop )
  111. {
  112. hr = CoCreateFreeThreadedMarshaler(this, &_pUnkFTM);
  113. }
  114. if ( FAILED( hr ) )
  115. {
  116. DBGPRINTF((
  117. DBG_CONTEXT,
  118. "ISAPI_REQUEST %p. Failed to CoCreate free threaded marshaler.\r\n",
  119. this
  120. ));
  121. goto ErrorExit;
  122. }
  123. IF_DEBUG( ISAPI )
  124. {
  125. DBGPRINTF((
  126. DBG_CONTEXT,
  127. "ISAPI_REQUEST %p created successfully.\r\n",
  128. this
  129. ));
  130. }
  131. return hr;
  132. ErrorExit:
  133. DBG_ASSERT( FAILED( hr ) );
  134. DBGPRINTF((
  135. DBG_CONTEXT,
  136. "Failed to create ISAPI_REQUEST %p. HRESULT=%08x.\r\n",
  137. this,
  138. hr
  139. ));
  140. return hr;
  141. }
  142. HRESULT STDMETHODCALLTYPE
  143. ISAPI_REQUEST::QueryInterface(
  144. REFIID riid,
  145. void __RPC_FAR *__RPC_FAR *ppvObject
  146. )
  147. /*++
  148. Routine Description:
  149. COM Goo
  150. Arguments:
  151. riid - Id of the interface requested
  152. ppvObject - Upon return, points to requested interface
  153. Return Value:
  154. HRESULT
  155. --*/
  156. {
  157. DBG_ASSERT( CheckSignature() );
  158. DBG_ASSERT( ppvObject );
  159. *ppvObject = NULL;
  160. /*
  161. DBGPRINTF((
  162. DBG_CONTEXT,
  163. "WAM_REQUEST::QueryInterface looking for ... ( " GUID_FORMAT " )\n",
  164. GUID_EXPAND( &riid)
  165. ));
  166. */
  167. if( riid == IID_IIsapiCore )
  168. {
  169. *ppvObject = static_cast<IIsapiCore *>( this );
  170. }
  171. else if ( riid == IID_IMarshal )
  172. {
  173. if ( _pUnkFTM == NULL )
  174. {
  175. DBG_ASSERT(FALSE);
  176. return E_NOINTERFACE;
  177. }
  178. else
  179. {
  180. return _pUnkFTM->QueryInterface(riid, ppvObject);
  181. }
  182. }
  183. else if( riid == IID_IUnknown )
  184. {
  185. *ppvObject = static_cast<IIsapiCore *>( this );
  186. }
  187. else if ( _pUnkFTM != NULL )
  188. {
  189. return _pUnkFTM->QueryInterface(riid, ppvObject);
  190. }
  191. else
  192. {
  193. return E_NOINTERFACE;
  194. }
  195. DBG_ASSERT( *ppvObject );
  196. ((IUnknown *)*ppvObject)->AddRef();
  197. /*
  198. DBGPRINTF((
  199. DBG_CONTEXT,
  200. "WAM_REQUEST::QueryInterface found ( " GUID_FORMAT ", %p )\n",
  201. GUID_EXPAND( &riid),
  202. *ppvObject
  203. ));
  204. */
  205. return NOERROR;
  206. }
  207. ULONG STDMETHODCALLTYPE
  208. ISAPI_REQUEST::AddRef(
  209. void
  210. )
  211. /*++
  212. Routine Description:
  213. COM Goo - adds a reference to the object
  214. Arguments:
  215. None
  216. Return Value:
  217. The number of references remaining at completion of this call
  218. --*/
  219. {
  220. LONG cRefs;
  221. DBG_ASSERT( CheckSignature() );
  222. cRefs = InterlockedIncrement( &_cRefs );
  223. //
  224. // Log the reference ( sm_pTraceLog!=NULL if DBG=1)
  225. //
  226. if ( sm_pTraceLog != NULL )
  227. {
  228. WriteRefTraceLog( sm_pTraceLog,
  229. cRefs,
  230. this );
  231. }
  232. return cRefs;
  233. }
  234. ULONG STDMETHODCALLTYPE
  235. ISAPI_REQUEST::Release(
  236. void
  237. )
  238. /*++
  239. Routine Description:
  240. COM Goo - deletes a referece to the object, and deletes
  241. the object upon zero references
  242. Arguments:
  243. None
  244. Return Value:
  245. The number of references remaining at completion of this call
  246. --*/
  247. {
  248. LONG cRefs;
  249. BOOL fIsOop = _fIsOop;
  250. W3_ISAPI_HANDLER * pW3IsapiHandler = NULL;
  251. DBG_ASSERT( CheckSignature() );
  252. //
  253. // WARNING - This object is always created by W3_ISAPI_HANDLER,
  254. // and that code uses the return value from Release
  255. // to determine if it's safe to advance the core
  256. // state machine. It is essential that this function
  257. // only return 0 in the case where it's called delete.
  258. //
  259. cRefs = InterlockedDecrement( &_cRefs );
  260. if ( sm_pTraceLog != NULL )
  261. {
  262. WriteRefTraceLog( sm_pTraceLog,
  263. cRefs,
  264. this );
  265. }
  266. if ( ( cRefs == 1 ) && fIsOop )
  267. {
  268. _pWamProcess->RemoveIsapiRequestFromList( this );
  269. }
  270. if ( cRefs == 0 )
  271. {
  272. DBG_ASSERT( _pW3Context );
  273. DBG_REQUIRE( ( pW3IsapiHandler = (W3_ISAPI_HANDLER*)_pW3Context->QueryHandler() ) != NULL );
  274. delete this;
  275. //
  276. // Notify the W3_ISAPI_HANDLER that we are done with it
  277. //
  278. pW3IsapiHandler->IsapiRequestFinished();
  279. return 0;
  280. }
  281. return cRefs;
  282. }
  283. HRESULT STDMETHODCALLTYPE
  284. ISAPI_REQUEST::GetServerVariable(
  285. LPSTR szVariableName,
  286. BYTE * szBuffer,
  287. DWORD cbBuffer,
  288. DWORD * pcbBufferRequired
  289. )
  290. /*++
  291. Routine Description:
  292. Returns the value of a server variable
  293. Arguments:
  294. szVariableName - The name of the server variable
  295. szBuffer - Upon return, contains the value of the server variable
  296. cbBuffer - The size of szBuffer.
  297. pcbBufferRequired - On successful return, the number of bytes copied
  298. to the buffer. On failure, the number of bytes
  299. required to hold szBuffer.
  300. Return Value:
  301. HRESULT
  302. --*/
  303. {
  304. HRESULT hr = NOERROR;
  305. //
  306. // The only current caller for this function is w3isapi.dll, which does
  307. // parameter validation from any outside code. So, we can get away with
  308. // just asserting here.
  309. //
  310. DBG_ASSERT( CheckSignature() );
  311. DBG_ASSERT( _pW3Context );
  312. DBG_ASSERT( szVariableName );
  313. DBG_ASSERT( pcbBufferRequired );
  314. DBG_ASSERT( szBuffer || ( cbBuffer == 0 ) );
  315. hr = SERVER_VARIABLE_HASH::GetServerVariable(
  316. _pW3Context,
  317. szVariableName,
  318. (LPSTR)szBuffer,
  319. &cbBuffer
  320. );
  321. *pcbBufferRequired = cbBuffer;
  322. return hr;
  323. }
  324. HRESULT STDMETHODCALLTYPE
  325. ISAPI_REQUEST::ReadClient(
  326. DWORD64 IsaContext,
  327. BYTE *pBuffer,
  328. DWORD cbBuffer,
  329. DWORD dwBytesToRead,
  330. DWORD *pdwSyncBytesRead,
  331. DWORD dwFlags
  332. )
  333. /*++
  334. Routine Description:
  335. Reads data from the client
  336. Arguments:
  337. IsaContext - The ISAPI_CONTEXT for this request (opaque)
  338. pBuffer - Contains read data upon return for sync reads
  339. cbBuffer - The size of pSyncReadBuffer
  340. dwBytesToRead - The number of bytes to read
  341. pdwSyncBytesRead - The number of bytes copied to pBuffer in sync case
  342. dwFlags - HSE_IO_* flags from caller
  343. Return Value:
  344. HRESULT
  345. --*/
  346. {
  347. DWORD dwBytesRead;
  348. HRESULT hr = NOERROR;
  349. BOOL fAsync = !!( dwFlags & HSE_IO_ASYNC );
  350. //
  351. // The only current caller for this function is w3isapi.dll, which does
  352. // parameter validation from any outside code. So, we can get away with
  353. // just asserting here.
  354. //
  355. DBG_ASSERT( CheckSignature() );
  356. DBG_ASSERT( _pW3Context );
  357. DBG_ASSERT( fAsync == !!IsaContext );
  358. DBG_ASSERT( dwBytesToRead );
  359. DBG_ASSERT( pdwSyncBytesRead || fAsync );
  360. //
  361. // Make /W4 happy...
  362. //
  363. if ( pBuffer == NULL && cbBuffer != 0 )
  364. {
  365. DBG_ASSERT( pBuffer || ( cbBuffer == 0 ) );
  366. }
  367. if ( fAsync )
  368. {
  369. DBG_ASSERT( _IsapiContext == 0 );
  370. _IsapiContext = IsaContext;
  371. }
  372. //
  373. // If this is an OOP async read, then we need to create a
  374. // local buffer to read into.
  375. //
  376. if ( _fIsOop && fAsync )
  377. {
  378. DBG_ASSERT( _pAsyncReadBuffer == NULL );
  379. _pAsyncReadBuffer = (LPBYTE)LocalAlloc( LPTR, dwBytesToRead );
  380. if ( !_pAsyncReadBuffer )
  381. {
  382. goto ErrorExit;
  383. }
  384. //
  385. // This reference insures that if the OOP host crashes and
  386. // COM releases all the OOP-held references, that this
  387. // object will survive until the I/O completion occurs.
  388. //
  389. AddRef();
  390. hr = _pW3Context->ReceiveEntity(
  391. fAsync ? W3_FLAG_ASYNC : W3_FLAG_SYNC,
  392. _pAsyncReadBuffer,
  393. dwBytesToRead,
  394. &dwBytesRead
  395. );
  396. }
  397. else
  398. {
  399. hr = _pW3Context->ReceiveEntity(
  400. fAsync ? W3_FLAG_ASYNC : W3_FLAG_SYNC,
  401. pBuffer,
  402. dwBytesToRead,
  403. fAsync ? &dwBytesRead : pdwSyncBytesRead
  404. );
  405. }
  406. //
  407. // If the request is chunked, look for ERROR_HANDLE_EOF. This
  408. // is how http.sys signals the end of a chunked request.
  409. //
  410. // Since an ISAPI extension is looking for a successful, zero
  411. // byte read, we'll need to change the result of the above call.
  412. //
  413. // Note that on an asynchronous call, we'll need to trigger a
  414. // "fake" completion with zero bytes.
  415. //
  416. if ( FAILED( hr ) && _pW3Context->QueryRequest()->IsChunkedRequest() )
  417. {
  418. if ( hr == HRESULT_FROM_WIN32( ERROR_HANDLE_EOF ) )
  419. {
  420. hr = NOERROR;
  421. if ( fAsync )
  422. {
  423. POST_MAIN_COMPLETION( _pW3Context->QueryMainContext() );
  424. }
  425. else
  426. {
  427. *pdwSyncBytesRead = 0;
  428. }
  429. }
  430. }
  431. //
  432. // We now return you to your regular error handling program.
  433. //
  434. if ( FAILED( hr ) )
  435. {
  436. //
  437. // If ReceiveEntity fails for some reason other than
  438. // EOF, then consider this a non recoverable
  439. // error and set the error to be WSAECONNRESET for
  440. // compatibility with legacy ISAPI code.
  441. //
  442. hr = HRESULT_FROM_WIN32( WSAECONNRESET );
  443. if ( _fIsOop && fAsync )
  444. {
  445. //
  446. // Release the above reference, since no completion
  447. // will be coming.
  448. //
  449. Release();
  450. }
  451. goto ErrorExit;
  452. }
  453. return hr;
  454. ErrorExit:
  455. DBG_ASSERT( FAILED( hr ) );
  456. if ( fAsync &&
  457. _IsapiContext != 0 )
  458. {
  459. _IsapiContext = 0;
  460. }
  461. if ( _pAsyncReadBuffer )
  462. {
  463. LocalFree( _pAsyncReadBuffer );
  464. _pAsyncReadBuffer = NULL;
  465. }
  466. return hr;
  467. }
  468. HRESULT STDMETHODCALLTYPE
  469. ISAPI_REQUEST::WriteClient(
  470. DWORD64 IsaContext,
  471. BYTE * pBuffer,
  472. DWORD cbBuffer,
  473. DWORD dwFlags
  474. )
  475. /*++
  476. Routine Description:
  477. Writes data to the client
  478. Arguments:
  479. IsaContext - The ISAPI_CONTEXT for this request (opaque)
  480. pBuffer - Contains the data to write
  481. cbBuffer - The amount of data to be written
  482. dwFlags - HSE_IO_* flags from caller
  483. Return Value:
  484. HRESULT
  485. --*/
  486. {
  487. W3_RESPONSE * pResponse;
  488. HRESULT hr = NOERROR;
  489. BOOL fAsync = !!( dwFlags & HSE_IO_ASYNC );
  490. //
  491. // The only current caller for this function is w3isapi.dll, which does
  492. // parameter validation from any outside code. So, we can get away with
  493. // just asserting here.
  494. //
  495. DBG_ASSERT( CheckSignature() );
  496. DBG_ASSERT( _pW3Context );
  497. DBG_ASSERT( fAsync == !!IsaContext );
  498. DBG_ASSERT( pBuffer || ( cbBuffer == 0 ) );
  499. //
  500. // For a zero byte send, just return
  501. //
  502. // If the call was async, we'll need to fire off a completion.
  503. //
  504. // Note that this case shouldn't ever happen, as the w3isapi.dll
  505. // code that calls this currently does a check for a zero byte
  506. // write attempt. That code is somewhat broken in that a completion
  507. // will never occur for a zero byte completion. That's the way all
  508. // previous versions of ISAPI have worked, though. This code is
  509. // here for the sole purpose that this interface could work properly
  510. // with an API that expects a completion on a zero byte async write.
  511. //
  512. if ( cbBuffer == 0 )
  513. {
  514. if ( fAsync )
  515. {
  516. POST_MAIN_COMPLETION( _pW3Context->QueryMainContext() );
  517. }
  518. return hr;
  519. }
  520. if ( fAsync )
  521. {
  522. DBG_ASSERT( _IsapiContext == 0 );
  523. _IsapiContext = IsaContext;
  524. }
  525. DBG_REQUIRE( ( pResponse = _pW3Context->QueryResponse() ) != NULL );
  526. //
  527. // If this as an OOP async write then we will work from a local copy
  528. // of pBuffer.
  529. //
  530. if ( _fIsOop && fAsync )
  531. {
  532. DBG_ASSERT( _pAsyncWriteBuffer == NULL );
  533. _pAsyncWriteBuffer = (LPBYTE)LocalAlloc( LPTR, cbBuffer );
  534. if ( !_pAsyncWriteBuffer )
  535. {
  536. goto ErrorExit;
  537. }
  538. memcpy( _pAsyncWriteBuffer, pBuffer, cbBuffer );
  539. pBuffer = _pAsyncWriteBuffer;
  540. }
  541. //
  542. // Before sending the current data, we need to clear out
  543. // any outstanding chunks from the response object. This can't
  544. // ever cause a problem for a purely synchronous ISAPI. And,
  545. // since w3isapi.dll protects against multiple outstanding
  546. // asynchronous I/O, we shouldn't see a problem with a
  547. // purely asynchronous I/O.
  548. //
  549. // If an ISAPI sends data asynchronously and then follows up
  550. // with a second, synchronous send, then it's possible that
  551. // the second send could clear the chunks from the first before
  552. // they've been fully processed. This is a really, really
  553. // dumb thing for an ISAPI to do, since the response would
  554. // likely be scrambled at the client. So, we'll live with
  555. // problems in that scenario.
  556. //
  557. pResponse->Clear();
  558. if (!_pW3Context->QueryResponseSent())
  559. {
  560. _pW3Context->SetDisconnect( TRUE );
  561. }
  562. //
  563. // Now setup the buffer we want to send
  564. //
  565. hr = pResponse->AddMemoryChunkByReference(
  566. pBuffer,
  567. cbBuffer
  568. );
  569. if ( FAILED( hr ) )
  570. {
  571. goto ErrorExit;
  572. }
  573. //
  574. // Ok, now send what we've got.
  575. //
  576. if ( _fIsOop && fAsync )
  577. {
  578. //
  579. // This reference insures that if the OOP host crashes and
  580. // COM releases all the OOP-held references, that this
  581. // object will survive until the I/O completion occurs.
  582. //
  583. AddRef();
  584. }
  585. hr = _pW3Context->SendEntity(
  586. ( fAsync ? W3_FLAG_ASYNC : W3_FLAG_SYNC ) | W3_FLAG_MORE_DATA
  587. );
  588. if ( FAILED( hr ) )
  589. {
  590. //
  591. // If SendEntity fails, consider this a non recoverable
  592. // error and set the error to be WSAECONNRESET for
  593. // compatibility with legacy ISAPI code.
  594. //
  595. hr = HRESULT_FROM_WIN32( WSAECONNRESET );
  596. if ( _fIsOop && fAsync )
  597. {
  598. //
  599. // Release the above reference, since no I/O completion
  600. // will ever happen.
  601. //
  602. Release();
  603. }
  604. goto ErrorExit;
  605. }
  606. return hr;
  607. ErrorExit:
  608. DBG_ASSERT( FAILED( hr ) );
  609. //
  610. // Note that checking for async here is not an optimization.
  611. //
  612. // ISAPI guards against two concurrent async operations, but
  613. // it's valid to have a synchronous and asynchronous operation
  614. // happening currently (ie. async write, exec url, etc.,
  615. // concurrent with a synchronous read).
  616. //
  617. // If we don't check for async, it's possible for a failed
  618. // synchronous read to reset the _IsapiContext that belongs
  619. // to some other action that's running async.
  620. //
  621. if ( fAsync &&
  622. _IsapiContext != 0 )
  623. {
  624. _IsapiContext = 0;
  625. }
  626. if ( _pAsyncWriteBuffer )
  627. {
  628. LocalFree( _pAsyncWriteBuffer );
  629. _pAsyncWriteBuffer = NULL;
  630. }
  631. return hr;
  632. }
  633. HRESULT STDMETHODCALLTYPE
  634. ISAPI_REQUEST::SendResponseHeaders(
  635. BOOL fDisconnect,
  636. LPSTR szStatus,
  637. LPSTR szHeaders,
  638. DWORD
  639. )
  640. /*++
  641. Routine Description:
  642. Sends response headers to the client
  643. Arguments:
  644. fDisconnect - If FALSE, then we need to avoid closing the connection
  645. szStatus - The status to send (ie. "200 OK")
  646. szHeaders - The headers to send (ie. "foo: value1\r\nBar: value2\r\n")
  647. dwFlags - HSE_IO_* flags from caller
  648. Return Value:
  649. HRESULT
  650. --*/
  651. {
  652. W3_RESPONSE * pResponse;
  653. STACK_STRA( strStatus,64);
  654. STACK_STRA( strHeaders,128);
  655. LPSTR szCookedStatus = szStatus;
  656. LPSTR szCookedHeaders = szHeaders;
  657. LPSTR pCursor = NULL;
  658. HRESULT hr;
  659. //
  660. // The only current caller for this function is w3isapi.dll, which does
  661. // parameter validation from any outside code. So, we can get away with
  662. // just asserting here.
  663. //
  664. DBG_ASSERT( CheckSignature() );
  665. DBG_ASSERT( _pW3Context );
  666. DBG_REQUIRE( ( pResponse = _pW3Context->QueryResponse() ) != NULL );
  667. //
  668. // Legacy ISAPI Gymnastics:
  669. //
  670. // Some ISAPI extensions will try and piggy-back response
  671. // headers onto the status string that they pass to this
  672. // function (ie. "200 OK\r\nFoo: bar".) While this would
  673. // work in IIS 5 - since IIS 5 didn't try and validate the
  674. // stream - it doesn't fly with http.sys. Ultimately, this
  675. // will cause http.sys to fail our send response call.
  676. //
  677. // So, to accommodate these ISAPIs, we'll look for this and
  678. // move any such piggy-backed headers into the right argument.
  679. //
  680. if ( szStatus )
  681. {
  682. pCursor = strpbrk( szStatus, "\r\n" );
  683. }
  684. if ( pCursor )
  685. {
  686. //
  687. // Create a local copy of the status and
  688. // strip off the extra header data.
  689. //
  690. hr = strStatus.Copy( szStatus );
  691. if ( FAILED( hr ) )
  692. {
  693. return ( hr );
  694. }
  695. strStatus.SetLen( pCursor - szStatus );
  696. //
  697. // Eat the \r\n preceding the header
  698. //
  699. while ( *pCursor == '\r' ||
  700. *pCursor == '\n' )
  701. {
  702. pCursor++;
  703. }
  704. //
  705. // Create a local copy of the headers
  706. //
  707. hr = strHeaders.Copy( pCursor );
  708. if ( FAILED( hr ) )
  709. {
  710. return hr;
  711. }
  712. //
  713. // We'll want to make sure that strHeaders ends
  714. // properly with a "\r\n" at this point. Probably the
  715. // easiest way to do this is to just eat any trailing
  716. // '\r' or '\n' characters and then append it (some ISAPI
  717. // developers omit the '\r' and just go with '\n'...)
  718. //
  719. pCursor = strHeaders.QueryStr() + strHeaders.QueryCCH() - 1;
  720. while ( pCursor > strHeaders.QueryStr() &&
  721. ( *pCursor == '\r' ||
  722. *pCursor == '\n' ) )
  723. {
  724. pCursor--;
  725. }
  726. strHeaders.SetLen( pCursor - strHeaders.QueryStr() + 1 );
  727. hr = strHeaders.Append( "\r\n" );
  728. if ( FAILED( hr ) )
  729. {
  730. return hr;
  731. }
  732. //
  733. // If we were passed a non-NULL pointer for szHeaders, we'll
  734. // need to append that data to strHeaders. We'll assume that
  735. // szHeaders was correctly formed by the caller and skip the
  736. // "\r\n" games.
  737. //
  738. // Else, if we were passed a NULL pointer for szHeaders, we
  739. // still need to append the final "\r\n" before the entity
  740. // body.
  741. //
  742. if ( szHeaders )
  743. {
  744. hr = strHeaders.Append( szHeaders );
  745. }
  746. else
  747. {
  748. hr = strHeaders.Append( "\r\n" );
  749. }
  750. if ( FAILED( hr ) )
  751. {
  752. return hr;
  753. }
  754. //
  755. // Finally, set szCookedStatus and szCookedHeaders to point
  756. // at our new data.
  757. //
  758. szCookedStatus = strStatus.QueryStr();
  759. szCookedHeaders = strHeaders.QueryStr();
  760. }
  761. //
  762. // Set the disconnect disposition
  763. //
  764. _pW3Context->SetDisconnect( fDisconnect );
  765. //
  766. // Need to clear any existing response
  767. //
  768. pResponse->Clear();
  769. //
  770. // Setup response from ISAPI
  771. //
  772. hr = pResponse->BuildResponseFromIsapi(
  773. _pW3Context,
  774. szCookedStatus,
  775. szCookedHeaders,
  776. szCookedHeaders ? (DWORD)strlen( szCookedHeaders ) : 0
  777. );
  778. if ( FAILED( hr ) )
  779. {
  780. return hr;
  781. }
  782. //
  783. // Is the status is access denied, then set the sub status to
  784. // "Denied by Application"
  785. //
  786. if ( pResponse->QueryStatusCode() == HttpStatusUnauthorized.statusCode )
  787. {
  788. pResponse->SetStatus( HttpStatusUnauthorized,
  789. Http401Application );
  790. }
  791. hr = _pW3Context->SendResponse(
  792. W3_FLAG_SYNC
  793. | W3_FLAG_MORE_DATA
  794. | W3_FLAG_NO_ERROR_BODY
  795. | W3_FLAG_NO_CONTENT_LENGTH );
  796. if ( FAILED( hr ) )
  797. {
  798. //
  799. // If SendResponse fails, consider this a non recoverable
  800. // error and set the error to be WSAECONNRESET for
  801. // compatibility with legacy ISAPI code.
  802. //
  803. hr = HRESULT_FROM_WIN32( WSAECONNRESET );
  804. }
  805. return hr;
  806. }
  807. HRESULT STDMETHODCALLTYPE
  808. ISAPI_REQUEST::MapPath(
  809. BYTE * szPath,
  810. DWORD cbPath,
  811. DWORD * pcbBufferRequired,
  812. BOOL fUnicode
  813. )
  814. /*++
  815. Routine Description:
  816. Maps a URL to a physical path
  817. Arguments:
  818. szPath - On entry, the URL to map
  819. - On return, the mapped physical path
  820. cbPath - The size of szPath
  821. pcbBufferRequired - On successful return, the number of szPath
  822. On error return, the number of bytes needed in szPath
  823. fUnicode - If TRUE, szPath should be a UNICODE string on entry
  824. and return
  825. Return Value:
  826. HRESULT
  827. --*/
  828. {
  829. STACK_STRU( struUrl,MAX_PATH );
  830. STACK_STRU( struPath,MAX_PATH );
  831. HRESULT hr;
  832. //
  833. // The only current caller for this function is w3isapi.dll, which does
  834. // parameter validation from any outside code. So, we can get away with
  835. // just asserting here.
  836. //
  837. DBG_ASSERT( CheckSignature() );
  838. DBG_ASSERT( _pW3Context );
  839. DBG_ASSERT( szPath || ( cbPath == 0 ) );
  840. DBG_ASSERT( pcbBufferRequired );
  841. //
  842. // This is kind of a weird function - the return string
  843. // gets copied over the top of the source string.
  844. //
  845. if ( fUnicode )
  846. {
  847. hr = struUrl.Copy( (LPWSTR)szPath );
  848. }
  849. else
  850. {
  851. hr = struUrl.CopyA( (LPSTR)szPath );
  852. }
  853. if ( FAILED( hr ) )
  854. {
  855. return hr;
  856. }
  857. hr = W3_STATE_URLINFO::MapPath(
  858. _pW3Context,
  859. struUrl,
  860. &struPath,
  861. TRUE,
  862. NULL,
  863. NULL,
  864. NULL,
  865. NULL,
  866. NULL
  867. );
  868. if ( FAILED( hr ) )
  869. {
  870. return hr;
  871. }
  872. *pcbBufferRequired = cbPath;
  873. if ( fUnicode )
  874. {
  875. return struPath.CopyToBuffer( (LPWSTR)szPath, pcbBufferRequired );
  876. }
  877. else
  878. {
  879. STACK_STRA (straPath, MAX_PATH );
  880. if (FAILED(hr = straPath.CopyW(struPath.QueryStr(),
  881. struPath.QueryCCH())))
  882. {
  883. return hr;
  884. }
  885. return straPath.CopyToBuffer( (LPSTR)szPath, pcbBufferRequired );
  886. }
  887. }
  888. HRESULT STDMETHODCALLTYPE
  889. ISAPI_REQUEST::MapPathEx(
  890. BYTE * szUrl,
  891. DWORD ,
  892. BYTE * szPath,
  893. DWORD cbPath,
  894. DWORD * pcbBufferRequired,
  895. DWORD * pcchMatchingPath,
  896. DWORD * pcchMatchingUrl,
  897. DWORD * pdwFlags,
  898. BOOL fUnicode
  899. )
  900. /*++
  901. Routine Description:
  902. Does path mapping, plus a bit more
  903. Arguments:
  904. szUrl - The URL to map
  905. szPath - Upon return, the physical path for the URL
  906. cbPath - The size of szPath
  907. pcbBufferRequired - Upon failed return, the size needed for szPath
  908. pcchMatchingPath - Upon return, the number of characters in szPath
  909. that correspond to the vroot in the URL
  910. pcchMatchingUrl - Upon return, the number of characters in szUrl
  911. that correspond to the vroot in the URL
  912. pdwFlags - Upon return, the metadata AccessPerm flags for the URL
  913. fUnicode - If TRUE, the caller wants to talk UNICODE
  914. Return Value:
  915. HRESULT
  916. --*/
  917. {
  918. STACK_STRU( struUrl,MAX_PATH );
  919. STACK_STRU( struPath,MAX_PATH );
  920. DWORD cbPathCopied;
  921. DWORD cchMatchingPathA;
  922. DWORD cchMatchingUrlA;
  923. HRESULT hr;
  924. DBG_ASSERT( CheckSignature() );
  925. DBG_ASSERT( _pW3Context );
  926. if ( fUnicode )
  927. {
  928. hr = struUrl.Copy( (LPWSTR)szUrl );
  929. }
  930. else
  931. {
  932. hr = struUrl.CopyA( (LPSTR)szUrl );
  933. }
  934. if ( FAILED( hr ) )
  935. {
  936. return hr;
  937. }
  938. //
  939. // Call W3_STATE_URLINFO::MapPath to do the work
  940. //
  941. hr = W3_STATE_URLINFO::MapPath(
  942. _pW3Context,
  943. struUrl,
  944. &struPath,
  945. TRUE,
  946. pcchMatchingPath,
  947. pcchMatchingUrl,
  948. &cchMatchingPathA,
  949. &cchMatchingUrlA,
  950. pdwFlags
  951. );
  952. if ( FAILED( hr ) )
  953. {
  954. return hr;
  955. }
  956. //
  957. // W3_STATE_URLINFO::MapPath works by looking for a cache entry
  958. // for the requested szUrl. If it exists, the returned information
  959. // will come from the cache data. This causes a potential problem
  960. // if the cache contains a URL as "/foo/" and the caller to this
  961. // function passes "/foo" as the URL. In this case, *pcchMatchingUrl
  962. // will be 5, as it's derived from the cache data. It would be bad,
  963. // though, to pass a *pcchMatchingUrl greater than the length of the
  964. // szUrl we were given...
  965. //
  966. if ( fUnicode )
  967. {
  968. if ( *pcchMatchingUrl &&
  969. ( ( ((LPWSTR)szUrl)[*pcchMatchingUrl - 1] == L'\0' ) ||
  970. ( ((LPWSTR)szUrl)[*pcchMatchingUrl - 1] == L'/' ) ) )
  971. {
  972. (*pcchMatchingUrl)--;
  973. }
  974. }
  975. else
  976. {
  977. //
  978. // Use the ANSI matching value
  979. //
  980. *pcchMatchingUrl = cchMatchingUrlA;
  981. if ( *pcchMatchingUrl &&
  982. ( ( szUrl[*pcchMatchingUrl - 1] == '\0' ) ||
  983. ( szUrl[*pcchMatchingUrl - 1] == '/' ) ) )
  984. {
  985. (*pcchMatchingUrl)--;
  986. }
  987. }
  988. if ( pcbBufferRequired )
  989. {
  990. if ( fUnicode )
  991. {
  992. *pcbBufferRequired = (struPath.QueryCCH() + 1) * sizeof(WCHAR);
  993. }
  994. else
  995. {
  996. *pcbBufferRequired = struPath.QueryCCH() + 1;
  997. }
  998. }
  999. if ( szPath )
  1000. {
  1001. if ( fUnicode )
  1002. {
  1003. cbPathCopied = cbPath;
  1004. hr = struPath.CopyToBuffer( (LPWSTR)szPath, &cbPathCopied );
  1005. if ( hr == HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) &&
  1006. cbPath >= sizeof(WCHAR) )
  1007. {
  1008. //
  1009. // Copy what we can.
  1010. //
  1011. // Note that there are ISAPI extensions that depend on
  1012. // being able to get a truncated path in the case where
  1013. // MAX_PATH is not sufficient to store the complete data.
  1014. //
  1015. // These extensions depend on using ERROR_INSUFFICIENT_BUFFER
  1016. // as a warning that the data is truncated.
  1017. //
  1018. memset( szPath, 0, cbPath );
  1019. memcpy( szPath, struPath.QueryStr(), cbPath - sizeof(WCHAR) );
  1020. }
  1021. }
  1022. else
  1023. {
  1024. //
  1025. // Convert the path to ANSI
  1026. //
  1027. STACK_STRA( strAnsiPath, MAX_PATH+1 );
  1028. DWORD cbAnsiPath;
  1029. DWORD dwError;
  1030. //
  1031. // Get the ANSI version of the path.
  1032. //
  1033. cbAnsiPath = WideCharToMultiByte( CP_ACP,
  1034. 0,
  1035. struPath.QueryStr(),
  1036. -1,
  1037. strAnsiPath.QueryStr(),
  1038. MAX_PATH,
  1039. NULL,
  1040. NULL );
  1041. if ( cbAnsiPath == 0 )
  1042. {
  1043. dwError = GetLastError();
  1044. if ( dwError == ERROR_INSUFFICIENT_BUFFER )
  1045. {
  1046. //
  1047. // Get the size of the buffer needed and
  1048. // call it again.
  1049. //
  1050. cbAnsiPath = WideCharToMultiByte( CP_ACP,
  1051. 0,
  1052. struPath.QueryStr(),
  1053. -1,
  1054. NULL,
  1055. 0,
  1056. NULL,
  1057. NULL );
  1058. if ( cbAnsiPath == 0 )
  1059. {
  1060. return HRESULT_FROM_WIN32( GetLastError() );
  1061. }
  1062. hr = strAnsiPath.Resize( cbAnsiPath );
  1063. if ( FAILED( hr ) )
  1064. {
  1065. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1066. }
  1067. cbAnsiPath = WideCharToMultiByte( CP_ACP,
  1068. 0,
  1069. struPath.QueryStr(),
  1070. -1,
  1071. strAnsiPath.QueryStr(),
  1072. cbAnsiPath,
  1073. NULL,
  1074. NULL );
  1075. if ( cbAnsiPath == 0 )
  1076. {
  1077. return HRESULT_FROM_WIN32( GetLastError() );
  1078. }
  1079. }
  1080. else
  1081. {
  1082. return HRESULT_FROM_WIN32( dwError );
  1083. }
  1084. }
  1085. cbPathCopied = cbPath;
  1086. strAnsiPath.SetLen( cbAnsiPath - 1 );
  1087. hr = strAnsiPath.CopyToBuffer(
  1088. (LPSTR)szPath,
  1089. &cbPathCopied
  1090. );
  1091. if ( hr == HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) &&
  1092. cbPath >= sizeof(CHAR) )
  1093. {
  1094. //
  1095. // Copy what we can.
  1096. //
  1097. // Note that there are ISAPI extensions that depend on
  1098. // being able to get a truncated path in the case where
  1099. // MAX_PATH is not sufficient to store the complete data.
  1100. //
  1101. // These extensions depend on using ERROR_INSUFFICIENT_BUFFER
  1102. // as a warning that the data is truncated.
  1103. //
  1104. memset( szPath, 0, cbPath );
  1105. memcpy( szPath, strAnsiPath.QueryStr(), cbPath - sizeof(CHAR) );
  1106. }
  1107. }
  1108. }
  1109. if ( pcchMatchingPath &&
  1110. !fUnicode )
  1111. {
  1112. //
  1113. // Use the ANSI matching value
  1114. //
  1115. *pcchMatchingPath = cchMatchingPathA;
  1116. }
  1117. return hr;
  1118. }
  1119. HRESULT STDMETHODCALLTYPE
  1120. ISAPI_REQUEST::TransmitFile(
  1121. DWORD64 IsaContext,
  1122. DWORD_PTR hFile,
  1123. DWORD64 cbOffset,
  1124. DWORD64 cbWrite,
  1125. LPSTR szStatusCode,
  1126. BYTE * pHead,
  1127. DWORD cbHead,
  1128. BYTE * pTail,
  1129. DWORD cbTail,
  1130. DWORD dwFlags
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. Transmits a file to the client
  1135. Arguments:
  1136. IsaContext - The ISAPI_CONTEXT for this request (opaque)
  1137. hFile - Handle to file (requires FILE_FLAG_SEQUENTIAL_SCAN)
  1138. cbOffset - Offset in file to begin transmitting
  1139. cbWrite - The number of bytes to transmit
  1140. szStatusCode - HTTP status to return (ie "200 OK")
  1141. pHead - Bytes to send before file data
  1142. cbHead - The size of pHead
  1143. pTail - Bytes to send after file data
  1144. cbTail - The size of pTail
  1145. dwFlags - HSE_IO_* flags from the caller
  1146. Return Value:
  1147. HRESULT
  1148. --*/
  1149. {
  1150. W3_ISAPI_HANDLER * pW3IsapiHandler;
  1151. W3_RESPONSE * pResponse;
  1152. DWORD dwW3Flags;
  1153. BOOL fSendAsResponse;
  1154. HRESULT hr;
  1155. //
  1156. // The only current caller for this function is w3isapi.dll, which does
  1157. // parameter validation from any outside code. So, we can get away with
  1158. // just asserting here.
  1159. //
  1160. DBG_ASSERT( CheckSignature() );
  1161. DBG_ASSERT( _pW3Context );
  1162. DBG_ASSERT( IsaContext );
  1163. DBG_ASSERT( cbHead == 0 || pHead != NULL );
  1164. DBG_ASSERT( cbTail == 0 || pTail != NULL );
  1165. DBG_ASSERT( (HANDLE)hFile != INVALID_HANDLE_VALUE );
  1166. DBG_ASSERT( dwFlags & HSE_IO_ASYNC );
  1167. DBG_REQUIRE( ( pResponse = _pW3Context->QueryResponse() ) != NULL );
  1168. DBG_REQUIRE( ( pW3IsapiHandler = (W3_ISAPI_HANDLER*)_pW3Context->QueryHandler() ) != NULL );
  1169. DBG_ASSERT( _IsapiContext == 0 );
  1170. _IsapiContext = IsaContext;
  1171. //
  1172. // If the caller is OOP, then make copies
  1173. // of the file handle, head data and tail data. We
  1174. // don't need to make a copy of the status because
  1175. // the BuildResponseFromIsapi function does that itself.
  1176. //
  1177. if ( _fIsOop )
  1178. {
  1179. if ( hFile != NULL )
  1180. {
  1181. hr = pW3IsapiHandler->DuplicateWamProcessHandleForLocalUse(
  1182. (HANDLE)hFile, &_hTfFile
  1183. );
  1184. if ( FAILED( hr ) )
  1185. {
  1186. hr = HRESULT_FROM_WIN32( GetLastError() );
  1187. goto ErrorExit;
  1188. }
  1189. hFile = (DWORD_PTR)_hTfFile;
  1190. }
  1191. if ( pHead )
  1192. {
  1193. _pTfHead = (LPBYTE)LocalAlloc( LPTR, cbHead );
  1194. if ( !_pTfHead )
  1195. {
  1196. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1197. goto ErrorExit;
  1198. }
  1199. memcpy( _pTfHead, pHead, cbHead );
  1200. pHead = _pTfHead;
  1201. }
  1202. if ( pTail )
  1203. {
  1204. _pTfTail = (LPBYTE)LocalAlloc( LPTR, cbTail );
  1205. if ( !_pTfTail )
  1206. {
  1207. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1208. goto ErrorExit;
  1209. }
  1210. memcpy( _pTfTail, pTail, cbTail );
  1211. pTail = _pTfTail;
  1212. }
  1213. }
  1214. //
  1215. // Convert the HSE_IO_* flags to W3_FLAG_* flags
  1216. //
  1217. // Init the flags for sending
  1218. dwW3Flags = W3_FLAG_ASYNC | W3_FLAG_MORE_DATA;
  1219. // If disconnect flag is not set, then we'll keep the connection open
  1220. if ( !( dwFlags & HSE_IO_DISCONNECT_AFTER_SEND ) )
  1221. {
  1222. _pW3Context->SetDisconnect( FALSE );
  1223. }
  1224. else
  1225. {
  1226. _pW3Context->SetDisconnect( TRUE );
  1227. }
  1228. //
  1229. // Clear any previous chunks from the response
  1230. //
  1231. pResponse->Clear();
  1232. //
  1233. // If HSE_IO_SEND_HEADERS is specified, then we're sending
  1234. // the initial part of the response (and pHead will be an
  1235. // LPSTR containing the headers that the caller wants to
  1236. // send), else we'll be sending this data completely as
  1237. // entity data.
  1238. //
  1239. fSendAsResponse = !!( dwFlags & HSE_IO_SEND_HEADERS );
  1240. if ( fSendAsResponse )
  1241. {
  1242. //
  1243. // Set the status using data from the caller
  1244. //
  1245. hr = pResponse->BuildResponseFromIsapi( _pW3Context,
  1246. szStatusCode,
  1247. (LPSTR)pHead,
  1248. cbHead );
  1249. if ( FAILED( hr ) )
  1250. {
  1251. goto ErrorExit;
  1252. }
  1253. //
  1254. // Is the status is access denied, then set the sub status to
  1255. // "Denied by Application"
  1256. //
  1257. if ( pResponse->QueryStatusCode() == HttpStatusUnauthorized.statusCode )
  1258. {
  1259. pResponse->SetStatus( HttpStatusUnauthorized,
  1260. Http401Application );
  1261. }
  1262. }
  1263. else
  1264. {
  1265. //
  1266. // Do something with pHead if provided
  1267. //
  1268. if ( cbHead )
  1269. {
  1270. hr = pResponse->AddMemoryChunkByReference(
  1271. pHead,
  1272. cbHead
  1273. );
  1274. if ( FAILED( hr ) )
  1275. {
  1276. goto ErrorExit;
  1277. }
  1278. }
  1279. }
  1280. //
  1281. // Now add the file handle to the response. Note that it's
  1282. // allowed for the caller to pass a NULL handle. In that case,
  1283. // we won't add it, and any present pHead and pTail will still
  1284. // get sent to the client.
  1285. //
  1286. if ( hFile )
  1287. {
  1288. hr = pResponse->AddFileHandleChunk(
  1289. (HANDLE)hFile,
  1290. cbOffset,
  1291. cbWrite
  1292. );
  1293. if ( FAILED( hr ) )
  1294. {
  1295. goto ErrorExit;
  1296. }
  1297. }
  1298. //
  1299. // Add the tail if provided
  1300. //
  1301. if ( cbTail )
  1302. {
  1303. hr = pResponse->AddMemoryChunkByReference(
  1304. pTail,
  1305. cbTail
  1306. );
  1307. if ( FAILED( hr ) )
  1308. {
  1309. goto ErrorExit;
  1310. }
  1311. }
  1312. //
  1313. // Ok, now that the stuff is all set up, send it, either
  1314. // as a response or as entity
  1315. //
  1316. if ( _fIsOop )
  1317. {
  1318. //
  1319. // This reference insures that if the OOP host crashes and
  1320. // COM releases all the OOP-held references, that this
  1321. // object will survive until the I/O completion occurs.
  1322. //
  1323. AddRef();
  1324. }
  1325. if ( fSendAsResponse )
  1326. {
  1327. hr = _pW3Context->SendResponse( dwW3Flags
  1328. | W3_FLAG_NO_ERROR_BODY
  1329. | W3_FLAG_NO_CONTENT_LENGTH
  1330. | W3_FLAG_MORE_DATA );
  1331. }
  1332. else
  1333. {
  1334. hr = _pW3Context->SendEntity( dwW3Flags
  1335. | W3_FLAG_MORE_DATA );
  1336. }
  1337. if ( FAILED( hr ) )
  1338. {
  1339. //
  1340. // If SendEntity or SendResponse fail, consider this
  1341. // a non recoverable error and set the error to be
  1342. // WSAECONNRESET for compatibility with legacy ISAPI code.
  1343. //
  1344. hr = HRESULT_FROM_WIN32( WSAECONNRESET );
  1345. if ( _fIsOop )
  1346. {
  1347. //
  1348. // Release the above reference, since no I/O completion will
  1349. // occur.
  1350. //
  1351. Release();
  1352. }
  1353. goto ErrorExit;
  1354. }
  1355. return hr;
  1356. ErrorExit:
  1357. DBG_ASSERT( FAILED( hr ) );
  1358. if ( _IsapiContext != 0 )
  1359. {
  1360. _IsapiContext = 0;
  1361. }
  1362. if ( _fIsOop )
  1363. {
  1364. if ( _hTfFile != NULL && _hTfFile != INVALID_HANDLE_VALUE )
  1365. {
  1366. CloseHandle( _hTfFile );
  1367. _hTfFile = INVALID_HANDLE_VALUE;
  1368. }
  1369. if ( _pTfHead )
  1370. {
  1371. LocalFree( _pTfHead );
  1372. _pTfHead = NULL;
  1373. }
  1374. if ( _pTfTail )
  1375. {
  1376. LocalFree( _pTfTail );
  1377. _pTfTail = NULL;
  1378. }
  1379. }
  1380. return hr;
  1381. }
  1382. HRESULT STDMETHODCALLTYPE
  1383. ISAPI_REQUEST::SetConnectionClose(
  1384. BOOL fClose
  1385. )
  1386. /*++
  1387. Routine Description:
  1388. Sets the W3_CONTEXT to close (or not) connection
  1389. upon completion of the response.
  1390. Arguments:
  1391. fClose - BOOL to pass to SetDisconnect
  1392. Return Value:
  1393. HRESULT
  1394. --*/
  1395. {
  1396. DBG_ASSERT( CheckSignature() );
  1397. _pW3Context->SetDisconnect( fClose );
  1398. return NOERROR;
  1399. }
  1400. HRESULT STDMETHODCALLTYPE
  1401. ISAPI_REQUEST::SendRedirect(
  1402. LPCSTR szLocation,
  1403. BOOL fDisconnect
  1404. )
  1405. /*++
  1406. Routine Description:
  1407. Sends a 302 redirect message to the client
  1408. Arguments:
  1409. szLocation - The URL to redirect to.
  1410. fDisconnect - If TRUE, the close connection
  1411. Return Value:
  1412. HRESULT
  1413. --*/
  1414. {
  1415. STACK_STRA( strLocation, MAX_PATH );
  1416. HTTP_STATUS httpStatus = { 302, REASON("Object Moved") };
  1417. HRESULT hr;
  1418. DBG_ASSERT( CheckSignature() );
  1419. DBG_ASSERT( _pW3Context );
  1420. DBG_ASSERT( szLocation );
  1421. //
  1422. // Use W3_CONTEXT::SetupHttpRedirect to build the redirect
  1423. // response.
  1424. //
  1425. hr = strLocation.Copy( szLocation );
  1426. if ( FAILED( hr ) )
  1427. {
  1428. return hr;
  1429. }
  1430. _pW3Context->SetDisconnect( fDisconnect );
  1431. hr = _pW3Context->SetupHttpRedirect(
  1432. strLocation,
  1433. FALSE, // Don't include the original query string
  1434. httpStatus
  1435. );
  1436. if ( FAILED( hr ) )
  1437. {
  1438. return hr;
  1439. }
  1440. //
  1441. // Now send the response synchronously (the calling ISAPI might
  1442. // do something silly like send more data after this function
  1443. // returns, so we can't do it asynchronously.)
  1444. //
  1445. hr = _pW3Context->SendResponse(
  1446. W3_FLAG_SYNC |
  1447. W3_FLAG_MORE_DATA
  1448. );
  1449. if ( FAILED( hr ) )
  1450. {
  1451. //
  1452. // If SendResponse fails, consider this a non recoverable
  1453. // error and set the error to be WSAECONNRESET for
  1454. // compatibility with legacy ISAPI code.
  1455. //
  1456. hr = HRESULT_FROM_WIN32( WSAECONNRESET );
  1457. }
  1458. return hr;
  1459. }
  1460. HRESULT STDMETHODCALLTYPE
  1461. ISAPI_REQUEST::GetCertificateInfoEx(
  1462. DWORD cbAllocated,
  1463. DWORD * pdwCertEncodingType,
  1464. BYTE * pbCertEncoded,
  1465. DWORD * pcbCertEncoded,
  1466. DWORD * pdwCertificateFlags
  1467. )
  1468. /*++
  1469. Routine Description:
  1470. Gets certificate info
  1471. Arguments:
  1472. cbAllocated - The size of the pbCertEncoded buffer
  1473. pdwCertEncodingType - Upon return, the cert encoding type
  1474. pbCertEncoded - Upon return, contains the cert info
  1475. pcbCertEncoded - Upon successful return, the number of bytes
  1476. in pbCertEncoded. On failed return, the number
  1477. of bytes required to contain pbCertEncoded
  1478. pdwCertificateFlags - Upon return, the certificate flags
  1479. Return Value:
  1480. HRESULT
  1481. --*/
  1482. {
  1483. DBG_ASSERT( CheckSignature() );
  1484. DBG_ASSERT( _pW3Context );
  1485. return _pW3Context->GetCertificateInfoEx( cbAllocated,
  1486. pdwCertEncodingType,
  1487. pbCertEncoded,
  1488. pcbCertEncoded,
  1489. pdwCertificateFlags );
  1490. }
  1491. HRESULT STDMETHODCALLTYPE
  1492. ISAPI_REQUEST::AppendLog(
  1493. LPSTR szExtraParam,
  1494. USHORT StatusCode
  1495. )
  1496. /*++
  1497. Routine Description:
  1498. Append the string to the querystring logged
  1499. Arguments:
  1500. szExtraParam - the string to be appended
  1501. Return Value:
  1502. HRESULT
  1503. --*/
  1504. {
  1505. HRESULT hr;
  1506. //
  1507. // The only current caller for this function is w3isapi.dll,
  1508. // which validates the parameters.
  1509. //
  1510. DBG_ASSERT( CheckSignature() );
  1511. DBG_ASSERT( _pW3Context );
  1512. if (StatusCode != 0)
  1513. {
  1514. _pW3Context->QueryResponse()->SetStatusCode(StatusCode);
  1515. }
  1516. if (szExtraParam[0] != '\0')
  1517. {
  1518. STRA &strLogParam = _pW3Context->QueryMainContext()
  1519. ->QueryLogContext()->m_strLogParam;
  1520. if (strLogParam.IsEmpty())
  1521. {
  1522. STACK_STRU (strQueryString, 128);
  1523. if (FAILED(hr = _pW3Context->QueryRequest()->GetQueryStringA(&strLogParam)))
  1524. {
  1525. return hr;
  1526. }
  1527. }
  1528. return strLogParam.Append(szExtraParam);
  1529. }
  1530. return S_OK;
  1531. }
  1532. HRESULT STDMETHODCALLTYPE
  1533. ISAPI_REQUEST::ExecuteUrl(
  1534. DWORD64 IsaContext,
  1535. EXEC_URL_INFO * pExecUrlInfo
  1536. )
  1537. /*++
  1538. Routine Description:
  1539. Execute a child request
  1540. Arguments:
  1541. ISaContext - The ISAPI_CONTEXT for this request (opaque)
  1542. pExecUrlInfo - Description of request to execute
  1543. Return Value:
  1544. HRESULT
  1545. --*/
  1546. {
  1547. W3_ISAPI_HANDLER * pIsapiHandler = NULL;
  1548. HRESULT hr = NO_ERROR;
  1549. BOOL fAsync;
  1550. BYTE * pbOriginalEntity = NULL;
  1551. //
  1552. // The parameters (i.e. HSE_EXEC_URL_INFO structure) was validated on
  1553. // the W3ISAPI.DLL side, so we can make assumptions about validity
  1554. //
  1555. DBG_ASSERT( CheckSignature() );
  1556. DBG_ASSERT( pExecUrlInfo != NULL );
  1557. DBG_ASSERT( _pW3Context );
  1558. DBG_REQUIRE( ( pIsapiHandler = (W3_ISAPI_HANDLER*)_pW3Context->QueryHandler() ) != NULL );
  1559. fAsync = TRUE;
  1560. DBG_ASSERT( fAsync == !!IsaContext );
  1561. if ( fAsync )
  1562. {
  1563. DBG_ASSERT( _IsapiContext == 0 );
  1564. _IsapiContext = IsaContext;
  1565. }
  1566. //
  1567. // If we're OOP, we need to dup the user token (if there) and the
  1568. // entity body (if there and this is async request)
  1569. //
  1570. if ( _fIsOop )
  1571. {
  1572. //
  1573. // Duplicate the user token if there
  1574. //
  1575. if ( pExecUrlInfo->pUserInfo != NULL &&
  1576. pExecUrlInfo->pUserInfo->hImpersonationToken != NULL )
  1577. {
  1578. DBG_ASSERT( _hExecUrlToken == NULL );
  1579. hr = pIsapiHandler->DuplicateWamProcessHandleForLocalUse(
  1580. (HANDLE) pExecUrlInfo->pUserInfo->hImpersonationToken,
  1581. &_hExecUrlToken );
  1582. if ( FAILED( hr ) )
  1583. {
  1584. goto Finished;
  1585. }
  1586. pExecUrlInfo->pUserInfo->hImpersonationToken = reinterpret_cast<DWORD_PTR> (_hExecUrlToken);
  1587. }
  1588. //
  1589. // Duplicate the entity buffer if there and this is async request
  1590. //
  1591. if ( fAsync &&
  1592. pExecUrlInfo->pEntity != NULL &&
  1593. pExecUrlInfo->pEntity->lpbData != NULL &&
  1594. pExecUrlInfo->pEntity->cbAvailable > 0 )
  1595. {
  1596. DBG_ASSERT( _pbExecUrlEntity == NULL );
  1597. _pbExecUrlEntity = LocalAlloc( LMEM_FIXED,
  1598. pExecUrlInfo->pEntity->cbAvailable );
  1599. if ( _pbExecUrlEntity == NULL )
  1600. {
  1601. hr = HRESULT_FROM_WIN32( GetLastError() );
  1602. goto Finished;
  1603. }
  1604. memcpy( _pbExecUrlEntity,
  1605. pExecUrlInfo->pEntity->lpbData,
  1606. pExecUrlInfo->pEntity->cbAvailable );
  1607. //
  1608. // Remember the original pointer to entity body. We must
  1609. // maintain it on exit so that RPC unmarshalls the correct
  1610. // buffer :-(
  1611. //
  1612. pbOriginalEntity = pExecUrlInfo->pEntity->lpbData;
  1613. pExecUrlInfo->pEntity->lpbData = (LPBYTE) _pbExecUrlEntity;
  1614. }
  1615. }
  1616. //
  1617. // Execute the darn thing
  1618. //
  1619. if ( _fIsOop && fAsync )
  1620. {
  1621. //
  1622. // This reference insures that if the OOP host crashes and
  1623. // COM releases all the OOP-held references, that this
  1624. // object will survive until the I/O completion occurs.
  1625. //
  1626. AddRef();
  1627. }
  1628. hr = _pW3Context->CleanIsapiExecuteUrl( pExecUrlInfo );
  1629. if ( FAILED( hr ) )
  1630. {
  1631. if ( _fIsOop && fAsync )
  1632. {
  1633. //
  1634. // Release the above reference, since no I/O completion will
  1635. // occur.
  1636. //
  1637. Release();
  1638. }
  1639. }
  1640. //
  1641. // If nothing is pending, then we can clean up any dup'd stuff now
  1642. //
  1643. Finished:
  1644. if ( FAILED( hr ) &&
  1645. fAsync &&
  1646. _IsapiContext != 0 )
  1647. {
  1648. _IsapiContext = 0;
  1649. }
  1650. if ( FAILED( hr ) || !fAsync )
  1651. {
  1652. if ( _pbExecUrlEntity != NULL )
  1653. {
  1654. LocalFree( _pbExecUrlEntity );
  1655. _pbExecUrlEntity = NULL;
  1656. }
  1657. if ( _hExecUrlToken != NULL )
  1658. {
  1659. CloseHandle( _hExecUrlToken );
  1660. _hExecUrlToken = NULL;
  1661. }
  1662. }
  1663. //
  1664. // Regardless of return status, we need to restore the entity pointer
  1665. // if needed so RPC unmarshalls the right thing
  1666. //
  1667. if ( pbOriginalEntity != NULL )
  1668. {
  1669. DBG_ASSERT( pExecUrlInfo != NULL );
  1670. DBG_ASSERT( pExecUrlInfo->pEntity != NULL );
  1671. pExecUrlInfo->pEntity->lpbData = pbOriginalEntity;
  1672. }
  1673. return hr;
  1674. }
  1675. HRESULT STDMETHODCALLTYPE
  1676. ISAPI_REQUEST::SendCustomError(
  1677. DWORD64 IsaContext,
  1678. CHAR * pszStatus,
  1679. USHORT uHttpSubError
  1680. )
  1681. /*++
  1682. Routine Description:
  1683. Send a custom error (if available, otherwise error out with
  1684. ERROR_FILE_NOT_FOUND)
  1685. Arguments:
  1686. IsaContext - The ISAPI_CONTEXT for this request (opaque)
  1687. pszStatus - Status line
  1688. uHttpSubError - Sub error
  1689. Return Value:
  1690. HRESULT
  1691. --*/
  1692. {
  1693. HRESULT hr;
  1694. BOOL fAsync;
  1695. HSE_CUSTOM_ERROR_INFO customErrorInfo;
  1696. DBG_ASSERT( CheckSignature() );
  1697. //
  1698. // If we have a non-NULL IsaContext, then this is an async request
  1699. //
  1700. fAsync = !!IsaContext;
  1701. if ( fAsync )
  1702. {
  1703. DBG_ASSERT( _IsapiContext == 0 );
  1704. _IsapiContext = IsaContext;
  1705. }
  1706. if ( _fIsOop && fAsync )
  1707. {
  1708. //
  1709. // This reference insures that if the OOP host crashes and
  1710. // COM releases all the OOP-held references, that this
  1711. // object will survive until the I/O completion occurs.
  1712. //
  1713. AddRef();
  1714. }
  1715. customErrorInfo.pszStatus = pszStatus;
  1716. customErrorInfo.uHttpSubError = uHttpSubError;
  1717. customErrorInfo.fAsync = fAsync;
  1718. hr = _pW3Context->CleanIsapiSendCustomError( &customErrorInfo );
  1719. if ( FAILED( hr ) )
  1720. {
  1721. if ( fAsync && _IsapiContext != 0 )
  1722. {
  1723. _IsapiContext = 0;
  1724. }
  1725. if ( _fIsOop && fAsync )
  1726. {
  1727. //
  1728. // Release the above reference, since no I/O completion
  1729. // will ever happen.
  1730. //
  1731. Release();
  1732. }
  1733. }
  1734. return hr;
  1735. }
  1736. HRESULT STDMETHODCALLTYPE
  1737. ISAPI_REQUEST::GetExecuteUrlStatus(
  1738. USHORT * pChildStatusCode,
  1739. USHORT * pChildSubErrorCode,
  1740. DWORD * pChildWin32Error
  1741. )
  1742. /*++
  1743. Routine Description:
  1744. Get the status of the last child execute
  1745. Arguments:
  1746. pChildStatusCode - Filled with status code of child execute
  1747. pChildSubErrorCode - Filled sub error if applicable
  1748. pChildWin32Error - Filled last Win32 saved for child request
  1749. Return Value:
  1750. HRESULT
  1751. --*/
  1752. {
  1753. DBG_ASSERT( CheckSignature() );
  1754. DBG_ASSERT( _pW3Context != NULL );
  1755. _pW3Context->QueryChildStatusAndError( pChildStatusCode,
  1756. pChildSubErrorCode,
  1757. pChildWin32Error );
  1758. return NO_ERROR;
  1759. }
  1760. HRESULT STDMETHODCALLTYPE
  1761. ISAPI_REQUEST::VectorSend(
  1762. DWORD64 IsaContext,
  1763. BOOL fDisconnect,
  1764. LPSTR pszStatus,
  1765. LPSTR pszHeaders,
  1766. VECTOR_ELEMENT *pElements,
  1767. DWORD nElementCount,
  1768. BOOL fFinalSend,
  1769. BOOL fCacheResponse
  1770. )
  1771. /*++
  1772. Routine description
  1773. Do a vector send of multiple file handle/memory chunks
  1774. Parameters
  1775. IsaContext - The ISAPI_CONTEXT for this request (opaque)
  1776. fDisconnect - Do we disconnect after send
  1777. pszStatus - The status to be sent if any
  1778. pszHeaders - The headers to be sent if any
  1779. pElements - The file handle/memory chunks to be sent
  1780. nElementCount - The number of these chunks
  1781. fFinalSend - Should we tell http.sys on behalf of the ISAPI that this
  1782. is the final send for this response
  1783. fCacheResponse - Should we ask http.sys to cache this response
  1784. Return value
  1785. HRESULT
  1786. --*/
  1787. {
  1788. W3_ISAPI_HANDLER * pW3IsapiHandler;
  1789. HRESULT hr = S_OK;
  1790. DWORD cchHeaders = 0;
  1791. W3_RESPONSE * pResponse;
  1792. BOOL fAsync;
  1793. BOOL fFragmentCacheUsed = FALSE;
  1794. WCHAR * pszFullFragmentName;
  1795. DWORD i;
  1796. BOOL fSwitchToParsed = FALSE;
  1797. DBG_ASSERT( CheckSignature() );
  1798. DBG_ASSERT( _pW3Context );
  1799. DBG_REQUIRE( ( pResponse = _pW3Context->QueryResponse() ) != NULL );
  1800. DBG_REQUIRE( ( pW3IsapiHandler = (W3_ISAPI_HANDLER*)_pW3Context->QueryHandler() ) != NULL );
  1801. //
  1802. // A non-NULL context indicates async request
  1803. //
  1804. fAsync = !!IsaContext;
  1805. if ( fAsync )
  1806. {
  1807. DBG_ASSERT( _IsapiContext == 0 );
  1808. _IsapiContext = IsaContext;
  1809. }
  1810. if (pszHeaders != NULL)
  1811. {
  1812. cchHeaders = (DWORD)strlen(pszHeaders);
  1813. }
  1814. if ( _fIsOop )
  1815. {
  1816. //
  1817. // Need to make copies of the file handles and maybe even memory buffer
  1818. //
  1819. if ( fAsync && pszHeaders )
  1820. {
  1821. _pTfHead = (LPBYTE)LocalAlloc(LMEM_FIXED, cchHeaders + 1 );
  1822. if ( _pTfHead == NULL )
  1823. {
  1824. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1825. goto Exit;
  1826. }
  1827. memcpy( _pTfHead, pszHeaders, cchHeaders + 1 );
  1828. pszHeaders = (LPSTR)_pTfHead;
  1829. }
  1830. if (!_bufVectorElements.Resize(nElementCount * sizeof(VECTOR_ELEMENT)))
  1831. {
  1832. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  1833. goto Exit;
  1834. }
  1835. ZeroMemory(_bufVectorElements.QueryPtr(),
  1836. nElementCount * sizeof(VECTOR_ELEMENT));
  1837. VECTOR_ELEMENT *pNewElements = (VECTOR_ELEMENT *)_bufVectorElements.QueryPtr();
  1838. for (i=0; i<nElementCount; i++)
  1839. {
  1840. if (pElements[i].hFile)
  1841. {
  1842. //
  1843. // File handle chunk
  1844. //
  1845. hr = pW3IsapiHandler->DuplicateWamProcessHandleForLocalUse(
  1846. (HANDLE)pElements[i].hFile,
  1847. (HANDLE *)&pNewElements[i].hFile);
  1848. if (FAILED(hr))
  1849. {
  1850. goto Exit;
  1851. }
  1852. pNewElements[i].cbOffset = pElements[i].cbOffset;
  1853. pNewElements[i].cbFileSize = pElements[i].cbFileSize;
  1854. }
  1855. else if (pElements[i].pBuffer)
  1856. {
  1857. //
  1858. // Memory buffer chunk
  1859. //
  1860. if (fAsync)
  1861. {
  1862. //
  1863. // Need to copy the buffer too
  1864. //
  1865. pNewElements[i].pBuffer = (BYTE *)LocalAlloc(LMEM_FIXED, pElements[i].cbBufSize);
  1866. if (pNewElements[i].pBuffer == NULL)
  1867. {
  1868. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  1869. goto Exit;
  1870. }
  1871. memcpy(pNewElements[i].pBuffer,
  1872. pElements[i].pBuffer,
  1873. pElements[i].cbBufSize);
  1874. }
  1875. else
  1876. {
  1877. pNewElements[i].pBuffer = pElements[i].pBuffer;
  1878. }
  1879. pNewElements[i].cbBufSize = pElements[i].cbBufSize;
  1880. }
  1881. _nElementCount++;
  1882. }
  1883. pElements = pNewElements;
  1884. }
  1885. //
  1886. // First Clear any goo left from a previous Send
  1887. //
  1888. pResponse->Clear();
  1889. //
  1890. // We must always obey the fDisconnect flag
  1891. // assuming the SSFVectorSend always correctly sets it.
  1892. //
  1893. _pW3Context->SetDisconnect(fDisconnect);
  1894. //
  1895. // Now do the real work
  1896. //
  1897. if (pszStatus != NULL)
  1898. {
  1899. hr = pResponse->BuildResponseFromIsapi( _pW3Context,
  1900. pszStatus,
  1901. pszHeaders,
  1902. cchHeaders );
  1903. if (FAILED(hr))
  1904. {
  1905. goto Exit;
  1906. }
  1907. //
  1908. // Is the status is access denied, then set the sub status to
  1909. // "Denied by Application"
  1910. //
  1911. if ( pResponse->QueryStatusCode() == HttpStatusUnauthorized.statusCode )
  1912. {
  1913. pResponse->SetStatus( HttpStatusUnauthorized,
  1914. Http401Application );
  1915. }
  1916. }
  1917. for (i=0; i<nElementCount; i++)
  1918. {
  1919. if (pElements[i].hFile)
  1920. {
  1921. hr = pResponse->AddFileHandleChunk((HANDLE)pElements[i].hFile,
  1922. pElements[i].cbOffset,
  1923. pElements[i].cbFileSize);
  1924. }
  1925. else if (pElements[i].pBuffer)
  1926. {
  1927. hr = pResponse->AddMemoryChunkByReference(pElements[i].pBuffer,
  1928. pElements[i].cbBufSize);
  1929. }
  1930. else
  1931. {
  1932. if (FAILED(hr = _pW3Context->QueryHeaderBuffer()->AllocateSpace(
  1933. pElements[i].pszFragmentName,
  1934. (DWORD)wcslen(pElements[i].pszFragmentName),
  1935. &pszFullFragmentName)))
  1936. {
  1937. goto Exit;
  1938. }
  1939. hr = pResponse->AddFragmentChunk(pszFullFragmentName,
  1940. (USHORT)wcslen(pszFullFragmentName) * sizeof(WCHAR));
  1941. fFragmentCacheUsed = TRUE;
  1942. }
  1943. if (FAILED(hr))
  1944. {
  1945. goto Exit;
  1946. }
  1947. }
  1948. if (fFragmentCacheUsed)
  1949. {
  1950. //
  1951. // Cannot used fragment-cache if using either compression or send-raw data filters
  1952. //
  1953. W3_METADATA *pMetaData = _pW3Context->QueryUrlContext()->QueryMetaData();
  1954. if ( !_pW3Context->QueryDoneWithCompression() &&
  1955. pMetaData->QueryDoDynamicCompression() )
  1956. {
  1957. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1958. goto Exit;
  1959. }
  1960. if ( _pW3Context->IsNotificationNeeded( SF_NOTIFY_SEND_RAW_DATA ) )
  1961. {
  1962. hr = HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  1963. goto Exit;
  1964. }
  1965. //
  1966. // We also cannot generate content-length in this case
  1967. //
  1968. _pW3Context->QueryMainContext()->SetShouldGenerateContentLength( FALSE );
  1969. }
  1970. if ( _fIsOop && fAsync )
  1971. {
  1972. //
  1973. // This reference insures that if the OOP host crashes and
  1974. // COM releases all the OOP-held references, that this
  1975. // object will survive until the I/O completion occurs.
  1976. //
  1977. AddRef();
  1978. }
  1979. if (pszStatus != NULL)
  1980. {
  1981. //
  1982. // If the response is to be cached, then we'll need to switch to
  1983. // parsed mode.
  1984. //
  1985. if (fCacheResponse)
  1986. {
  1987. _fCacheResponse = TRUE;
  1988. fSwitchToParsed = TRUE;
  1989. }
  1990. //
  1991. // If the ISAPI is doing a keep-alive single-send, is
  1992. // referencing a fragment (1+), and did not specify a
  1993. // content-length header themselves, then switch to
  1994. // parsed so that HTTP.SYS can do the work for us
  1995. //
  1996. if (fFragmentCacheUsed &&
  1997. !fSwitchToParsed &&
  1998. fFinalSend &&
  1999. !fDisconnect &&
  2000. pszHeaders != NULL &&
  2001. strstr( pszHeaders, "Content-Length: " ) == NULL &&
  2002. strstr( pszHeaders, "Transfer-Encoding: chunked" ) == NULL)
  2003. {
  2004. fSwitchToParsed = TRUE;
  2005. }
  2006. //
  2007. // Do the switch
  2008. //
  2009. if (fSwitchToParsed)
  2010. {
  2011. hr = _pW3Context->QueryResponse()->SwitchToParsedMode();
  2012. if (FAILED(hr))
  2013. {
  2014. Release();
  2015. goto Exit;
  2016. }
  2017. }
  2018. hr = _pW3Context->SendResponse( (fAsync ? W3_FLAG_ASYNC : W3_FLAG_SYNC)
  2019. | (fFinalSend ? 0 : W3_FLAG_MORE_DATA)
  2020. | W3_FLAG_NO_ERROR_BODY
  2021. | W3_FLAG_NO_CONTENT_LENGTH );
  2022. }
  2023. else
  2024. {
  2025. hr = _pW3Context->SendEntity( (fAsync ? W3_FLAG_ASYNC : W3_FLAG_SYNC)
  2026. | (fFinalSend ? 0 : W3_FLAG_MORE_DATA) );
  2027. }
  2028. if (FAILED(hr))
  2029. {
  2030. //
  2031. // If SendEntity or SendResponse fail, consider this
  2032. // a non recoverable error and set the error to be
  2033. // WSAECONNRESET for compatibility with legacy ISAPI code.
  2034. //
  2035. hr = HRESULT_FROM_WIN32( WSAECONNRESET );
  2036. if ( _fIsOop && fAsync )
  2037. {
  2038. //
  2039. // Release the above reference, since no I/O completion will
  2040. // occur.
  2041. //
  2042. Release();
  2043. }
  2044. }
  2045. Exit:
  2046. if ( FAILED( hr ) && fAsync && _IsapiContext != 0 )
  2047. {
  2048. _IsapiContext = 0;
  2049. }
  2050. if ( _fIsOop &&
  2051. (FAILED(hr) || !fAsync) )
  2052. {
  2053. //
  2054. // Need to destroy handles/memory buffers we copied
  2055. //
  2056. if ( _pTfHead )
  2057. {
  2058. LocalFree( _pTfHead );
  2059. _pTfHead = NULL;
  2060. }
  2061. for (i=0; i<_nElementCount; i++)
  2062. {
  2063. if (pElements[i].hFile)
  2064. {
  2065. CloseHandle((HANDLE)pElements[i].hFile);
  2066. }
  2067. else if (pElements[i].pBuffer && fAsync)
  2068. {
  2069. LocalFree(pElements[i].pBuffer);
  2070. }
  2071. }
  2072. _nElementCount = 0;
  2073. }
  2074. return hr;
  2075. }
  2076. HRESULT
  2077. ISAPI_REQUEST::GetCustomError(
  2078. DWORD dwError,
  2079. DWORD dwSubError,
  2080. DWORD dwBufferSize,
  2081. BYTE *pvBuffer,
  2082. DWORD *pdwRequiredBufferSize,
  2083. BOOL *pfIsFileError,
  2084. BOOL *pfSendErrorBody)
  2085. /*++
  2086. Routine Description:
  2087. Finds the CustomError for this error and subError. The results are returned
  2088. in pvBuffer provided there is enough buffer space. The amount of buffer space
  2089. required is returned in pdwRequestBufferSize regardless.
  2090. Arguments:
  2091. dwError - major error (e.g. 500)
  2092. dwSubError - sub error (e.g. 13)
  2093. dwBufferSize - size, in bytes, of buffer at pvBuffer
  2094. pvBuffer - pointer to buffer for result
  2095. pdwRequiredBufferSize - amount of buffer used/need
  2096. pfIsFileError - return boolean if custom error is a filename
  2097. pfSendErrorBody - upon return, TRUE if error body should be sent
  2098. Return Value:
  2099. HRESULT
  2100. --*/
  2101. {
  2102. HRESULT hr = NOERROR;
  2103. W3_METADATA *pMetadata = NULL;
  2104. LPSTR pMimeStr = "text/html";
  2105. STACK_STRA(mimeStr, 64);
  2106. STACK_STRU( strError, 64 );
  2107. DBG_ASSERT( CheckSignature() );
  2108. // first dig out the W3 Metadata pointer
  2109. pMetadata = _pW3Context->QueryUrlContext()->QueryMetaData();
  2110. DBG_ASSERT( pMetadata != NULL );
  2111. // get the custom error for this error code
  2112. hr = pMetadata->FindCustomError( (USHORT)dwError,
  2113. (USHORT)dwSubError,
  2114. pfIsFileError,
  2115. &strError );
  2116. // if successful, and the custom error is a file, we need to
  2117. // get the file's mime type
  2118. if (SUCCEEDED(hr) && *pfIsFileError) {
  2119. // lookup the MIME_ENTRY for this file.
  2120. if (SUCCEEDED(SelectMimeMappingForFileExt(strError.QueryStr(),pMetadata->QueryMimeMap(), &mimeStr))) {
  2121. pMimeStr = mimeStr.QueryStr();
  2122. }
  2123. }
  2124. // if found, convert the UNICODE string to ANSI
  2125. if (SUCCEEDED(hr)) {
  2126. int ret;
  2127. ret = WideCharToMultiByte(CP_ACP,
  2128. 0,
  2129. strError.QueryStr(),
  2130. -1,
  2131. (LPSTR)pvBuffer,
  2132. dwBufferSize,
  2133. NULL,
  2134. NULL);
  2135. *pdwRequiredBufferSize = ret;
  2136. // check return. If zero, then the conversion failed.
  2137. // GetLastError() contains the error.
  2138. if (ret == 0) {
  2139. DWORD winError = GetLastError();
  2140. // if InsufBuff, then call again to get the required size
  2141. if (winError == ERROR_INSUFFICIENT_BUFFER) {
  2142. *pdwRequiredBufferSize = WideCharToMultiByte(CP_ACP,
  2143. 0,
  2144. strError.QueryStr(),
  2145. -1,
  2146. NULL,
  2147. 0,
  2148. NULL,
  2149. NULL);
  2150. // if the error is a filename, then include in the required
  2151. // buffer size the length of the mime string
  2152. if (*pfIsFileError) {
  2153. *pdwRequiredBufferSize += (DWORD)strlen(pMimeStr) + 1;
  2154. }
  2155. }
  2156. // in any case, make a HRESULT from the win32 error and return that
  2157. hr = HRESULT_FROM_WIN32(winError);
  2158. }
  2159. // if we continue to be successful, the next step is to put
  2160. // the mime string after the null byte of the file name
  2161. if (SUCCEEDED(hr) && *pfIsFileError) {
  2162. int fileLen = (int)strlen((char *)pvBuffer);
  2163. // make sure we have enough buffer
  2164. if ((fileLen + strlen(pMimeStr) + 2) > dwBufferSize) {
  2165. hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  2166. }
  2167. else {
  2168. // looks like we do. Copy the mime string in
  2169. strcpy(&((char *)pvBuffer)[fileLen+1],pMimeStr);
  2170. pdwRequiredBufferSize += strlen(pMimeStr) + 1;
  2171. }
  2172. }
  2173. }
  2174. if ( pfSendErrorBody != NULL )
  2175. {
  2176. *pfSendErrorBody = _pW3Context->QuerySendErrorBody();
  2177. }
  2178. return hr;
  2179. }
  2180. HRESULT STDMETHODCALLTYPE
  2181. ISAPI_REQUEST::TestConnection(
  2182. BOOL *pfIsConnected
  2183. )
  2184. /*++
  2185. Routine Description:
  2186. returns state of the connection (TRUE = opened, FALSE = closed)
  2187. Arguments:
  2188. pfIsConnected - sets to TRUE if connection is still open,
  2189. FALSE if it was closed already
  2190. Return Value:
  2191. HRESULT
  2192. --*/
  2193. {
  2194. HRESULT hr = NOERROR;
  2195. W3_CONNECTION * pConnection = NULL;
  2196. W3_MAIN_CONTEXT * pMainContext = NULL;
  2197. DBG_ASSERT( CheckSignature() );
  2198. DBG_ASSERT( _pW3Context != NULL );
  2199. pMainContext = _pW3Context->QueryMainContext();
  2200. DBG_ASSERT( pMainContext != NULL );
  2201. pConnection = pMainContext->QueryConnection( TRUE );
  2202. if ( pConnection == NULL )
  2203. {
  2204. //
  2205. // Issue 02/08/2001 jaroslad:
  2206. // QueryConnection currently doesn't have a way to return
  2207. // error that occured. For now assume that out of memory
  2208. // occured
  2209. //
  2210. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  2211. //
  2212. // we will not touch pfIsConnected in the case of error
  2213. // it is caller's responsibility to check if this call
  2214. // succeeded before using pfIsConnected
  2215. //
  2216. }
  2217. else
  2218. {
  2219. *pfIsConnected = pConnection->QueryConnected();
  2220. }
  2221. return hr;
  2222. }
  2223. HRESULT STDMETHODCALLTYPE
  2224. ISAPI_REQUEST::GetSspiInfo(
  2225. BYTE *pCredHandle,
  2226. DWORD cbCredHandle,
  2227. BYTE *pCtxtHandle,
  2228. DWORD cbCtxtHandle)
  2229. /*++
  2230. Routine Description:
  2231. Returns SSPI info about the request
  2232. Arguments:
  2233. pCredHandle - Upon return, contains the credential handle
  2234. cbCredHandle - The size of pCredHandle
  2235. pCtxtHandle - Upon return, contains the context handle
  2236. cbCtxtHandle - The size of pCtxtHandle
  2237. Return Value:
  2238. HRESULT
  2239. --*/
  2240. {
  2241. W3_USER_CONTEXT * pUserContext;
  2242. DBG_ASSERT( CheckSignature() );
  2243. DBG_ASSERT( _pW3Context != NULL );
  2244. if ( _fIsOop )
  2245. {
  2246. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  2247. }
  2248. pUserContext = _pW3Context->QueryUserContext();
  2249. DBG_ASSERT( pUserContext != NULL );
  2250. return pUserContext->GetSspiInfo( pCredHandle,
  2251. cbCredHandle,
  2252. pCtxtHandle,
  2253. cbCtxtHandle );
  2254. }
  2255. HRESULT STDMETHODCALLTYPE
  2256. ISAPI_REQUEST::QueryToken(
  2257. BYTE *szUrl,
  2258. DWORD,
  2259. DWORD dwTokenType,
  2260. DWORD64 *pToken,
  2261. BOOL fUnicode)
  2262. /*++
  2263. Routine Description:
  2264. Returns the VR token for the request
  2265. Arguments:
  2266. szUrl - The URL for which we need to get the token
  2267. cbUrl - The size of szUrl
  2268. dwTokenType - Either TOKEN_VR_TOKEN or TOKEN_ANONYMOUS_TOKEN
  2269. pToken - Upon return, points to the resulting token
  2270. fUnicode - If TRUE, szUrl is UNICODE, else it's ANSI
  2271. Return Value:
  2272. HRESULT
  2273. --*/
  2274. {
  2275. STACK_STRU( struUrl,MAX_PATH );
  2276. W3_URL_INFO * pUrlInfo = NULL;
  2277. W3_METADATA * pMetaData = NULL;
  2278. TOKEN_CACHE_ENTRY * pTokenEntry = NULL;
  2279. HANDLE hToken = NULL;
  2280. HANDLE hTokenLocalDuplicate = NULL;
  2281. HRESULT hr;
  2282. BOOL fSuccess;
  2283. DBG_ASSERT( _pW3Context );
  2284. DBG_ASSERT( szUrl );
  2285. DBG_ASSERT( pToken );
  2286. DBG_ASSERT( dwTokenType == TOKEN_VR_TOKEN ||
  2287. dwTokenType == TOKEN_ANONYMOUS_TOKEN );
  2288. //
  2289. // Get the metadata for the specified URL
  2290. //
  2291. if ( fUnicode )
  2292. {
  2293. hr = struUrl.Copy( (LPWSTR)szUrl );
  2294. }
  2295. else
  2296. {
  2297. hr = struUrl.CopyA( (LPSTR)szUrl );
  2298. }
  2299. if ( FAILED( hr ) )
  2300. {
  2301. return hr;
  2302. }
  2303. DBG_ASSERT( g_pW3Server->QueryUrlInfoCache() != NULL );
  2304. hr = g_pW3Server->QueryUrlInfoCache()->GetUrlInfo(
  2305. _pW3Context,
  2306. struUrl,
  2307. &pUrlInfo );
  2308. if ( FAILED( hr ) )
  2309. {
  2310. return hr;
  2311. }
  2312. DBG_ASSERT( pUrlInfo != NULL );
  2313. pMetaData = pUrlInfo->QueryMetaData();
  2314. DBG_ASSERT( pMetaData != NULL );
  2315. //
  2316. // Assume that the VR token is NULL, unless we can determine otherwise
  2317. //
  2318. *pToken = NULL;
  2319. //
  2320. // Ok, so now let's get the token
  2321. //
  2322. if ( dwTokenType == TOKEN_VR_TOKEN )
  2323. {
  2324. hr = pMetaData->GetAndRefVrAccessToken( &pTokenEntry );
  2325. if( FAILED( hr ) )
  2326. {
  2327. return hr;
  2328. }
  2329. }
  2330. else if ( dwTokenType == TOKEN_ANONYMOUS_TOKEN )
  2331. {
  2332. hr = pMetaData->GetAndRefAnonymousToken( &pTokenEntry );
  2333. if( FAILED( hr ) )
  2334. {
  2335. return hr;
  2336. }
  2337. }
  2338. else
  2339. {
  2340. DBG_ASSERT( FALSE );
  2341. }
  2342. if ( pTokenEntry != NULL )
  2343. {
  2344. hToken = pTokenEntry->QueryImpersonationToken();
  2345. }
  2346. if ( hToken )
  2347. {
  2348. //
  2349. // Need to duplicate the handle. This is really only necessary for
  2350. // OOP requests, but we need to do it for both, so that the extension
  2351. // doesn't need to worry about knowing if it's inproc or not before
  2352. // deciding if it needs to close the handle.
  2353. //
  2354. fSuccess = DupTokenWithSameImpersonationLevel(
  2355. hToken,
  2356. MAXIMUM_ALLOWED,
  2357. TokenPrimary,
  2358. &hTokenLocalDuplicate
  2359. );
  2360. if( fSuccess )
  2361. {
  2362. if( _fIsOop )
  2363. {
  2364. HANDLE hTokenRemote = NULL;
  2365. fSuccess = DuplicateHandle(
  2366. GetCurrentProcess(),
  2367. hTokenLocalDuplicate,
  2368. _pWamProcess->QueryProcess(),
  2369. &hTokenRemote,
  2370. 0,
  2371. FALSE,
  2372. DUPLICATE_SAME_ACCESS
  2373. );
  2374. CloseHandle(hTokenLocalDuplicate);
  2375. hTokenLocalDuplicate = NULL;
  2376. *pToken = (DWORD64)hTokenRemote;
  2377. }
  2378. else
  2379. {
  2380. *pToken = reinterpret_cast<DWORD64>(hTokenLocalDuplicate);
  2381. }
  2382. }
  2383. }
  2384. pUrlInfo->DereferenceCacheEntry();
  2385. if ( pTokenEntry != NULL )
  2386. {
  2387. pTokenEntry->DereferenceCacheEntry();
  2388. pTokenEntry = NULL;
  2389. }
  2390. return hr;
  2391. }
  2392. HRESULT STDMETHODCALLTYPE
  2393. ISAPI_REQUEST::ReportAsUnhealthy(
  2394. BYTE *szImage,
  2395. DWORD,
  2396. BYTE *szReason,
  2397. DWORD cbReason)
  2398. /*++
  2399. Routine Description:
  2400. Handles an ISAPI reporting itself as unhealthy
  2401. Arguments:
  2402. szImage - A UNICODE string with the ISAPI image name
  2403. cbImage - The size of szImage
  2404. szReason - A UNICODE string from the ISAPI indicating the problem
  2405. cbReason - The size of szReason
  2406. Return Value:
  2407. HRESULT
  2408. --*/
  2409. {
  2410. W3_ISAPI_HANDLER * pW3IsapiHandler;
  2411. const WCHAR * pszEventLog[2];
  2412. DBG_ASSERT( _pW3Context );
  2413. DBG_ASSERT( szImage );
  2414. DBG_ASSERT( cbReason == 0 || szReason != NULL );
  2415. DBG_REQUIRE( ( pW3IsapiHandler = (W3_ISAPI_HANDLER*)_pW3Context->QueryHandler() ) != NULL );
  2416. //
  2417. // First, log the event. After we set the unhealthy flag,
  2418. // this process could get terminated at any time.
  2419. //
  2420. // There are two possible messages to log, depending on
  2421. // whether the extension gave us a reason for being
  2422. // unhealthy.
  2423. //
  2424. pszEventLog[0] = reinterpret_cast<WCHAR*>( szImage );
  2425. if ( cbReason > 0 )
  2426. {
  2427. pszEventLog[1] = reinterpret_cast<WCHAR*>( szReason );
  2428. g_pW3Server->LogEvent(
  2429. W3_EVENT_UNHEALTHY_ISAPI,
  2430. 2,
  2431. pszEventLog,
  2432. 0
  2433. );
  2434. }
  2435. else
  2436. {
  2437. g_pW3Server->LogEvent(
  2438. W3_EVENT_UNHEALTHY_ISAPI_NO_REASON,
  2439. 1,
  2440. pszEventLog,
  2441. 0
  2442. );
  2443. }
  2444. //
  2445. // Now tell someone that we feel sick
  2446. //
  2447. UlAtqSetUnhealthy();
  2448. return NO_ERROR;
  2449. }
  2450. HRESULT STDMETHODCALLTYPE
  2451. ISAPI_REQUEST::AddFragmentToCache(
  2452. VECTOR_ELEMENT * pVectorElement,
  2453. WCHAR * pszFragmentName
  2454. )
  2455. /*++
  2456. Routine Description:
  2457. Add the fragment to cache
  2458. Arguments:
  2459. pVectorElement - The fragment to be added
  2460. pszFragmentName - name of the fragment
  2461. Return Value:
  2462. HRESULT
  2463. --*/
  2464. {
  2465. HTTP_DATA_CHUNK DataChunk;
  2466. ZeroMemory(&DataChunk, sizeof DataChunk);
  2467. if (pVectorElement->hFile)
  2468. {
  2469. DataChunk.DataChunkType = HttpDataChunkFromFileHandle;
  2470. DataChunk.FromFileHandle.FileHandle = (HANDLE)pVectorElement->hFile;
  2471. DataChunk.FromFileHandle.ByteRange.StartingOffset.QuadPart = pVectorElement->cbOffset;
  2472. DataChunk.FromFileHandle.ByteRange.Length.QuadPart = pVectorElement->cbFileSize;
  2473. }
  2474. else if (pVectorElement->pBuffer)
  2475. {
  2476. DataChunk.DataChunkType = HttpDataChunkFromMemory;
  2477. DataChunk.FromMemory.pBuffer = pVectorElement->pBuffer;
  2478. DataChunk.FromMemory.BufferLength = pVectorElement->cbBufSize;
  2479. }
  2480. return UlAtqAddFragmentToCache(&DataChunk,
  2481. pszFragmentName);
  2482. }
  2483. HRESULT STDMETHODCALLTYPE
  2484. ISAPI_REQUEST::ReadFragmentFromCache(
  2485. WCHAR * pszFragmentName,
  2486. BYTE * pvBuffer,
  2487. DWORD cbSize,
  2488. DWORD * pcbCopied
  2489. )
  2490. /*++
  2491. Routine Description:
  2492. Read the fragment from cache
  2493. Arguments:
  2494. pszFragmentName - name of the fragment
  2495. pvBuffer - the buffer to read in
  2496. cbSize - the size of the buffer
  2497. pcbCopied - the amount copied in on return
  2498. Return Value:
  2499. HRESULT
  2500. --*/
  2501. {
  2502. return UlAtqReadFragmentFromCache(pszFragmentName,
  2503. pvBuffer,
  2504. cbSize,
  2505. pcbCopied);
  2506. }
  2507. HRESULT STDMETHODCALLTYPE
  2508. ISAPI_REQUEST::RemoveFragmentFromCache(
  2509. WCHAR * pszFragmentName
  2510. )
  2511. /*++
  2512. Routine Description:
  2513. Remove the fragment from cache
  2514. Arguments:
  2515. pszFragmentName - name of the fragment
  2516. Return Value:
  2517. HRESULT
  2518. --*/
  2519. {
  2520. return UlAtqRemoveFragmentFromCache(pszFragmentName);
  2521. }
  2522. HRESULT
  2523. ISAPI_REQUEST::PreprocessIoCompletion(
  2524. DWORD cbIo
  2525. )
  2526. /*++
  2527. Routine Description:
  2528. Handles cleanup for any functions that use fCopiedData=TRUE.
  2529. In the case of a TransmitFile or WriteClient, this just
  2530. involves closing handles and freeing buffers. In the case
  2531. of ReadClient, we need to push the read buffer to the OOP
  2532. process.
  2533. Arguments:
  2534. cbIo - The number of bytes in a read buffer, if present
  2535. Return Value:
  2536. HRESULT
  2537. --*/
  2538. {
  2539. W3_ISAPI_HANDLER * pW3IsapiHandler;
  2540. HRESULT hr = NOERROR;
  2541. DWORD i;
  2542. DBG_ASSERT( CheckSignature() );
  2543. DBG_ASSERT( _pW3Context );
  2544. DBG_REQUIRE( ( pW3IsapiHandler = (W3_ISAPI_HANDLER*)_pW3Context->QueryHandler() ) != NULL );
  2545. //
  2546. // Cleanup any existing TF info, since we're done with it.
  2547. //
  2548. if ( _hTfFile != NULL && _hTfFile != INVALID_HANDLE_VALUE )
  2549. {
  2550. CloseHandle( _hTfFile );
  2551. _hTfFile = INVALID_HANDLE_VALUE;
  2552. }
  2553. if ( _pTfHead )
  2554. {
  2555. LocalFree( _pTfHead );
  2556. _pTfHead = NULL;
  2557. }
  2558. if ( _pTfTail )
  2559. {
  2560. LocalFree( _pTfTail );
  2561. _pTfTail = NULL;
  2562. }
  2563. //
  2564. // Cleanup any existing async write buffer
  2565. //
  2566. if ( _pAsyncWriteBuffer )
  2567. {
  2568. LocalFree( _pAsyncWriteBuffer );
  2569. _pAsyncWriteBuffer = NULL;
  2570. }
  2571. //
  2572. // If we have an async read buffer, then push the data
  2573. // to the WAM process and free it
  2574. //
  2575. if ( _pAsyncReadBuffer )
  2576. {
  2577. hr = pW3IsapiHandler->MarshalAsyncReadBuffer(
  2578. _IsapiContext,
  2579. _pAsyncReadBuffer,
  2580. cbIo
  2581. );
  2582. //
  2583. // Note that the above function could fail if, for
  2584. // example, the dllhost has crashed. There's not
  2585. // anything we can do about it here, though. We'll
  2586. // ignore it.
  2587. //
  2588. LocalFree( _pAsyncReadBuffer );
  2589. _pAsyncReadBuffer = NULL;
  2590. }
  2591. //
  2592. // Clean up HSE_EXEC_URL stuff
  2593. //
  2594. if ( _pbExecUrlEntity != NULL )
  2595. {
  2596. LocalFree( _pbExecUrlEntity );
  2597. _pbExecUrlEntity = NULL;
  2598. }
  2599. if ( _hExecUrlToken != NULL )
  2600. {
  2601. CloseHandle( _hExecUrlToken );
  2602. _hExecUrlToken = NULL;
  2603. }
  2604. //
  2605. // Need to destroy handles/memory buffers we copied for vector send
  2606. //
  2607. VECTOR_ELEMENT *pElements = (VECTOR_ELEMENT *)_bufVectorElements.QueryPtr();
  2608. for (i=0; i<_nElementCount; i++)
  2609. {
  2610. if (pElements[i].hFile)
  2611. {
  2612. CloseHandle((HANDLE)pElements[i].hFile);
  2613. }
  2614. else if (pElements[i].pBuffer)
  2615. {
  2616. LocalFree(pElements[i].pBuffer);
  2617. }
  2618. }
  2619. _nElementCount = 0;
  2620. return hr;
  2621. }
  2622. HRESULT STDMETHODCALLTYPE
  2623. ISAPI_REQUEST::GetMetadataProperty(
  2624. DWORD dwPropertyId,
  2625. BYTE * pbBuffer,
  2626. DWORD cbBuffer,
  2627. DWORD * pcbBufferRequired
  2628. )
  2629. /*++
  2630. Routine Description:
  2631. Retrieves a metabase property
  2632. Arguments:
  2633. dwPropertyId - MD_ property ID (must be of type UT_FILE)
  2634. pbBuffer - Buffer to receive serialized data
  2635. cbBuffer - Size of buffer
  2636. pcbBufferRequired - Filled with size of buffer required
  2637. Return Value:
  2638. HRESULT
  2639. --*/
  2640. {
  2641. URL_CONTEXT * pUrlContext;
  2642. W3_METADATA * pMetadata;
  2643. DBG_ASSERT( _pW3Context );
  2644. pUrlContext = _pW3Context->QueryUrlContext();
  2645. DBG_ASSERT( pUrlContext != NULL );
  2646. pMetadata = pUrlContext->QueryMetaData();
  2647. DBG_ASSERT( pMetadata != NULL );
  2648. return pMetadata->GetMetadataProperty( _pW3Context,
  2649. dwPropertyId,
  2650. pbBuffer,
  2651. cbBuffer,
  2652. pcbBufferRequired );
  2653. }
  2654. HRESULT STDMETHODCALLTYPE
  2655. ISAPI_REQUEST::GetCacheInvalidationCallback(
  2656. DWORD64 *pfnCallback)
  2657. {
  2658. //
  2659. // BUGBUG: CODEWORK: will need another mechanism if we want to implement
  2660. // this for OOP
  2661. //
  2662. if (_fIsOop)
  2663. {
  2664. return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  2665. }
  2666. *(PFN_HSE_CACHE_INVALIDATION_CALLBACK *)pfnCallback = UlAtqFlushUlCache;
  2667. return S_OK;
  2668. }
  2669. HRESULT STDMETHODCALLTYPE
  2670. ISAPI_REQUEST::CloseConnection(
  2671. VOID
  2672. )
  2673. {
  2674. W3_RESPONSE * pResponse;
  2675. DWORD cbSent = NULL;
  2676. HRESULT hr;
  2677. DBG_ASSERT( CheckSignature() );
  2678. DBG_ASSERT( _pW3Context );
  2679. DBG_REQUIRE( ( pResponse = _pW3Context->QueryResponse() ) != NULL );
  2680. //
  2681. // Tell http.sys to close the connection. This send should not
  2682. // cause http.sys to clean up the request - and logging data
  2683. // sent later (when the ISAPI is done) should be correctly
  2684. // handled.
  2685. //
  2686. hr = SendEntityBodyAndLogDataHelper( _pW3Context,
  2687. _pW3Context->QueryUlatqContext(),
  2688. FALSE,
  2689. HTTP_SEND_RESPONSE_FLAG_DISCONNECT,
  2690. 0,
  2691. NULL,
  2692. &cbSent );
  2693. if ( FAILED( hr ) )
  2694. {
  2695. //
  2696. // If SendEntity fails, consider this a non recoverable
  2697. // error and set the error to be WSAECONNRESET for
  2698. // compatibility with legacy ISAPI code.
  2699. //
  2700. hr = HRESULT_FROM_WIN32( WSAECONNRESET );
  2701. }
  2702. return hr;
  2703. }
  2704. HRESULT STDMETHODCALLTYPE
  2705. ISAPI_REQUEST::AllocateMemory(
  2706. DWORD cbSize,
  2707. DWORD64 * ppvBuffer
  2708. )
  2709. /*++
  2710. Routine Description:
  2711. Allocate some per-request memory
  2712. Arguments:
  2713. cbSize - Size to allocate
  2714. ppvBuffer - Filled with buffer
  2715. Return Value:
  2716. HRESULT
  2717. --*/
  2718. {
  2719. DWORD64 dwBuffer;
  2720. VOID * pvBuffer;
  2721. DBG_ASSERT( CheckSignature() );
  2722. DBG_ASSERT( _pW3Context );
  2723. pvBuffer = _pW3Context->ContextAlloc( cbSize );
  2724. if ( pvBuffer == NULL )
  2725. {
  2726. return HRESULT_FROM_WIN32( GetLastError() );
  2727. }
  2728. *ppvBuffer = (DWORD64) pvBuffer;
  2729. return S_OK;
  2730. }
  2731. ISAPI_REQUEST::~ISAPI_REQUEST()
  2732. /*++
  2733. Routine Description:
  2734. Destructor
  2735. Arguments:
  2736. None
  2737. Return Value:
  2738. None
  2739. --*/
  2740. {
  2741. DBG_ASSERT( CheckSignature() );
  2742. //
  2743. // Release the free threaded marshaler
  2744. //
  2745. if ( _pUnkFTM )
  2746. {
  2747. _pUnkFTM->Release();
  2748. _pUnkFTM = NULL;
  2749. }
  2750. //
  2751. // Dissociate ourselves from the WAM_PROCESS, if present
  2752. //
  2753. if ( _pWamProcess )
  2754. {
  2755. if (_pWamProcess->QueryCrashed())
  2756. {
  2757. AppendLog(SZ_FAILED_OOP_REQUEST_LOG_MESSAGE,
  2758. 500);
  2759. }
  2760. _pWamProcess->DecrementRequestCount();
  2761. _pWamProcess->Release();
  2762. _pWamProcess = NULL;
  2763. }
  2764. _dwSignature = ISAPI_REQUEST_SIGNATURE_FREE;
  2765. IF_DEBUG( ISAPI )
  2766. {
  2767. DBGPRINTF((
  2768. DBG_CONTEXT,
  2769. "ISAPI_REQUEST %p has been destroyed.\r\n",
  2770. this
  2771. ));
  2772. }
  2773. }