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.

1853 lines
47 KiB

  1. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. //
  3. // BODY.CPP
  4. //
  5. // Common implementation classes from which request body and
  6. // response body are derived.
  7. //
  8. // Copyright 1986-1997 Microsoft Corporation, All Rights Reserved
  9. //
  10. #include <_davprs.h>
  11. #include <body.h>
  12. // ========================================================================
  13. //
  14. // CLASS IAcceptObserver
  15. //
  16. // ------------------------------------------------------------------------
  17. //
  18. // IAcceptObserver::~IAcceptObserver()
  19. //
  20. // Out of line virtual destructor necessary for proper deletion
  21. // of objects of derived classes via this class
  22. //
  23. IAcceptObserver::~IAcceptObserver() {}
  24. // ========================================================================
  25. //
  26. // CLASS IAsyncPersistObserver
  27. //
  28. // ------------------------------------------------------------------------
  29. //
  30. // IAsyncPersistObserver::~IAsyncPersistObserver()
  31. //
  32. // Out of line virtual destructor necessary for proper deletion
  33. // of objects of derived classes via this class
  34. //
  35. IAsyncPersistObserver::~IAsyncPersistObserver() {}
  36. // ========================================================================
  37. //
  38. // CLASS IAsyncIStreamObserver
  39. //
  40. // ------------------------------------------------------------------------
  41. //
  42. // IAsyncIStreamObserver::~IAsyncIStreamObserver()
  43. //
  44. // Out of line virtual destructor necessary for proper deletion
  45. // of objects of derived classes via this class
  46. //
  47. IAsyncIStreamObserver::~IAsyncIStreamObserver() {}
  48. // ========================================================================
  49. //
  50. // CLASS CIStreamAsyncStream
  51. //
  52. class CIStreamAsyncStream : public IAsyncStream
  53. {
  54. //
  55. // The OLE IStream
  56. //
  57. IStream& m_stm;
  58. // NOT IMPLEMENTED
  59. //
  60. CIStreamAsyncStream( const CIStreamAsyncStream& );
  61. CIStreamAsyncStream& operator=( const CIStreamAsyncStream& );
  62. public:
  63. // CREATORS
  64. //
  65. CIStreamAsyncStream( IStream& stm ) : m_stm(stm) {}
  66. // ACCESSORS
  67. //
  68. void AsyncWrite( const BYTE * pbBuf,
  69. UINT cbToWrite,
  70. IAsyncWriteObserver& obsAsyncWrite );
  71. };
  72. // ------------------------------------------------------------------------
  73. //
  74. // CIStreamAsyncStream::AsyncWrite()
  75. //
  76. void
  77. CIStreamAsyncStream::AsyncWrite(
  78. const BYTE * pbBuf,
  79. UINT cbToWrite,
  80. IAsyncWriteObserver& obsAsyncWrite )
  81. {
  82. ULONG cbWritten;
  83. HRESULT hr;
  84. hr = m_stm.Write( pbBuf,
  85. cbToWrite,
  86. &cbWritten );
  87. obsAsyncWrite.WriteComplete( cbWritten, hr );
  88. }
  89. // ========================================================================
  90. //
  91. // CLASS IBodyPartVisitor
  92. //
  93. // ------------------------------------------------------------------------
  94. //
  95. // IBodyPartVisitor::~IBodyPartVisitor()
  96. //
  97. // Out of line virtual destructor necessary for proper deletion
  98. // of objects of derived classes via this class
  99. //
  100. IBodyPartVisitor::~IBodyPartVisitor() {}
  101. // ========================================================================
  102. //
  103. // CLASS IBodyPart
  104. //
  105. // ------------------------------------------------------------------------
  106. //
  107. // IBodyPart::~IBodyPart()
  108. //
  109. // Out of line virtual destructor necessary for proper deletion
  110. // of objects of derived classes via this class
  111. //
  112. IBodyPart::~IBodyPart() {}
  113. // ------------------------------------------------------------------------
  114. //
  115. // CTextBodyPart::CTextBodyPart()
  116. //
  117. CTextBodyPart::CTextBodyPart( UINT cbText, LPCSTR lpszText )
  118. {
  119. AddTextBytes( cbText, lpszText );
  120. }
  121. // ------------------------------------------------------------------------
  122. //
  123. // CTextBodyPart::CTextBodyPart()
  124. //
  125. VOID
  126. CTextBodyPart::AddTextBytes( UINT cbText, LPCSTR lpszText )
  127. {
  128. m_bufText.Append( cbText, lpszText );
  129. }
  130. // ------------------------------------------------------------------------
  131. //
  132. // CTextBodyPart::Rewind()
  133. //
  134. VOID
  135. CTextBodyPart::Rewind()
  136. {
  137. //
  138. // Since a text body part is implemented as a randomly-
  139. // accessible array there is nothing to "rewind".
  140. //
  141. }
  142. // ------------------------------------------------------------------------
  143. //
  144. // CTextBodyPart::Accept()
  145. //
  146. VOID
  147. CTextBodyPart::Accept( IBodyPartVisitor& v,
  148. UINT64 ibPos64,
  149. IAcceptObserver& obsAccept )
  150. {
  151. Assert( ibPos64 < m_bufText.CbSize() );
  152. //
  153. // Just visit all of the remaining text in the buffer. The visitor
  154. // may not process it all, but that will be reflected in the next
  155. // call to this function.
  156. // NOTE: To be compatable with IBodyPart the position is passed
  157. // in as 64 bit value (this is necessary to support file body parts
  158. // that are bigger than 4GB). However we do not want anyone to create
  159. // text body parts that are bigger than 4GB. So assert that it is not
  160. // the case here and truncate the passed in 64 bit value to 32 bits.
  161. //
  162. Assert(0 == (0xFFFFFFFF00000000 & ibPos64));
  163. v.VisitBytes(
  164. reinterpret_cast<const BYTE *>(m_bufText.PContents()) + static_cast<UINT>(ibPos64),
  165. m_bufText.CbSize() - static_cast<UINT>(ibPos64),
  166. obsAccept );
  167. }
  168. // ========================================================================
  169. //
  170. // CLASS CFileBodyPart
  171. //
  172. // ------------------------------------------------------------------------
  173. //
  174. // CFileBodyPart::CFileBodyPart()
  175. //
  176. CFileBodyPart::CFileBodyPart( const auto_ref_handle& hf,
  177. UINT64 ibFile64,
  178. UINT64 cbFile64 ) :
  179. m_hf(hf),
  180. m_ibFile64(ibFile64),
  181. m_cbFile64(cbFile64)
  182. {
  183. // We do not support byteranges on the files larger than 4GB. But due to the fact that byterange
  184. // processing is all DWORD based in adition to the check for default file length value we do the
  185. // check for default byterange value. If _HSE_TF_INFO will ever be fixed to take file size values
  186. // larger than DWORD then we would be able to move our byterange processing to UINT64 base and
  187. // the second check below would go away.
  188. //
  189. if ((0xFFFFFFFFFFFFFFFF == cbFile64) || // If we got the default file length value indicating that we want data up to the end of the file
  190. (0x00000000FFFFFFFF == cbFile64)) // If we got the default byterange value indicating that we want the data up to the end of the file
  191. {
  192. LARGE_INTEGER cbFileSize;
  193. if (!GetFileSizeEx(hf.get(), &cbFileSize))
  194. {
  195. DebugTrace( "CFileBodyPart::CFileBodyPart() - GetFileSizeEx() failed with last error (0x%08lX)\n", GetLastError() );
  196. throw CLastErrorException();
  197. }
  198. m_cbFile64 = cbFileSize.QuadPart;
  199. }
  200. }
  201. // ------------------------------------------------------------------------
  202. //
  203. // CFileBodyPart::Rewind()
  204. //
  205. VOID
  206. CFileBodyPart::Rewind()
  207. {
  208. //
  209. // Since the files in file body parts are opened overlapped,
  210. // they do not have internal file pointers, hence they never
  211. // need to be rewound.
  212. //
  213. }
  214. // ------------------------------------------------------------------------
  215. //
  216. // CFileBodyPart::Accept()
  217. //
  218. VOID
  219. CFileBodyPart::Accept( IBodyPartVisitor& v,
  220. UINT64 ibPos64,
  221. IAcceptObserver& obsAccept )
  222. {
  223. if (ibPos64 < m_cbFile64)
  224. {
  225. //
  226. // Just visit the remainder of the file. The visitor
  227. // may not process it all, but that will be reflected in the next
  228. // call to this function.
  229. //
  230. v.VisitFile( m_hf,
  231. m_ibFile64 + ibPos64,
  232. m_cbFile64 - ibPos64,
  233. obsAccept );
  234. }
  235. else
  236. {
  237. //
  238. // We should always have something to accept unless we have a
  239. // 0-length file body part. In that case, just tell the observer
  240. // how much was visited: nothing.
  241. //
  242. obsAccept.AcceptComplete(0);
  243. }
  244. }
  245. // ========================================================================
  246. //
  247. // CLASS CAsyncReadVisitor
  248. //
  249. // A body part visitor that asynchronously reads body parts into
  250. // a fixed size, caller-supplied, buffer.
  251. //
  252. class CAsyncReadVisitor :
  253. public IBodyPartVisitor,
  254. private IAsyncReadObserver
  255. {
  256. //
  257. // Error information
  258. //
  259. HRESULT m_hr;
  260. //
  261. // User's buffer and its size
  262. //
  263. LPBYTE m_pbBufUser;
  264. UINT m_cbBufUser;
  265. //
  266. // Accept observer passed to VisitStream(). This observer must
  267. // be stashed in a member variable because reading from the stream
  268. // is asynchronous and we need to be able to notify the observer
  269. // when the read completes.
  270. //
  271. IAcceptObserver * m_pobsAccept;
  272. //
  273. // IBodyPartVisitor
  274. //
  275. VOID VisitBytes( const BYTE * pbData,
  276. UINT cbToRead,
  277. IAcceptObserver& obsAccept );
  278. VOID VisitFile( const auto_ref_handle& hf,
  279. UINT64 ibOffset64,
  280. UINT64 cbToRead64,
  281. IAcceptObserver& obsAccept );
  282. VOID VisitStream( IAsyncStream& stm,
  283. UINT cbToRead,
  284. IAcceptObserver& obsAccept );
  285. VOID VisitComplete();
  286. //
  287. // IAsyncReadObserver for async streams visited via VisitStream()
  288. //
  289. VOID ReadComplete( UINT cbRead, HRESULT hr );
  290. // NOT IMPLEMENTED
  291. //
  292. CAsyncReadVisitor( const CAsyncReadVisitor& );
  293. CAsyncReadVisitor& operator=( const CAsyncReadVisitor& );
  294. public:
  295. // CREATORS
  296. //
  297. CAsyncReadVisitor() :
  298. // Always start with clean member variables
  299. m_hr(S_OK),
  300. m_pbBufUser(NULL),
  301. m_cbBufUser(0),
  302. m_pobsAccept(NULL)
  303. {
  304. }
  305. // ACCESSORS
  306. //
  307. HRESULT Hresult() const { return m_hr; }
  308. // MANIPULATORS
  309. //
  310. VOID
  311. Configure( LPBYTE pbBufUser,
  312. UINT cbBufUser )
  313. {
  314. m_pbBufUser = pbBufUser;
  315. m_cbBufUser = cbBufUser;
  316. // Also reset our HRESULT
  317. m_hr = S_OK;
  318. }
  319. };
  320. // ------------------------------------------------------------------------
  321. //
  322. // CAsyncReadVisitor::VisitBytes()
  323. //
  324. VOID
  325. CAsyncReadVisitor::VisitBytes( const BYTE * pbData,
  326. UINT cbToRead,
  327. IAcceptObserver& obsAccept )
  328. {
  329. cbToRead = min(cbToRead, m_cbBufUser);
  330. memcpy(m_pbBufUser, pbData, cbToRead);
  331. obsAccept.AcceptComplete(cbToRead);
  332. }
  333. // ------------------------------------------------------------------------
  334. //
  335. // CAsyncReadVisitor::VisitFile()
  336. //
  337. // Not implemented because 1) request bodies cannot have file
  338. // body parts and 2) CAsyncReadVisitor is currently only used
  339. // with request bodies. Should we ever need this for response
  340. // bodies we'll need to write the code at that point.
  341. //
  342. // The old implementation used ReadFileEx() to read from the file
  343. // asynchronously. In a nutshell, we couldn't use ReadFileEx()
  344. // because it relied on APC for calling back its completion routine.
  345. // APC in turn required the calling thread to enter an alertable
  346. // wait state. Typically, we would only call VisitFile() from an
  347. // I/O completion port thread pool, and those threads are never
  348. // in an alertable wait state, thus the completion routine for
  349. // ReadFileEx() would never be called.
  350. //
  351. VOID
  352. CAsyncReadVisitor::VisitFile( const auto_ref_handle&,
  353. UINT64,
  354. UINT64,
  355. IAcceptObserver& obsAccept )
  356. {
  357. TrapSz( "CAsyncReadVisitor::VisitFile() is not implemented!!" );
  358. //
  359. // If, for whatever random reason, someone actually does call
  360. // this function, at least do something predictable: fail gracefully.
  361. //
  362. m_hr = E_FAIL;
  363. obsAccept.AcceptComplete( 0 );
  364. }
  365. // ------------------------------------------------------------------------
  366. //
  367. // CAsyncReadVisitor::VisitStream()
  368. //
  369. VOID
  370. CAsyncReadVisitor::VisitStream( IAsyncStream& stmSrc,
  371. UINT cbToRead,
  372. IAcceptObserver& obsAccept )
  373. {
  374. //
  375. // Read into our user's buffer only as much of the stream as is
  376. // immediately available -- i.e. the amount of data that can be
  377. // read without pending the read operation. Note that on input
  378. // cbToRead is the amount of data remaining to be read from the
  379. // stream -- it is not all necessarily immediately available.
  380. //
  381. // X5 162502: This used to say min(stmSrc.CbReady(),...) here
  382. // instead of min(cbToRead,...). This was not a problem on IIS5
  383. // because there was always at least some data immediately available
  384. // when our ISAPI was called. However, on the Local Store, it may
  385. // be such that when we call the ISAPI, there is no data immediately
  386. // available. This turned out to be a problem because we would get
  387. // here and cbToRead would be assigned to 0, which would end up
  388. // making it look like we'd finished (end of stream), which would
  389. // cause XML parse errors (0-byte XML bodies don't parse well!).
  390. //
  391. cbToRead = min(cbToRead, m_cbBufUser);
  392. //
  393. // Save off the observer and start reading. Even though this is
  394. // an AsyncRead() call, we have limited the request to what can
  395. // be read immediately, so our ReadComplete() should be called
  396. // before the AsyncRead() call returns. This is important because
  397. // we are reading directly into the user's buffer. The buffer
  398. // is valid for the duration of this visit.
  399. //
  400. m_pobsAccept = &obsAccept;
  401. stmSrc.AsyncRead(m_pbBufUser, cbToRead, *this);
  402. }
  403. // ------------------------------------------------------------------------
  404. //
  405. // CAsyncReadVisitor::ReadComplete()
  406. //
  407. // Called when the AsyncRead() of the stream by VisitStream() completes.
  408. //
  409. VOID
  410. CAsyncReadVisitor::ReadComplete( UINT cbRead, HRESULT hr )
  411. {
  412. //
  413. // Latch in any error returned.
  414. //
  415. m_hr = hr;
  416. //
  417. // Notify our observer of the number of bytes read.
  418. //
  419. Assert(m_pobsAccept);
  420. m_pobsAccept->AcceptComplete(cbRead);
  421. }
  422. // ------------------------------------------------------------------------
  423. //
  424. // CAsyncReadVisitor::VisitComplete()
  425. //
  426. VOID
  427. CAsyncReadVisitor::VisitComplete()
  428. {
  429. m_hr = S_FALSE;
  430. }
  431. // ========================================================================
  432. //
  433. // CLASS CAsyncCopyToVisitor
  434. //
  435. // A body part visitor that asynchronously copies body parts into
  436. // a destination async stream.
  437. //
  438. class CAsyncCopyToVisitor :
  439. public IBodyPartVisitor,
  440. private IAsyncWriteObserver,
  441. private IAsyncCopyToObserver
  442. {
  443. //
  444. // CAsyncCopyToVisitor forwards its refcounting calls to this
  445. // parent object (settable via SetRCParent()). We are a non-refcounted
  446. // member of another object (e.g. CAsyncPersistor below) -- so our
  447. // lifetime must be determined by the lifetime of our parent object.
  448. //
  449. IRefCounted * m_prcParent;
  450. //
  451. // Error information
  452. //
  453. HRESULT m_hr;
  454. //
  455. // The destination stream
  456. //
  457. IAsyncStream * m_pstmDst;
  458. //
  459. // The count of bytes to copy and the count copied
  460. //
  461. ULONG m_cbToCopy;
  462. ULONG m_cbCopied;
  463. //
  464. // The Accept() observer to notify when we're done
  465. // visiting upon completion of an AsyncWrite()
  466. // or AsyncCopyTo() on the destination stream.
  467. //
  468. IAcceptObserver * m_pobsAccept;
  469. //
  470. // IBodyPartVisitor
  471. //
  472. VOID VisitBytes( const BYTE * pbData,
  473. UINT cbToCopy,
  474. IAcceptObserver& obsAccept );
  475. VOID VisitFile( const auto_ref_handle& hf,
  476. UINT64 ibOffset64,
  477. UINT64 cbToCopy64,
  478. IAcceptObserver& obsAccept );
  479. VOID VisitStream( IAsyncStream& stm,
  480. UINT cbToCopy,
  481. IAcceptObserver& obsAccept );
  482. VOID VisitComplete();
  483. //
  484. // IAsyncWriteObserver
  485. //
  486. VOID WriteComplete( UINT cbWritten, HRESULT hr );
  487. //
  488. // IAsyncCopyToObserver
  489. //
  490. VOID CopyToComplete( UINT cbCopied, HRESULT hr );
  491. // NOT IMPLEMENTED
  492. //
  493. CAsyncCopyToVisitor( const CAsyncCopyToVisitor& );
  494. CAsyncCopyToVisitor& operator=( const CAsyncCopyToVisitor& );
  495. public:
  496. // CREATORS
  497. //
  498. CAsyncCopyToVisitor() :
  499. m_prcParent(NULL),
  500. m_hr(S_OK),
  501. m_pstmDst(NULL),
  502. m_cbToCopy(0),
  503. m_cbCopied(0)
  504. {
  505. }
  506. // ACCESSORS
  507. //
  508. HRESULT Hresult() const { return m_hr; }
  509. UINT CbCopied() const { return m_cbCopied; }
  510. // MANIPULATORS
  511. //
  512. VOID
  513. Configure( IAsyncStream& stmDst,
  514. ULONG cbToCopy )
  515. {
  516. m_pstmDst = &stmDst;
  517. m_cbToCopy = cbToCopy;
  518. m_cbCopied = 0;
  519. m_hr = S_OK;
  520. }
  521. VOID
  522. SetRCParent(IRefCounted * prcParent)
  523. {
  524. Assert(prcParent);
  525. m_prcParent = prcParent;
  526. }
  527. // Refcounting for IAsyncWriteObserver. Since this is not a refcounted
  528. // object we forward the refcouting to the object with which we
  529. // were configured.
  530. //
  531. void AddRef()
  532. {
  533. Assert( m_prcParent );
  534. m_prcParent->AddRef();
  535. }
  536. void Release()
  537. {
  538. Assert( m_prcParent );
  539. m_prcParent->Release();
  540. }
  541. };
  542. // ------------------------------------------------------------------------
  543. //
  544. // CAsyncCopyToVisitor::WriteComplete()
  545. //
  546. void
  547. CAsyncCopyToVisitor::WriteComplete( UINT cbWritten, HRESULT hr )
  548. {
  549. ActvTrace( "DAV: TID %3d: 0x%08lX: CAsyncCopyToVisitor::WriteComplete() called. hr = 0x%08lX, cbWritten = %u\n", GetCurrentThreadId(), this, hr, cbWritten );
  550. m_cbCopied += cbWritten;
  551. m_hr = hr;
  552. m_pobsAccept->AcceptComplete( cbWritten );
  553. }
  554. // ------------------------------------------------------------------------
  555. //
  556. // CAsyncCopyToVisitor::VisitBytes()
  557. //
  558. void
  559. CAsyncCopyToVisitor::VisitBytes( const BYTE * pbData,
  560. UINT cbToCopy,
  561. IAcceptObserver& obsAccept )
  562. {
  563. ActvTrace( "DAV: TID %3d: 0x%08lX: CAsyncCopyToVisitor::VisitBytes() called. cbToCopy = %u\n", GetCurrentThreadId(), this, cbToCopy );
  564. //
  565. // Remember the accept observer so that we can notify it when
  566. // the AsyncWrite() below completes.
  567. //
  568. m_pobsAccept = &obsAccept;
  569. //
  570. // Start writing
  571. //
  572. cbToCopy = min( cbToCopy, m_cbToCopy - m_cbCopied );
  573. m_pstmDst->AsyncWrite( pbData, cbToCopy, *this );
  574. }
  575. // ------------------------------------------------------------------------
  576. //
  577. // CAsyncCopyToVisitor::VisitFile()
  578. //
  579. // Not implemented because 1) request bodies cannot have file
  580. // body parts and 2) CAsyncCopyToVisitor is currently only used
  581. // with request bodies. Should we ever need this for response
  582. // bodies we'll need to write the code at that point.
  583. //
  584. // The old implementation used ReadFileEx() to read from the file
  585. // asynchronously. In a nutshell, we couldn't use ReadFileEx()
  586. // because it relied on APC for calling back its completion routine.
  587. // APC in turn required the calling thread to enter an alertable
  588. // wait state. Typically, we would only call VisitFile() from an
  589. // I/O completion port thread pool, and those threads are never
  590. // in an alertable wait state, thus the completion routine for
  591. // ReadFileEx() would never be called.
  592. //
  593. void
  594. CAsyncCopyToVisitor::VisitFile( const auto_ref_handle&,
  595. UINT64,
  596. UINT64,
  597. IAcceptObserver& obsAccept )
  598. {
  599. TrapSz( "CAsyncCopyToVisitor::VisitFile() is not implemented!!" );
  600. //
  601. // If, for whatever random reason, someone actually does call
  602. // this function, at least do something predictable: fail gracefully.
  603. //
  604. m_hr = E_FAIL;
  605. obsAccept.AcceptComplete( 0 );
  606. }
  607. // ------------------------------------------------------------------------
  608. //
  609. // CAsyncCopyToVisitor::VisitStream()
  610. //
  611. void
  612. CAsyncCopyToVisitor::VisitStream( IAsyncStream& stmSrc,
  613. UINT cbToCopy,
  614. IAcceptObserver& obsAccept )
  615. {
  616. ActvTrace( "DAV: TID %3d: 0x%08lX: CAsyncCopyToVisitor::VisitStream() called. cbToCopy = %u\n", GetCurrentThreadId(), this, cbToCopy );
  617. //
  618. // Remember the accept observer so that we can notify it when
  619. // the AsyncCopyTo() below completes.
  620. //
  621. m_pobsAccept = &obsAccept;
  622. //
  623. // Start copying
  624. //
  625. cbToCopy = min( cbToCopy, m_cbToCopy - m_cbCopied );
  626. stmSrc.AsyncCopyTo( *m_pstmDst, cbToCopy, *this );
  627. }
  628. // ------------------------------------------------------------------------
  629. //
  630. // CAsyncCopyToVisitor::CopyToComplete()
  631. //
  632. void
  633. CAsyncCopyToVisitor::CopyToComplete( UINT cbCopied, HRESULT hr )
  634. {
  635. m_cbCopied += cbCopied;
  636. m_hr = hr;
  637. ActvTrace( "DAV: TID %3d: 0x%08lX: CAsyncCopyToVisitor::CopyToComplete() hr = 0x%08lX, cbCopied = %u, m_cbCopied = %u\n", GetCurrentThreadId(), this, hr, cbCopied, m_cbCopied );
  638. m_pobsAccept->AcceptComplete( cbCopied );
  639. }
  640. // ------------------------------------------------------------------------
  641. //
  642. // CAsyncCopyToVisitor::VisitComplete()
  643. //
  644. VOID
  645. CAsyncCopyToVisitor::VisitComplete()
  646. {
  647. m_hr = S_FALSE;
  648. }
  649. // ========================================================================
  650. //
  651. // CLASS CBodyAsIStream
  652. //
  653. // Provides once-only access to the entire body as an OLE COM IStream using
  654. // either IStream::Read() and IStream::CopyTo().
  655. //
  656. class CBodyAsIStream :
  657. public CStreamNonImpl,
  658. private IAcceptObserver
  659. {
  660. //
  661. // Iterator used to traverse the body
  662. //
  663. IBody::iterator * m_pitBody;
  664. //
  665. // The three states of the read operation started by the most recent
  666. // call to CBodyAsIStream::Read():
  667. //
  668. // READ_ACTIVE
  669. // The read is active. It may or may not complete
  670. // synchronously. This is the initial state.
  671. //
  672. // READ_PENDING
  673. // The read is pending. The read did not complete before
  674. // we had to return to the caller. CBodyAsIStream::Read()
  675. // returns E_PENDING and the stream observer (below) is notified
  676. // when the read completes.
  677. //
  678. // READ_COMPLETE
  679. // The read completed before we had to return to the
  680. // caller. CBodyAsIStream::Read() does not return E_PENDING
  681. // and the stream observer (below) is not notified.
  682. //
  683. // Note: m_lStatus is meaningless (and hence uninitialized/invalid) until
  684. // CBodyAsIStream::Read() is called.
  685. //
  686. enum
  687. {
  688. READ_ACTIVE,
  689. READ_PENDING,
  690. READ_COMPLETE,
  691. READ_INVALID_STATUS = -1
  692. };
  693. LONG m_lStatus;
  694. //
  695. // Status of last completed operation.
  696. //
  697. HRESULT m_hr;
  698. //
  699. // Async visitor used for Read().
  700. //
  701. CAsyncReadVisitor m_arv;
  702. //
  703. // Count of bytes read in the visit started by the most recent
  704. // call to CBodyAsIStream::Read().
  705. //
  706. // Note: m_cbRead is meaningless (and hence uninitialized) until
  707. // CBodyAsIStream::Read() is called.
  708. //
  709. UINT m_cbRead;
  710. //
  711. // Reference to the async I/O completion observer. We notify this
  712. // observer from CBodyAsIStream::AcceptComplete() when the async
  713. // Accept() call we make in CBodyAsIStream::Read() completes for
  714. // a read that we have pended.
  715. //
  716. IAsyncIStreamObserver& m_obsStream;
  717. // IAcceptObserver callback used when accepting async read visitor
  718. // to asynchronoulsy refill the buffer.
  719. //
  720. VOID AcceptComplete( UINT64 cbRead64 );
  721. // NOT IMPLEMENTED
  722. //
  723. CBodyAsIStream( const CBodyAsIStream& );
  724. CBodyAsIStream& operator=( const CBodyAsIStream& );
  725. public:
  726. CBodyAsIStream( IBody& body,
  727. IAsyncIStreamObserver& obs ) :
  728. m_pitBody(body.GetIter()),
  729. m_lStatus(READ_INVALID_STATUS),
  730. m_hr(S_OK),
  731. m_cbRead(0),
  732. m_obsStream(obs)
  733. {
  734. }
  735. // COM IStream ACCESSORS/MANIPULATORS
  736. //
  737. virtual /* [local] */ HRESULT STDMETHODCALLTYPE Read(
  738. /* [length_is][size_is][out] */ void __RPC_FAR *,
  739. /* [in] */ ULONG,
  740. /* [out] */ ULONG __RPC_FAR *);
  741. //$WORKAROUND: MSXML is calling our Stat() method. (X5#89140)
  742. // Our parent (CStreamNonImpl) has a TrapSz() there, so
  743. // avoid it by implementing our own Stat() call here,
  744. // that just returns E_NOTIMPL.
  745. // MSXML doesn't care if this is not implemented, just so long
  746. // as it doesn't crash/assert/dbgbreak. If they get results
  747. // back here, they do other security checking that we don't
  748. // need or want!
  749. //
  750. virtual HRESULT STDMETHODCALLTYPE Stat(
  751. /* [out] */ STATSTG __RPC_FAR *,
  752. /* [in] */ DWORD)
  753. {
  754. return E_NOTIMPL;
  755. }
  756. //$WORKAROUND: end
  757. };
  758. // ------------------------------------------------------------------------
  759. //
  760. // CBodyAsIStream::Read()
  761. //
  762. HRESULT STDMETHODCALLTYPE
  763. CBodyAsIStream::Read( LPVOID pv,
  764. ULONG cbToRead,
  765. ULONG * pcbRead )
  766. {
  767. HRESULT hr = S_OK;
  768. Assert( cbToRead > 0 );
  769. Assert( !IsBadWritePtr(pv, cbToRead) );
  770. Assert( !pcbRead || !IsBadWritePtr(pcbRead, sizeof(ULONG)) );
  771. BodyStreamTrace( "DAV: TID %3d: 0x%08lX: CBodyAsIStream::Read() called to read %lu bytes from stream\n", GetCurrentThreadId(), this, cbToRead );
  772. //
  773. // If we are called on the Read() again while the previous read is pending
  774. // return with the same indication - that operation is still pending.
  775. // This is done to protect ourselves from the external callers like MSXML
  776. // parser, that tries to read data from us, we return E_PENDING, and then
  777. // they are turning around and calling into us again without waiting for
  778. // the previous pending read to complete. Our code does handle only one
  779. // outstanding async IO at a time. So the check below allows us to ignore
  780. // the IOs that are attempted to start while previous one is pending. This
  781. // works as long as the caller does expect to be called back only once for
  782. // any amount of async IOs issued while the original IO is still pending.
  783. // If the last condition is not met the only thing left to us would be to
  784. // error out so we do not crash and for the callers to fix their behaviour
  785. // so the code would work.
  786. //
  787. if (READ_PENDING == InterlockedCompareExchange( &m_lStatus,
  788. READ_PENDING,
  789. READ_PENDING ))
  790. {
  791. return E_PENDING;
  792. }
  793. //
  794. // As this is an STDMETHODCALLTYPE function, we need to wrap the whole thing
  795. // in a try/catch block to keep exceptions due to memory allocation failures
  796. // from propagating out.
  797. //
  798. // Note: We don't expect anything in this try/catch block to throw a "hard"
  799. // Win32 exception so we don't need a CWin32ExceptionHandler in the block.
  800. //
  801. try
  802. {
  803. //
  804. // Check for errors from the previous (pended) read.
  805. //
  806. hr = m_arv.Hresult();
  807. if ( FAILED(hr) )
  808. {
  809. DebugTrace( "CBodyAsIStream::Read() - Error from previous async read 0x%08lX\n", hr );
  810. goto ret;
  811. }
  812. //
  813. // Set up our visitor to read directly into the caller's buffer.
  814. //
  815. m_arv.Configure(static_cast<LPBYTE>(pv), cbToRead);
  816. //
  817. // Clear out the count of bytes read from the previous run
  818. //
  819. m_cbRead = 0;
  820. //
  821. // Set our status to actively reading. When we call Accept(), this status will
  822. // change in one of two possible ways: If we finish accepting before our
  823. // Accept() call returns then the status will be set to READ_COMPLETE and
  824. // we will complete this Read() call synchronously. If not then it will still
  825. // be set to READ_ACTIVE at the point where we test and set it below to
  826. // READ_PENDING.
  827. //
  828. m_lStatus = READ_ACTIVE;
  829. //
  830. // Visit the body.
  831. //
  832. m_pitBody->Accept( m_arv, *this );
  833. //
  834. // Check the visit status. If the visit has not completed at this
  835. // point then attempt to pend the read operation and return E_PENDING
  836. // to our caller. If we successfully pend the operation then our
  837. // AcceptComplete() routine will notify our stream observer when the
  838. // read completes.
  839. //
  840. if ( READ_ACTIVE == m_lStatus &&
  841. READ_ACTIVE == InterlockedExchange( &m_lStatus, READ_PENDING ) )
  842. {
  843. BodyStreamTrace( "DAV: TID %3d: 0x%08lX: CBodyAsIStream::Read() Returning E_PENDING\n", GetCurrentThreadId(), this );
  844. hr = E_PENDING;
  845. goto ret;
  846. }
  847. //
  848. // Check for errors from the current read.
  849. //
  850. hr = m_arv.Hresult();
  851. if ( FAILED(hr) )
  852. {
  853. DebugTrace( "CBodyAsIStream::Read() - Error from current read 0x%08lX\n", hr );
  854. goto ret;
  855. }
  856. //
  857. // If we're at End Of Stream then return what we got.
  858. //
  859. if ( S_FALSE == hr )
  860. {
  861. //
  862. // Don't return S_FALSE when we're also returning
  863. // data. The IStream spec is unclear on whether
  864. // that is allowed.
  865. //
  866. if ( m_cbRead > 0 )
  867. hr = S_OK;
  868. }
  869. //
  870. // Return the number of bytes read if the caller asked for
  871. // that information.
  872. //
  873. if ( pcbRead )
  874. *pcbRead = m_cbRead;
  875. }
  876. catch ( CDAVException& e )
  877. {
  878. hr = e.Hresult();
  879. Assert( FAILED(hr) );
  880. }
  881. ret:
  882. return hr;
  883. }
  884. // ------------------------------------------------------------------------
  885. //
  886. // CBodyAsIStream::AcceptComplete()
  887. //
  888. // Called when the Accept() call started in Read() to asynchronously
  889. // refill the buffer completes.
  890. //
  891. VOID
  892. CBodyAsIStream::AcceptComplete( UINT64 cbRead64 )
  893. {
  894. BodyStreamTrace( "DAV: TID %3d: 0x%08lX: CBodyAsIStream::AcceptComplete() cbRead64 = %lu\n", GetCurrentThreadId(), this, cbRead64 );
  895. //
  896. // Update the count of bytes that our Accept() call successfully
  897. // read into the user's buffer. We are accepting in piecies so the
  898. // accepted amount should be really much less than 4GB.
  899. //
  900. Assert(0 == (0xFFFFFFFF00000000 & cbRead64));
  901. m_cbRead = static_cast<UINT>(cbRead64);
  902. //
  903. // Set status to READ_COMPLETE. If the read operation pended --
  904. // i.e. the previous state was READ_PENDING, not READ_ACTIVE --
  905. // then we must wake up the stream observer and tell it that
  906. // we are done.
  907. //
  908. if ( READ_PENDING == InterlockedExchange( &m_lStatus, READ_COMPLETE ) )
  909. m_obsStream.AsyncIOComplete();
  910. }
  911. // ========================================================================
  912. //
  913. // CLASS CAsyncPersistor
  914. //
  915. // Implements an async driven object to persist a body to an IAsyncStream.
  916. //
  917. class CAsyncPersistor :
  918. public CMTRefCounted,
  919. public IRefCounted,
  920. private IAcceptObserver
  921. {
  922. //
  923. // Body iterator
  924. //
  925. IBody::iterator * m_pitBody;
  926. //
  927. // Async driving mechanism
  928. //
  929. CAsyncDriver<CAsyncPersistor> m_driver;
  930. friend class CAsyncDriver<CAsyncPersistor>;
  931. //
  932. // Caller-supplied observer to notify when we're done persisting.
  933. //
  934. auto_ref_ptr<IAsyncPersistObserver> m_pobsPersist;
  935. //
  936. // CopyTo visitor used to persist the body
  937. //
  938. CAsyncCopyToVisitor m_actv;
  939. //
  940. // CAsyncDriver callback
  941. //
  942. VOID Run();
  943. //
  944. // IAcceptObserver callback used when accepting async copyto visitor
  945. // to asynchronously persist the body to the destination stream.
  946. //
  947. VOID AcceptComplete( UINT64 cbCopied64 );
  948. // NOT IMPLEMENTED
  949. //
  950. CAsyncPersistor( const CAsyncPersistor& );
  951. CAsyncPersistor& operator=( const CAsyncPersistor& );
  952. public:
  953. // CREATORS
  954. //
  955. CAsyncPersistor( IBody& body,
  956. IAsyncStream& stm,
  957. IAsyncPersistObserver& obs ) :
  958. m_pitBody(body.GetIter()),
  959. m_pobsPersist(&obs)
  960. {
  961. //
  962. // Set the CopyTo() parameters here, once. If we ever need
  963. // to copy request bodies larger than ULONG_MAX bytes, we'll
  964. // need to move this call down into Run().
  965. //
  966. m_actv.Configure(stm, ULONG_MAX);
  967. }
  968. // MANIUPLATORS
  969. //
  970. VOID Start()
  971. {
  972. m_driver.Start(*this);
  973. }
  974. // Refcounting -- forward all refcounting requests to our refcounting
  975. // implementation base class: CMTRefCounted.
  976. //
  977. void AddRef() { CMTRefCounted::AddRef(); }
  978. void Release() { CMTRefCounted::Release(); }
  979. };
  980. // ------------------------------------------------------------------------
  981. //
  982. // CAsyncPersistor::Run()
  983. //
  984. VOID
  985. CAsyncPersistor::Run()
  986. {
  987. PersistTrace( "DAV: TID %3d: 0x%08lX: CAsyncPersistor::Run() called\n", GetCurrentThreadId(), this );
  988. //
  989. // AddRef() for Accept(). Use auto_ref_ptr for exception-safety.
  990. //
  991. auto_ref_ptr<CAsyncPersistor> pRef(this);
  992. m_actv.SetRCParent(this);
  993. m_pitBody->Accept(m_actv, *this);
  994. pRef.relinquish();
  995. }
  996. // ------------------------------------------------------------------------
  997. //
  998. // CAsyncPersistor::AcceptComplete()
  999. //
  1000. VOID
  1001. CAsyncPersistor::AcceptComplete( UINT64 cbCopied64 )
  1002. {
  1003. //
  1004. // Take ownership of the reference added in Run().
  1005. //
  1006. auto_ref_ptr<CAsyncPersistor> pRef;
  1007. pRef.take_ownership(this);
  1008. //
  1009. // We're done when the status of the CopyTo visitor is
  1010. // S_FALSE (success) or an error.
  1011. //
  1012. HRESULT hr = m_actv.Hresult();
  1013. PersistTrace( "DAV: TID %3d: 0x%08lX: CAsyncPersistor::AcceptComplete() hr = 0x%08lX\n, cbCopied64 = %ud\n", GetCurrentThreadId(), this, hr, cbCopied64 );
  1014. if ( FAILED(hr) || S_FALSE == hr )
  1015. {
  1016. Assert( m_pobsPersist.get() );
  1017. m_pobsPersist->PersistComplete(hr);
  1018. }
  1019. else
  1020. {
  1021. Start();
  1022. }
  1023. }
  1024. // ========================================================================
  1025. //
  1026. // CLASS IBody
  1027. //
  1028. // ------------------------------------------------------------------------
  1029. //
  1030. // IBody::~IBody()
  1031. //
  1032. // Out of line virtual destructor necessary for proper deletion
  1033. // of objects of derived classes via this class
  1034. //
  1035. IBody::~IBody() {}
  1036. // ========================================================================
  1037. //
  1038. // CLASS IBody::iterator
  1039. //
  1040. // ------------------------------------------------------------------------
  1041. //
  1042. // IBody::iterator::~iterator()
  1043. //
  1044. // Out of line virtual destructor necessary for proper deletion
  1045. // of objects of derived classes via this class
  1046. //
  1047. IBody::iterator::~iterator() {}
  1048. // ========================================================================
  1049. //
  1050. // CLASS CList
  1051. //
  1052. // The body part list implementation uses the STL list template.
  1053. // Body parts are stored in auto_ptrs so that they are automatically
  1054. // destroyed as they are removed from the list or when the list itself is
  1055. // destroyed.
  1056. //
  1057. // This class does not by itself need to provide any sort of thread-safety.
  1058. //
  1059. typedef std::list<
  1060. auto_ptr_obsolete<IBodyPart>,
  1061. heap_allocator< auto_ptr_obsolete<IBodyPart> >
  1062. > CList;
  1063. // ========================================================================
  1064. //
  1065. // CLASS CBodyPartList
  1066. //
  1067. // Encapsulates access to the list of body parts. The reason for this
  1068. // seemingly extra level of encapsulation is that it enables us to
  1069. // change the list implementation easily without touching code which
  1070. // uses the list.
  1071. //
  1072. // !!! IMPORTANT !!!
  1073. // When accessing/modifying the raw STL list through CBodyPartList,
  1074. // we must acquire our critical section. Threads may be iterating
  1075. // over the list via our iterator, CBodyPartListIter, while we are modifying
  1076. // the list and the STL list and its iterator are not thread-safe.
  1077. // In other words, CBodyPartListIter and CBodyPartList share the same critsec.
  1078. //
  1079. class CBodyPartList
  1080. {
  1081. // The list
  1082. //
  1083. CList m_list;
  1084. // Critical section to serialize access to the above list
  1085. //
  1086. CCriticalSection m_csList;
  1087. // NOT IMPLEMENTED
  1088. //
  1089. CBodyPartList( const CBodyPartList& );
  1090. CBodyPartList& operator=( const CBodyPartList& );
  1091. friend class CBodyPartListIter;
  1092. public:
  1093. // CREATORS
  1094. //
  1095. CBodyPartList() {}
  1096. // ACCESSORS
  1097. //
  1098. const BOOL FIsEmpty() const
  1099. {
  1100. //
  1101. // Note: we don't currently acquire the critical section
  1102. // proctecting the raw list as we expect this function
  1103. // to not be called once we are accessing the list
  1104. // from multiple threads.
  1105. //
  1106. //
  1107. // Return whether there are any body parts in the list
  1108. //
  1109. return m_list.empty();
  1110. }
  1111. // MANIPULATORS
  1112. //
  1113. VOID Clear()
  1114. {
  1115. //
  1116. // Note: we don't currently acquire the critical section
  1117. // proctecting the raw list as we expect this function
  1118. // to not be called once we are accessing the list
  1119. // from multiple threads.
  1120. //
  1121. //
  1122. // Remove all body parts from the list (at which point they
  1123. // should be automatically destroyed).
  1124. //
  1125. m_list.clear();
  1126. }
  1127. VOID PushPart( IBodyPart * pBodyPart )
  1128. {
  1129. CSynchronizedBlock sb(m_csList);
  1130. //
  1131. // Our iterator (CBodyPartList iter, below) uses the STL
  1132. // list reverse_iterator to traverse the list from back to
  1133. // front, so we append body parts to the *front* of the list.
  1134. //
  1135. m_list.push_front( auto_ptr_obsolete<IBodyPart>(pBodyPart) );
  1136. }
  1137. };
  1138. // ========================================================================
  1139. //
  1140. // CLASS CBodyPartListIter
  1141. //
  1142. // Implements an iterator for CBodyPartList
  1143. //
  1144. // This implementation uses the reverse STL list iterator corresponding
  1145. // to the usage of the STL list type in CBodyPartList. STL iterators
  1146. // have some syntactic sugar that we need to note here:
  1147. //
  1148. // * (deref) of an iterator gives the thing pointed to
  1149. // ++ (increment) of an iterator goes to the "next" item
  1150. // -- (decrement) of an iterator goes to the "previous" item
  1151. //
  1152. // We use the reverse iterator because of the behavior we need at
  1153. // the end of the list w.r.t. adding new items. When an iterator
  1154. // reaches the end of the list and items are later added there,
  1155. // we want the iterator to refer to the first of the new items rather
  1156. // than the new end-of-list. The forward STL iterator has the
  1157. // latter behavior.
  1158. //
  1159. // !!! IMPORTANT !!!
  1160. // When accessing/modifying the raw STL list through our iterator
  1161. // we must acquire CBodyPartList's critical section. Threads may
  1162. // be modifying the list while we are iterating through it and
  1163. // the STL list and its iterator are not thread-safe. In other words,
  1164. // CBodyPartListIter and CBodyPartList share the same critsec.
  1165. //
  1166. class CBodyPartListIter
  1167. {
  1168. // Pointer to the list to iterate on
  1169. //
  1170. CBodyPartList * m_pBodyPartList;
  1171. // The raw STL list iterator
  1172. //
  1173. CList::reverse_iterator m_itRaw;
  1174. // CBodyPartList ACCESSORS
  1175. //
  1176. CCriticalSection& CritsecList() const
  1177. {
  1178. Assert( m_pBodyPartList );
  1179. return m_pBodyPartList->m_csList;
  1180. }
  1181. CList& RawList() const
  1182. {
  1183. Assert( m_pBodyPartList );
  1184. return m_pBodyPartList->m_list;
  1185. }
  1186. // NOT IMPLEMENTED
  1187. //
  1188. CBodyPartListIter( const CBodyPartListIter& );
  1189. CBodyPartListIter& operator=( const CBodyPartListIter& );
  1190. public:
  1191. // CREATORS
  1192. //
  1193. CBodyPartListIter() :
  1194. m_pBodyPartList(NULL)
  1195. {
  1196. }
  1197. VOID Start( CBodyPartList& m_bodyPartList )
  1198. {
  1199. m_pBodyPartList = &m_bodyPartList;
  1200. //
  1201. // Note: we don't currently acquire the critical section
  1202. // proctecting the raw list as we expect this function
  1203. // to not be called once we are accessing the list
  1204. // from multiple threads.
  1205. //
  1206. m_itRaw = RawList().rbegin();
  1207. }
  1208. // ACCESSORS
  1209. //
  1210. BOOL FDone()
  1211. {
  1212. CSynchronizedBlock sb(CritsecList());
  1213. return m_itRaw == RawList().rend();
  1214. }
  1215. IBodyPart * PItem()
  1216. {
  1217. CSynchronizedBlock sb(CritsecList());
  1218. return *m_itRaw;
  1219. }
  1220. // MANIPULATORS
  1221. //
  1222. // ------------------------------------------------------------------------
  1223. //
  1224. // CBody::Prune()
  1225. //
  1226. // Bumps the iterator to the next item in the list
  1227. //
  1228. VOID Next()
  1229. {
  1230. CSynchronizedBlock sb(CritsecList());
  1231. //
  1232. // We had better not already be at the end...
  1233. //
  1234. Assert( m_itRaw != RawList().rend() );
  1235. ++m_itRaw;
  1236. }
  1237. // ------------------------------------------------------------------------
  1238. //
  1239. // CBody::Prune()
  1240. //
  1241. // Prunes the list at this iterator's current position. Removes items
  1242. // from the current position to the end of the list. Does not remove
  1243. // the current item.
  1244. //
  1245. VOID Prune()
  1246. {
  1247. CSynchronizedBlock sb(CritsecList());
  1248. //
  1249. // Unfortunately the STL only allows us to erase between two
  1250. // forward iterators. And there is no way to get a forward
  1251. // iterator directly from a reverse iterator. So we must
  1252. // start a forward iterator at the end of the list and walk
  1253. // it backward the same distance that our reverse iterator
  1254. // is from its "beginning" of the list and then erase the
  1255. // items between the forward iterator and the end of the list.
  1256. //
  1257. CList::iterator itErase = RawList().end();
  1258. for ( CList::reverse_iterator it = RawList().rbegin();
  1259. it != m_itRaw;
  1260. ++it )
  1261. {
  1262. --itErase;
  1263. }
  1264. if ( itErase != RawList().end() )
  1265. RawList().erase( ++itErase, RawList().end() );
  1266. }
  1267. };
  1268. // ========================================================================
  1269. //
  1270. // CLASS CBody
  1271. //
  1272. class CBody : public IBody
  1273. {
  1274. // ========================================================================
  1275. //
  1276. // CLASS iterator
  1277. //
  1278. class iterator :
  1279. public IBody::iterator,
  1280. private IAcceptObserver
  1281. {
  1282. //
  1283. // Iterator to walk the body part list.
  1284. //
  1285. CBodyPartListIter m_itPart;
  1286. //
  1287. // Pointer to the current body part referred to by the
  1288. // above iterator.
  1289. //
  1290. IBodyPart * m_pBodyPart;
  1291. //
  1292. // Current position in the above part.
  1293. //
  1294. UINT64 m_ibPart64;
  1295. //
  1296. // Observer to call when Accept() completes -- set on each
  1297. // Accept() call.
  1298. //
  1299. IAcceptObserver * m_pobsAccept;
  1300. //
  1301. // IAcceptObserver
  1302. //
  1303. VOID AcceptComplete( UINT64 cbAccepted64 );
  1304. // NOT IMPLEMENTED
  1305. //
  1306. iterator( const iterator& );
  1307. iterator& operator=( const iterator& );
  1308. public:
  1309. iterator() {}
  1310. VOID Start( CBodyPartList& bodyPartList )
  1311. {
  1312. m_itPart.Start(bodyPartList);
  1313. m_pBodyPart = NULL;
  1314. }
  1315. VOID Accept( IBodyPartVisitor& v,
  1316. IAcceptObserver& obsAccept );
  1317. VOID Prune();
  1318. };
  1319. // Body part list and current position in that list
  1320. //
  1321. CBodyPartList m_bodyPartList;
  1322. // Our iterator
  1323. //
  1324. iterator m_it;
  1325. //
  1326. // Inline helper to add a body part
  1327. //
  1328. void _AddBodyPart( IBodyPart * pBodyPart )
  1329. {
  1330. m_bodyPartList.PushPart(pBodyPart);
  1331. }
  1332. // NOT IMPLEMENTED
  1333. //
  1334. CBody( const CBody& );
  1335. CBody& operator=( const CBody& );
  1336. public:
  1337. CBody() {}
  1338. // ACCESSORS
  1339. //
  1340. BOOL FIsEmpty() const;
  1341. BOOL FIsAtEnd() const;
  1342. UINT64 CbSize64() const;
  1343. // MANIPULATORS
  1344. //
  1345. void AddText( LPCSTR lpszText,
  1346. UINT cbText );
  1347. void AddFile( const auto_ref_handle& hf,
  1348. UINT64 ibFile,
  1349. UINT64 cbFile );
  1350. void AddStream( IStream& stm );
  1351. void AddStream( IStream& stm,
  1352. UINT ibOffset,
  1353. UINT cbSize );
  1354. void AddBodyPart( IBodyPart * pBodyPart );
  1355. void AsyncPersist( IAsyncStream& stm,
  1356. IAsyncPersistObserver& obs );
  1357. IStream * GetIStream( IAsyncIStreamObserver& obs )
  1358. {
  1359. return new CBodyAsIStream(*this, obs);
  1360. }
  1361. IBody::iterator * GetIter();
  1362. VOID Clear();
  1363. };
  1364. // ------------------------------------------------------------------------
  1365. //
  1366. // CBody::GetIter()
  1367. //
  1368. IBody::iterator *
  1369. CBody::GetIter()
  1370. {
  1371. m_it.Start(m_bodyPartList);
  1372. return &m_it;
  1373. }
  1374. // ------------------------------------------------------------------------
  1375. //
  1376. // CBody::FIsEmpty()
  1377. //
  1378. BOOL
  1379. CBody::FIsEmpty() const
  1380. {
  1381. return m_bodyPartList.FIsEmpty();
  1382. }
  1383. // ------------------------------------------------------------------------
  1384. //
  1385. // CBody::CbSize64()
  1386. //
  1387. UINT64
  1388. CBody::CbSize64() const
  1389. {
  1390. UINT64 cbSize64 = 0;
  1391. //
  1392. // Sum the sizes of all the body parts
  1393. //
  1394. CBodyPartListIter it;
  1395. for ( it.Start(const_cast<CBodyPartList&>(m_bodyPartList));
  1396. !it.FDone();
  1397. it.Next() )
  1398. {
  1399. cbSize64 += it.PItem()->CbSize64();
  1400. }
  1401. return cbSize64;
  1402. }
  1403. // ------------------------------------------------------------------------
  1404. //
  1405. // CBody::AddText()
  1406. //
  1407. // Adds static text to the body by creating a text body part with
  1408. // its own copy of the text and adding that body part to the
  1409. // body part list.
  1410. //
  1411. // !!!
  1412. // For best performance, implement your own text body part on top
  1413. // of your text data source rather than copying it via this function
  1414. // as doing so avoids making an extra copy of the data from the
  1415. // data source in memory.
  1416. //
  1417. void
  1418. CBody::AddText( LPCSTR lpszText, UINT cbText )
  1419. {
  1420. _AddBodyPart( new CTextBodyPart(cbText, lpszText) );
  1421. }
  1422. // ------------------------------------------------------------------------
  1423. //
  1424. // CBody::AddFile()
  1425. //
  1426. void
  1427. CBody::AddFile( const auto_ref_handle& hf,
  1428. UINT64 ibFile64,
  1429. UINT64 cbFile64 )
  1430. {
  1431. _AddBodyPart( new CFileBodyPart(hf, ibFile64, cbFile64) );
  1432. }
  1433. // ------------------------------------------------------------------------
  1434. //
  1435. // CBody::AddStream()
  1436. //
  1437. void
  1438. CBody::AddStream( IStream& stm )
  1439. {
  1440. TrapSz("Stream body parts no longer implemented");
  1441. }
  1442. // ------------------------------------------------------------------------
  1443. //
  1444. // CBody::AddStream()
  1445. //
  1446. void
  1447. CBody::AddStream( IStream& stm,
  1448. UINT ibOffset,
  1449. UINT cbSize )
  1450. {
  1451. TrapSz("Stream body parts no longer implemented");
  1452. }
  1453. // ------------------------------------------------------------------------
  1454. //
  1455. // CBody::AddBodyPart()
  1456. //
  1457. void
  1458. CBody::AddBodyPart( IBodyPart * pBodyPart )
  1459. {
  1460. _AddBodyPart( pBodyPart );
  1461. }
  1462. // ------------------------------------------------------------------------
  1463. //
  1464. // CBody::Clear()
  1465. //
  1466. VOID
  1467. CBody::Clear()
  1468. {
  1469. m_bodyPartList.Clear();
  1470. }
  1471. // ------------------------------------------------------------------------
  1472. //
  1473. // CBody::iterator::Accept()
  1474. //
  1475. // Accepts an asynchronous body part visitor (v) at the iterator's
  1476. // current position. The Accept() observer (obsAccept) is notified
  1477. // when the visitor finishes.
  1478. //
  1479. // Lifetimes of both the visitor and the observer are controled
  1480. // outside the scope of this function; i.e. it is assumed that
  1481. // the observer will still be valid when the visitor finishes.
  1482. //
  1483. VOID
  1484. CBody::iterator::Accept( IBodyPartVisitor& v,
  1485. IAcceptObserver& obsAccept )
  1486. {
  1487. //
  1488. // If we've reached the end of the body, then we're done.
  1489. //
  1490. if ( m_itPart.FDone() )
  1491. {
  1492. v.VisitComplete();
  1493. obsAccept.AcceptComplete(0);
  1494. return;
  1495. }
  1496. //
  1497. // We're not at the end of the body. If we are starting
  1498. // a new part then rewind the part and our current position.
  1499. //
  1500. if ( NULL == m_pBodyPart )
  1501. {
  1502. m_pBodyPart = m_itPart.PItem();
  1503. m_pBodyPart->Rewind();
  1504. m_ibPart64 = 0;
  1505. }
  1506. //
  1507. // Save off the observer so that we can call it back when
  1508. // the body part is done accepting the visitor.
  1509. //
  1510. m_pobsAccept = &obsAccept;
  1511. //
  1512. // Accept the specified visitor starting from the current
  1513. // position in the current body part.
  1514. //
  1515. m_pBodyPart->Accept( v, m_ibPart64, *this );
  1516. }
  1517. // ------------------------------------------------------------------------
  1518. //
  1519. // CBody::iterator::AcceptComplete()
  1520. //
  1521. // IBodyPart::AcceptObserver method called by the body part when it is
  1522. // done with the visitor we told it to accept in Accept() above.
  1523. //
  1524. VOID
  1525. CBody::iterator::AcceptComplete( UINT64 cbAccepted64 )
  1526. {
  1527. Assert( m_pBodyPart );
  1528. m_ibPart64 += cbAccepted64;
  1529. //
  1530. // If we reach the end of the current body part then tell
  1531. // our iterator to go to the next part. If we hit the end
  1532. // of the body, we will catch that condition in Accept() the
  1533. // next time we get called there.
  1534. //
  1535. if ( m_ibPart64 == m_pBodyPart->CbSize64() )
  1536. {
  1537. m_itPart.Next();
  1538. //
  1539. // Null out the current body part so we will know to
  1540. // fetch the next one on the next call to Accept().
  1541. //
  1542. m_pBodyPart = NULL;
  1543. }
  1544. //
  1545. // Callback our observer
  1546. //
  1547. m_pobsAccept->AcceptComplete(cbAccepted64);
  1548. }
  1549. // ------------------------------------------------------------------------
  1550. //
  1551. // CBody::iterator::Prune()
  1552. //
  1553. // Deletes items from the body part list up to, but not including,
  1554. // the part at the current list position. This minimizes the
  1555. // memory footprint for large one-pass async partwise operations
  1556. // such as request persisting or response transmission.
  1557. //
  1558. VOID
  1559. CBody::iterator::Prune()
  1560. {
  1561. m_itPart.Prune();
  1562. }
  1563. // ------------------------------------------------------------------------
  1564. //
  1565. // CBody::AsyncPersist()
  1566. //
  1567. void
  1568. CBody::AsyncPersist( IAsyncStream& stm,
  1569. IAsyncPersistObserver& obs )
  1570. {
  1571. PersistTrace( "DAV: TID %3d: 0x%08lX: CBody::AsyncPersist() called\n", GetCurrentThreadId(), this );
  1572. auto_ref_ptr<CAsyncPersistor>
  1573. pPersistor(new CAsyncPersistor(*this, stm, obs));
  1574. pPersistor->Start();
  1575. }
  1576. // ------------------------------------------------------------------------
  1577. //
  1578. // NewBody()
  1579. //
  1580. IBody * NewBody()
  1581. {
  1582. return new CBody();
  1583. }
  1584. // ------------------------------------------------------------------------
  1585. //
  1586. // CXMLBody::ScAddTextBytes
  1587. //
  1588. SCODE
  1589. CXMLBody::ScAddTextBytes ( UINT cbText, LPCSTR lpszText )
  1590. {
  1591. Assert (lpszText);
  1592. // Create the text body part if necessary
  1593. //
  1594. if (!m_ptbp.get())
  1595. m_ptbp = new CTextBodyPart(0, NULL);
  1596. // Add the piece to the body part
  1597. //
  1598. m_ptbp->AddTextBytes (cbText, lpszText);
  1599. // Add to body part list if this body part has reach a proper size
  1600. //
  1601. if (m_fChunked && (m_ptbp->CbSize64() > CB_XMLBODYPART_SIZE))
  1602. SendCurrentChunk();
  1603. return S_OK;
  1604. }