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.

2962 lines
78 KiB

  1. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. //
  3. // RESPONSE.CPP
  4. //
  5. // HTTP 1.1/DAV 1.0 response handling via ISAPI
  6. //
  7. //
  8. // Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  9. //
  10. #include <_davprs.h>
  11. #include <new.h>
  12. #include "ecb.h"
  13. #include "header.h"
  14. #include "body.h"
  15. #include "instdata.h"
  16. #include "custerr.h"
  17. enum
  18. {
  19. //
  20. // Protocol overhead for a chunk prefix, which is:
  21. //
  22. // chunk-size - formatted as 1*HEX
  23. // CRLF
  24. //
  25. CB_CHUNK_PREFIX = 2 * sizeof(ULONG) + 2,
  26. //
  27. // Protocol overhead for a chunk suffix, which is:
  28. //
  29. // CRLF - at the end of chunk-data
  30. // 0 - if this is the last chunk
  31. // CRLF - again, if this is the last chunk
  32. // CRLF - terminate the chunked-body (no trailers)
  33. //
  34. CB_CHUNK_SUFFIX = 7,
  35. //
  36. // Maximum amount of data (in bytes) per packet.
  37. // We SHOULD limit ourselves to a reasonable maximum amount
  38. // to get good chunking performance. At one time, we had to
  39. // ourselves to 8K at most because the socket transport layer
  40. // did not accept more than this amount for sending.
  41. // WriteClient() and SSF::HSE_REQ_TRANSMIT_FILE failed when
  42. // more than this amount is submitted.
  43. //
  44. // However, as of 06/03/1999, bumping this amount to 64K seems
  45. // to work just fine.
  46. //
  47. CB_PACKET_MAX = 64 * 1024, // 64K
  48. //
  49. // So the amount of data that we can put in a chunk then is just
  50. // the max packet size minus the chunked encoding protocol overhead
  51. // minus one byte because packets containing headers must be
  52. // null-terminated (IIS doesn't use the byte counts we pass in).
  53. //
  54. CB_WSABUFS_MAX = CB_PACKET_MAX - CB_CHUNK_PREFIX - CB_CHUNK_SUFFIX - 1
  55. };
  56. //
  57. // Utility to check if the HTTP response code is one of the
  58. // "real" error response codes. Inlined here so that we use
  59. // it consistantly. Particularly, this is used to check if
  60. // we want to do custom error processing.
  61. //
  62. static BOOL inline FErrorStatusCode ( int nCode )
  63. {
  64. return ( ( nCode >= 400 ) && ( nCode <= 599 ) );
  65. }
  66. // ========================================================================
  67. //
  68. // CLASS CWSABufs
  69. //
  70. class CWSABufs
  71. {
  72. //
  73. // Having a small number of buffers in a fixed size array means
  74. // that we can delay, if not avoid altogether, dynamic allocation.
  75. // The number of buffers is somewhat arbitrary, but should be large
  76. // enough to handle the common cases. For example, DAVOWS GET
  77. // typically uses two buffers: one for the headers, one for the body.
  78. // Another example: error responses can use up to eight buffers (one
  79. // per text body part added via AddText() by
  80. // CResponse::FinalizeContent()).
  81. //
  82. enum
  83. {
  84. C_WSABUFS_FIXED = 8
  85. };
  86. WSABUF m_rgWSABufsFixed[C_WSABUFS_FIXED];
  87. //
  88. // Dynamically sized array of WSABUFs for when we need more buffers
  89. // than we can hold in the fixed array.
  90. //
  91. auto_heap_ptr<WSABUF> m_pargWSABufs;
  92. //
  93. // Pointer to which of the two WSABUF arrays above we use.
  94. //
  95. WSABUF * m_pWSABufs;
  96. //
  97. // Count of WSABUFs allocated/used
  98. //
  99. UINT m_cWSABufsAllocated;
  100. UINT m_cWSABufsUsed;
  101. //
  102. // Total size of the data in all WSABUFS used
  103. //
  104. UINT m_cbWSABufs;
  105. // NOT IMPLEMENTED
  106. //
  107. CWSABufs( const CWSABufs& );
  108. CWSABufs& operator=( const CWSABufs& );
  109. public:
  110. // CREATORS
  111. //
  112. CWSABufs();
  113. // MANIPULATORS
  114. //
  115. UINT CbAddItem( const BYTE * pbItem, UINT cbItem );
  116. VOID Clear()
  117. {
  118. m_cWSABufsUsed = 0;
  119. m_cbWSABufs = 0;
  120. }
  121. // ACCESSORS
  122. //
  123. UINT CbSize() const
  124. {
  125. return m_cbWSABufs;
  126. }
  127. VOID DumpTo( LPBYTE lpbBuf,
  128. UINT ibFrom,
  129. UINT cbToDump ) const;
  130. };
  131. // ------------------------------------------------------------------------
  132. //
  133. // CWSABufs::CWSABufs()
  134. //
  135. CWSABufs::CWSABufs() :
  136. m_pWSABufs(m_rgWSABufsFixed),
  137. m_cWSABufsAllocated(C_WSABUFS_FIXED),
  138. m_cWSABufsUsed(0),
  139. m_cbWSABufs(0)
  140. {
  141. }
  142. // ------------------------------------------------------------------------
  143. //
  144. // CWSABufs::CbAddItem()
  145. //
  146. UINT
  147. CWSABufs::CbAddItem( const BYTE * pbItem, UINT cbItem )
  148. {
  149. //
  150. // We can only hold up to CB_WSABUFS_MAX bytes. Any more than
  151. // that would exceed the capacity of the socket transport layer's
  152. // buffer at transmit time.
  153. //
  154. Assert( m_cbWSABufs <= CB_WSABUFS_MAX );
  155. //
  156. // Limit what we add so that the total does not exceed CB_WSABUFS_MAX.
  157. //
  158. cbItem = min( cbItem, CB_WSABUFS_MAX - m_cbWSABufs );
  159. //
  160. // Resize the WSABUF array if necessary.
  161. //
  162. if ( m_cWSABufsUsed == m_cWSABufsAllocated )
  163. {
  164. m_cWSABufsAllocated *= 2;
  165. if ( m_pWSABufs == m_rgWSABufsFixed )
  166. {
  167. m_pargWSABufs =
  168. reinterpret_cast<WSABUF *>(
  169. g_heap.Alloc( sizeof(WSABUF) *
  170. m_cWSABufsAllocated ));
  171. CopyMemory( m_pargWSABufs,
  172. m_rgWSABufsFixed,
  173. sizeof(WSABUF) * m_cWSABufsUsed );
  174. }
  175. else
  176. {
  177. m_pargWSABufs.realloc( sizeof(WSABUF) * m_cWSABufsAllocated );
  178. }
  179. m_pWSABufs = m_pargWSABufs;
  180. }
  181. //
  182. // Add the new data to the end of the array
  183. //
  184. m_pWSABufs[m_cWSABufsUsed].len = cbItem;
  185. m_pWSABufs[m_cWSABufsUsed].buf = const_cast<LPSTR>(
  186. reinterpret_cast<LPCSTR>(pbItem));
  187. ++m_cWSABufsUsed;
  188. //
  189. // Update the total byte count
  190. //
  191. m_cbWSABufs += cbItem;
  192. return cbItem;
  193. }
  194. // ------------------------------------------------------------------------
  195. //
  196. // CWSABufs::DumpTo()
  197. //
  198. // Dumps cbToDump bytes of data from the WSA buffers starting at ibFrom
  199. // into a block of contiguous memory starting at lpbBuf.
  200. //
  201. VOID
  202. CWSABufs::DumpTo( LPBYTE lpbBuf,
  203. UINT ibFrom,
  204. UINT cbToDump ) const
  205. {
  206. UINT iWSABuf;
  207. Assert( !IsBadWritePtr(lpbBuf, m_cbWSABufs + 1) );
  208. //
  209. // Skip WSA buffers up to the first one from which we will copy.
  210. //
  211. for ( iWSABuf = 0;
  212. iWSABuf < m_cWSABufsUsed && m_pWSABufs[iWSABuf].len <= ibFrom;
  213. iWSABuf++ )
  214. {
  215. ibFrom -= m_pWSABufs[iWSABuf].len;
  216. ++iWSABuf;
  217. }
  218. //
  219. // Copy data from this and subsequent buffers up to the lesser
  220. // of the number of bytes requested or the number of bytes
  221. // remaining in the WSA buffers.
  222. //
  223. for ( ;
  224. iWSABuf < m_cWSABufsUsed && cbToDump > 0;
  225. iWSABuf++ )
  226. {
  227. UINT cbToCopy = min(m_pWSABufs[iWSABuf].len - ibFrom, cbToDump);
  228. memcpy( lpbBuf,
  229. m_pWSABufs[iWSABuf].buf + ibFrom,
  230. cbToCopy );
  231. cbToDump -= cbToCopy;
  232. lpbBuf += cbToCopy;
  233. ibFrom = 0;
  234. }
  235. }
  236. // ========================================================================
  237. //
  238. // CLASS CResponse
  239. //
  240. // The response consists of a header and a body.
  241. //
  242. class CResponse : public IResponse
  243. {
  244. // Our reference to the ECB. This must a refcounted reference because
  245. // the lifetime of the response object is indefinite.
  246. //
  247. auto_ref_ptr<IEcb> m_pecb;
  248. //
  249. // Response status (not to be confused with HTTP status below)
  250. //
  251. enum RESPONSE_STATUS
  252. {
  253. RS_UNSENT = 0,
  254. RS_DEFERRED,
  255. RS_FORWARDED,
  256. RS_REDIRECTED,
  257. RS_SENDING
  258. };
  259. RESPONSE_STATUS m_rs;
  260. //
  261. // The variable that will hold one of 2 values:
  262. // 0 - we never started the responce through
  263. // the transmitter, it was never created
  264. // 1 - we already attempted to initiate the
  265. // responce, so no new initiations should
  266. // be allowed
  267. //
  268. LONG m_lRespStarted;
  269. //
  270. // HTTP status code (e.g. 501)
  271. //
  272. int m_iStatusCode;
  273. //
  274. // IIS-defined suberror used in custom error processing
  275. // to generate the most specific response body possible
  276. // for a given status code.
  277. //
  278. UINT m_uiSubError;
  279. //
  280. // Full status line (e.g. "HTTP/1.1 404 Resource Not Found")
  281. // generated whenever the status code is set.
  282. //
  283. auto_heap_ptr<CHAR> m_lpszStatusLine;
  284. //
  285. // Body detail for error response body.
  286. //
  287. auto_heap_ptr<CHAR> m_lpszBodyDetail;
  288. //
  289. // Response header cache
  290. //
  291. CHeaderCacheForResponse m_hcHeaders;
  292. // Response body
  293. //
  294. auto_ptr<IBody> m_pBody;
  295. BOOL m_fSupressBody;
  296. //
  297. // The response transmitter. Make this class a friend for
  298. // easy access to private data (ecb, headers, body parts, etc.)
  299. //
  300. friend class CTransmitter;
  301. CTransmitter * m_pTransmitter;
  302. //
  303. // Private helpers
  304. //
  305. VOID FinalizeContent( BOOL fResponseComplete );
  306. VOID SetStatusLine( int iStatusCode );
  307. //
  308. // NOT IMPLEMENTED
  309. //
  310. CResponse( const CResponse& );
  311. CResponse& operator=( const CResponse& );
  312. public:
  313. // CREATORS
  314. //
  315. CResponse( IEcb& ecb );
  316. // ACCESSORS
  317. //
  318. IEcb * GetEcb() const;
  319. BOOL FIsEmpty() const;
  320. BOOL FIsUnsent() const;
  321. DWORD DwStatusCode() const;
  322. DWORD DwSubError() const;
  323. LPCSTR LpszStatusDescription() const;
  324. LPCSTR LpszStatusCode() const;
  325. LPCSTR LpszGetHeader( LPCSTR pszName ) const;
  326. // MANIPULATORS
  327. //
  328. VOID SetStatus( int iStatusCode,
  329. LPCSTR lpszReserved,
  330. UINT uiCustomSubError,
  331. LPCSTR lpszBodyDetail,
  332. UINT uiBodyDetail );
  333. VOID ClearHeaders() { m_hcHeaders.ClearHeaders(); }
  334. VOID SetHeader( LPCSTR pszName, LPCSTR pszValue, BOOL fMultiple = FALSE );
  335. VOID SetHeader( LPCSTR pszName, LPCWSTR pwszValue, BOOL fMultiple = FALSE );
  336. VOID ClearBody() { m_pBody->Clear(); }
  337. VOID SupressBody() { m_fSupressBody = TRUE; }
  338. VOID AddBodyText( UINT cbText, LPCSTR pszText );
  339. VOID AddBodyText( UINT cchText, LPCWSTR pwszText );
  340. VOID AddBodyFile( const auto_ref_handle& hf,
  341. UINT64 ibFile64,
  342. UINT64 cbFile64 );
  343. VOID AddBodyStream( IStream& stm );
  344. VOID AddBodyStream( IStream& stm, UINT ibOffset, UINT cbSize );
  345. VOID AddBodyPart( IBodyPart * pBodyPart );
  346. //
  347. // Various sending mechanisms
  348. //
  349. SCODE ScForward( LPCWSTR pwszURI,
  350. BOOL fKeepQueryString = TRUE,
  351. BOOL fCustomErrorUrl = FALSE);
  352. SCODE ScRedirect( LPCSTR pszURI );
  353. VOID Defer() { m_rs = RS_DEFERRED; }
  354. VOID SendPartial();
  355. VOID SendComplete();
  356. VOID SendStart( BOOL fComplete );
  357. VOID FinishMethod();
  358. };
  359. // ========================================================================
  360. //
  361. // CLASS CTransmitter
  362. //
  363. class CTransmitter :
  364. public CMTRefCounted,
  365. private IBodyPartVisitor,
  366. private IAsyncCopyToObserver,
  367. private IAcceptObserver,
  368. private IAsyncStream,
  369. private IIISAsyncIOCompleteObserver
  370. {
  371. //
  372. // Back-reference to our response object. This is an
  373. // auto_ref because, once created, the transmitter owns
  374. // the response.
  375. //
  376. auto_ref_ptr<CResponse> m_pResponse;
  377. //
  378. // Transfer coding method
  379. //
  380. TRANSFER_CODINGS m_tc;
  381. //
  382. // Error information
  383. //
  384. HRESULT m_hr;
  385. //
  386. // Iterator used to traverse the body
  387. //
  388. IBody::iterator * m_pitBody;
  389. //
  390. // Async driving mechanism
  391. //
  392. CAsyncDriver<CTransmitter> m_driver;
  393. friend class CAsyncDriver<CTransmitter>;
  394. //
  395. // Buffers for headers and text body parts
  396. //
  397. StringBuffer<CHAR> m_bufHeaders;
  398. ChainedStringBuffer<CHAR> m_bufBody;
  399. //
  400. // Accept observer passed to VisitStream(). This observer must
  401. // be stashed in a member variable because reading from the stream
  402. // is asynchronous and we need to be able to notify the observer
  403. // when the read completes.
  404. //
  405. IAcceptObserver * m_pobsAccept;
  406. //
  407. // WSA buffers for text data
  408. //
  409. CWSABufs m_wsabufsPrefix;
  410. CWSABufs m_wsabufsSuffix;
  411. CWSABufs * m_pwsabufs;
  412. //
  413. // TransmitFile info for file data
  414. //
  415. auto_ref_handle m_hf;
  416. HSE_TF_INFO m_tfi;
  417. //
  418. // Fixed-size buffers to hold prefix and suffix text packets
  419. // being transmitted until async I/O completes.
  420. //
  421. BYTE m_rgbPrefix[CB_PACKET_MAX];
  422. BYTE m_rgbSuffix[CB_PACKET_MAX];
  423. //
  424. // Amount of header data left to accept
  425. //
  426. UINT m_cbHeadersToAccept;
  427. //
  428. // Amount of header data left to send.
  429. //
  430. UINT m_cbHeadersToSend;
  431. // ------------------------------------------------------------------------
  432. //
  433. // FSendingIISHeaders()
  434. //
  435. // Returns TRUE if we want to have IIS format and send a status
  436. // line along with any custom headers of its own.
  437. //
  438. BOOL FSendingIISHeaders() const
  439. {
  440. //
  441. // If we have headers to send and we haven't sent any
  442. // of them yet then we want to include custom IIS
  443. // headers as well.
  444. //
  445. return m_cbHeadersToSend &&
  446. (m_cbHeadersToSend == m_bufHeaders.CbSize());
  447. }
  448. //
  449. // Flag which is TRUE when the impl has submitted the last
  450. // part of the response for transmitting. It can be FALSE
  451. // only with chunked responses.
  452. //
  453. BOOL m_fImplDone;
  454. //
  455. // Transmitter status. The transmitter status is always one
  456. // of the following:
  457. //
  458. enum
  459. {
  460. //
  461. // STATUS_IDLE
  462. // The transmitter is idle. That is, it is not executing
  463. // any of the state functions below.
  464. //
  465. STATUS_IDLE,
  466. //
  467. // STATUS_RUNNING_ACCEPT_PENDING
  468. // The transmitter is running. The impl has added new
  469. // response data (via ImplStart()) to be accepted while
  470. // the transmitter is working on existing data on another
  471. // thread.
  472. //
  473. STATUS_RUNNING_ACCEPT_PENDING,
  474. //
  475. // STATUS_RUNNING_ACCEPTING
  476. // The transmitter is running and accepting existing
  477. // response data.
  478. //
  479. STATUS_RUNNING_ACCEPTING,
  480. //
  481. // STATUS_RUNNING_ACCEPT_DONE
  482. // The transmitter is running and has finished accepting
  483. // all existing response data. If the transmitter is
  484. // working on a chunked response then it will go idle
  485. // from here until the impl indicates that it has added
  486. // more data via ImplStart().
  487. //
  488. STATUS_RUNNING_ACCEPT_DONE
  489. };
  490. LONG m_lStatus;
  491. //
  492. // Function which returns TRUE if the entire response has
  493. // been accepted, FALSE otherwise.
  494. //
  495. BOOL FAcceptedCompleteResponse() const
  496. {
  497. //
  498. // We have accepted the last chunk of the response when
  499. // the impl is done adding chunks to the response and we've
  500. // accepted the last chunk added.
  501. //
  502. // !!! IMPORTANT !!!
  503. // The order of comparison here (m_lStatus then m_fImplDone)
  504. // is important. Checking the other way around could result
  505. // in a false positive if another thread were in ImplStart()
  506. // right after setting m_fImplDone to TRUE.
  507. //
  508. return (STATUS_RUNNING_ACCEPT_DONE == m_lStatus) && m_fImplDone;
  509. }
  510. //
  511. // IAcceptObserver
  512. //
  513. VOID AcceptComplete( UINT64 );
  514. //
  515. // Transmitter state functions. When running, the transmitter is
  516. // always executing one of the following state functions:
  517. //
  518. // SAccept
  519. // The accepting state. When in this state the transmitter
  520. // accepts resposne data in preparation for transmitting it.
  521. // The impl can add data to the response body while the transmitter
  522. // is accepting it -- the mechanism is thread-safe. In fact the
  523. // best performance is realized when the transmitter accepts and
  524. // transmits data at the same rate that the impl adds it.
  525. // When the transmitter accepts a sufficient amount data
  526. // (determined by the amount and type of data accepted)
  527. // it enters the transmitting state.
  528. //
  529. // STransmit
  530. // The transmitting state. The transmitter is transmitting
  531. // accepted response data via the selected method (m_pfnTransmitMethod).
  532. // The impl can add data to the response body while the transmitter
  533. // is in this state. When transmission completes (the transmit methods
  534. // are asynchronous) the transmitter enters the cleanup state.
  535. //
  536. // SCleanup
  537. // The cleanup state. Cleans up transmitted data. From here the
  538. // transmitter enters the accepting state if there is more data to
  539. // transmit or the idle state if there isn't and the impl hasn't
  540. // finished adding data yet.
  541. //
  542. typedef VOID (CTransmitter::*PFNSTATE)();
  543. VOID SAccept();
  544. VOID STransmit();
  545. VOID SCleanup();
  546. PFNSTATE m_pfnState;
  547. //
  548. // Transmit methods. When the transmitter enters the transmit state,
  549. // it will transmit accepted data via the selected transmit method.
  550. //
  551. typedef VOID (CTransmitter::*PFNTRANSMIT)();
  552. VOID TransmitNothing();
  553. VOID AsyncTransmitFile();
  554. VOID AsyncTransmitText();
  555. VOID SyncTransmitHeaders();
  556. PFNTRANSMIT m_pfnTransmitMethod;
  557. //
  558. // CAsyncDriver
  559. //
  560. VOID Run();
  561. VOID Start()
  562. {
  563. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX Start()\n", GetCurrentThreadId(), this );
  564. m_driver.Start(*this);
  565. }
  566. //
  567. // IAsyncStream
  568. //
  569. VOID AsyncWrite( const BYTE * pbBuf,
  570. UINT cbToWrite,
  571. IAsyncWriteObserver& obsAsyncWrite );
  572. //
  573. // IAsyncCopyToObserver
  574. //
  575. VOID CopyToComplete( UINT cbCopied, HRESULT hr );
  576. //
  577. // IIISAsyncIOCompleteObserver
  578. //
  579. VOID IISIOComplete( DWORD dwcbSent,
  580. DWORD dwLastError );
  581. // NOT IMPLEMENTED
  582. //
  583. CTransmitter( const CTransmitter& );
  584. CTransmitter& operator=( const CTransmitter& );
  585. public:
  586. // CREATORS
  587. //
  588. CTransmitter( CResponse& response );
  589. ~CTransmitter() { TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX Transmitter destroyed\n", GetCurrentThreadId(), this ); }
  590. //
  591. // IBodyPartVisitor
  592. //
  593. VOID VisitBytes( const BYTE * pbData,
  594. UINT cbToSend,
  595. IAcceptObserver& obsAccept );
  596. VOID VisitFile( const auto_ref_handle& hf,
  597. UINT64 ibOffset64,
  598. UINT64 cbToSend64,
  599. IAcceptObserver& obsAccept );
  600. VOID VisitStream( IAsyncStream& stm,
  601. UINT cbToSend,
  602. IAcceptObserver& obsAccept );
  603. VOID VisitComplete();
  604. VOID ImplStart( BOOL fResponseComplete );
  605. };
  606. // ========================================================================
  607. //
  608. // CLASS IResponse
  609. //
  610. // ------------------------------------------------------------------------
  611. //
  612. // IResponse::~IResponse()
  613. //
  614. IResponse::~IResponse()
  615. {
  616. }
  617. // ========================================================================
  618. //
  619. // CLASS CResponse
  620. //
  621. // ------------------------------------------------------------------------
  622. //
  623. // CResponse::CResponse()
  624. //
  625. CResponse::CResponse( IEcb& ecb ) :
  626. m_pecb(&ecb),
  627. m_pBody(NewBody()),
  628. m_pTransmitter(NULL),
  629. m_rs(RS_UNSENT),
  630. m_iStatusCode(0),
  631. m_uiSubError(CSE_NONE),
  632. m_fSupressBody(FALSE),
  633. m_lRespStarted(0)
  634. {
  635. }
  636. // ------------------------------------------------------------------------
  637. //
  638. // CResponse::GetEcb()
  639. //
  640. // Returns the pointer to the ECB. We are holding a ref on it
  641. // so make sure that returned pointer is used no longer than this
  642. // response object.
  643. //
  644. IEcb *
  645. CResponse::GetEcb() const
  646. {
  647. //
  648. // Return the raw pointer
  649. //
  650. return m_pecb.get();
  651. }
  652. // ------------------------------------------------------------------------
  653. //
  654. // CResponse::FIsEmpty()
  655. //
  656. // Returns TRUE if the response is empty, FALSE otherwise.
  657. //
  658. BOOL
  659. CResponse::FIsEmpty() const
  660. {
  661. //
  662. // The response is empty IFF no status code has been set
  663. //
  664. return m_iStatusCode == 0;
  665. }
  666. // ------------------------------------------------------------------------
  667. //
  668. // CResponse::FIsUnsent()
  669. //
  670. // Returns TRUE if the response is unsent (not deferred,
  671. // forwarded or redirected), FALSE otherwise.
  672. //
  673. BOOL
  674. CResponse::FIsUnsent() const
  675. {
  676. return m_rs == RS_UNSENT;
  677. }
  678. // ------------------------------------------------------------------------
  679. //
  680. // CResponse::DwStatusCode()
  681. //
  682. DWORD
  683. CResponse::DwStatusCode() const
  684. {
  685. return m_iStatusCode;
  686. }
  687. // ------------------------------------------------------------------------
  688. //
  689. // CResponse::DwSubError()
  690. //
  691. DWORD
  692. CResponse::DwSubError() const
  693. {
  694. return m_uiSubError;
  695. }
  696. // ------------------------------------------------------------------------
  697. //
  698. // CResponse::LpszStatusDescription()
  699. //
  700. LPCSTR
  701. CResponse::LpszStatusDescription() const
  702. {
  703. //
  704. // Getting just the status description is a little tricky since
  705. // we only keep around the full status line (to avoid having to
  706. // compute it more than once). Given that the format of the
  707. // status line is ALWAYS "HTTP-version Status-Code Description"
  708. // we know that the status line always appears immediately after
  709. // the HTTP version and status code.
  710. //
  711. return m_lpszStatusLine +
  712. strlen( m_pecb->LpszVersion() ) + // description
  713. 1 + // " "
  714. 3 + // 3-digit status code (e.g. "404")
  715. 1; // " "
  716. //
  717. // Ok, so it's not that tricky...
  718. //
  719. }
  720. // ------------------------------------------------------------------------
  721. //
  722. // CResponse::LpszStatusCode()
  723. //
  724. LPCSTR
  725. CResponse::LpszStatusCode() const
  726. {
  727. Assert( m_lpszStatusLine != NULL );
  728. return m_lpszStatusLine +
  729. strlen(m_pecb->LpszVersion()) +
  730. 1; // (e.g. "HTTP/1.1 200 OK" -> "200 OK")
  731. }
  732. // ------------------------------------------------------------------------
  733. //
  734. // CResponse::LpszGetHeader()
  735. //
  736. LPCSTR
  737. CResponse::LpszGetHeader( LPCSTR pszName ) const
  738. {
  739. return m_hcHeaders.LpszGetHeader( pszName );
  740. }
  741. // ------------------------------------------------------------------------
  742. //
  743. // CResponse::SetStatus()
  744. //
  745. // Sets the status line portion of the response, superceding any
  746. // previously set status line.
  747. //
  748. // Parameters:
  749. // iStatusCode [in]
  750. // A standard HTTP/DAV response status code (e.g. 404)
  751. //
  752. // lpszReserved [in]
  753. // Reserved. Must be NULL.
  754. //
  755. // uiCustomSubError [in]
  756. // Custom error Sub Error (CSE). If the status code is in the
  757. // error range ([400,599]) and this value is anything except
  758. // CSE_NONE then this value specifies the suberror used to
  759. // generate a more specific custom error response body than
  760. // the default for a given status code.
  761. //
  762. // lpszBodyDetail [in]
  763. // Optional string to use as detail in an error response body.
  764. // If NULL, use uiBodyDetail instead. If that is also 0,
  765. // an error response body just consists of an HTML
  766. // version of the status line.
  767. //
  768. // uiBodyDetail [in]
  769. // Optional resource id to use as detail in an error response body.
  770. // If 0, an error response body just consists of an HTML
  771. // version of the status line.
  772. //
  773. VOID
  774. CResponse::SetStatus( int iStatusCode,
  775. LPCSTR lpszReserved,
  776. UINT uiCustomSubError,
  777. LPCSTR lpszBodyDetail,
  778. UINT uiBodyDetail )
  779. {
  780. CHAR rgchStatusDescription[256];
  781. // We must not change the response status once the response has
  782. // started sending. Sometimes it's hard for client to keep track
  783. // response has started sending. Now that the response object
  784. // has the information, we can simply ignore the set status request
  785. // when the response has started sending
  786. //
  787. // was Assert( RS_SENDING != m_rs );
  788. //
  789. if (RS_SENDING == m_rs)
  790. return;
  791. // If we are setting the same status code again,
  792. // do nothing!
  793. //
  794. if ( m_iStatusCode == iStatusCode )
  795. return;
  796. // Quick check -- the iStatusCode must be in the valid HSC range:
  797. // 100 - 599.
  798. // Assert this here to catch any callers who forget to map their
  799. // SCODEs/HRESULTs to HSCs first (HscFromHresult).
  800. //
  801. Assert (100 <= iStatusCode &&
  802. 599 >= iStatusCode);
  803. // When a 304 response is to be generated, the request becomes
  804. // very much like a HEAD request in that the whole response is
  805. // processed, but not transmitted. The important part here is
  806. // that you do not want to overwrite the 304 response with any
  807. // other code other than error responses.
  808. //
  809. if ( m_iStatusCode == 304 ) // HSC_NOT_MODIFIED
  810. {
  811. // 304's should really be restricted to GET/HEAD
  812. //
  813. AssertSz ((!strcmp (m_pecb->LpszMethod(), "GET") ||
  814. !strcmp (m_pecb->LpszMethod(), "HEAD") ||
  815. !strcmp (m_pecb->LpszMethod(), "PROPFIND")),
  816. "304 returned on non-GET/HEAD request");
  817. if ( iStatusCode < 300 )
  818. return;
  819. DebugTrace ("non-success response over-rides 304 response\n");
  820. }
  821. //
  822. // Remember the status code for our own use ...
  823. //
  824. m_iStatusCode = iStatusCode;
  825. //
  826. // ... and stash it away in the ECB as well.
  827. // IIS uses it for logging.
  828. //
  829. m_pecb->SetStatusCode( iStatusCode );
  830. //
  831. // Remember the suberror for custom error processing
  832. //
  833. m_uiSubError = uiCustomSubError;
  834. //
  835. // IF we are setting a NEW status code (we are),
  836. // AND it's an error status code,
  837. // clear out the body.
  838. //
  839. if ( FErrorStatusCode(m_iStatusCode) )
  840. {
  841. m_pBody->Clear();
  842. }
  843. SetStatusLine( iStatusCode );
  844. //
  845. // Save the error body detail (if any). We'll use it in
  846. // CResponse::FinalizeContent() later to build the error response
  847. // body if the final result is an error.
  848. //
  849. m_lpszBodyDetail.clear();
  850. //
  851. // Figure out what to use for the body detail string:
  852. //
  853. // Use the string if one is provided. If no string
  854. // is provided, use the resource ID. If no resource ID,
  855. // then don't bother setting any body detail!
  856. //
  857. if ( !lpszBodyDetail && uiBodyDetail )
  858. {
  859. //
  860. // Load up the body detail string
  861. //
  862. LpszLoadString( uiBodyDetail,
  863. m_pecb->LcidAccepted(),
  864. rgchStatusDescription,
  865. sizeof(rgchStatusDescription) );
  866. lpszBodyDetail = rgchStatusDescription;
  867. }
  868. // Save off the body detail string.
  869. //
  870. if ( lpszBodyDetail )
  871. {
  872. m_lpszBodyDetail = LpszAutoDupSz( lpszBodyDetail );
  873. }
  874. }
  875. // ------------------------------------------------------------------------
  876. //
  877. // CResponse::SetHeader()
  878. //
  879. // Sets the specified header to the specified value
  880. //
  881. // If lpszValue is NULL, deletes the header
  882. //
  883. VOID
  884. CResponse::SetHeader( LPCSTR pszName, LPCSTR pszValue, BOOL fMultiple )
  885. {
  886. // We must not modify any headers once the response has started sending.
  887. // It is up to the impl to enforce this -- we just assert it here.
  888. //
  889. Assert( RS_SENDING != m_rs );
  890. if ( pszValue == NULL )
  891. m_hcHeaders.DeleteHeader( pszName );
  892. else
  893. m_hcHeaders.SetHeader( pszName, pszValue, fMultiple );
  894. }
  895. VOID
  896. CResponse::SetHeader( LPCSTR pszName, LPCWSTR pwszValue, BOOL fMultiple )
  897. {
  898. // We must not modify any headers once the response has started sending.
  899. // It is up to the impl to enforce this -- we just assert it here.
  900. //
  901. Assert( RS_SENDING != m_rs );
  902. if ( pwszValue == NULL )
  903. m_hcHeaders.DeleteHeader( pszName );
  904. else
  905. {
  906. UINT cchValue = static_cast<UINT>(wcslen(pwszValue));
  907. UINT cbValue = cchValue * 3;
  908. CStackBuffer<CHAR> pszValue(cbValue + 1);
  909. // We have received wide string for the value. We need to convert it
  910. // to skinny.
  911. //
  912. cbValue = WideCharToMultiByte(CP_ACP,
  913. 0,
  914. pwszValue,
  915. cchValue + 1,
  916. pszValue.get(),
  917. cbValue + 1,
  918. NULL,
  919. NULL);
  920. if (0 == cbValue)
  921. {
  922. DebugTrace ( "CResponse::SetHeader(). Error 0x%08lX from WideCharToMultiByte()\n", GetLastError() );
  923. throw CLastErrorException();
  924. }
  925. m_hcHeaders.SetHeader( pszName, pszValue.get(), fMultiple );
  926. }
  927. }
  928. // ------------------------------------------------------------------------
  929. //
  930. // CResponse::AddBodyText()
  931. //
  932. // Appends a string to the response body
  933. //
  934. VOID
  935. CResponse::AddBodyText( UINT cbText, LPCSTR pszText )
  936. {
  937. m_pBody->AddText( pszText, cbText );
  938. }
  939. VOID
  940. CResponse::AddBodyText( UINT cchText, LPCWSTR pwszText )
  941. {
  942. UINT cbText = cchText * 3;
  943. CStackBuffer<CHAR> pszText(cbText);
  944. LPCSTR pszTextToAdd;
  945. // We have received wide string for the value. We need to convert it
  946. // to skinny.
  947. //
  948. if (cbText)
  949. {
  950. cbText = WideCharToMultiByte(CP_ACP,
  951. 0,
  952. pwszText,
  953. cchText,
  954. pszText.get(),
  955. cbText,
  956. NULL,
  957. NULL);
  958. if (0 == cbText)
  959. {
  960. DebugTrace ( "CResponse::SetHeader(). Error 0x%08lX from WideCharToMultiByte()\n", GetLastError() );
  961. throw CLastErrorException();
  962. }
  963. pszTextToAdd = pszText.get();
  964. }
  965. else
  966. {
  967. // Make sure that we do not pass NULL forward,
  968. // but instead we use empty string, as the callee
  969. // may not handle NULL.
  970. //
  971. pszTextToAdd = gc_szEmpty;
  972. }
  973. m_pBody->AddText( pszTextToAdd, cbText );
  974. }
  975. // ------------------------------------------------------------------------
  976. //
  977. // CResponse::AddBodyFile()
  978. //
  979. // Appends a file to the current response state
  980. //
  981. VOID
  982. CResponse::AddBodyFile( const auto_ref_handle& hf,
  983. UINT64 ibFile64,
  984. UINT64 cbFile64 )
  985. {
  986. m_pBody->AddFile( hf, ibFile64, cbFile64 );
  987. }
  988. // ------------------------------------------------------------------------
  989. //
  990. // CResponse::AddBodyStream()
  991. //
  992. // Appends a stream to the current response state
  993. //
  994. VOID
  995. CResponse::AddBodyStream( IStream& stm )
  996. {
  997. m_pBody->AddStream( stm );
  998. }
  999. // ------------------------------------------------------------------------
  1000. //
  1001. // CResponse::AddBodyStream()
  1002. //
  1003. // Appends a stream to the current response state
  1004. //
  1005. VOID
  1006. CResponse::AddBodyStream( IStream& stm, UINT ibOffset, UINT cbSize )
  1007. {
  1008. m_pBody->AddStream( stm, ibOffset, cbSize );
  1009. }
  1010. // ------------------------------------------------------------------------
  1011. //
  1012. // CResponse::AddBodyPart()
  1013. //
  1014. // Appends a body part to the current response state
  1015. //
  1016. VOID CResponse::AddBodyPart( IBodyPart * pBodyPart )
  1017. {
  1018. m_pBody->AddBodyPart( pBodyPart );
  1019. }
  1020. // ------------------------------------------------------------------------
  1021. //
  1022. // CResponse::ScForward()
  1023. //
  1024. // Instructs IIS to forward responsibility for handling the
  1025. // current request to another ISAPI.
  1026. //
  1027. // Returns:
  1028. // S_OK - if forwarding succeeded, error otherwise
  1029. //
  1030. SCODE
  1031. CResponse::ScForward( LPCWSTR pwszURI, BOOL fKeepQueryString, BOOL fCustomErrorUrl)
  1032. {
  1033. CStackBuffer<CHAR, MAX_PATH> pszQS;
  1034. LPCSTR pszQueryString;
  1035. SCODE sc = S_OK;
  1036. //
  1037. // Verify that the response is still unsent. A response can be
  1038. // either sent, forwarded, or redirected, but only one of the three
  1039. // and only once
  1040. //
  1041. AssertSz( m_rs == RS_UNSENT || m_rs == RS_DEFERRED,
  1042. "Response already sent, forwarded or redirected!" );
  1043. Assert(pwszURI);
  1044. // Get the query string
  1045. //
  1046. pszQueryString = m_pecb->LpszQueryString();
  1047. // If there was custom error processing, construct query string for it ...
  1048. //
  1049. if (fCustomErrorUrl)
  1050. {
  1051. // The query string for custom error to be forwarded is to be of the
  1052. // format ?nnn;originaluri, where nnn is the error code. Find out the
  1053. // length of the URL. Reallocate required space accounting for ?nnn;
  1054. // and '\0' termination.
  1055. //
  1056. UINT cb = 1 + 3 + 1 + static_cast<UINT>(strlen(m_pecb->LpszRequestUrl())) + 1;
  1057. LPSTR psz = pszQS.resize(cb);
  1058. if (NULL == psz)
  1059. {
  1060. DebugTrace( "CResponse::ScForward() - Error while allocating memory 0x%08lX\n", E_OUTOFMEMORY );
  1061. sc = E_OUTOFMEMORY;
  1062. goto ret;
  1063. }
  1064. _snprintf (psz, cb, "?%03d;%s",
  1065. max(min(m_iStatusCode, 999), 100),
  1066. m_pecb->LpszRequestUrl());
  1067. Assert (0 == psz[cb - 1]);
  1068. // Just point the query string to the start.
  1069. // Note that if we are handling a custom error url we discard
  1070. // original query string
  1071. //
  1072. pszQueryString = pszQS.get();
  1073. }
  1074. //
  1075. // ... otherwise if we have query string processing, construct the
  1076. // query string too...
  1077. //
  1078. else if (fKeepQueryString && pszQueryString && *pszQueryString)
  1079. {
  1080. // The composed query string has to be of the format ?querystring
  1081. // and '\0' termination.
  1082. //
  1083. UINT cb = 1 + static_cast<UINT>(strlen(pszQueryString)) + 1;
  1084. LPSTR psz = pszQS.resize(cb);
  1085. if (NULL == psz)
  1086. {
  1087. DebugTrace( "CResponse::ScForward() - Error while allocating memory 0x%08lX\n", E_OUTOFMEMORY );
  1088. sc = E_OUTOFMEMORY;
  1089. goto ret;
  1090. }
  1091. _snprintf (psz, cb, "?%s", m_pecb->LpszRequestUrl());
  1092. Assert (0 == psz[cb - 1]);
  1093. // Just point the query string to the start
  1094. //
  1095. pszQueryString = pszQS.get();
  1096. }
  1097. //
  1098. // ... otherwise we do not need the query string
  1099. //
  1100. else
  1101. {
  1102. pszQueryString = NULL;
  1103. }
  1104. // If the forward request URI is fully qualified, strip it to
  1105. // an absolute URI
  1106. //
  1107. if ( FAILED( ScStripAndCheckHttpPrefix( *m_pecb, &pwszURI )))
  1108. {
  1109. DebugTrace( "CResponse::ScForward() - ScStripAndCheckHttpPrefix() failed, "
  1110. "forward request not local to this server.\n" );
  1111. // Why do we override error maping to 502 Bad Gateway with
  1112. // the error maping to 404 Not Found?
  1113. //
  1114. sc = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND );
  1115. goto ret;
  1116. }
  1117. // Forward the request to the child ISAPI
  1118. //
  1119. sc = m_pecb->ScExecuteChild( pwszURI, pszQueryString, fCustomErrorUrl );
  1120. if (FAILED(sc))
  1121. {
  1122. DebugTrace( "CResponse::ScForward() - IEcb::ScExecuteChild() "
  1123. "failed to execute child ISAPI for %S (0x%08lX)\n",
  1124. pwszURI,
  1125. sc );
  1126. goto ret;
  1127. }
  1128. m_rs = RS_FORWARDED;
  1129. ret:
  1130. return sc;
  1131. }
  1132. // ------------------------------------------------------------------------
  1133. //
  1134. // CResponse::ScRedirect()
  1135. //
  1136. // Instructs IIS to send a redirect (300) response to the client.
  1137. //
  1138. // Returns:
  1139. // S_OK - if forwarding succeeded, error otherwise
  1140. //
  1141. SCODE
  1142. CResponse::ScRedirect( LPCSTR pszURI )
  1143. {
  1144. SCODE sc = S_OK;
  1145. //
  1146. // Verify that the response is still unsent. A response can be
  1147. // either sent, forwarded, or redirected, but only one of the three
  1148. // and only once
  1149. //
  1150. AssertSz( m_rs == RS_UNSENT || m_rs == RS_DEFERRED,
  1151. "Response already sent, forwarded or redirected!" );
  1152. //
  1153. // Tell IIS to send a redirect response
  1154. //
  1155. sc = m_pecb->ScSendRedirect( pszURI );
  1156. if (FAILED(sc))
  1157. {
  1158. DebugTrace( "CResponse::FRedirect() - ServerSupportFunction() failed to redirect to %hs (0x%08lX)\n", pszURI, sc );
  1159. goto ret;
  1160. }
  1161. m_rs = RS_REDIRECTED;
  1162. ret:
  1163. return sc;
  1164. }
  1165. // ------------------------------------------------------------------------
  1166. //
  1167. // CResponse::FinalizeContent()
  1168. //
  1169. // Prepare the response for sending by filling in computed values for
  1170. // headers (Content-Length, Connection, etc) and body (for error
  1171. // responses). After this function is called, the response should be
  1172. // ready for transmission.
  1173. //
  1174. VOID
  1175. CResponse::FinalizeContent( BOOL fResponseComplete )
  1176. {
  1177. BOOL fDoingCustomError = m_pecb->FProcessingCEUrl();
  1178. // Special case:
  1179. // If we have a FAILING error code, DO NOT send back an ETag header.
  1180. //
  1181. // This is somewhat of a hack because we should never have set an
  1182. // ETag on an error response in the first place. However, several
  1183. // places in the code blindly stuff the ETag into the response headers
  1184. // before determining the final status code. So rather than
  1185. // fix the code in each place (which is a pain) we filter out
  1186. // the ETag here.
  1187. //
  1188. // 300-level responses are considered to be errors by FSuccessHSC(),
  1189. // but the HTTP/1.1 spec says that an ETag must be emitted for
  1190. // a "304 Not Modified" response, so we treat that status code
  1191. // as a special case.
  1192. //
  1193. if (!FSuccessHSC(m_iStatusCode) && m_iStatusCode != 304)
  1194. m_hcHeaders.DeleteHeader( gc_szETag );
  1195. // Handle error responses. This may mean setting default or custom
  1196. // error body text, or executing an error-handling URL. In the latter
  1197. // case, we want to get out immediately after fowarding.
  1198. //
  1199. if ( FErrorStatusCode(m_iStatusCode) )
  1200. {
  1201. if ( m_pBody->FIsEmpty() && !fDoingCustomError && !m_pecb->FBrief())
  1202. {
  1203. if (m_pecb->FIIS60OrAfter())
  1204. {
  1205. // For IIS 6.0 or after, we use the new way to send custom error
  1206. //
  1207. HSE_CUSTOM_ERROR_INFO custErr;
  1208. UINT cbStatusLine;
  1209. // Perf Wadeh, we should hold on to the string till the IO completion
  1210. // routine returns
  1211. //
  1212. auto_heap_ptr<CHAR> pszStatus;
  1213. // Make sure that status line starts with one of HTTP versions.
  1214. //
  1215. Assert(!_strnicmp(m_lpszStatusLine.get(), gc_szHTTP, gc_cchHTTP));
  1216. Assert(' ' == m_lpszStatusLine[gc_cchHTTP_X_X]);
  1217. // Allocate the space for status string that we pass onto the CEcb.
  1218. // We will treat the space occupied by ' ' as accounting for space
  1219. // we will need for '\0' in the mathematics below.
  1220. //
  1221. cbStatusLine = static_cast<UINT>(strlen(m_lpszStatusLine.get()));
  1222. cbStatusLine -= gc_cchHTTP_X_X;
  1223. pszStatus = static_cast<LPSTR>(g_heap.Alloc(cbStatusLine));
  1224. if (NULL != pszStatus.get())
  1225. {
  1226. // m_lpszStatusLine has format "HP/x.x nnn yyyy...", where
  1227. // nnn is the status code. IIS expects up to pass in format
  1228. // "nnn yyyy....", so we need to skip the version part.
  1229. // Note, all the version part are of same length, this makes
  1230. // the adjustment easier. We copy including '\0' termination.
  1231. //
  1232. memcpy(pszStatus.get(), m_lpszStatusLine.get() + gc_cchHTTP_X_X + 1, cbStatusLine);
  1233. // Populate custom error info
  1234. //
  1235. custErr.pszStatus = pszStatus.get();
  1236. custErr.uHttpSubError = static_cast<USHORT>(m_uiSubError);
  1237. custErr.fAsync = TRUE;
  1238. // Try to send the custom error. The ownership of the string
  1239. // will be taken by CEcb only in the case of success.
  1240. //
  1241. if (SUCCEEDED(m_pecb->ScAsyncCustomError60After( custErr,
  1242. pszStatus.get() )))
  1243. {
  1244. // Relinquish the ref, as if we succeeeded in the function
  1245. // above it has been taken ownership by CEcb.
  1246. //
  1247. pszStatus.relinquish();
  1248. m_rs = RS_FORWARDED;
  1249. return;
  1250. }
  1251. }
  1252. // Otherwise, fall through to send error
  1253. }
  1254. else
  1255. {
  1256. // Try a custom error. If a custom error exists, use it.
  1257. // Note that a custom error can refer to a URL in which
  1258. // case the request is forwarded to that URL to generate
  1259. // appropriate error content. If there is no custom error,
  1260. // then use the body detail (if any) formatted as a short
  1261. // HTML document. Before we start we check if the ECB is
  1262. // already for a custom error request. This is to prevent
  1263. // us from recursively calling ourselves on some custom error
  1264. // url that does not exist.
  1265. //
  1266. if ( FSetCustomErrorResponse( *m_pecb, *this ) )
  1267. {
  1268. //
  1269. // If the custom error caused the response to be forwarded
  1270. // (i.e. the custom error was a URL) then we are done.
  1271. //
  1272. if ( m_rs == RS_FORWARDED)
  1273. return;
  1274. //
  1275. // Raid NT5:187545 & X5:70652
  1276. //
  1277. // This is somewhat of a hack: IIS won't send a
  1278. // Connection: close header for us if the following
  1279. // conditions are true:
  1280. //
  1281. // 1. The original request was keep-alive.
  1282. // 2. We are sending an error response.
  1283. // 3. We have a file response body.
  1284. // 4. We intend to send the body.
  1285. //
  1286. // Because we are in this code path, we know we are sending
  1287. // an error (condition 2). If custom error processing added
  1288. // a body, we know that it must be a file body because the
  1289. // only custom error types are URL or file, and the URL case
  1290. // is handled above by fowarding the response. So, if we have
  1291. // a body, then condition 3 is satisfied. To check for
  1292. // condition 1, test the state of the connection before we
  1293. // close it (below). Condition 4 is satisfied if and only
  1294. // if do not supress the body. The body is supressed, for
  1295. // example, in a HEAD response.
  1296. //
  1297. // If all of the conditions are satisfied, then add our own
  1298. // Connection: close header.
  1299. //
  1300. if ( m_pecb->FKeepAlive() &&
  1301. !m_pBody->FIsEmpty() &&
  1302. !m_fSupressBody )
  1303. {
  1304. SetHeader( gc_szConnection, gc_szClose );
  1305. }
  1306. }
  1307. }
  1308. }
  1309. // Check if the body is still empty and send some
  1310. // stuff.
  1311. //
  1312. if ( m_pBody->FIsEmpty() )
  1313. {
  1314. m_hcHeaders.SetHeader( gc_szContent_Type, gc_szText_HTML );
  1315. m_pBody->AddText( "<body><h2>" );
  1316. m_pBody->AddText( m_lpszStatusLine );
  1317. m_pBody->AddText( "</h2>" );
  1318. if ( m_lpszBodyDetail != NULL && *m_lpszBodyDetail )
  1319. {
  1320. m_pBody->AddText( "<br><h3>" );
  1321. m_pBody->AddText( m_lpszBodyDetail );
  1322. m_pBody->AddText( "</h3>" );
  1323. }
  1324. m_pBody->AddText( "</body>" );
  1325. }
  1326. // error response: Always close the connection.
  1327. //
  1328. m_pecb->CloseConnection();
  1329. }
  1330. // Set the status code from the original request
  1331. // if we are procesing the custom URL. We expect that
  1332. // the query string is of the format XXX;original url.
  1333. //
  1334. if ( fDoingCustomError )
  1335. {
  1336. LPCSTR lpszQueryString = m_pecb->LpszQueryString();
  1337. int iOrgStatCode = 0;
  1338. // Normally we expect the query string to be present.
  1339. // However there is a possibility that ISAPIs can initiate
  1340. // this request and some ISAPI may misbehave.
  1341. // So we check if the query string is really there and
  1342. // silently fail.
  1343. //
  1344. if (lpszQueryString)
  1345. {
  1346. if ( 1 == sscanf(lpszQueryString, "%3d;", &iOrgStatCode) )
  1347. {
  1348. // IIS behaved as per the promise.
  1349. // Set the response code in the ecb and hack our
  1350. // status line accordingly.
  1351. //
  1352. m_pecb->SetStatusCode( iOrgStatCode );
  1353. SetStatusLine( iOrgStatCode );
  1354. }
  1355. }
  1356. // error response: Always close the connection.
  1357. //
  1358. m_pecb->CloseConnection();
  1359. DebugTrace("CResponse::FinalizeContent Original Status code in CEURL request %d",
  1360. iOrgStatCode );
  1361. }
  1362. //
  1363. // If we can chunk the response and we don't have a complete
  1364. // response already then include a Transfer-Encoding: chunked
  1365. // header.
  1366. //
  1367. if ( m_pecb->FCanChunkResponse() && !fResponseComplete )
  1368. {
  1369. m_hcHeaders.SetHeader( gc_szTransfer_Encoding, gc_szChunked );
  1370. }
  1371. //
  1372. // Otherwise the response body is already complete (i.e. we
  1373. // can quickly calculate its content length) or the client
  1374. // won't let us do chunking so set the correct Content-Length header.
  1375. //
  1376. else
  1377. {
  1378. char rgchContentLength[24];
  1379. // WININET HACK
  1380. // A 304 *can* send back all the headers of the real resource,
  1381. // (and we're trying to be a good little HTTP server, so we do!)
  1382. // BUT if we send back a >0 content-length on a 304, WININET
  1383. // hangs trying to read the body (which isn't there!).
  1384. // So hack the content type in this one case.
  1385. //
  1386. if (m_iStatusCode != 304)
  1387. {
  1388. _ui64toa( m_pBody->CbSize64(), rgchContentLength, 10 );
  1389. }
  1390. else
  1391. _ultoa( 0, rgchContentLength, 10 );
  1392. m_hcHeaders.SetHeader( gc_szContent_Length, rgchContentLength );
  1393. }
  1394. //
  1395. // If the body is to be supressed, then nuke it
  1396. //
  1397. // We nuke the body in two cases: if the body was suppressed
  1398. // or if the status code is a 304 not-modified.
  1399. //
  1400. if ( m_fSupressBody || (m_iStatusCode == 304)) // HSC_NOT_MODIFIED
  1401. m_pBody->Clear();
  1402. //
  1403. // Nuke the status line and headers (EVEN DBG HEADERS!)
  1404. // for HTTP/0.9 responses.
  1405. //
  1406. if ( !strcmp( m_pecb->LpszVersion(), gc_szHTTP_0_9 ) )
  1407. {
  1408. //
  1409. // Clear the status line.
  1410. //
  1411. m_lpszStatusLine.clear();
  1412. //
  1413. // Clear the headers.
  1414. //
  1415. m_hcHeaders.ClearHeaders();
  1416. }
  1417. }
  1418. // ------------------------------------------------------------------------
  1419. //
  1420. // CResponse::SetStatusLine()
  1421. //
  1422. // Sets the status line according to the info given.
  1423. //
  1424. VOID
  1425. CResponse::SetStatusLine(int iStatusCode)
  1426. {
  1427. CHAR rgchStatusDescription[256];
  1428. //
  1429. // Load up the status string
  1430. //
  1431. // (Conveniently, the status description resource ID
  1432. // for any given status code is just the status code itself!)
  1433. //
  1434. LpszLoadString( iStatusCode,
  1435. m_pecb->LcidAccepted(),
  1436. rgchStatusDescription,
  1437. sizeof(rgchStatusDescription) );
  1438. //
  1439. // Generate the status line by concatenating the HTTP
  1440. // version string, the status code (in decimal) and
  1441. // the status description.
  1442. //
  1443. {
  1444. CHAR rgchStatusLine[256];
  1445. UINT cchStatusLine;
  1446. _snprintf(rgchStatusLine,
  1447. sizeof(rgchStatusLine),
  1448. "%s %03d %s",
  1449. m_pecb->LpszVersion(),
  1450. iStatusCode,
  1451. rgchStatusDescription);
  1452. rgchStatusLine[CElems(rgchStatusLine) - 1] = 0;
  1453. m_lpszStatusLine.clear();
  1454. m_lpszStatusLine = LpszAutoDupSz( rgchStatusLine );
  1455. }
  1456. }
  1457. // ------------------------------------------------------------------------
  1458. //
  1459. // CResponse::SendStart()
  1460. //
  1461. // Starts sending accumulated response data. If fComplete is TRUE then
  1462. // the accumulated data constitutes the entire response or remainder
  1463. // thereof.
  1464. //
  1465. VOID
  1466. CResponse::SendStart( BOOL fComplete )
  1467. {
  1468. switch ( m_rs )
  1469. {
  1470. case RS_UNSENT:
  1471. {
  1472. Assert( fComplete );
  1473. if (0 == InterlockedCompareExchange(&m_lRespStarted,
  1474. 1,
  1475. 0))
  1476. {
  1477. FinalizeContent( fComplete );
  1478. if ( m_rs == RS_UNSENT )
  1479. {
  1480. Assert( m_pTransmitter == NULL );
  1481. m_pTransmitter = new CTransmitter(*this);
  1482. m_pTransmitter->ImplStart( fComplete );
  1483. // This is the path where response is complete.
  1484. // The ref of transmitter will be be taken
  1485. // ownership inside ImplStart() so noone should
  1486. // attempt to access it after this point as it
  1487. // may be released.
  1488. //
  1489. m_pTransmitter = NULL;
  1490. // Change the state after the transmitter pointer
  1491. // is changed to NULL, so that any thread that comes
  1492. // into SendStart() in the RS_SENDING state could be
  1493. // checked and denied the service. (i.e. by the time
  1494. // we check state for RS_SENDING we know that pointer
  1495. // is NULL if it is ment to be nulled in here).
  1496. //
  1497. m_rs = RS_SENDING;
  1498. }
  1499. }
  1500. break;
  1501. }
  1502. case RS_DEFERRED:
  1503. {
  1504. //
  1505. // If the client does not accept a chunked response then we
  1506. // cannot start sending until the response is complete because
  1507. // we need the entire response to be able to compute the
  1508. // content length
  1509. //
  1510. if ( fComplete || m_pecb->FCanChunkResponse() )
  1511. {
  1512. if (0 == InterlockedCompareExchange(&m_lRespStarted,
  1513. 1,
  1514. 0))
  1515. {
  1516. FinalizeContent( fComplete );
  1517. if ( m_rs == RS_DEFERRED )
  1518. {
  1519. Assert( m_pTransmitter == NULL );
  1520. m_pTransmitter = new CTransmitter(*this);
  1521. m_pTransmitter->ImplStart( fComplete );
  1522. // This is the path where response is complete.
  1523. // The ref of transmitter will be be taken
  1524. // ownership inside ImplStart() so noone should
  1525. // attempt to access it after this point as it
  1526. // may be released.
  1527. //
  1528. if ( fComplete )
  1529. {
  1530. m_pTransmitter = NULL;
  1531. }
  1532. // Change the state after the transmitter pointer
  1533. // is changed to NULL, so that any thread that comes
  1534. // into SendStart() in the RS_SENDING state could be
  1535. // checked and denied the service. (i.e. by the time
  1536. // we check state for RS_SENDING we know that pointer
  1537. // is NULL if it is ment to be nulled in here).
  1538. //
  1539. m_rs = RS_SENDING;
  1540. }
  1541. }
  1542. }
  1543. break;
  1544. }
  1545. //
  1546. // If we're forwarding to another ISAPI or we already sent back
  1547. // a redirection response, then don't do anything further.
  1548. //
  1549. case RS_FORWARDED:
  1550. case RS_REDIRECTED:
  1551. {
  1552. break;
  1553. }
  1554. case RS_SENDING:
  1555. {
  1556. Assert( m_rs == RS_SENDING );
  1557. Assert( m_pecb->FCanChunkResponse() );
  1558. // If someone came here when transmitter is not available
  1559. // (was not created or complete response was already sent
  1560. // and the pointer was NULL-ed above, then there is no work
  1561. // for us.
  1562. //
  1563. if (NULL != m_pTransmitter)
  1564. {
  1565. m_pTransmitter->ImplStart( fComplete );
  1566. }
  1567. break;
  1568. }
  1569. default:
  1570. {
  1571. TrapSz( "Unknown response transmitter state!" );
  1572. }
  1573. }
  1574. }
  1575. // ------------------------------------------------------------------------
  1576. //
  1577. // CResponse::SendPartial()
  1578. //
  1579. // Starts sending accumulated response data. Callers may continue to add
  1580. // response data after calling this function.
  1581. //
  1582. VOID
  1583. CResponse::SendPartial()
  1584. {
  1585. SendStart( FALSE );
  1586. }
  1587. // ------------------------------------------------------------------------
  1588. //
  1589. // CResponse::SendComplete)
  1590. //
  1591. // Starts sending all of the accumulated response data. Callers must not
  1592. // add response data after calling this function.
  1593. //
  1594. VOID
  1595. CResponse::SendComplete()
  1596. {
  1597. SendStart( TRUE );
  1598. }
  1599. // ------------------------------------------------------------------------
  1600. //
  1601. // CResponse::FinishMethod()
  1602. //
  1603. VOID
  1604. CResponse::FinishMethod()
  1605. {
  1606. //
  1607. // If no one else has taken responsibility for sending the
  1608. // response, then send the entire thing now.
  1609. //
  1610. if ( m_rs == RS_UNSENT )
  1611. SendStart( TRUE );
  1612. }
  1613. // ------------------------------------------------------------------------
  1614. //
  1615. // CTransmitter::CTransmitter()
  1616. //
  1617. // A few things to note about this constructor:
  1618. //
  1619. // The keep-alive value is cached to avoid having to get it off of the
  1620. // IEcb for every packet transmitted. Getting the value from the IEcb
  1621. // can incur a SSF call. Since the value can't change once we start
  1622. // transmitting, it is safe to cache it.
  1623. //
  1624. // The size of the text buffer is initialized to be twice as large as
  1625. // the maximum amount of text data that can be sent in a single network
  1626. // packet. The reason for this is to eliminate reallocations when adding
  1627. // to the buffer. The buffer may potentially be used for prefix and
  1628. // suffix text data, each being up to CB_WSABUFS_MAX in size.
  1629. //
  1630. // Headers are dumped into the text buffer and a pointer to them is
  1631. // then added to the WSABufs so that the headers count against the
  1632. // total amount of text that can be accepted for the first packet.
  1633. // If additional body text is later added to the WSABufs for that packet,
  1634. // it may be transmitted along with the headers in the same packet.
  1635. //
  1636. CTransmitter::CTransmitter( CResponse& response ) :
  1637. m_pResponse(&response),
  1638. m_hr(S_OK),
  1639. m_tc(TC_UNKNOWN),
  1640. m_pitBody(response.m_pBody->GetIter()),
  1641. m_bufBody(2 * CB_WSABUFS_MAX),
  1642. m_cbHeadersToSend(0),
  1643. m_cbHeadersToAccept(0),
  1644. m_fImplDone(FALSE),
  1645. m_pwsabufs(&m_wsabufsPrefix),
  1646. m_lStatus(STATUS_IDLE),
  1647. m_pfnTransmitMethod(TransmitNothing)
  1648. {
  1649. ZeroMemory( &m_tfi, sizeof(HSE_TF_INFO) );
  1650. //
  1651. // If we are sending a status line and headers (i.e. we don't
  1652. // have an HTTP/0.9 response) then set up to send them along
  1653. // with the custom IIS headers in the first packet.
  1654. //
  1655. if ( response.m_lpszStatusLine )
  1656. {
  1657. response.m_hcHeaders.DumpData( m_bufHeaders );
  1658. m_bufHeaders.Append( 2, gc_szCRLF ); // Append extra CR/LF
  1659. m_cbHeadersToAccept = m_bufHeaders.CbSize();
  1660. m_cbHeadersToSend = m_cbHeadersToAccept;
  1661. m_pfnTransmitMethod = SyncTransmitHeaders;
  1662. }
  1663. //
  1664. // Add the first transmitter ref on the impl's behalf.
  1665. // This ref is released when the impl says that it's
  1666. // done with the response in ImplStart().
  1667. //
  1668. // Other refs may be added by the transmitter itself
  1669. // whenever it starts an async operation, so this
  1670. // ref may not be the last one released.
  1671. //
  1672. AddRef();
  1673. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX Transmitter created\n",
  1674. GetCurrentThreadId(),
  1675. this );
  1676. }
  1677. // ------------------------------------------------------------------------
  1678. //
  1679. // CTransmitter::ImplStart()
  1680. //
  1681. VOID
  1682. CTransmitter::ImplStart( BOOL fResponseComplete )
  1683. {
  1684. // We must not be called with fResponseComplete equal to TRUE
  1685. // several times. We can finish doing the work only once.
  1686. // This would prevent us from taking out IIS process if the
  1687. // callers would make that mistake.
  1688. //
  1689. if (m_fImplDone)
  1690. {
  1691. TrapSz("CTransmitter::ImplStart got called twice! That is illegal! Please grab a DEV to look at it!");
  1692. return;
  1693. }
  1694. //
  1695. // If we don't know it already, figure out the transfer coding
  1696. // to use in the response.
  1697. //
  1698. if ( TC_UNKNOWN == m_tc )
  1699. {
  1700. //
  1701. // If the response is not complete then we should not have
  1702. // a Content-Length header in the response.
  1703. //
  1704. Assert( fResponseComplete ||
  1705. NULL == m_pResponse->LpszGetHeader( gc_szContent_Length ) );
  1706. //
  1707. // Use chunked coding in the response only if the client
  1708. // will accept it and if we don't have a complete response
  1709. // (i.e. we do not have a Content-Length header).
  1710. //
  1711. m_tc = (!fResponseComplete && m_pResponse->m_pecb->FCanChunkResponse()) ?
  1712. TC_CHUNKED :
  1713. TC_IDENTITY;
  1714. }
  1715. Assert( m_tc != TC_UNKNOWN );
  1716. //
  1717. // If the impl says it's done with the response then
  1718. // ensure we release its ref to the transmitter when
  1719. // we're done here.
  1720. //
  1721. auto_ref_ptr<CTransmitter> pRef;
  1722. if ( fResponseComplete )
  1723. pRef.take_ownership(this);
  1724. //
  1725. // Note whether this is the last chunk of the response
  1726. // being added by the impl.
  1727. //
  1728. // !!!IMPORTANT!!!
  1729. // Set m_fImplDone before changing the status below because the
  1730. // transmitter may already be running (if this is a chunked response)
  1731. // and may run to completion before we get a chance to do anything
  1732. // after the InterlockedExchange() below.
  1733. //
  1734. m_fImplDone = fResponseComplete;
  1735. //
  1736. // Tell everyone that there is new data pending and ping the transmitter.
  1737. //
  1738. LONG lStatusPrev =
  1739. InterlockedExchange( &m_lStatus, STATUS_RUNNING_ACCEPT_PENDING );
  1740. //
  1741. // If the transmitter is idle then start it accepting.
  1742. //
  1743. if ( STATUS_IDLE == lStatusPrev )
  1744. {
  1745. m_pfnState = SAccept;
  1746. Start();
  1747. }
  1748. }
  1749. // ------------------------------------------------------------------------
  1750. //
  1751. // CTransmitter::SAccept()
  1752. //
  1753. // Accept data for transmitting.
  1754. //
  1755. VOID
  1756. CTransmitter::SAccept()
  1757. {
  1758. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX SAccept()\n", GetCurrentThreadId(), this );
  1759. //
  1760. // At this point we are either about to accept newly pended response
  1761. // data or we are continuing to accept existing data. Either way
  1762. // we are going to be accepting, so change the status to reflect that.
  1763. //
  1764. Assert( STATUS_RUNNING_ACCEPT_PENDING == m_lStatus ||
  1765. STATUS_RUNNING_ACCEPTING == m_lStatus );
  1766. m_lStatus = STATUS_RUNNING_ACCEPTING;
  1767. //
  1768. // If we have headers left to accept then
  1769. // accept as much of them as possible.
  1770. //
  1771. if ( m_cbHeadersToAccept > 0 )
  1772. {
  1773. UINT cbAccepted = m_wsabufsPrefix.CbAddItem(
  1774. reinterpret_cast<const BYTE *>(m_bufHeaders.PContents()) +
  1775. (m_bufHeaders.CbSize() - m_cbHeadersToAccept),
  1776. m_cbHeadersToAccept );
  1777. m_cbHeadersToAccept -= cbAccepted;
  1778. //
  1779. // If we could not accept all of the headers then send
  1780. // whatever we did accept now and we will accept more
  1781. // the next time around.
  1782. //
  1783. if ( m_cbHeadersToAccept > 0 )
  1784. {
  1785. //
  1786. // Presumably we did not accept all of the headers
  1787. // because we filled up the prefix WSABUF.
  1788. //
  1789. Assert( m_wsabufsPrefix.CbSize() == CB_WSABUFS_MAX );
  1790. //
  1791. // Send the headers
  1792. //
  1793. m_pfnState = STransmit;
  1794. Start();
  1795. return;
  1796. }
  1797. }
  1798. //
  1799. // Accept a body part. CTransmitter::AcceptComplete() will be called
  1800. // repeatedly for body parts as they are accepted.
  1801. //
  1802. // Add a transmitter ref before starting the next async operation.
  1803. // Use auto_ref_ptr to simplify resource recording and to
  1804. // prevent resource leaks if an exception is thrown.
  1805. // Ref is claimed by AcceptComplete() below.
  1806. //
  1807. {
  1808. auto_ref_ptr<CTransmitter> pRef(this);
  1809. m_pitBody->Accept( *this, *this );
  1810. pRef.relinquish();
  1811. }
  1812. }
  1813. // ------------------------------------------------------------------------
  1814. //
  1815. // CTransmitter::VisitComplete()
  1816. //
  1817. // IBodyPartVisitor callback called when we accept the last response body
  1818. // part added so far. Note that the impl may still be adding body parts
  1819. // on another thread at this point.
  1820. //
  1821. VOID
  1822. CTransmitter::VisitComplete()
  1823. {
  1824. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX VisitComplete()\n", GetCurrentThreadId(), this );
  1825. //
  1826. // Sanity check: the transmitter must be running (or we wouldn't
  1827. // be here) and we must be accepting data. In fact we think we
  1828. // just finished or we wouldn't be here. However ImplStart() may
  1829. // have pended new data between the time we were called and now.
  1830. //
  1831. Assert( STATUS_RUNNING_ACCEPT_PENDING == m_lStatus ||
  1832. STATUS_RUNNING_ACCEPTING == m_lStatus );
  1833. //
  1834. // If ImplStart() has not pended any new data yet then let
  1835. // everyone know that we are done accepting for now.
  1836. //
  1837. (VOID) InterlockedCompareExchange( &m_lStatus,
  1838. STATUS_RUNNING_ACCEPT_DONE,
  1839. STATUS_RUNNING_ACCEPTING );
  1840. }
  1841. // ------------------------------------------------------------------------
  1842. //
  1843. // CTransmitter::AcceptComplete()
  1844. //
  1845. // IAcceptObserver callback called when we are done accepting data from
  1846. // a body part. We don't care here how much data was accepted --
  1847. // each VisitXXX() function takes care of limiting the amount of
  1848. // accepted data by putting the transmitter into the transmit state
  1849. // once the optimal amount of data for a transmittable packet is reached.
  1850. // Here we only care about the case where we reach the end of the response
  1851. // body before accepting an optimal amount of data.
  1852. //
  1853. VOID
  1854. CTransmitter::AcceptComplete( UINT64 )
  1855. {
  1856. //
  1857. // Claim the transmitter ref added by AcceptBody()
  1858. //
  1859. auto_ref_ptr<CTransmitter> pRef;
  1860. pRef.take_ownership(this);
  1861. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX AcceptComplete()\n", GetCurrentThreadId(), this );
  1862. //
  1863. // If we have finished accepting the entire the response
  1864. // then transmit it.
  1865. //
  1866. if ( FAcceptedCompleteResponse() )
  1867. {
  1868. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX AcceptComplete() - Last chunk accepted.\n", GetCurrentThreadId(), this );
  1869. m_pfnState = STransmit;
  1870. Start();
  1871. }
  1872. //
  1873. // If there is still data left to accept or ImplStart() has pended
  1874. // more data then continue accepting.
  1875. //
  1876. // Otherwise there is nothing to accept so try to go idle. ImplStart()
  1877. // may pend new data right as we try to go idle. If that happens then
  1878. // just continue accepting as if the data had been pended before.
  1879. //
  1880. else if ( STATUS_RUNNING_ACCEPT_DONE != m_lStatus ||
  1881. STATUS_RUNNING_ACCEPT_PENDING ==
  1882. InterlockedCompareExchange( &m_lStatus,
  1883. STATUS_IDLE,
  1884. STATUS_RUNNING_ACCEPT_DONE ) )
  1885. {
  1886. Start();
  1887. }
  1888. }
  1889. // ------------------------------------------------------------------------
  1890. //
  1891. // CTransmitter::STransmit()
  1892. //
  1893. // Transmit accepted data via the current transmit method.
  1894. //
  1895. VOID
  1896. CTransmitter::STransmit()
  1897. {
  1898. (this->*m_pfnTransmitMethod)();
  1899. }
  1900. // ------------------------------------------------------------------------
  1901. //
  1902. // CTransmitter::SCleanup()
  1903. //
  1904. // Cleanup transmitted data.
  1905. //
  1906. VOID
  1907. CTransmitter::SCleanup()
  1908. {
  1909. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX SCleanup()\n", GetCurrentThreadId(), this );
  1910. //
  1911. // Quick check: If we are done accepting/transmitting the response then
  1912. // don't bother doing any explicit cleanup here -- our destructor
  1913. // will take care of everything.
  1914. //
  1915. if ( FAcceptedCompleteResponse() )
  1916. {
  1917. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX SCleanup() - Last chunk has been transmitted.\n", GetCurrentThreadId(), this );
  1918. return;
  1919. }
  1920. //
  1921. // Clear any file part.
  1922. //
  1923. ZeroMemory( &m_tfi, sizeof(HSE_TF_INFO) );
  1924. //
  1925. // Clear any buffered text parts.
  1926. //
  1927. m_bufBody.Clear();
  1928. //
  1929. // Clear the WSABUFS and use the prefix buffers again.
  1930. //
  1931. m_wsabufsPrefix.Clear();
  1932. m_wsabufsSuffix.Clear();
  1933. m_pwsabufs = &m_wsabufsPrefix;
  1934. //
  1935. // Destroy any body parts we just sent.
  1936. //
  1937. m_pitBody->Prune();
  1938. //
  1939. // Reset the transmit method
  1940. //
  1941. m_pfnTransmitMethod = TransmitNothing;
  1942. //
  1943. // At this point the transmitter must be running and in
  1944. // one of the three accepting states.
  1945. //
  1946. Assert( (STATUS_RUNNING_ACCEPT_PENDING == m_lStatus) ||
  1947. (STATUS_RUNNING_ACCEPTING == m_lStatus) ||
  1948. (STATUS_RUNNING_ACCEPT_DONE == m_lStatus) );
  1949. //
  1950. // If there is still data left to accept or ImplStart() has pended
  1951. // more data then continue accepting.
  1952. //
  1953. // Otherwise there is nothing to accept so try to go idle. ImplStart()
  1954. // may pend new data right as we try to go idle. If that happens then
  1955. // just continue accepting as if the data had been pended before.
  1956. //
  1957. if ( STATUS_RUNNING_ACCEPT_DONE != m_lStatus ||
  1958. STATUS_RUNNING_ACCEPT_PENDING ==
  1959. InterlockedCompareExchange( &m_lStatus,
  1960. STATUS_IDLE,
  1961. STATUS_RUNNING_ACCEPT_DONE ) )
  1962. {
  1963. m_pfnState = SAccept;
  1964. Start();
  1965. }
  1966. }
  1967. // ------------------------------------------------------------------------
  1968. //
  1969. // CTransmitter::Run()
  1970. //
  1971. VOID
  1972. CTransmitter::Run()
  1973. {
  1974. //
  1975. // Keep things running as long as we're still transmitting
  1976. //
  1977. if ( !FAILED(m_hr) )
  1978. {
  1979. //
  1980. // Assert: we aren't idle if we're executing state functions.
  1981. //
  1982. Assert( m_lStatus != STATUS_IDLE );
  1983. (this->*m_pfnState)();
  1984. }
  1985. }
  1986. // ------------------------------------------------------------------------
  1987. //
  1988. // CTransmitter::IISIOComplete()
  1989. //
  1990. // Response transmitter async I/O completion routine.
  1991. //
  1992. VOID
  1993. CTransmitter::IISIOComplete( DWORD dwcbSent,
  1994. DWORD dwLastError )
  1995. {
  1996. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX IISIOComplete() Sent %d bytes (last error = %d)\n", GetCurrentThreadId(), this, dwcbSent, dwLastError );
  1997. //
  1998. // Take ownership of the transmitter reference added
  1999. // on our behalf by the thread that started the async I/O.
  2000. //
  2001. auto_ref_ptr<CTransmitter> pRef;
  2002. pRef.take_ownership(this);
  2003. //
  2004. // If we had headers left to send then theoretically we just
  2005. // finished sending some of them. If so then subtract off
  2006. // what we just sent before continuing.
  2007. //
  2008. if ( m_cbHeadersToSend > 0 && dwLastError == ERROR_SUCCESS )
  2009. {
  2010. // Note: dwcbSent does not in any way give use the amount of
  2011. // headers sent. Use the size of the prefix buffer instead.
  2012. //
  2013. Assert( m_wsabufsPrefix.CbSize() <= m_cbHeadersToSend );
  2014. m_cbHeadersToSend -= m_wsabufsPrefix.CbSize();
  2015. }
  2016. //
  2017. // Proceed with cleanup.
  2018. //
  2019. m_hr = HRESULT_FROM_WIN32(dwLastError);
  2020. m_pfnState = SCleanup;
  2021. Start();
  2022. }
  2023. // ------------------------------------------------------------------------
  2024. //
  2025. // CTransmitter::TransmitNothing()
  2026. //
  2027. // This transmit function is used as the initial default transmit function.
  2028. // If no body data is accepted for transmission before the transmitter
  2029. // is invoked (e.g. either because the body is empty, or because the
  2030. // previous transmission transmitted the last of the body).
  2031. //
  2032. VOID
  2033. CTransmitter::TransmitNothing()
  2034. {
  2035. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX TransmitNothing()\n", GetCurrentThreadId(), this );
  2036. //
  2037. // Nothing to transmit, just proceed to cleanup.
  2038. //
  2039. m_pfnState = SCleanup;
  2040. Start();
  2041. }
  2042. // ------------------------------------------------------------------------
  2043. //
  2044. // CTransmitter::SyncTransmitHeaders()
  2045. //
  2046. VOID
  2047. CTransmitter::SyncTransmitHeaders()
  2048. {
  2049. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX SyncTransmitHeaders()\n", GetCurrentThreadId(), this );
  2050. HSE_SEND_HEADER_EX_INFO shei = { 0 };
  2051. //
  2052. // This function should (obviously) only be used to send headers
  2053. // including IIS headers.
  2054. //
  2055. Assert( m_cbHeadersToSend > 0 );
  2056. Assert( FSendingIISHeaders() );
  2057. shei.cchHeader = m_wsabufsPrefix.CbSize();
  2058. if ( shei.cchHeader > 0 )
  2059. {
  2060. Assert( shei.cchHeader + 1 <= sizeof(m_rgbPrefix) );
  2061. //
  2062. // Dump the contents of the prefix WSABUF into our prefix buffer
  2063. //
  2064. m_wsabufsPrefix.DumpTo( m_rgbPrefix,
  2065. 0,
  2066. shei.cchHeader );
  2067. //
  2068. // Null-terminate the headers because IIS doesn't pay any attention
  2069. // to cchHeader....
  2070. //
  2071. m_rgbPrefix[shei.cchHeader] = '\0';
  2072. shei.pszHeader = reinterpret_cast<LPSTR>(m_rgbPrefix);
  2073. }
  2074. shei.pszStatus = m_pResponse->LpszStatusCode();
  2075. shei.cchStatus = static_cast<DWORD>(strlen(shei.pszStatus));
  2076. shei.fKeepConn = m_pResponse->m_pecb->FKeepAlive();
  2077. if ( m_pResponse->m_pecb->FSyncTransmitHeaders(shei) )
  2078. {
  2079. m_cbHeadersToSend -= shei.cchHeader;
  2080. }
  2081. else
  2082. {
  2083. DebugTrace( "CTransmitter::SyncTransmitHeaders() - SSF::HSE_REQ_SEND_RESPONSE_HEADER_EX failed (%d)\n", GetLastError() );
  2084. m_hr = HRESULT_FROM_WIN32(GetLastError());
  2085. }
  2086. //
  2087. // Next thing to do is cleanup the headers we just transmitted.
  2088. //
  2089. m_pfnState = SCleanup;
  2090. Start();
  2091. }
  2092. // ------------------------------------------------------------------------
  2093. //
  2094. // PbEmitChunkPrefix()
  2095. //
  2096. // Emit a chunked encoding prefix.
  2097. //
  2098. inline LPBYTE
  2099. PbEmitChunkPrefix( LPBYTE pbBuf,
  2100. UINT cbSize )
  2101. {
  2102. //
  2103. // Emit the chunk size expressed in hex
  2104. //
  2105. _ultoa( cbSize,
  2106. reinterpret_cast<LPSTR>(pbBuf),
  2107. 16 );
  2108. pbBuf += strlen(reinterpret_cast<LPSTR>(pbBuf));
  2109. //
  2110. // followed by a CRLF
  2111. //
  2112. *pbBuf++ = '\r';
  2113. *pbBuf++ = '\n';
  2114. return pbBuf;
  2115. }
  2116. // ------------------------------------------------------------------------
  2117. //
  2118. // PbEmitChunkSuffix()
  2119. //
  2120. // Emit a chunked encoding suffix.
  2121. //
  2122. inline LPBYTE
  2123. PbEmitChunkSuffix( LPBYTE pbBuf,
  2124. BOOL fLastChunk )
  2125. {
  2126. //
  2127. // CRLF to end the current chunk
  2128. //
  2129. *pbBuf++ = '\r';
  2130. *pbBuf++ = '\n';
  2131. //
  2132. // If this is the last chunk
  2133. //
  2134. if ( fLastChunk )
  2135. {
  2136. //
  2137. // then add a 0-length chunk
  2138. //
  2139. *pbBuf++ = '0';
  2140. *pbBuf++ = '\r';
  2141. *pbBuf++ = '\n';
  2142. //
  2143. // and there are no trailers,
  2144. // so just add the final CRLF
  2145. // to finish things off.
  2146. //
  2147. *pbBuf++ = '\r';
  2148. *pbBuf++ = '\n';
  2149. }
  2150. return pbBuf;
  2151. }
  2152. // ------------------------------------------------------------------------
  2153. //
  2154. // CTransmitter::AsyncTransmitFile()
  2155. //
  2156. VOID
  2157. CTransmitter::AsyncTransmitFile()
  2158. {
  2159. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX AsyncTransmitFile()\n", GetCurrentThreadId(), this );
  2160. Assert( m_tfi.hFile != NULL );
  2161. //
  2162. // Always async I/O
  2163. //
  2164. m_tfi.dwFlags = HSE_IO_ASYNC;
  2165. //
  2166. // Start building up the prefix...
  2167. //
  2168. LPBYTE pbPrefix = m_rgbPrefix;
  2169. //
  2170. // If we are sending headers then we dump those out
  2171. // first followed by the chunk prefix (if we are using
  2172. // Transfer-Encoding: chunked.
  2173. //
  2174. if ( m_cbHeadersToSend )
  2175. {
  2176. Assert( m_wsabufsPrefix.CbSize() > 0 );
  2177. m_wsabufsPrefix.DumpTo( pbPrefix,
  2178. 0,
  2179. m_wsabufsPrefix.CbSize() );
  2180. pbPrefix += m_wsabufsPrefix.CbSize();
  2181. if ( TC_CHUNKED == m_tc )
  2182. {
  2183. pbPrefix = PbEmitChunkPrefix( pbPrefix,
  2184. m_tfi.BytesToWrite +
  2185. m_wsabufsSuffix.CbSize() );
  2186. }
  2187. //
  2188. // Oh yeah, we need to do a little more work here when
  2189. // we are including IIS headers
  2190. //
  2191. if ( FSendingIISHeaders() )
  2192. {
  2193. // First, tell IIS to include the headers and format
  2194. // the status code.
  2195. //
  2196. m_tfi.dwFlags |= HSE_IO_SEND_HEADERS;
  2197. m_tfi.pszStatusCode = m_pResponse->LpszStatusCode();
  2198. //
  2199. // Then null-terminate the headers in the prefix because
  2200. // IIS doesn't pay any attention to m_tfi.HeadLength in
  2201. // this case.
  2202. //
  2203. // Note: we do NOT increment pbPrefix here because we are
  2204. // not including the NULL as part of the data. It's just
  2205. // there to keep IIS from overrunning our buffer. Yes,
  2206. // our buffer size accounts for this. We assert it below.
  2207. //
  2208. *pbPrefix = '\0';
  2209. }
  2210. }
  2211. //
  2212. // Otherwise, we are not sending headers so all of the data
  2213. // in the prefix WSABUF is body data, so emit the chunk prefix
  2214. // before dumping the body data.
  2215. //
  2216. else
  2217. {
  2218. if ( TC_CHUNKED == m_tc )
  2219. {
  2220. pbPrefix = PbEmitChunkPrefix( pbPrefix,
  2221. m_tfi.BytesToWrite +
  2222. m_wsabufsSuffix.CbSize() +
  2223. m_wsabufsPrefix.CbSize() );
  2224. }
  2225. if ( m_wsabufsPrefix.CbSize() )
  2226. {
  2227. m_wsabufsPrefix.DumpTo( pbPrefix,
  2228. 0,
  2229. m_wsabufsPrefix.CbSize() );
  2230. pbPrefix += m_wsabufsPrefix.CbSize();
  2231. }
  2232. }
  2233. //
  2234. // It's sort of after the fact, but assert that we didn't
  2235. // overrun the buffer. Remember, we might have stuffed a
  2236. // null in at *pbPrefix, so don't forget to include it.
  2237. //
  2238. Assert( pbPrefix - m_rgbPrefix + 1 <= sizeof(m_rgbPrefix) );
  2239. //
  2240. // Finish up the prefix
  2241. //
  2242. m_tfi.HeadLength = (DWORD)(pbPrefix - m_rgbPrefix);
  2243. m_tfi.pHead = m_rgbPrefix;
  2244. //
  2245. // Now start building up the suffix...
  2246. //
  2247. LPBYTE pbSuffix = m_rgbSuffix;
  2248. //
  2249. // If there is any data in the suffix WSABUF then add that first.
  2250. //
  2251. if ( m_wsabufsSuffix.CbSize() )
  2252. {
  2253. m_wsabufsSuffix.DumpTo( pbSuffix,
  2254. 0,
  2255. m_wsabufsSuffix.CbSize() );
  2256. pbSuffix += m_wsabufsSuffix.CbSize();
  2257. }
  2258. //
  2259. // If we are using Transfer-Encoding: chunked then append the
  2260. // protocol suffix.
  2261. //
  2262. if ( TC_CHUNKED == m_tc )
  2263. pbSuffix = PbEmitChunkSuffix( pbSuffix, FAcceptedCompleteResponse() );
  2264. //
  2265. // It's sort of after the fact, but assert that we didn't
  2266. // overrun the buffer.
  2267. //
  2268. Assert( pbSuffix - m_rgbSuffix <= sizeof(m_rgbSuffix) );
  2269. //
  2270. // Finish up the suffix
  2271. //
  2272. m_tfi.TailLength = (DWORD)(pbSuffix - m_rgbSuffix);
  2273. m_tfi.pTail = m_rgbSuffix;
  2274. //
  2275. // If this will be the last packet sent AND we will be closing
  2276. // the connection, then also throw the HSE_IO_DISCONNECT_AFTER_SEND
  2277. // flag. This VASTLY improves throughput by allowing IIS to close
  2278. // and reuse the socket as soon as the file is sent.
  2279. //
  2280. if ( FAcceptedCompleteResponse() &&
  2281. !m_pResponse->m_pecb->FKeepAlive() )
  2282. {
  2283. m_tfi.dwFlags |= HSE_IO_DISCONNECT_AFTER_SEND;
  2284. }
  2285. //
  2286. // Start async I/O to transmit the file. Make sure the transmitter
  2287. // has an added ref if the async I/O starts successfully. Use
  2288. // auto_ref to make things exception-proof.
  2289. //
  2290. {
  2291. SCODE sc = S_OK;
  2292. auto_ref_ptr<CTransmitter> pRef(this);
  2293. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX prefix=%d, suffix=%d, content=%d\n", GetCurrentThreadId(), this, m_tfi.HeadLength, m_tfi.TailLength, m_tfi.BytesToWrite );
  2294. sc = m_pResponse->m_pecb->ScAsyncTransmitFile( m_tfi, *this );
  2295. if (FAILED(sc))
  2296. {
  2297. DebugTrace( "CTransmitter::AsyncTransmitFile() - IEcb::ScAsyncTransmitFile() failed with error 0x%08lX\n", sc );
  2298. IISIOComplete( 0, sc );
  2299. }
  2300. pRef.relinquish();
  2301. }
  2302. }
  2303. // ------------------------------------------------------------------------
  2304. //
  2305. // CTransmitter::AsyncTransmitText()
  2306. //
  2307. // Start transmitting the text-only response.
  2308. //
  2309. VOID
  2310. CTransmitter::AsyncTransmitText()
  2311. {
  2312. LPBYTE pb = m_rgbPrefix;
  2313. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX AsyncTransmitText()\n", GetCurrentThreadId(), this );
  2314. //
  2315. // If we are sending text then there must be data in m_wsabufsPrefix.
  2316. //
  2317. Assert( m_wsabufsPrefix.CbSize() > 0 );
  2318. //
  2319. // Figure out the amount of headers we have in the prefix WSABUF.
  2320. // Given that all of the headers must be transmitted before any
  2321. // of the body, the amount of headers in the WSABUF is the lesser
  2322. // of the amount of headers left to send or the size of the WSABUF.
  2323. //
  2324. // The size of the body chunk is whatever is left (if anything).
  2325. //
  2326. UINT cbHeaders = min(m_cbHeadersToSend, m_wsabufsPrefix.CbSize());
  2327. UINT cbChunk = m_wsabufsPrefix.CbSize() - cbHeaders;
  2328. //
  2329. // If we are sending any headers then dump those out first.
  2330. //
  2331. if ( cbHeaders )
  2332. {
  2333. m_wsabufsPrefix.DumpTo( pb,
  2334. 0,
  2335. cbHeaders );
  2336. pb += cbHeaders;
  2337. }
  2338. //
  2339. // Then, if we are using Transfer-Encoding: chunked, include
  2340. // the size of this chunk.
  2341. //
  2342. if ( TC_CHUNKED == m_tc )
  2343. pb = PbEmitChunkPrefix( pb, cbChunk );
  2344. //
  2345. // Next, dump out the data for this chunk
  2346. //
  2347. if ( cbChunk > 0 )
  2348. {
  2349. m_wsabufsPrefix.DumpTo( pb,
  2350. cbHeaders,
  2351. cbChunk );
  2352. pb += cbChunk;
  2353. }
  2354. //
  2355. // Finally, dump out the chunk suffix if we're using
  2356. // chunked encoding.
  2357. //
  2358. if ( TC_CHUNKED == m_tc )
  2359. pb = PbEmitChunkSuffix( pb, FAcceptedCompleteResponse() );
  2360. //
  2361. // It's sort of after the fact, but assert that we didn't
  2362. // overrun the buffer.
  2363. //
  2364. Assert( pb - m_rgbPrefix <= sizeof(m_rgbPrefix) );
  2365. //
  2366. // Start async I/O to transmit the text. Make sure the transmitter
  2367. // has an added ref if the async I/O starts successfully. Use
  2368. // auto_ref to make things exception-proof.
  2369. //
  2370. {
  2371. SCODE sc = S_OK;
  2372. auto_ref_ptr<CTransmitter> pRef(this);
  2373. sc = m_pResponse->m_pecb->ScAsyncWrite( m_rgbPrefix,
  2374. static_cast<DWORD>(pb - m_rgbPrefix),
  2375. *this );
  2376. if (FAILED(sc))
  2377. {
  2378. DebugTrace( "CTransmitter::AsyncTransmitText() - IEcb::ScAsyncWrite() failed to start transmitting with error 0x%08lX\n", sc );
  2379. IISIOComplete( 0, sc );
  2380. }
  2381. pRef.relinquish();
  2382. }
  2383. }
  2384. // ------------------------------------------------------------------------
  2385. //
  2386. // CTransmitter::VisitBytes()
  2387. //
  2388. VOID
  2389. CTransmitter::VisitBytes( const BYTE * pbData,
  2390. UINT cbToSend,
  2391. IAcceptObserver& obsAccept )
  2392. {
  2393. // TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX VisitBytes()\n", GetCurrentThreadId(), this );
  2394. UINT cbAccepted;
  2395. //
  2396. //$IIS If we still have IIS headers to send, then we must send them now.
  2397. //$IIS One might wonder why we can't simply be clever and effecient
  2398. //$IIS and just add the bytes to send along with the headers. The reason
  2399. //$IIS we cannot is because the IIS send headers call pays no attention
  2400. //$IIS to the stated size of the headers and sends only up to the first
  2401. //$IIS NULL. Since binary body part data could contain several NULLs,
  2402. //$IIS the result would be that part of the body would be lost.
  2403. //
  2404. if ( FSendingIISHeaders() )
  2405. {
  2406. m_pfnState = STransmit;
  2407. obsAccept.AcceptComplete( 0 );
  2408. return;
  2409. }
  2410. //
  2411. // Accept as many bytes as we can. Note that we may not
  2412. // accept everything because of the WSABUFS size limit.
  2413. // (See CWSABufs class definition for an explanation.)
  2414. //
  2415. cbAccepted = m_pwsabufs->CbAddItem( pbData, cbToSend );
  2416. //
  2417. // If we accepted anything at all, then we'll want to use
  2418. // the text transmitter to send it later, unless we are
  2419. // already planning to use another transmitter (e.g. the
  2420. // file transmitter or header transmitter) for better
  2421. // performance.
  2422. //
  2423. if ( cbAccepted > 0 && m_pfnTransmitMethod == TransmitNothing )
  2424. m_pfnTransmitMethod = AsyncTransmitText;
  2425. //
  2426. // If we couldn't accept everything, then the WSABUFS are full
  2427. // so we have to transmit them before we can accept anything more.
  2428. //
  2429. if ( cbAccepted < cbToSend )
  2430. m_pfnState = STransmit;
  2431. //
  2432. // Finally, don't forget to tell our observer that we're done visiting.
  2433. //
  2434. obsAccept.AcceptComplete( cbAccepted );
  2435. }
  2436. // ------------------------------------------------------------------------
  2437. //
  2438. // CTransmitter::VisitFile()
  2439. //
  2440. VOID
  2441. CTransmitter::VisitFile( const auto_ref_handle& hf,
  2442. UINT64 ibOffset64,
  2443. UINT64 cbToSend64,
  2444. IAcceptObserver& obsAccept )
  2445. {
  2446. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX VisitFile()\n", GetCurrentThreadId(), this );
  2447. //
  2448. // We can only transmit one file at a time. If we've already
  2449. // accepted a file for transmission then we cannot accept another
  2450. // one. We must transmit now.
  2451. //
  2452. if ( m_tfi.hFile != NULL )
  2453. {
  2454. m_pfnState = STransmit;
  2455. obsAccept.AcceptComplete( 0 );
  2456. return;
  2457. }
  2458. // If we need to send headers with this packet, then we can only
  2459. // send them along with the file
  2460. //
  2461. // Accept as much of the file as we were told to. The amount of
  2462. // file data we can transmit is unlimited.
  2463. //
  2464. m_hf = hf;
  2465. m_tfi.hFile = m_hf.get();
  2466. // Our way of seting it up depends on the fact if the file is larger
  2467. // than 4GB. Also we have no way to do offsets that are above 4GB
  2468. // through _HSE_TF_INFO. We should not get them here though as
  2469. // byteranges are disabled for files above 4GB. And seting 0 for
  2470. // BytesToWrite is special value that is to be used to ask for the
  2471. // whole file.
  2472. //
  2473. Assert(0 == (0xFFFFFFFF00000000 & ibOffset64));
  2474. m_tfi.Offset = static_cast<DWORD>(ibOffset64);
  2475. if (0x00000000FFFFFFFF < cbToSend64)
  2476. {
  2477. m_tfi.BytesToWrite = 0;
  2478. }
  2479. else
  2480. {
  2481. m_tfi.BytesToWrite = static_cast<DWORD>(cbToSend64);
  2482. }
  2483. //
  2484. // Subsequent text data (if any) will form the suffix to the file data,
  2485. // so cut over to the suffix WSABUFs.
  2486. //
  2487. m_pwsabufs = &m_wsabufsSuffix;
  2488. //
  2489. // Use the file transmitter come send time.
  2490. //
  2491. m_pfnTransmitMethod = AsyncTransmitFile;
  2492. obsAccept.AcceptComplete( cbToSend64 );
  2493. }
  2494. // ------------------------------------------------------------------------
  2495. //
  2496. // CTransmitter::VisitStream()
  2497. //
  2498. VOID
  2499. CTransmitter::VisitStream( IAsyncStream& stmSrc,
  2500. UINT cbToSend,
  2501. IAcceptObserver& obsAccept )
  2502. {
  2503. TransmitTrace( "DAV: CTransmitter: TID %3d: 0x%08lX VisitStream()\n", GetCurrentThreadId(), this );
  2504. //
  2505. //$IIS If we still have IIS headers to send, then we must send them now.
  2506. //$IIS One might wonder why we can't simply be clever and effecient
  2507. //$IIS and just stream in bytes to send along with the headers. The reason
  2508. //$IIS we cannot is because the IIS send headers call pays no attention
  2509. //$IIS to the stated size of the headers and sends only up to the first
  2510. //$IIS NULL. Since binary body part data could contain several NULLs,
  2511. //$IIS the result would be that part of the body would be lost.
  2512. //
  2513. if ( FSendingIISHeaders() )
  2514. {
  2515. m_pfnState = STransmit;
  2516. obsAccept.AcceptComplete( 0 );
  2517. return;
  2518. }
  2519. m_pobsAccept = &obsAccept;
  2520. cbToSend = min( cbToSend, CB_WSABUFS_MAX - m_pwsabufs->CbSize() );
  2521. //
  2522. // Add a transmitter ref before starting the next async operation.
  2523. // Use auto_ref_ptr to simplify resource recording and to
  2524. // prevent resource leaks if an exception is thrown.
  2525. //
  2526. auto_ref_ptr<CTransmitter> pRef(this);
  2527. stmSrc.AsyncCopyTo( *this, cbToSend, *this );
  2528. pRef.relinquish();
  2529. }
  2530. // ------------------------------------------------------------------------
  2531. //
  2532. // CTransmitter::CopyToComplete()
  2533. //
  2534. VOID
  2535. CTransmitter::CopyToComplete( UINT cbCopied, HRESULT hr )
  2536. {
  2537. //
  2538. // Claim the transmitter ref added by VisitStream()
  2539. //
  2540. auto_ref_ptr<CTransmitter> pRef;
  2541. pRef.take_ownership(this);
  2542. m_hr = hr;
  2543. m_pobsAccept->AcceptComplete( cbCopied );
  2544. }
  2545. // ------------------------------------------------------------------------
  2546. //
  2547. // CTransmitter::AsyncWrite()
  2548. //
  2549. // "Write" text to the transmitter by adding it to the transmit buffers.
  2550. // Despite its name, this call executes synchronously (note the call
  2551. // to WriteComplete() at the end) so it does NOT need an additional
  2552. // transmitter reference.
  2553. //
  2554. VOID
  2555. CTransmitter::AsyncWrite(
  2556. const BYTE * pbBuf,
  2557. UINT cbToWrite,
  2558. IAsyncWriteObserver& obsAsyncWrite )
  2559. {
  2560. UINT cbWritten;
  2561. Assert( cbToWrite <= CB_WSABUFS_MAX - m_pwsabufs->CbSize() );
  2562. cbWritten = m_pwsabufs->CbAddItem(
  2563. reinterpret_cast<LPBYTE>(m_bufBody.Append( cbToWrite,
  2564. reinterpret_cast<LPCSTR>(pbBuf) )),
  2565. cbToWrite );
  2566. //
  2567. // If we accepted anything at all, then we'll want to use
  2568. // the text transmitter to send it later, unless we are
  2569. // already planning to use another transmitter (e.g. the
  2570. // file transmitter or header transmitter) for better
  2571. // performance.
  2572. //
  2573. if ( cbWritten > 0 && m_pfnTransmitMethod == TransmitNothing )
  2574. m_pfnTransmitMethod = AsyncTransmitText;
  2575. if ( m_pwsabufs->CbSize() == CB_WSABUFS_MAX )
  2576. m_pfnState = STransmit;
  2577. obsAsyncWrite.WriteComplete( cbWritten, NOERROR );
  2578. }
  2579. // ========================================================================
  2580. //
  2581. // FREE FUNCTIONS
  2582. //
  2583. // ------------------------------------------------------------------------
  2584. //
  2585. // NewResponse
  2586. //
  2587. IResponse * NewResponse( IEcb& ecb )
  2588. {
  2589. return new CResponse(ecb);
  2590. }
  2591. //
  2592. // Disable stubborn level 4 warnings generated by expansion of inline STL
  2593. // member functions. Why do it way down here? Because it appears to
  2594. // silence these expanded functions without supressing warnings for any
  2595. // code we've written above!
  2596. //
  2597. #pragma warning(disable:4146) // negative unsigned is still unsigned