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.

5312 lines
141 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Response object
  6. File: response.cpp
  7. Owner: CGrant
  8. This file contains the code for the implementation of the Response object.
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include "response.h"
  13. #include "request.h"
  14. #include "Cookies.h"
  15. #include "perfdata.h"
  16. #include "winsock2.h"
  17. #include "memchk.h"
  18. #pragma warning (disable: 4355) // ignore: "'this' used in base member init
  19. static const char s_szContentLengthHeader[] = "Content-Length: ";
  20. static const char s_szContentTypeHeader[] = "Content-Type: ";
  21. static const char s_szCharSetHTML[] = "; Charset=";
  22. static const char s_szCacheControl[] = "Cache-control: ";
  23. static const char s_szCacheControlPrivate[] = "Cache-control: private\r\n";
  24. static const char s_szTransferEncoding[] = "Transfer-Encoding: chunked\r\n";
  25. static const char s_szHTML[] = "text/html";
  26. static const char s_szCDF[] = "application/x-cdf";
  27. static const char s_szDefaultStatus[] = "200 OK";
  28. #if VECTSTATS
  29. //
  30. // a mechanism to collect statistics about response vector length and fragment sizes
  31. //
  32. #if DEBUG
  33. #define COLLECT_RESP_VECT_STATS TRUE
  34. #else
  35. #define COLLECT_RESP_VECT_STATS FALSE
  36. #endif
  37. static BOOL fCollectRespVectStats = COLLECT_RESP_VECT_STATS;
  38. static VOID RespVectStat_DataSizeStats(BOOL fHtmlData, DWORD cch)
  39. {
  40. if (!fCollectRespVectStats)
  41. return;
  42. if (cch == 0)
  43. InterlockedIncrement(&sRespVecStats.ZeroSizeBlocks);
  44. if (fHtmlData)
  45. {
  46. if (cch <= 0x10)
  47. InterlockedIncrement(&sRespVecStats.HTML16);
  48. else if (cch <= 0x20)
  49. InterlockedIncrement(&sRespVecStats.HTML32);
  50. else if (cch <= 0x30)
  51. InterlockedIncrement(&sRespVecStats.HTML48);
  52. else if (cch <= 0x40)
  53. InterlockedIncrement(&sRespVecStats.HTML64);
  54. else if (cch <= 0x80)
  55. InterlockedIncrement(&sRespVecStats.HTML128);
  56. else if (cch <= 0x100)
  57. InterlockedIncrement(&sRespVecStats.HTML256);
  58. else if (cch <= 0x200)
  59. InterlockedIncrement(&sRespVecStats.HTML512);
  60. else if (cch <= 0x400)
  61. InterlockedIncrement(&sRespVecStats.HTML1024);
  62. else if (cch <= 0x800)
  63. InterlockedIncrement(&sRespVecStats.HTML2048);
  64. else if (cch <= 0x1000)
  65. InterlockedIncrement(&sRespVecStats.HTML4096);
  66. else if (cch <= 0x2000)
  67. InterlockedIncrement(&sRespVecStats.HTML8192);
  68. else if (cch <= 0x4000)
  69. InterlockedIncrement(&sRespVecStats.HTML16384);
  70. else
  71. InterlockedIncrement(&sRespVecStats.HTMLbig);
  72. if (cch > MAX_HTML_IN_RESPONSE_BUFFER)
  73. InterlockedExchangeAdd(&sRespVecStats.TotalReferencedHTMLBytes, cch);
  74. else
  75. InterlockedExchangeAdd(&sRespVecStats.TotalCopiedHTMLBytes, cch);
  76. }
  77. else
  78. InterlockedIncrement(&sRespVecStats.DynamicBlocks);
  79. }
  80. static VOID RespVectStat_VectorSizeStats(DWORD ca)
  81. {
  82. if (!fCollectRespVectStats)
  83. return;
  84. if (ca <= 0x8)
  85. InterlockedIncrement(&sRespVecStats.Vect8);
  86. else if (ca <= 0x10)
  87. InterlockedIncrement(&sRespVecStats.Vect16);
  88. else if (ca <= 0x20)
  89. InterlockedIncrement(&sRespVecStats.Vect32);
  90. else if (ca <= 0x40)
  91. InterlockedIncrement(&sRespVecStats.Vect64);
  92. else if (ca <= 0x60)
  93. InterlockedIncrement(&sRespVecStats.Vect96);
  94. else if (ca <= 0x80)
  95. InterlockedIncrement(&sRespVecStats.Vect128);
  96. else if (ca <= 0xC0)
  97. InterlockedIncrement(&sRespVecStats.Vect192);
  98. else if (ca <= 0x100)
  99. InterlockedIncrement(&sRespVecStats.Vect256);
  100. else if (ca <= 0x200)
  101. InterlockedIncrement(&sRespVecStats.Vect512);
  102. else if (ca <= 0x400)
  103. InterlockedIncrement(&sRespVecStats.Vect1024);
  104. else if (ca <= 0x800)
  105. InterlockedIncrement(&sRespVecStats.Vect2048);
  106. else if (ca <= 0x1000)
  107. InterlockedIncrement(&sRespVecStats.Vect4096);
  108. else
  109. InterlockedIncrement(&sRespVecStats.VectBig);
  110. }
  111. #else // VECTSTATS
  112. #define RespVectStat_DataSizeStats(fHtmlData, ccb)
  113. #define RespVectStat_VectorSizeStats(ca)
  114. #endif // VECTSTATS
  115. ResponseVectorStatistics sRespVecStats = {0};
  116. inline void AddtoTotalByteOut(int cByteOut)
  117. {
  118. #ifndef PERF_DISABLE
  119. g_PerfData.Add_REQTOTALBYTEOUT(cByteOut);
  120. #endif
  121. }
  122. inline const char *GetResponseMimeType(CIsapiReqInfo *pIReq)
  123. {
  124. TCHAR *szPath = pIReq->QueryPszPathTranslated();
  125. DWORD cch = pIReq->QueryCchPathTranslated();
  126. if (cch > 4 && _tcscmp(szPath + cch - 4, _T(".CDX")) == 0)
  127. {
  128. return s_szCDF;
  129. }
  130. else
  131. {
  132. return s_szHTML;
  133. }
  134. }
  135. /*
  136. *
  137. *
  138. *
  139. * C R e s p o n s e C o o k i e s
  140. *
  141. *
  142. *
  143. */
  144. //===================================================================
  145. // CResponseCookies::CResponseCookies
  146. //
  147. // Constructor.
  148. //===================================================================
  149. CResponseCookies::CResponseCookies(CResponse *pResponse, IUnknown *pUnkOuter)
  150. : m_ISupportErrImp(this, pUnkOuter, IID_IRequestDictionary)
  151. {
  152. m_punkOuter = pUnkOuter;
  153. if (pResponse)
  154. pResponse->AddRef();
  155. m_pResponse = pResponse;
  156. m_pRequest = NULL;
  157. CDispatch::Init(IID_IRequestDictionary);
  158. }
  159. //===================================================================
  160. // CResponseCookies::~CResponseCookies
  161. //
  162. // Destructor.
  163. //===================================================================
  164. CResponseCookies::~CResponseCookies()
  165. {
  166. if (m_pRequest)
  167. m_pRequest->Release();
  168. if (m_pResponse)
  169. m_pResponse->Release();
  170. }
  171. //===================================================================
  172. // CResponseCookies::ReInit
  173. //
  174. // Parameters:
  175. // pRequest - pointer to the request object. Will need it to
  176. // read the request for the cookies
  177. //
  178. // Returns:
  179. // always S_OK, unlest pRequest is NULL.
  180. //===================================================================
  181. HRESULT CResponseCookies::ReInit(CRequest *pRequest)
  182. {
  183. if (pRequest)
  184. pRequest->AddRef();
  185. if (m_pRequest)
  186. m_pRequest->Release();
  187. m_pRequest = pRequest; // CRequest is not ref counted, so no need for AddRef/Release
  188. if (m_pRequest == NULL)
  189. return E_POINTER;
  190. return S_OK;
  191. }
  192. /*===================================================================
  193. CResponseCookies::QueryInterface
  194. CResponseCookies::AddRef
  195. CResponseCookies::Release
  196. IUnknown members for CResponseCookies object.
  197. ===================================================================*/
  198. STDMETHODIMP CResponseCookies::QueryInterface(const IID &idInterface, void **ppvObj)
  199. {
  200. *ppvObj = NULL;
  201. if (idInterface == IID_IUnknown || idInterface == IID_IRequestDictionary || idInterface == IID_IDispatch)
  202. *ppvObj = this;
  203. else if (idInterface == IID_ISupportErrorInfo)
  204. *ppvObj = &m_ISupportErrImp;
  205. if (*ppvObj != NULL)
  206. {
  207. static_cast<IUnknown *>(*ppvObj)->AddRef();
  208. return S_OK;
  209. }
  210. return ResultFromScode(E_NOINTERFACE);
  211. }
  212. STDMETHODIMP_(ULONG) CResponseCookies::AddRef()
  213. {
  214. return m_punkOuter->AddRef();
  215. }
  216. STDMETHODIMP_(ULONG) CResponseCookies::Release()
  217. {
  218. return m_punkOuter->Release();
  219. }
  220. /*===================================================================
  221. CResponseCookies::get_Item
  222. Function called from DispInvoke to get values from the Response.Cookies
  223. collection. If the Cookie does not exist, then a new one is created
  224. and added to the Request dictionary
  225. Parameters:
  226. varKey VARIANT [in], which parameter to get the value of - Empty means whole collection
  227. pvarReturn VARIANT *, [out] value of the requested parameter
  228. Returns:
  229. S_OK on success, E_FAIL on failure.
  230. ===================================================================*/
  231. HRESULT CResponseCookies::get_Item(VARIANT varKey, VARIANT *pvarReturn)
  232. {
  233. if (FAILED(m_pResponse->CheckForTombstone()))
  234. return E_FAIL;
  235. char *szKey=NULL; // ascii value of 'varKey'
  236. CRequestHit *pRequestHit; // pointer to request bucket
  237. DWORD vt = 0; // Variant type of key
  238. CWCharToMBCS convKey;
  239. if (m_pResponse->FHeadersWritten())
  240. {
  241. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  242. return E_FAIL;
  243. }
  244. // Initialize things
  245. //
  246. V_VT(pvarReturn) = VT_DISPATCH;
  247. V_DISPATCH(pvarReturn) = NULL;
  248. VARIANT *pvarKey = &varKey;
  249. HRESULT hrReturn = S_OK;
  250. // BUG 937: VBScript passes VT_VARIANT|VT_BYREF when passing obect
  251. // produced by IEnumVariant
  252. //
  253. // Use VariantResolveDispatch which will:
  254. //
  255. // * Copy BYREF variants for us using VariantCopyInd
  256. // * handle E_OUTOFMEMORY for us
  257. // * get the default value from an IDispatch, which seems
  258. // like an appropriate conversion.
  259. //
  260. VARIANT varKeyCopy;
  261. VariantInit(&varKeyCopy);
  262. vt = V_VT(pvarKey);
  263. if ((vt != VT_BSTR) && (vt != VT_I2) && (vt != VT_I4))
  264. {
  265. if (FAILED(VariantResolveDispatch(&varKeyCopy, &varKey, IID_IRequestDictionary, IDE_REQUEST)))
  266. goto LExit;
  267. pvarKey = &varKeyCopy;
  268. }
  269. vt = V_VT(pvarKey);
  270. switch(vt)
  271. {
  272. // Bug 95201 support all numberic sub-types
  273. case VT_I1: case VT_I2: case VT_I8:
  274. case VT_UI1: case VT_UI2: case VT_UI4: case VT_UI8:
  275. case VT_R4: case VT_R8:
  276. // Coerce all integral types to VT_I4
  277. if (FAILED(hrReturn = VariantChangeType(pvarKey, pvarKey, 0, VT_I4)))
  278. goto LExit;
  279. // fallthru to VT_I4
  280. case VT_I4:
  281. case VT_BSTR:
  282. break;
  283. default:
  284. ExceptionId(IID_IRequestDictionary, IDE_COOKIE, IDE_EXPECTING_STR);
  285. hrReturn = E_FAIL;
  286. goto LExit;
  287. }
  288. if (FAILED(m_pRequest->CheckForTombstone()))
  289. {
  290. hrReturn = E_FAIL;
  291. goto LExit;
  292. }
  293. if (m_pRequest->m_pData->m_fLoadCookies)
  294. {
  295. char *szCookie = m_pRequest->GetIReq()->QueryPszCookie();
  296. if (FAILED(hrReturn = m_pRequest->LoadVariables(COOKIE, szCookie, m_pRequest->GetCodePage())))
  297. goto LExit;
  298. m_pRequest->m_pData->m_fLoadCookies = FALSE;
  299. }
  300. if (vt == VT_BSTR)
  301. {
  302. if (FAILED(hrReturn = convKey.Init(V_BSTR(pvarKey),m_pRequest->GetCodePage()))) {
  303. if (hrReturn == E_OUTOFMEMORY) {
  304. ExceptionId(IID_IResponse, IDE_COOKIE, IDE_OOM);
  305. goto LExit;
  306. }
  307. hrReturn = NO_ERROR;
  308. szKey = "";
  309. }
  310. else {
  311. szKey = convKey.GetString();
  312. }
  313. // Bug 456: Don't allow assignment to DenaliSessionID
  314. if (strncmp(szKey, SZ_SESSION_ID_COOKIE_PREFIX, CCH_SESSION_ID_COOKIE_PREFIX) == 0)
  315. {
  316. ExceptionId(IID_IResponse, IDE_COOKIE, IDE_RESPONSE_MODIFY_SESS_COOKIE);
  317. hrReturn = E_FAIL;
  318. goto LExit;
  319. }
  320. pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->FindElem(szKey, strlen(szKey)));
  321. }
  322. else
  323. {
  324. // Look up item by index
  325. int iCount = 0;
  326. if (vt == VT_I2)
  327. {
  328. iCount = V_I2(pvarKey);
  329. }
  330. else
  331. {
  332. iCount = V_I4(pvarKey);
  333. }
  334. // The Request hits for all cookies are stored with the request object
  335. if ((iCount < 1) || (iCount > (int) m_pRequest->m_pData->m_Cookies.m_dwCount))
  336. {
  337. hrReturn = E_FAIL;
  338. goto LExit;
  339. }
  340. pRequestHit = m_pRequest->m_pData->m_Cookies.m_rgRequestHit[iCount - 1];
  341. }
  342. if (pRequestHit)
  343. {
  344. CCookie *pDictionary = pRequestHit->m_pCookieData;
  345. if (pDictionary == NULL)
  346. goto LNotFound;
  347. if (FAILED(pDictionary->QueryInterface(IID_IWriteCookie, reinterpret_cast<void **>(&V_DISPATCH(pvarReturn)))))
  348. Assert (FALSE);
  349. goto LExit;
  350. }
  351. LNotFound:
  352. // don't allow empty cookie names
  353. //
  354. if (szKey != NULL && *szKey == '\0')
  355. {
  356. ExceptionId(IID_IResponse, IDE_COOKIE, IDE_COOKIE_NO_NAME);
  357. hrReturn = E_FAIL;
  358. goto LExit;
  359. }
  360. // Create a new RequestHit if there is no key by this name
  361. if (pRequestHit == NULL)
  362. {
  363. pRequestHit = new CRequestHit;
  364. if (pRequestHit == NULL || FAILED(pRequestHit->Init(szKey, TRUE)))
  365. {
  366. if (pRequestHit)
  367. delete pRequestHit;
  368. ExceptionId(IID_IResponse, IDE_COOKIE, IDE_OOM);
  369. hrReturn = E_OUTOFMEMORY;
  370. goto LExit;
  371. }
  372. m_pRequest->GetStrings()->AddElem(pRequestHit);
  373. }
  374. // Create a new cookie, with an initial unassigned value.
  375. if (pRequestHit->m_pCookieData == NULL)
  376. {
  377. pRequestHit->m_pCookieData = new CCookie(m_pResponse->GetIReq(),m_pRequest->GetCodePage());
  378. if (pRequestHit->m_pCookieData == NULL || FAILED(pRequestHit->m_pCookieData->Init()))
  379. {
  380. ExceptionId(IID_IResponse, IDE_COOKIE, IDE_OOM);
  381. hrReturn = E_OUTOFMEMORY;
  382. goto LExit;
  383. }
  384. }
  385. // Add this Request hit to the ResponseCookies array of hits
  386. if (!m_pRequest->m_pData->m_Cookies.AddRequestHit(pRequestHit))
  387. {
  388. return E_OUTOFMEMORY;
  389. }
  390. // Query for IWriteCookie
  391. if (FAILED(pRequestHit->m_pCookieData->QueryInterface(IID_IWriteCookie, reinterpret_cast<void **>(&V_DISPATCH(pvarReturn)))))
  392. {
  393. Assert (FALSE);
  394. }
  395. LExit:
  396. VariantClear(&varKeyCopy);
  397. return hrReturn;
  398. }
  399. /*===================================================================
  400. CResponseCookies::get_Count
  401. Parameters:
  402. pcValues - count is stored in *pcValues
  403. ===================================================================*/
  404. STDMETHODIMP CResponseCookies::get_Count(int *pcValues)
  405. {
  406. if (FAILED(m_pRequest->CheckForTombstone()))
  407. return E_FAIL;
  408. return m_pRequest->m_pData->m_Cookies.get_Count(pcValues);
  409. }
  410. /*===================================================================
  411. CResponseCookies::get_Key
  412. Function called from DispInvoke to get keys from the response cookie collection.
  413. Parameters:
  414. vKey VARIANT [in], which parameter to get the key of
  415. pvarReturn VARIANT *, [out] value of the requested parameter
  416. Returns:
  417. S_OK on success, E_FAIL on failure.
  418. ===================================================================*/
  419. HRESULT CResponseCookies::get_Key(VARIANT varKey, VARIANT *pVar)
  420. {
  421. if (FAILED(m_pRequest->CheckForTombstone()))
  422. return E_FAIL;
  423. return m_pRequest->m_pData->m_Cookies.get_Key(varKey, pVar);
  424. }
  425. /*===================================================================
  426. CResponseCookies::get__NewEnum
  427. Return a new enumerator
  428. ===================================================================*/
  429. HRESULT CResponseCookies::get__NewEnum(IUnknown **ppEnumReturn)
  430. {
  431. if (FAILED(m_pResponse->CheckForTombstone()))
  432. return E_FAIL;
  433. *ppEnumReturn = NULL;
  434. CRequestIterator *pIterator = new CRequestIterator(m_pRequest, COOKIE);
  435. if (pIterator == NULL)
  436. return E_OUTOFMEMORY;
  437. HRESULT hrInit = pIterator->Init();
  438. if (FAILED(hrInit))
  439. {
  440. delete pIterator;
  441. return hrInit;
  442. }
  443. *ppEnumReturn = pIterator;
  444. return S_OK;
  445. }
  446. /*===================================================================
  447. CResponseCookies::QueryHeaderSize
  448. Returns:
  449. returns the number of bytes required for the cookie headers.
  450. ===================================================================*/
  451. size_t CResponseCookies::QueryHeaderSize()
  452. {
  453. if (FAILED(m_pRequest->CheckForTombstone()))
  454. return 0;
  455. int cbHeaders = 0;
  456. for (CRequestHit *pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->Head());
  457. pRequestHit != NULL;
  458. pRequestHit = static_cast<CRequestHit *>(pRequestHit->m_pNext))
  459. {
  460. CCookie *pCookie = pRequestHit->m_pCookieData;
  461. if (pCookie == NULL || !pCookie->IsDirty())
  462. continue;
  463. // add two bytes for '\r\n'
  464. //
  465. // CCookie::GetCookieHeaderSize adds one byte for NUL terminator, so
  466. // just add one byte here.
  467. //
  468. // CResponse::WriteHeaders does not want to know about the NUL yet.
  469. //
  470. cbHeaders += pCookie->GetCookieHeaderSize(reinterpret_cast<char *>(pRequestHit->m_pKey)) + 1;
  471. }
  472. return cbHeaders;
  473. }
  474. /*===================================================================
  475. CResponseCookies::GetHeaders
  476. Parameters:
  477. szBuffer - contains the destination buffer for the cookie header
  478. text
  479. Returns:
  480. return a pointer to the NUL character in the destination
  481. ===================================================================*/
  482. char *CResponseCookies::GetHeaders(char *szBuffer)
  483. {
  484. if (FAILED(m_pRequest->CheckForTombstone()))
  485. {
  486. szBuffer[0] = '\0';
  487. return szBuffer;
  488. }
  489. for (CRequestHit *pRequestHit = static_cast<CRequestHit *>(m_pRequest->GetStrings()->Head());
  490. pRequestHit != NULL;
  491. pRequestHit = static_cast<CRequestHit *>(pRequestHit->m_pNext))
  492. {
  493. CCookie *pCookie = pRequestHit->m_pCookieData;
  494. if (pCookie == NULL || !pCookie->IsDirty())
  495. continue;
  496. szBuffer = pCookie->GetCookieHeader(reinterpret_cast<char *>(pRequestHit->m_pKey), szBuffer);
  497. szBuffer = strcpyExA(szBuffer, "\r\n");
  498. }
  499. return szBuffer;
  500. }
  501. /*
  502. *
  503. *
  504. *
  505. * C R e s p o n s e V e c t o r
  506. *
  507. *
  508. *
  509. */
  510. /*===================================================================
  511. The CResponseVector object maintains a vector of pointers to data blocks in the
  512. response buffers and HTML data in the templates for an efficient VectorSend.
  513. The current entry can be open for accumulating data (extending the size of current
  514. block). Insert() will open a new vector entry for the data block and close it.
  515. Append() adds to the current (open) entry or creates a new entry. Close() closes
  516. the current entry.
  517. ====================================================================*/
  518. /*===================================================================
  519. CResponseVector::CResponseVector
  520. Constructor
  521. Parameters:
  522. None
  523. Returns:
  524. Nothing
  525. Side Effects
  526. None
  527. ===================================================================*/
  528. CResponseVector::CResponseVector()
  529. {
  530. m_pExtVector = NULL;
  531. m_cExtVectorSize = 0;
  532. m_iCurrentEntry = 0;
  533. m_fEntryIsOpen = FALSE;
  534. m_cchTotalBuffered = 0;
  535. }
  536. /*===================================================================
  537. CResponseVector::~CResponseVector
  538. Destructor
  539. Clear() does all the work
  540. Parameters:
  541. None
  542. Returns:
  543. Nothing
  544. Side Effects
  545. Frees memory
  546. ===================================================================*/
  547. CResponseVector::~CResponseVector()
  548. {
  549. Clear();
  550. }
  551. /*===================================================================
  552. CResponseVector::Clear
  553. resets the instance, freeing any dynamically allocated memory
  554. Parameters:
  555. None
  556. Returns:
  557. Nothing
  558. Side Effects
  559. Frees memory
  560. ===================================================================*/
  561. VOID CResponseVector::Clear()
  562. {
  563. // update statistics
  564. RespVectStat_VectorSizeStats( GetEntryCount());
  565. // Free auxilary vector
  566. if (m_pExtVector)
  567. {
  568. free(m_pExtVector);
  569. m_pExtVector = NULL;
  570. }
  571. m_cExtVectorSize = 0;
  572. m_iCurrentEntry = 0;
  573. m_fEntryIsOpen = FALSE;
  574. m_cchTotalBuffered = 0;
  575. }
  576. /*===================================================================
  577. CResponseVector::Append
  578. For an open entry, increases the size of buffer the entry points to.
  579. If the entry is closed, a new entry is opened.
  580. Parameters:
  581. pData pointer to the new data
  582. cbSize size of data
  583. Returns:
  584. HRESULT
  585. Side Effects
  586. None
  587. ===================================================================*/
  588. HRESULT CResponseVector::Append(char * pData, DWORD cbSize)
  589. {
  590. HRESULT hr;
  591. LPWSABUF pEntry;
  592. if (cbSize == 0)
  593. { // no point in storing zero size data
  594. return S_OK;
  595. }
  596. Assert( !IsBadReadPtr( pData, cbSize));
  597. if (IsEntryOpen())
  598. { // append to an open entry
  599. pEntry = GetEntry( m_iCurrentEntry);
  600. Assert(pData == (pEntry->buf + pEntry->len));
  601. pEntry->len += cbSize;
  602. m_cchTotalBuffered += cbSize;
  603. return S_OK;
  604. }
  605. if (m_iCurrentEntry >= (RESPONSE_VECTOR_INTRINSIC_SIZE + m_cExtVectorSize))
  606. { // need to grow the vector
  607. if (FAILED(hr = GrowVector()))
  608. {
  609. return hr;
  610. }
  611. }
  612. m_fEntryIsOpen = TRUE;
  613. pEntry = GetEntry( m_iCurrentEntry);
  614. pEntry->len = cbSize;
  615. pEntry->buf = pData;
  616. m_cchTotalBuffered += cbSize;
  617. return S_OK;
  618. }
  619. /*===================================================================
  620. CResponseVector::GrowVector
  621. Allocate space in the auxilary vector. The auxilary vector is created with
  622. RESPONSE_VECTOR_INITIAL_ALLOC elements and grown by a factor of
  623. RESPONSE_VECTOR_REALLOC_FACTOR.
  624. Factor the current size is an efficient method to grow hash and index tables.
  625. Parameters:
  626. None
  627. Returns:
  628. HRESULT Indicating success or type of failure
  629. Side Effects
  630. May cause memory to be allocated
  631. ===================================================================*/
  632. HRESULT CResponseVector::GrowVector()
  633. {
  634. LPVOID pVectorTmp;
  635. DWORD cNewEntries;
  636. if (m_pExtVector == NULL)
  637. {
  638. // first dynamic allocation
  639. cNewEntries = RESPONSE_VECTOR_INITIAL_ALLOC;
  640. pVectorTmp = malloc( cNewEntries * sizeof(WSABUF));
  641. }
  642. else
  643. {
  644. // expand current auxilary vector
  645. cNewEntries = RESPONSE_VECTOR_REALLOC_FACTOR * m_cExtVectorSize;
  646. pVectorTmp = realloc(m_pExtVector, cNewEntries * sizeof(WSABUF));
  647. }
  648. if (!pVectorTmp)
  649. return E_OUTOFMEMORY;
  650. m_pExtVector = (LPWSABUF)pVectorTmp;
  651. m_cExtVectorSize = cNewEntries;
  652. return S_OK;
  653. }
  654. /*
  655. *
  656. *
  657. *
  658. * C R e s p o n s e B u f f e r
  659. *
  660. *
  661. *
  662. */
  663. /*===================================================================
  664. The CResponseBuffer object maintains an array of buffers.
  665. If buffering is turned on, the Response.Write and Response.WriteBlock
  666. methods will write to the buffers in these arrays rather then directly
  667. back to the client. Response.Flush writes the content of the buffers to
  668. the client and then frees the buffers. Response.Clear frees the buffers without
  669. writing to the client
  670. ====================================================================*/
  671. /*===================================================================
  672. CResponseBuffer::CResponseBuffer
  673. Constructor
  674. Parameters:
  675. None
  676. Returns:
  677. Nothing
  678. Side Effects
  679. None
  680. ===================================================================*/
  681. CResponseBuffer::CResponseBuffer()
  682. {
  683. m_pBufferSet = NULL;
  684. m_rgpchBuffers = &m_pchBuffer0;
  685. m_cBufferPointers = 1;
  686. m_pchBuffer0 = NULL;
  687. m_cBuffers = 0;
  688. m_iCurrentBuffer = 0;
  689. m_cchOffsetInCurrentBuffer = 0;
  690. m_dwBufferLimit = DEFAULT_BUFFER_LIMIT;
  691. m_fInited = FALSE;
  692. }
  693. /*===================================================================
  694. CResponseBuffer::Init
  695. Initializes the CResponseBuffer object
  696. Parameters:
  697. CResponseBufferSet * pointer to bufferset holding this object
  698. dwBufferLimit maximum to buffer
  699. Returns:
  700. S_OK Success
  701. E_OUTOFMEMORY Failure
  702. Side Effects
  703. Allocates memory
  704. ===================================================================*/
  705. HRESULT CResponseBuffer::Init(CResponseBufferSet * pBufferSet,
  706. DWORD dwBufferLimit)
  707. {
  708. Assert(pBufferSet);
  709. // Set the pointer to the enclosing response object
  710. m_pBufferSet = pBufferSet;
  711. m_dwBufferLimit = dwBufferLimit;
  712. m_fInited = TRUE;
  713. return S_OK;
  714. }
  715. /*===================================================================
  716. CResponseBuffer::~CResponseBuffer
  717. Destructor
  718. Parameters:
  719. None
  720. Returns:
  721. Nothing
  722. Side Effects
  723. Frees memory
  724. ===================================================================*/
  725. CResponseBuffer::~CResponseBuffer()
  726. {
  727. Assert(m_rgpchBuffers);
  728. // Free all the buffers we've allocated
  729. for (DWORD i = 0; i < m_cBuffers; i++)
  730. {
  731. if (m_rgpchBuffers[i])
  732. {
  733. ACACHE_FSA_FREE(ResponseBuffer, m_rgpchBuffers[i]);
  734. }
  735. }
  736. // Free the array of buffer pointers
  737. // (only if allocated - doesn't point to the member pointer
  738. if (m_cBufferPointers > 1)
  739. free(m_rgpchBuffers);
  740. }
  741. /*===================================================================
  742. CResponseBuffer::GrowBuffers
  743. Increases available buffer space
  744. Parameters:
  745. cchNewRequest count of bytes to be accomodated
  746. Returns:
  747. HRESULT Indicating success or type of failure
  748. Side Effects
  749. May cause memory to be allocated
  750. ===================================================================*/
  751. HRESULT CResponseBuffer::GrowBuffers(DWORD cchNewRequest)
  752. {
  753. Assert(m_fInited);
  754. // Calculate how many more buffers are needed
  755. DWORD cAddBuffers = (cchNewRequest+RESPONSE_BUFFER_SIZE-1)/RESPONSE_BUFFER_SIZE;
  756. // Always at least one must be there already
  757. Assert(m_rgpchBuffers);
  758. Assert(m_cBufferPointers);
  759. // Allocate more buffer pointers if needed
  760. if (cAddBuffers > (m_cBufferPointers - m_cBuffers)) // doesn't fit?
  761. {
  762. char **rgpchTmp;
  763. DWORD cNewBufferPointers = m_cBufferPointers + cAddBuffers + BUFFERS_INCREMENT;
  764. if (m_cBufferPointers == 1)
  765. rgpchTmp = (char **)malloc(cNewBufferPointers*sizeof(char *));
  766. else
  767. rgpchTmp = (char **)realloc(m_rgpchBuffers, cNewBufferPointers*sizeof(char *));
  768. if (!rgpchTmp)
  769. return E_OUTOFMEMORY;
  770. // preserve the first buffer pointer in the special case
  771. // of m_rgpchBuffers initally pointing to a member buffer pointer
  772. if (m_cBufferPointers == 1)
  773. rgpchTmp[0] = m_rgpchBuffers[0];
  774. m_rgpchBuffers = rgpchTmp;
  775. m_cBufferPointers = cNewBufferPointers;
  776. }
  777. // Allocate the new buffers
  778. for (DWORD i = 0; i < cAddBuffers; i++)
  779. {
  780. char *pchTmp = (char *)ACACHE_FSA_ALLOC(ResponseBuffer);
  781. if (!pchTmp)
  782. return E_OUTOFMEMORY;
  783. m_rgpchBuffers[m_cBuffers++] = pchTmp;
  784. }
  785. return S_OK;
  786. }
  787. /*===================================================================
  788. CResponseBuffer::Write
  789. Writes data to the CResponseBuffer object. We first write
  790. a data structure that describes this segment of the buffer.
  791. The data structure identifies which method is doing the
  792. writing, and contains an index to the starting buffer,
  793. the starting offset in that buffer, and the length of the
  794. data. The data itself is then writen to one or more buffers.
  795. New buffers are allocated as needed.
  796. Pointers to the data blocks in the response buffers are added to
  797. the ResponseVector for efficient writeto the client.
  798. Parameters:
  799. szSource pointer to buffer to read into the Response buffer
  800. cch count of bytes to be read into the Response buffer
  801. fChunkData indicates that the data should be chunked
  802. fTemplateData indicates (HTML) data that can be referenced rather than copied
  803. Returns:
  804. HRESULT Indicating success or type of failure
  805. Side Effects
  806. May cause memory to be allocated
  807. ===================================================================*/
  808. HRESULT CResponseBuffer::Write(char* szSource, DWORD cch, BOOL fChunkData, BOOL fTemplateData)
  809. {
  810. HRESULT hr = S_OK;
  811. char* pTmp;
  812. CHAR szBuf[16]; // to hold a sting with length of data + CRLF, if chunking
  813. int dwNumLen;
  814. Assert(m_fInited);
  815. // nothing to do if chunking and we got a zero junk.
  816. if ((cch == 0) && fChunkData)
  817. return S_OK;
  818. // check to see if we've blown out the buffer limit...
  819. if ((m_ResponseVector.BytesBuffered() + cch) > m_dwBufferLimit) {
  820. // dump the current contents so as not to obscure the error with the
  821. // buffered data
  822. Clear();
  823. // generate the error
  824. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_BUFFER_LIMIT_EXCEEDED);
  825. // return error so that the script engine stops
  826. hr = E_FAIL;
  827. goto lRet;
  828. }
  829. // add the chunk info if we're chunking
  830. if (fChunkData) {
  831. // chunk length
  832. _itoa(cch, szBuf, 16);
  833. dwNumLen = strlen(szBuf);
  834. // CR LF
  835. szBuf[dwNumLen] = '\r';
  836. szBuf[dwNumLen+1] = '\n';
  837. // call Write recursively.
  838. hr = Write(szBuf, dwNumLen+2, FALSE);
  839. if (FAILED(hr))
  840. goto lRet;
  841. }
  842. // Caclulate how much buffer space we have left
  843. DWORD cchBufferRemaining;
  844. if (m_cBuffers)
  845. cchBufferRemaining = RESPONSE_BUFFER_SIZE - m_cchOffsetInCurrentBuffer;
  846. else
  847. cchBufferRemaining = 0;
  848. // update statistics
  849. RespVectStat_DataSizeStats(fTemplateData, cch);
  850. if (fTemplateData && (cch > MAX_HTML_IN_RESPONSE_BUFFER))
  851. {
  852. // don't copy the data, just add it to the response vector
  853. hr = m_ResponseVector.Insert(szSource, cch);
  854. if (SUCCEEDED(hr))
  855. hr = m_pBufferSet->AddTemplateToArray();
  856. }
  857. else if (cch <= cchBufferRemaining)
  858. {
  859. // Enough space available, copy data to buffer
  860. pTmp = m_rgpchBuffers[m_iCurrentBuffer] + m_cchOffsetInCurrentBuffer;
  861. memcpy(pTmp, szSource, cch);
  862. hr = m_ResponseVector.Append(pTmp, cch);
  863. m_cchOffsetInCurrentBuffer += cch;
  864. }
  865. else
  866. {
  867. // Not enough space in current buffer, allocate more buffers
  868. hr = GrowBuffers(cch - cchBufferRemaining);
  869. if (FAILED(hr))
  870. {
  871. goto lRet;
  872. }
  873. // Copy data to the buffers, we loop to handle
  874. // the case where the data is larger then the buffer size
  875. while (cch)
  876. {
  877. if (RESPONSE_BUFFER_SIZE == m_cchOffsetInCurrentBuffer)
  878. {
  879. m_iCurrentBuffer++;
  880. m_cchOffsetInCurrentBuffer = 0;
  881. m_ResponseVector.Close();
  882. }
  883. DWORD cchToCopy = min(cch, (RESPONSE_BUFFER_SIZE - m_cchOffsetInCurrentBuffer));
  884. pTmp = m_rgpchBuffers[m_iCurrentBuffer] + m_cchOffsetInCurrentBuffer;
  885. memcpy(pTmp, szSource, cchToCopy);
  886. hr = m_ResponseVector.Append(pTmp, cchToCopy);
  887. m_cchOffsetInCurrentBuffer += cchToCopy;
  888. if (FAILED(hr))
  889. {
  890. goto lRet;
  891. }
  892. szSource += cchToCopy;
  893. cch -= cchToCopy;
  894. }
  895. }
  896. // add the trailing \r\n
  897. if (fChunkData)
  898. hr = Write(szBuf+dwNumLen, 2, FALSE);
  899. lRet:
  900. return hr;
  901. }
  902. /*===================================================================
  903. CResponseBuffer::Clear
  904. Deletes all information currently in the buffers, and restores
  905. the buffer array to it's starting state.
  906. Parameters:
  907. None
  908. Returns:
  909. S_OK success
  910. Side Effects
  911. May free memory
  912. ===================================================================*/
  913. HRESULT CResponseBuffer::Clear()
  914. {
  915. Assert(m_fInited);
  916. m_ResponseVector.Clear();
  917. if (m_cBuffers == 0)
  918. return S_OK;
  919. // Free all but the first of the allocated buffers
  920. for (DWORD i = 1; i < m_cBuffers; i++)
  921. {
  922. ACACHE_FSA_FREE(ResponseBuffer, m_rgpchBuffers[i]);
  923. m_rgpchBuffers[i] = NULL;
  924. }
  925. m_cBuffers = 1;
  926. m_iCurrentBuffer = 0;
  927. m_cchOffsetInCurrentBuffer = 0;
  928. return S_OK;
  929. }
  930. /*
  931. *
  932. *
  933. *
  934. * C D e b u g R e s p o n s e B u f f e r
  935. *
  936. *
  937. *
  938. */
  939. /*===================================================================
  940. CDebugResponseBuffer::AppendRecord
  941. Create client side debugger metadata record and appends it to
  942. the buffer
  943. Parameters:
  944. Returns:
  945. HRESULT Indicating success or type of failure
  946. ===================================================================*/
  947. HRESULT CDebugResponseBuffer::AppendRecord
  948. (
  949. const int cchBlockOffset,
  950. const int cchBlockLength,
  951. const int cchSourceOffset,
  952. const char *pszSourceFile
  953. )
  954. {
  955. HRESULT hr = S_OK;
  956. #define CCH_METADATA_RECORD_MAX 40 // without filename
  957. if (pszSourceFile)
  958. {
  959. char *pszBuf = new char [strlen(pszSourceFile) +
  960. CCH_METADATA_RECORD_MAX + 1];
  961. if (pszBuf)
  962. {
  963. sprintf(pszBuf, "%d,%d,%d,%s\r\n",
  964. cchBlockOffset, cchBlockLength, cchSourceOffset,
  965. pszSourceFile);
  966. hr = Write(pszBuf);
  967. delete [] pszBuf;
  968. }
  969. else
  970. {
  971. hr = E_OUTOFMEMORY;
  972. }
  973. }
  974. else
  975. {
  976. char szBuf[CCH_METADATA_RECORD_MAX+1];
  977. sprintf(szBuf, "%d,%d,%d\r\n",
  978. cchBlockOffset, cchBlockLength, cchSourceOffset);
  979. hr = Write(szBuf);
  980. }
  981. #undef CCH_METADATA_RECORD_MAX
  982. return hr;
  983. }
  984. /*
  985. *
  986. *
  987. *
  988. * C H T T P H e a d e r
  989. *
  990. *
  991. *
  992. */
  993. /*===================================================================
  994. CHTTPHeader::CHTTPHeader
  995. Constructor.
  996. ===================================================================*/
  997. CHTTPHeader::CHTTPHeader()
  998. :
  999. m_fInited(FALSE),
  1000. m_fNameAllocated(FALSE), m_fValueAllocated(FALSE),
  1001. m_szName(NULL), m_szValue(NULL),
  1002. m_cchName(0), m_cchValue(0),
  1003. m_pNext(NULL)
  1004. {
  1005. }
  1006. /*===================================================================
  1007. CHTTPHeader::~CHTTPHeader
  1008. Destructor
  1009. ===================================================================*/
  1010. CHTTPHeader::~CHTTPHeader()
  1011. {
  1012. if (m_fNameAllocated)
  1013. {
  1014. Assert(m_szName);
  1015. delete [] m_szName;
  1016. }
  1017. if (m_fValueAllocated)
  1018. {
  1019. Assert(m_szValue);
  1020. delete [] m_szValue;
  1021. }
  1022. }
  1023. /*===================================================================
  1024. HRESULT CHTTPHeader::InitHeader
  1025. Functions set the header strings. Agrument types combinations:
  1026. BSTR, BSTR
  1027. hardcoded char*, BSTR
  1028. hardcoded char*, hardcoded char*
  1029. hardcoded char*, int
  1030. Parameters:
  1031. Name, Value
  1032. Returns:
  1033. S_OK Success
  1034. ===================================================================*/
  1035. HRESULT CHTTPHeader::InitHeader(BSTR wszName, BSTR wszValue, UINT lCodePage /* CP_ACP */)
  1036. {
  1037. Assert(!m_fInited);
  1038. Assert(wszName);
  1039. CWCharToMBCS convStr;
  1040. HRESULT hr = S_OK;
  1041. // name
  1042. if (FAILED(hr = convStr.Init(wszName,lCodePage))) {
  1043. if (hr == E_OUTOFMEMORY)
  1044. return hr;
  1045. m_fNameAllocated = FALSE;
  1046. m_szName = "";
  1047. }
  1048. else {
  1049. m_szName = convStr.GetString(TRUE);
  1050. m_fNameAllocated = TRUE;
  1051. }
  1052. m_cchName = strlen(m_szName);
  1053. // value
  1054. int cch = wszValue ? wcslen(wszValue) : 0;
  1055. if (cch > 0)
  1056. {
  1057. if (FAILED(hr = convStr.Init(wszValue,lCodePage))) {
  1058. return hr;
  1059. }
  1060. m_szValue = convStr.GetString(TRUE);
  1061. m_fValueAllocated = TRUE;
  1062. m_cchValue = strlen(m_szValue);
  1063. }
  1064. else
  1065. {
  1066. m_szValue = NULL;
  1067. m_fValueAllocated = FALSE;
  1068. m_cchValue = 0;
  1069. }
  1070. m_fInited = TRUE;
  1071. return S_OK;
  1072. }
  1073. HRESULT CHTTPHeader::InitHeader(char *szName, BSTR wszValue, UINT lCodePage /* = CP_ACP */)
  1074. {
  1075. Assert(!m_fInited);
  1076. Assert(szName);
  1077. CWCharToMBCS convStr;
  1078. HRESULT hr = S_OK;
  1079. m_szName = szName;
  1080. m_cchName = strlen(m_szName);
  1081. m_fNameAllocated = FALSE;
  1082. int cch = wszValue ? wcslen(wszValue) : 0;
  1083. if (cch > 0)
  1084. {
  1085. if (FAILED(hr = convStr.Init(wszValue,lCodePage))) {
  1086. return hr;
  1087. }
  1088. m_szValue = convStr.GetString(TRUE);
  1089. m_fValueAllocated = TRUE;
  1090. m_cchValue = strlen(m_szValue);
  1091. }
  1092. else
  1093. {
  1094. m_szValue = NULL;
  1095. m_fValueAllocated = FALSE;
  1096. m_cchValue = 0;
  1097. }
  1098. m_fInited = TRUE;
  1099. return S_OK;
  1100. }
  1101. HRESULT CHTTPHeader::InitHeader(char *szName, char *szValue, BOOL fCopyValue)
  1102. {
  1103. Assert(!m_fInited);
  1104. Assert(szName);
  1105. m_szName = szName;
  1106. m_cchName = strlen(m_szName);
  1107. m_fNameAllocated = FALSE;
  1108. if (fCopyValue)
  1109. {
  1110. int cch = szValue ? strlen(szValue) : 0;
  1111. if (cch > 0)
  1112. {
  1113. m_szValue = new char[cch+1];
  1114. if (m_szValue == NULL)
  1115. return E_OUTOFMEMORY;
  1116. m_fValueAllocated = TRUE;
  1117. strcpy(m_szValue, szValue);
  1118. m_cchValue = cch;
  1119. }
  1120. else
  1121. {
  1122. m_szValue = NULL;
  1123. m_fValueAllocated = FALSE;
  1124. m_cchValue = 0;
  1125. }
  1126. }
  1127. else
  1128. {
  1129. m_szValue = szValue;
  1130. m_cchValue = strlen(m_szValue);
  1131. m_fValueAllocated = FALSE;
  1132. }
  1133. m_fInited = TRUE;
  1134. return S_OK;
  1135. }
  1136. HRESULT CHTTPHeader::InitHeader(char *szName, long lValue)
  1137. {
  1138. Assert(!m_fInited);
  1139. Assert(szName);
  1140. m_szName = szName;
  1141. m_cchName = strlen(m_szName);
  1142. m_fNameAllocated = FALSE;
  1143. ltoa(lValue, m_rgchLtoaBuffer, 10);
  1144. m_szValue = m_rgchLtoaBuffer;
  1145. m_cchValue = strlen(m_szValue);
  1146. m_fValueAllocated = FALSE;
  1147. m_fInited = TRUE;
  1148. return S_OK;
  1149. }
  1150. /*===================================================================
  1151. CHTTPHeader::Print
  1152. Prints the header into a buffer in "Header: Value\r\n" format.
  1153. Parameters:
  1154. szBuf buffer to fill
  1155. ===================================================================*/
  1156. void CHTTPHeader::Print
  1157. (
  1158. char *szBuf
  1159. )
  1160. {
  1161. Assert(m_fInited);
  1162. Assert(m_cchName);
  1163. Assert(m_szName);
  1164. memcpy(szBuf, m_szName, m_cchName);
  1165. szBuf += m_cchName;
  1166. *szBuf++ = ':';
  1167. *szBuf++ = ' ';
  1168. if (m_cchValue)
  1169. {
  1170. Assert(m_szValue);
  1171. memcpy(szBuf, m_szValue, m_cchValue);
  1172. szBuf += m_cchValue;
  1173. }
  1174. *szBuf++ = '\r';
  1175. *szBuf++ = '\n';
  1176. *szBuf = '\0';
  1177. }
  1178. /*
  1179. *
  1180. *
  1181. *
  1182. * C R e s p o n s e D a t a
  1183. *
  1184. *
  1185. *
  1186. */
  1187. /*===================================================================
  1188. CResponseBufferSet::CResponseBufferSet
  1189. Constructor
  1190. Parameters:
  1191. Returns:
  1192. Nothing.
  1193. ===================================================================*/
  1194. CResponseBufferSet::CResponseBufferSet()
  1195. {
  1196. m_pResponseBuffer = NULL;
  1197. m_pClientDebugBuffer = NULL;
  1198. m_pTemplate = NULL;
  1199. m_fCurTemplateInArray = FALSE;
  1200. m_fTemplateArrayAllocd = FALSE;
  1201. m_aTemplates[0] = NULL;
  1202. m_dwTemplatesRefd = 0;
  1203. m_ppTemplates = m_aTemplates;
  1204. m_dwArraySize = sizeof(m_aTemplates)/sizeof(CTemplate *);
  1205. }
  1206. /*===================================================================
  1207. CResponseBufferSet::~CResponseBufferSet
  1208. Destructor
  1209. Parameters:
  1210. Returns:
  1211. Nothing.
  1212. ===================================================================*/
  1213. CResponseBufferSet::~CResponseBufferSet()
  1214. {
  1215. if (m_pResponseBuffer)
  1216. delete m_pResponseBuffer;
  1217. if (m_pClientDebugBuffer)
  1218. delete m_pClientDebugBuffer;
  1219. // release any templates that were referenced
  1220. for (DWORD i=0; i < m_dwTemplatesRefd; i++)
  1221. m_aTemplates[i]->Release();
  1222. // delete the template array if it was allocated
  1223. if (m_fTemplateArrayAllocd)
  1224. free(m_ppTemplates);
  1225. }
  1226. /*===================================================================
  1227. CResponseBufferSet::Init
  1228. Initializes this object with the CResponseBuffer.
  1229. Parameters:
  1230. dwBufferLimit maximum to buffer
  1231. Returns:
  1232. Nothing.
  1233. ===================================================================*/
  1234. HRESULT CResponseBufferSet::Init(DWORD dwBufferLimit)
  1235. {
  1236. HRESULT hr = S_OK;
  1237. m_pResponseBuffer = new CResponseBuffer;
  1238. if (m_pResponseBuffer == NULL)
  1239. hr = E_OUTOFMEMORY;
  1240. if (SUCCEEDED(hr))
  1241. hr = m_pResponseBuffer->Init(this, dwBufferLimit);
  1242. return hr;
  1243. }
  1244. /*===================================================================
  1245. CResponseBufferSet::InitDebugBuffer
  1246. Clears or allocates a new CDebugResponseBuffer.
  1247. Parameters:
  1248. dwBufferLimit maximum to buffer
  1249. Returns:
  1250. Nothing.
  1251. ===================================================================*/
  1252. HRESULT CResponseBufferSet::InitDebugBuffer(DWORD dwBufferLimit)
  1253. {
  1254. HRESULT hr = S_OK;
  1255. if (m_pClientDebugBuffer) {
  1256. hr = m_pClientDebugBuffer->ClearAndStart();
  1257. }
  1258. else {
  1259. m_pClientDebugBuffer = new CDebugResponseBuffer;
  1260. if (m_pClientDebugBuffer)
  1261. hr = m_pClientDebugBuffer->InitAndStart(this, dwBufferLimit);
  1262. else
  1263. hr = E_OUTOFMEMORY;
  1264. }
  1265. return hr;
  1266. }
  1267. /*===================================================================
  1268. CResponseBufferSet::AddTemplateToArray
  1269. Takes the current m_pTemplate member variable and adds it to the
  1270. array of ppTemplates. A call to this routine likely indicates that
  1271. pTemplate memory is being referenced in the response data and so the
  1272. lifetime of the Template needs to include the async completion of
  1273. writing the data.
  1274. Parameters:
  1275. Returns:
  1276. Nothing.
  1277. ===================================================================*/
  1278. HRESULT CResponseBufferSet::AddTemplateToArray() {
  1279. DWORD i;
  1280. HRESULT hr = S_OK;
  1281. // nothing to do if it's already in the array
  1282. if (m_fCurTemplateInArray)
  1283. return hr;
  1284. // check the current list to see if it's already
  1285. // in there. Because of template swapping caused
  1286. // by child executes, a template could come and go
  1287. // in the response buffer structure. When the template
  1288. // is set again, it is first assumed to NOT be in the
  1289. // array.
  1290. for (i=0; i < m_dwTemplatesRefd; i++) {
  1291. if (m_pTemplate == m_ppTemplates[i]) {
  1292. // found it. Note that it's in aldready and return immediately
  1293. m_fCurTemplateInArray = TRUE;
  1294. return S_OK;
  1295. }
  1296. }
  1297. // ok, it's not currently in the array. We need to add it.
  1298. // first check to make sure that there is enough room in the
  1299. // array for the pointer.
  1300. if (i >= m_dwArraySize) {
  1301. // need to grow the array. The array grows in 128 entry
  1302. // chunks.
  1303. if (m_fTemplateArrayAllocd) {
  1304. // if it's already been dynamically allocated, then a realloc
  1305. // is in order.
  1306. void *pTemp;
  1307. // attempt the realloc
  1308. pTemp = realloc(m_ppTemplates, sizeof(CTemplate *)*(m_dwArraySize+128));
  1309. // if it's successful, then update the pointer with the new
  1310. // value. If not successful, return OOM
  1311. if (pTemp) {
  1312. // up the array size by the 128 chunk
  1313. m_dwArraySize += 128;
  1314. m_ppTemplates = (CTemplate **)pTemp;
  1315. }
  1316. else
  1317. hr = E_OUTOFMEMORY;
  1318. }
  1319. else {
  1320. // blew out the internal array. Need to allocate from
  1321. // the heap.
  1322. m_ppTemplates = (CTemplate **)malloc(sizeof(CTemplate *) * 128);
  1323. // if successful, note the new array size, copy the internal array
  1324. // in, and note that we've allocated the array.
  1325. if (m_ppTemplates) {
  1326. m_dwArraySize = 128;
  1327. memcpy(m_ppTemplates, m_aTemplates, sizeof(m_aTemplates));
  1328. m_fTemplateArrayAllocd = TRUE;
  1329. }
  1330. else {
  1331. m_ppTemplates = m_aTemplates;
  1332. hr = E_OUTOFMEMORY;
  1333. }
  1334. }
  1335. }
  1336. // if everything is still OK, then there is sufficient room in the array
  1337. // for the template.
  1338. if (SUCCEEDED(hr)) {
  1339. m_ppTemplates[m_dwTemplatesRefd++] = m_pTemplate;
  1340. m_pTemplate->AddRef();
  1341. m_fCurTemplateInArray = TRUE;
  1342. }
  1343. return hr;
  1344. }
  1345. /*===================================================================
  1346. CResponseBufferSet::SendResponseCompletion
  1347. Handles Async Write completion. Really not much to do here.
  1348. Just delete the BufferSet object.
  1349. Parameters:
  1350. CIsapiReqInfo *
  1351. PVOID // actually CResponseBufferSet
  1352. DWORD cbIO
  1353. DWORD dwError
  1354. Returns:
  1355. Nothing.
  1356. ===================================================================*/
  1357. VOID CResponseBufferSet::SendResponseCompletion(CIsapiReqInfo *pIReq,
  1358. PVOID pContext,
  1359. DWORD cbIO,
  1360. DWORD dwError)
  1361. {
  1362. CResponseBufferSet *pBufferSet = (CResponseBufferSet *)pContext;
  1363. #ifndef PERF_DISABLE
  1364. AddtoTotalByteOut(cbIO);
  1365. #endif
  1366. delete pBufferSet;
  1367. }
  1368. /*
  1369. *
  1370. *
  1371. *
  1372. * C R e s p o n s e D a t a
  1373. *
  1374. *
  1375. *
  1376. */
  1377. /*===================================================================
  1378. CResponseData::CResponseData
  1379. Constructor
  1380. Parameters:
  1381. CResponse *pResponse
  1382. Returns:
  1383. Nothing.
  1384. ===================================================================*/
  1385. CResponseData::CResponseData
  1386. (
  1387. CResponse *pResponse
  1388. )
  1389. :
  1390. m_ISupportErrImp(static_cast<IResponse *>(pResponse), this, IID_IResponse),
  1391. m_WriteCookies(pResponse, this),
  1392. m_cRefs(1)
  1393. {
  1394. m_pIReq = NULL;
  1395. m_pHitObj = NULL;
  1396. m_pFirstHeader = m_pLastHeader = NULL;
  1397. m_fResponseAborted = FALSE;
  1398. m_fWriteClientError = FALSE;
  1399. m_fIgnoreWrites = FALSE;
  1400. m_fBufferingOn = FALSE;
  1401. m_fFlushed = FALSE;
  1402. m_fChunkData = FALSE;
  1403. m_fChunkDataInited = FALSE;
  1404. m_fClientDebugMode = FALSE;
  1405. m_fClientDebugFlushIgnored = FALSE;
  1406. m_szCookieVal = NULL;
  1407. m_pszDefaultContentType = NULL;
  1408. m_pszContentType = NULL;
  1409. m_pszCharSet = NULL;
  1410. m_pszStatus = NULL;
  1411. m_pszCacheControl = NULL;
  1412. m_dwVersionMajor = 0;
  1413. m_dwVersionMinor = 0;
  1414. m_pBufferSet = NULL;
  1415. m_tExpires = -1;
  1416. m_pszDefaultExpires = NULL;
  1417. m_pfnGetScript = NULL;
  1418. m_pvGetScriptContext = NULL;
  1419. m_dwBufferLimit = DEFAULT_BUFFER_LIMIT;
  1420. }
  1421. /*===================================================================
  1422. CResponseData::~CResponseData
  1423. Destructor
  1424. Parameters:
  1425. Returns:
  1426. Nothing.
  1427. ===================================================================*/
  1428. CResponseData::~CResponseData()
  1429. {
  1430. // points to static string - no need to free
  1431. // m_pszDefaultContentType = NULL;
  1432. // Free any memory associated with the content-type
  1433. if (m_pszContentType)
  1434. free(m_pszContentType);
  1435. // Free any memory associated with the CacheControl
  1436. if (m_pszCacheControl)
  1437. free(m_pszCacheControl);
  1438. // Free any memory associated with the CharSet
  1439. if (m_pszCharSet)
  1440. free(m_pszCharSet);
  1441. // Free any memory associated with the status
  1442. if (m_pszStatus)
  1443. free(m_pszStatus);
  1444. // Free all headers
  1445. CHTTPHeader *pHeader = m_pFirstHeader;
  1446. while (pHeader)
  1447. {
  1448. CHTTPHeader *pNextHeader = pHeader->PNext();
  1449. delete pHeader;
  1450. pHeader = pNextHeader;
  1451. }
  1452. m_pFirstHeader = m_pLastHeader = NULL;
  1453. if (m_pBufferSet)
  1454. delete m_pBufferSet;
  1455. }
  1456. /*===================================================================
  1457. CResponseData::Init
  1458. Init
  1459. Parameters:
  1460. Returns:
  1461. Nothing.
  1462. ===================================================================*/
  1463. HRESULT CResponseData::Init()
  1464. {
  1465. HRESULT hr = S_OK;
  1466. m_pIReq = NULL;
  1467. // set the HEAD request flag to 0 un-inited
  1468. m_IsHeadRequest = 0;
  1469. // Initialize header list
  1470. m_pFirstHeader = m_pLastHeader = NULL;
  1471. m_pBufferSet = new CResponseBufferSet;
  1472. if (m_pBufferSet == NULL)
  1473. hr = E_OUTOFMEMORY;
  1474. if (SUCCEEDED(hr))
  1475. hr = m_pBufferSet->Init(m_dwBufferLimit);
  1476. return hr;
  1477. }
  1478. /*===================================================================
  1479. CResponseData::QueryInterface
  1480. CResponseData::AddRef
  1481. CResponseData::Release
  1482. IUnknown members for CRequestData object.
  1483. ===================================================================*/
  1484. STDMETHODIMP CResponseData::QueryInterface
  1485. (
  1486. REFIID iid,
  1487. void **ppvObj
  1488. )
  1489. {
  1490. if (iid == IID_IUnknown)
  1491. {
  1492. *ppvObj = this;
  1493. AddRef();
  1494. return S_OK;
  1495. }
  1496. else
  1497. {
  1498. *ppvObj = NULL;
  1499. return E_NOINTERFACE;
  1500. }
  1501. }
  1502. STDMETHODIMP_(ULONG) CResponseData::AddRef()
  1503. {
  1504. return ++m_cRefs;
  1505. }
  1506. STDMETHODIMP_(ULONG) CResponseData::Release(void)
  1507. {
  1508. if (--m_cRefs)
  1509. return m_cRefs;
  1510. delete this;
  1511. return 0;
  1512. }
  1513. /*
  1514. *
  1515. *
  1516. *
  1517. * C R e s p o n s e
  1518. *
  1519. *
  1520. *
  1521. */
  1522. /*===================================================================
  1523. CResponse::CResponse
  1524. Constructor
  1525. Parameters:
  1526. punkOuter object to ref count (can be NULL)
  1527. ===================================================================*/
  1528. CResponse::CResponse(IUnknown *punkOuter)
  1529. :
  1530. m_fInited(FALSE),
  1531. m_fDiagnostics(FALSE),
  1532. m_pUnkFTM(NULL),
  1533. m_pData(NULL)
  1534. {
  1535. CDispatch::Init(IID_IResponse);
  1536. if (punkOuter)
  1537. {
  1538. m_punkOuter = punkOuter;
  1539. m_fOuterUnknown = TRUE;
  1540. }
  1541. else
  1542. {
  1543. m_cRefs = 1;
  1544. m_fOuterUnknown = FALSE;
  1545. }
  1546. #ifdef DBG
  1547. m_fDiagnostics = TRUE;
  1548. #endif // DBG
  1549. }
  1550. /*===================================================================
  1551. CResponse::~CResponse
  1552. Destructor
  1553. Parameters:
  1554. None
  1555. Returns:
  1556. Nothing.
  1557. ===================================================================*/
  1558. CResponse::~CResponse()
  1559. {
  1560. Assert(!m_fInited);
  1561. Assert(m_fOuterUnknown || m_cRefs == 0); // must have 0 ref count
  1562. if ( m_pUnkFTM != NULL )
  1563. {
  1564. m_pUnkFTM->Release();
  1565. m_pUnkFTM = NULL;
  1566. }
  1567. }
  1568. /*===================================================================
  1569. CResponse::CleanUp
  1570. Deallocates members and removes m_pData
  1571. Parameters:
  1572. None
  1573. Returns:
  1574. HRESULT (S_OK)
  1575. ===================================================================*/
  1576. HRESULT CResponse::CleanUp()
  1577. {
  1578. if (m_pData)
  1579. {
  1580. m_pData->Release();
  1581. m_pData = NULL;
  1582. }
  1583. return S_OK;
  1584. }
  1585. /*===================================================================
  1586. CResponse::Init
  1587. Allocates m_pData
  1588. Performs any intiailization of a CResponse that's prone to failure
  1589. that we also use internally before exposing the object outside.
  1590. Parameters:
  1591. None
  1592. Returns:
  1593. S_OK on success.
  1594. ===================================================================*/
  1595. HRESULT CResponse::Init()
  1596. {
  1597. HRESULT hr = S_OK;
  1598. if (m_fInited)
  1599. return S_OK; // already inited
  1600. Assert(!m_pData);
  1601. // Create the FTM
  1602. if (m_pUnkFTM == NULL)
  1603. {
  1604. hr = CoCreateFreeThreadedMarshaler((IUnknown*)((IResponseImpl *)this), &m_pUnkFTM );
  1605. if ( FAILED(hr) )
  1606. {
  1607. Assert( m_pUnkFTM == NULL );
  1608. return (hr);
  1609. }
  1610. }
  1611. Assert( m_pUnkFTM != NULL );
  1612. m_pData = new CResponseData(this);
  1613. if (!m_pData)
  1614. return E_OUTOFMEMORY;
  1615. hr = m_pData->Init();
  1616. if (SUCCEEDED(hr))
  1617. m_fInited = TRUE;
  1618. else
  1619. CleanUp();
  1620. return hr;
  1621. }
  1622. /*===================================================================
  1623. CResponse::UnInit
  1624. Remove m_pData. Back to UnInited state
  1625. Parameters:
  1626. None
  1627. Returns:
  1628. HRESULT
  1629. ===================================================================*/
  1630. HRESULT CResponse::UnInit()
  1631. {
  1632. if (!m_fInited)
  1633. return S_OK; // already uninited
  1634. Assert(m_pData);
  1635. CleanUp();
  1636. Assert(!m_pData);
  1637. // Disconnect proxies NOW (in case we are in shutdown, or enter shutdown later & a proxy has a ref.)
  1638. CoDisconnectObject(static_cast<IResponseImpl *>(this), 0);
  1639. m_fInited = FALSE;
  1640. return S_OK;
  1641. }
  1642. /*===================================================================
  1643. CResponse::ReInitTemplate
  1644. This function is used to set the template member. It should only
  1645. be used for an ordinary script file's template, not for global.asa template.
  1646. Parameters:
  1647. Pointer to template
  1648. Returns:
  1649. S_OK on success.
  1650. ===================================================================*/
  1651. HRESULT CResponse::ReInitTemplate
  1652. (
  1653. CTemplate* pTemplate,
  1654. const char *szCookieVal
  1655. )
  1656. {
  1657. Assert(m_fInited);
  1658. Assert(m_pData);
  1659. Assert(pTemplate != NULL);
  1660. Assert(m_pData->m_pBufferSet->PTemplate() == NULL);
  1661. m_pData->m_pBufferSet->SetTemplate(pTemplate);
  1662. m_pData->m_szCookieVal = szCookieVal;
  1663. return(S_OK);
  1664. }
  1665. /*===================================================================
  1666. CResponse::SwapTemplate
  1667. Temporary substitutes Template in response
  1668. Used in child request execution
  1669. Parameters:
  1670. Pointer to the new template
  1671. Returns:
  1672. Pointer to the old template
  1673. ===================================================================*/
  1674. CTemplate *CResponse::SwapTemplate
  1675. (
  1676. CTemplate* pNewTemplate
  1677. )
  1678. {
  1679. Assert(m_fInited);
  1680. Assert(m_pData);
  1681. CTemplate *pOldTemplate = m_pData->m_pBufferSet->PTemplate();
  1682. m_pData->m_pBufferSet->SetTemplate(pNewTemplate);
  1683. return pOldTemplate;
  1684. }
  1685. /*===================================================================
  1686. CResponse::ReInit
  1687. Each Request we service will have a new CIsapiReqInfo.
  1688. This function is used to set the value of the CIsapiReqInfo.
  1689. Parameters:
  1690. Pointer to CIsapiReqInfo
  1691. Returns:
  1692. S_OK on success.
  1693. ===================================================================*/
  1694. HRESULT CResponse::ReInit
  1695. (
  1696. CIsapiReqInfo *pIReq,
  1697. const char *szCookieVal,
  1698. CRequest *pRequest,
  1699. PFNGETSCRIPT pfnGetScript,
  1700. void *pvGetScriptContext,
  1701. CHitObj *pHitObj
  1702. )
  1703. {
  1704. Assert(m_fInited);
  1705. Assert(m_pData);
  1706. CHTTPHeader *pCurr;
  1707. CLinkElem *pT;
  1708. CLinkElem *pNext;
  1709. // set the HEAD request flag to 0 un-inited
  1710. m_pData->m_IsHeadRequest = 0;
  1711. // ReInitialize the WriteCookie dictionary
  1712. if (FAILED(m_pData->m_WriteCookies.ReInit(pRequest)))
  1713. return E_FAIL;
  1714. // points to static string - no need to free
  1715. m_pData->m_pszDefaultContentType = NULL;
  1716. // Free any memory associated with the content type
  1717. if (m_pData->m_pszContentType != NULL)
  1718. {
  1719. free(m_pData->m_pszContentType);
  1720. m_pData->m_pszContentType = NULL;
  1721. }
  1722. // Free any memory associated with the content type
  1723. if (m_pData->m_pszCharSet != NULL)
  1724. {
  1725. free(m_pData->m_pszCharSet);
  1726. m_pData->m_pszCharSet = NULL;
  1727. }
  1728. // Free any memory associated with the status
  1729. if (m_pData->m_pszStatus != NULL)
  1730. {
  1731. free(m_pData->m_pszStatus);
  1732. m_pData->m_pszStatus = NULL;
  1733. }
  1734. // Free all headers
  1735. CHTTPHeader *pHeader = m_pData->m_pFirstHeader;
  1736. while (pHeader)
  1737. {
  1738. CHTTPHeader *pNextHeader = pHeader->PNext();
  1739. delete pHeader;
  1740. pHeader = pNextHeader;
  1741. }
  1742. m_pData->m_pFirstHeader = m_pData->m_pLastHeader = NULL;
  1743. m_pData->m_fResponseAborted = FALSE;
  1744. m_pData->m_fWriteClientError = FALSE;
  1745. m_pData->m_fIgnoreWrites = FALSE;
  1746. m_pData->m_pIReq = pIReq;
  1747. m_pData->m_szCookieVal = szCookieVal;
  1748. m_pData->m_pszDefaultContentType = NULL;
  1749. m_pData->m_pszContentType = NULL;
  1750. m_pData->m_pszCharSet = NULL;
  1751. m_pData->m_pszStatus = NULL;
  1752. m_pData->m_pfnGetScript = pfnGetScript;
  1753. m_pData->m_pvGetScriptContext = pvGetScriptContext;
  1754. m_pData->m_pHitObj = pHitObj;
  1755. m_pData->m_tExpires = -1;
  1756. m_pData->m_pszDefaultExpires = NULL;
  1757. // Ask for the HTTP version of the client
  1758. GetClientVerison();
  1759. // Set the default content type
  1760. if (m_pData->m_pIReq)
  1761. m_pData->m_pszDefaultContentType = GetResponseMimeType(m_pData->m_pIReq);
  1762. // Set the buffering flag to the global value
  1763. m_pData->m_fBufferingOn = (pHitObj->QueryAppConfig())->fBufferingOn();
  1764. m_pData->SetBufferLimit(pHitObj->QueryAppConfig()->dwBufferLimit());
  1765. // Buffering always on for client code debug
  1766. if (pHitObj && pHitObj->FClientCodeDebug())
  1767. {
  1768. m_pData->m_fBufferingOn = TRUE;
  1769. m_pData->m_fClientDebugMode = TRUE;
  1770. m_pData->m_fClientDebugFlushIgnored = FALSE;
  1771. }
  1772. else
  1773. {
  1774. m_pData->m_fClientDebugMode = FALSE;
  1775. m_pData->m_fClientDebugFlushIgnored = FALSE;
  1776. }
  1777. HRESULT hr = S_OK;
  1778. if (m_pData->m_fClientDebugMode)
  1779. {
  1780. hr = m_pData->m_pBufferSet->InitDebugBuffer(m_pData->m_dwBufferLimit);
  1781. }
  1782. return hr;
  1783. }
  1784. /*===================================================================
  1785. CResponse::QueryInterface
  1786. CResponse::AddRef
  1787. CResponse::Release
  1788. IUnknown members for CResponse object.
  1789. ===================================================================*/
  1790. STDMETHODIMP CResponse::QueryInterface
  1791. (
  1792. REFIID riid,
  1793. PPVOID ppv
  1794. )
  1795. {
  1796. *ppv = NULL;
  1797. /*
  1798. * The only calls for IUnknown are either in a nonaggregated
  1799. * case or when created in an aggregation, so in either case
  1800. * always return our IUnknown for IID_IUnknown.
  1801. */
  1802. // BUG FIX 683 added IID_IDenaliIntrinsic to prevent the user from
  1803. // storing intrinsic objects in the application and session object
  1804. if (IID_IUnknown == riid || IID_IDispatch == riid || IID_IResponse == riid || IID_IDenaliIntrinsic == riid)
  1805. *ppv = static_cast<IResponse *>(this);
  1806. // Support IStream for ADO/XML
  1807. else if (IID_IStream == riid)
  1808. *ppv = static_cast<IStream *>(this);
  1809. //Indicate that we support error information
  1810. else if (IID_ISupportErrorInfo == riid)
  1811. {
  1812. if (m_pData)
  1813. *ppv = &(m_pData->m_ISupportErrImp);
  1814. }
  1815. else if (IID_IMarshal == riid)
  1816. {
  1817. Assert( m_pUnkFTM != NULL );
  1818. if ( m_pUnkFTM == NULL )
  1819. {
  1820. return E_UNEXPECTED;
  1821. }
  1822. return m_pUnkFTM->QueryInterface( riid, ppv );
  1823. }
  1824. //AddRef any interface we'll return.
  1825. if (NULL != *ppv)
  1826. {
  1827. ((LPUNKNOWN)*ppv)->AddRef();
  1828. return S_OK;
  1829. }
  1830. return ResultFromScode(E_NOINTERFACE);
  1831. }
  1832. STDMETHODIMP_(ULONG) CResponse::AddRef(void)
  1833. {
  1834. if (m_fOuterUnknown)
  1835. return m_punkOuter->AddRef();
  1836. return InterlockedIncrement((LPLONG)&m_cRefs);
  1837. }
  1838. STDMETHODIMP_(ULONG) CResponse::Release(void)
  1839. {
  1840. if (m_fOuterUnknown)
  1841. return m_punkOuter->Release();
  1842. DWORD cRefs = InterlockedDecrement((LPLONG)&m_cRefs);
  1843. if (cRefs)
  1844. return cRefs;
  1845. delete this;
  1846. return 0;
  1847. }
  1848. /*===================================================================
  1849. CResponse::GetIDsOfNames
  1850. Special-case implementation for Response.WriteBlock and
  1851. Response.Write
  1852. Parameters:
  1853. riid REFIID reserved. Must be IID_NULL.
  1854. rgszNames OLECHAR ** pointing to the array of names to be mapped.
  1855. cNames UINT number of names to be mapped.
  1856. lcid LCID of the locale.
  1857. rgDispID DISPID * caller allocated array containing IDs
  1858. corresponging to those names in rgszNames.
  1859. Return Value:
  1860. HRESULT S_OK or a general error code.
  1861. ===================================================================*/
  1862. STDMETHODIMP CResponse::GetIDsOfNames
  1863. (
  1864. REFIID riid,
  1865. OLECHAR **rgszNames,
  1866. UINT cNames,
  1867. LCID lcid,
  1868. DISPID *rgDispID
  1869. )
  1870. {
  1871. const DISPID dispidWrite = 0x60020013;
  1872. const DISPID dispidWriteBlock = 0x60020014;
  1873. if (cNames == 1)
  1874. {
  1875. // first char 'W'
  1876. if (rgszNames[0][0] == L'w' || rgszNames[0][0] == L'W')
  1877. {
  1878. // swtich on strlen
  1879. switch (wcslen(rgszNames[0]))
  1880. {
  1881. case 5:
  1882. // case insensitive because user can type either way
  1883. if (wcsicmp(rgszNames[0], L"write") == 0)
  1884. {
  1885. *rgDispID = dispidWrite;
  1886. return S_OK;
  1887. }
  1888. break;
  1889. case 10:
  1890. // case sensitive because only we generate WriteBlock
  1891. if (wcscmp(rgszNames[0], L"WriteBlock") == 0)
  1892. {
  1893. *rgDispID = dispidWriteBlock;
  1894. return S_OK;
  1895. }
  1896. break;
  1897. }
  1898. }
  1899. }
  1900. // default to CDispatch's implementation
  1901. return CDispatch::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgDispID);
  1902. }
  1903. /*===================================================================
  1904. CResponse::CheckForTombstone
  1905. Tombstone stub for IResponse methods. If the object is
  1906. tombstone, does ExceptionId and fails.
  1907. Parameters:
  1908. Returns:
  1909. HRESULT E_FAIL if Tombstone
  1910. S_OK if not
  1911. ===================================================================*/
  1912. HRESULT CResponse::CheckForTombstone()
  1913. {
  1914. if (m_fInited)
  1915. {
  1916. // inited - good object
  1917. Assert(m_pData); // must be present for inited objects
  1918. return S_OK;
  1919. }
  1920. ExceptionId
  1921. (
  1922. IID_IResponse,
  1923. IDE_RESPONSE,
  1924. IDE_INTRINSIC_OUT_OF_SCOPE
  1925. );
  1926. return E_FAIL;
  1927. }
  1928. /*===================================================================
  1929. CResponse::StaticWrite
  1930. Static method. Sends data until either everything is sent
  1931. or there's an error.
  1932. Parameters:
  1933. pIReq CIsapiReqInfo to send
  1934. pchBuf pointer to buffer to send
  1935. cchBuf number of bytes to send (0 means do strlen())
  1936. pTemplate pointer to template if pchBuf points into a CTemplate
  1937. Returns:
  1938. HRESULT
  1939. ===================================================================*/
  1940. HRESULT CResponse::StaticWrite
  1941. (
  1942. CIsapiReqInfo *pIReq,
  1943. char *pchBuf,
  1944. DWORD cchBuf,
  1945. CTemplate *pTemplate
  1946. )
  1947. {
  1948. HRESULT hr = S_OK;
  1949. HSE_SEND_ENTIRE_RESPONSE_INFO HseResponseInfo;
  1950. WSABUF_VECTORS WsabuffVectors;
  1951. LPWSABUF_VECTORS pWsabuffVectors = NULL;
  1952. BOOL fHeadersWritten = pIReq->FHeadersWritten();
  1953. BOOL fHeadRequest = (stricmp(pIReq->QueryPszMethod(), "HEAD") == 0);
  1954. if (fHeadersWritten && fHeadRequest)
  1955. return S_OK;
  1956. ZeroMemory( &HseResponseInfo, sizeof(HSE_SEND_ENTIRE_RESPONSE_INFO));
  1957. CResponseBufferSet *pBufferSet = new CResponseBufferSet;
  1958. if (pBufferSet == NULL)
  1959. return E_OUTOFMEMORY;
  1960. hr = pBufferSet->Init(DEFAULT_BUFFER_LIMIT);
  1961. if (FAILED(hr))
  1962. goto LExit;
  1963. if (cchBuf == 0)
  1964. cchBuf = strlen(pchBuf);
  1965. if (!fHeadersWritten) {
  1966. hr = ConstructSimpleHeaders( &HseResponseInfo.HeaderInfo, cchBuf,
  1967. (char *)GetResponseMimeType(pIReq));
  1968. if (FAILED(hr))
  1969. goto LExit;
  1970. // set fKeepConn to TRUE to indicate that we do prefer that to
  1971. // keep the connection. SendClientResponse() may decide that
  1972. // it's not possible, though.
  1973. HseResponseInfo.HeaderInfo.fKeepConn = TRUE;
  1974. }
  1975. if (pTemplate)
  1976. pBufferSet->SetTemplate(pTemplate);
  1977. if (fHeadRequest)
  1978. goto LSendResponse;
  1979. hr = pBufferSet->PResponseBuffer()->Write(pchBuf,
  1980. cchBuf,
  1981. FALSE, // don't chunk the data
  1982. !!pTemplate); // is data in the template?
  1983. if (FAILED(hr))
  1984. goto LExit;
  1985. CResponseVector * pResponseVector = pBufferSet->PResponseBuffer()->GetResponseVector();
  1986. pResponseVector->GetVectors( &WsabuffVectors);
  1987. pWsabuffVectors = &WsabuffVectors;
  1988. LSendResponse:
  1989. if (!pIReq->SendClientResponse(CResponseBufferSet::SendResponseCompletion,
  1990. pBufferSet,
  1991. &HseResponseInfo,
  1992. pWsabuffVectors))
  1993. hr = HRESULT_FROM_WIN32(GetLastError());
  1994. LExit:
  1995. // if these values are set, then SendClientResponse didn't take
  1996. // ownership of this memory and it needs to be deleted here
  1997. if (HseResponseInfo.HeaderInfo.pszStatus)
  1998. free((PVOID)HseResponseInfo.HeaderInfo.pszStatus);
  1999. if (HseResponseInfo.HeaderInfo.pszHeader)
  2000. free((PVOID)HseResponseInfo.HeaderInfo.pszHeader);
  2001. if (FAILED(hr)) {
  2002. delete pBufferSet;
  2003. }
  2004. return hr;
  2005. }
  2006. /*===================================================================
  2007. CResponse::SyncWriteFile
  2008. Static method.
  2009. Sends entire response as a content of the file
  2010. Parameters:
  2011. pIReq CIsapiReqInfo to send
  2012. szFile file name
  2013. szMimeType mime type
  2014. szStatus HTTP status
  2015. szExtraHeaders additional HTTP headers to send
  2016. Returns:
  2017. HRESULT
  2018. ===================================================================*/
  2019. HRESULT CResponse::SyncWriteFile
  2020. (
  2021. CIsapiReqInfo *pIReq,
  2022. TCHAR *szFile,
  2023. char *szMimeType,
  2024. char *szStatus,
  2025. char *szExtraHeaders
  2026. )
  2027. {
  2028. HRESULT hr = S_OK;
  2029. CStaticWriteFileCB *pCB = NULL;
  2030. HANDLE hFile = INVALID_HANDLE_VALUE;
  2031. DWORD dwSize;
  2032. HSE_SEND_ENTIRE_RESPONSE_INFO hseResponseInfo;
  2033. BOOL fHeadersWritten = pIReq->FHeadersWritten();
  2034. BOOL fHeadRequest = (stricmp(pIReq->QueryPszMethod(), "HEAD") == 0);
  2035. if (fHeadersWritten && fHeadRequest)
  2036. return S_OK;
  2037. ZeroMemory( &hseResponseInfo, sizeof(HSE_SEND_ENTIRE_RESPONSE_INFO));
  2038. pCB = new CStaticWriteFileCB;
  2039. if (pCB == NULL) {
  2040. hr = E_OUTOFMEMORY;
  2041. goto LExit;
  2042. }
  2043. if (szMimeType == NULL)
  2044. szMimeType = (char *)GetResponseMimeType(pIReq);
  2045. // open the file
  2046. hFile = AspCreateFile(szFile,
  2047. GENERIC_READ, // access (read-write) mode
  2048. FILE_SHARE_READ, // share mode
  2049. NULL, // pointer to security descriptor
  2050. OPEN_EXISTING, // how to create
  2051. FILE_ATTRIBUTE_NORMAL, // file attributes
  2052. NULL // handle to file with attributes to copy
  2053. );
  2054. if (hFile == INVALID_HANDLE_VALUE)
  2055. {
  2056. DBGERROR((DBG_CONTEXT, "Could not open \"%S\". Win32 Error = %u\n",
  2057. szFile, GetLastError()));
  2058. hr = E_FAIL;
  2059. goto LExit;
  2060. }
  2061. // get file size
  2062. dwSize = GetFileSize(hFile, NULL);
  2063. if (dwSize == 0 || dwSize == 0xFFFFFFFF)
  2064. {
  2065. hr = E_FAIL;
  2066. goto LExit;
  2067. }
  2068. hr = ConstructSimpleHeaders( &hseResponseInfo.HeaderInfo, dwSize, szMimeType, szStatus, szExtraHeaders);
  2069. if (FAILED(hr))
  2070. goto LExit;
  2071. if (fHeadRequest)
  2072. goto LSendResponse;
  2073. // this is our way to transfer a file handle in a WSABUF
  2074. hseResponseInfo.cWsaBuf = 0xFFFFFFFF;
  2075. hseResponseInfo.rgWsaBuf = &(pCB->m_wsaBuf);
  2076. pCB->m_wsaBuf.len = dwSize;
  2077. pCB->m_wsaBuf.buf = (char *)hFile;
  2078. // ownership of the handle has been transferred to the WSABUF
  2079. hFile = INVALID_HANDLE_VALUE;
  2080. LSendResponse:
  2081. if (!pIReq->SendClientResponse(CResponse::StaticWriteFileCompletion,
  2082. pCB,
  2083. &hseResponseInfo)) {
  2084. DWORD dwError = GetLastError();
  2085. CResponse::StaticWriteFileCompletion(pIReq, pCB, 0, dwError);
  2086. hr = HRESULT_FROM_WIN32(dwError);
  2087. // DO NOT place a goto here!!! It will mess up the handling
  2088. // of the pCB cleanup.
  2089. }
  2090. // NULL out pCB so that it won't be freed below. The async compl
  2091. // is now responsible for it via either an error above, or by
  2092. // a real completion. Note that a goto above will mess this up
  2093. // and likely cause a double free.
  2094. pCB = NULL;
  2095. LExit:
  2096. // cleanup
  2097. if (hFile != INVALID_HANDLE_VALUE)
  2098. CloseHandle(hFile);
  2099. // if pCB is still non-zero, then it needs to be freed
  2100. if (pCB)
  2101. delete pCB;
  2102. return hr;
  2103. }
  2104. VOID CResponse::StaticWriteFileCompletion(CIsapiReqInfo *pIReq,
  2105. PVOID pContext,
  2106. DWORD cbIO,
  2107. DWORD dwError)
  2108. {
  2109. CStaticWriteFileCB *pCB = (CStaticWriteFileCB *)pContext;
  2110. #ifndef PERF_DISABLE
  2111. AddtoTotalByteOut(cbIO);
  2112. #endif
  2113. delete pCB;
  2114. }
  2115. /*===================================================================
  2116. CResponse::WriteScriptlessTemplate
  2117. Static method.
  2118. Sends entire response as a content of the [scriptless] template.
  2119. Parameters:
  2120. pIReq CIsapiReqInfo to send
  2121. pTemplate template
  2122. Returns:
  2123. HRESULT
  2124. ===================================================================*/
  2125. HRESULT CResponse::WriteScriptlessTemplate
  2126. (
  2127. CIsapiReqInfo *pIReq,
  2128. CTemplate *pTemplate
  2129. )
  2130. {
  2131. char* pbHTML = NULL;
  2132. ULONG cbHTML = 0;
  2133. ULONG cbSrcOffset = 0;
  2134. char* pbIncSrcFileName = NULL;
  2135. Assert(pTemplate && pTemplate->FScriptless());
  2136. HRESULT hr = pTemplate->GetHTMLBlock(0, &pbHTML, &cbHTML, &cbSrcOffset, &pbIncSrcFileName);
  2137. if (FAILED(hr))
  2138. return hr;
  2139. if (pbHTML == NULL || cbHTML == 0)
  2140. return E_FAIL;
  2141. hr = StaticWrite(pIReq, pbHTML, cbHTML, pTemplate);
  2142. return hr;
  2143. }
  2144. /*===================================================================
  2145. CResponse::WriteBlocksResponse
  2146. Static method.
  2147. Sends entire response as a content of a set of memory blocks.
  2148. Parameters:
  2149. pIReq CIsapiReqInfo to send
  2150. cBlocks number of blocks
  2151. pWsaBuf array of cBlocks structures with data pointers and length
  2152. cbTotal total amount of data
  2153. szMimeType mime type
  2154. szStatus HTTP status
  2155. szExtraHeaders additional HTTP headers to send
  2156. Note: we also use a WSABUF for file handles. This is encoded by cBlocks == 0xFFFFFFFF
  2157. Returns:
  2158. HRESULT
  2159. ===================================================================*/
  2160. HRESULT CResponse::WriteBlocksResponse
  2161. (
  2162. CIsapiReqInfo *pIReq,
  2163. DWORD cBlocks,
  2164. LPWSABUF pWsaBuf,
  2165. DWORD cbTotal,
  2166. char *szMimeType,
  2167. char *szStatus,
  2168. char *szExtraHeaders
  2169. )
  2170. {
  2171. HRESULT hr = S_OK;
  2172. HSE_SEND_ENTIRE_RESPONSE_INFO HseResponseInfo;
  2173. WSABUF_VECTORS WsabuffVectors;
  2174. LPWSABUF_VECTORS pWsabuffVectors = NULL;
  2175. BOOL fHeadersWritten = pIReq->FHeadersWritten();
  2176. BOOL fHeadRequest = (stricmp(pIReq->QueryPszMethod(), "HEAD") == 0);
  2177. if (fHeadersWritten && fHeadRequest)
  2178. return S_OK;
  2179. ZeroMemory( &HseResponseInfo, sizeof(HSE_SEND_ENTIRE_RESPONSE_INFO));
  2180. CResponseBufferSet *pBufferSet = new CResponseBufferSet;
  2181. if (pBufferSet == NULL)
  2182. return E_OUTOFMEMORY;
  2183. hr = pBufferSet->Init(DEFAULT_BUFFER_LIMIT);
  2184. if (FAILED(hr))
  2185. goto LExit;
  2186. if (!fHeadersWritten) {
  2187. if (szMimeType == NULL)
  2188. szMimeType = (char *)GetResponseMimeType(pIReq);
  2189. hr = ConstructSimpleHeaders( &HseResponseInfo.HeaderInfo,
  2190. cbTotal,
  2191. szMimeType,
  2192. szStatus,
  2193. szExtraHeaders);
  2194. if (FAILED(hr))
  2195. goto LExit;
  2196. // set fKeepConn to TRUE to indicate that we do prefer that to
  2197. // keep the connection. SendClientResponse() may decide that
  2198. // it's not possible, though.
  2199. HseResponseInfo.HeaderInfo.fKeepConn = TRUE;
  2200. }
  2201. if (fHeadRequest)
  2202. goto LSendResponse;
  2203. for (DWORD i = 0; SUCCEEDED(hr) && (i < cBlocks); i++) {
  2204. hr = pBufferSet->PResponseBuffer()->Write(pWsaBuf[i].buf,
  2205. pWsaBuf[i].len,
  2206. FALSE); // dont' chunk the data
  2207. if (FAILED(hr))
  2208. goto LExit;
  2209. }
  2210. CResponseVector * pResponseVector = pBufferSet->PResponseBuffer()->GetResponseVector();
  2211. pResponseVector->GetVectors( &WsabuffVectors);
  2212. pWsabuffVectors = &WsabuffVectors;
  2213. LSendResponse:
  2214. if (!pIReq->SendClientResponse(CResponseBufferSet::SendResponseCompletion,
  2215. pBufferSet,
  2216. &HseResponseInfo,
  2217. pWsabuffVectors))
  2218. hr = HRESULT_FROM_WIN32(GetLastError());
  2219. LExit:
  2220. // if these values are set, then SendClientResponse didn't take
  2221. // ownership of this memory and it needs to be deleted here
  2222. if (HseResponseInfo.HeaderInfo.pszStatus)
  2223. free((PVOID)HseResponseInfo.HeaderInfo.pszStatus);
  2224. if (HseResponseInfo.HeaderInfo.pszHeader)
  2225. free((PVOID)HseResponseInfo.HeaderInfo.pszHeader);
  2226. if (FAILED(hr)) {
  2227. delete pBufferSet;
  2228. }
  2229. return hr;
  2230. }
  2231. /*===================================================================
  2232. CResponse::ConstructSimpleHeaders
  2233. Static method.
  2234. Allocates and sets the Header parameters in pHeaderInfo.
  2235. NOTE - this routine allocates memory with malloc to populate the
  2236. headerinfo parameters. If this routine fails, it remains the
  2237. callers responsibility to clean up any allocated memory.
  2238. Parameters:
  2239. pHeaderInfo HSE_SEND_HEADER_EX_INFO struct to fill out
  2240. cbTotal bytes to send for ContentLength header
  2241. szMimeType MimeType
  2242. szStatus HTTP status string
  2243. szExtraHeaders other headers
  2244. Returns:
  2245. HRESULT
  2246. ===================================================================*/
  2247. HRESULT CResponse::ConstructSimpleHeaders
  2248. (
  2249. LPHSE_SEND_HEADER_EX_INFO pHeaderInfo,
  2250. DWORD cbTotal,
  2251. char *szMimeType,
  2252. char *szStatus,
  2253. char *szExtraHeaders
  2254. )
  2255. {
  2256. BOOL fCacheControlPrivate = FALSE;
  2257. // defaut status
  2258. if (szStatus == NULL)
  2259. {
  2260. szStatus = (char *)s_szDefaultStatus;
  2261. fCacheControlPrivate = TRUE;
  2262. }
  2263. else
  2264. {
  2265. fCacheControlPrivate = (strcmp(szStatus, s_szDefaultStatus) == 0);
  2266. }
  2267. // extra headers size
  2268. DWORD cbExtra = (szExtraHeaders != NULL) ? strlen(szExtraHeaders) : 0;
  2269. // send the header
  2270. char szLength[20];
  2271. ltoa(cbTotal, szLength, 10);
  2272. DWORD cchContentHeader = (DWORD)(0
  2273. + sizeof(s_szContentTypeHeader)-1 // Content-Type:
  2274. + strlen(szMimeType) // text/html
  2275. + 2 // \r\n
  2276. + cbExtra // Extra headers
  2277. + sizeof(s_szContentLengthHeader)-1 // Content-Length:
  2278. + strlen(szLength) // <length>
  2279. + 4 // \r\n\r\n
  2280. + 1); // '\0'
  2281. if (fCacheControlPrivate)
  2282. cchContentHeader += sizeof(s_szCacheControlPrivate)-1;
  2283. pHeaderInfo->pszHeader = (LPCSTR)malloc(cchContentHeader);
  2284. if (pHeaderInfo->pszHeader == NULL)
  2285. return E_OUTOFMEMORY;
  2286. char *szBuf = (char *)pHeaderInfo->pszHeader;
  2287. szBuf = strcpyExA(szBuf, s_szContentTypeHeader);
  2288. szBuf = strcpyExA(szBuf, szMimeType);
  2289. szBuf = strcpyExA(szBuf, "\r\n");
  2290. if (cbExtra > 0)
  2291. szBuf = strcpyExA(szBuf, szExtraHeaders);
  2292. if (fCacheControlPrivate)
  2293. szBuf = strcpyExA(szBuf, s_szCacheControlPrivate);
  2294. szBuf = strcpyExA(szBuf, s_szContentLengthHeader);
  2295. szBuf = strcpyExA(szBuf, szLength);
  2296. szBuf = strcpyExA(szBuf, "\r\n\r\n");
  2297. pHeaderInfo->pszStatus = StringDupA(szStatus);
  2298. if (pHeaderInfo->pszStatus == NULL)
  2299. return E_OUTOFMEMORY;
  2300. pHeaderInfo->cchStatus = strlen(szStatus);
  2301. pHeaderInfo->cchHeader = cchContentHeader;
  2302. pHeaderInfo->fKeepConn = FALSE;
  2303. return S_OK;
  2304. }
  2305. /*===================================================================
  2306. CResponse::ConstructHeaders
  2307. Fill a buffer with standard HTTP headers and any user created headers.
  2308. Parameters:
  2309. pHeaderInfo - pointer to header info structure to fill with header
  2310. details and pointers to content.
  2311. pHeaders - points to a resizable buffer object, to be sized and
  2312. filled with the header content.
  2313. Returns:
  2314. HRESULT S_OK on success
  2315. E_FAIL if unable to build expires headers
  2316. E_OUTOFMEMORY if memory failure
  2317. ===================================================================*/
  2318. HRESULT CResponse::ConstructHeaders
  2319. (
  2320. LPHSE_SEND_HEADER_EX_INFO pHeaderInfo
  2321. )
  2322. {
  2323. CHAR *szBuff = NULL;
  2324. DWORD cch = 0;
  2325. BOOL fContentTypeFound = FALSE;
  2326. HRESULT hr = S_OK;
  2327. // Static cookie buffer should be enough to fit:
  2328. // cookie name 20 chars
  2329. // cookie value 24 chars
  2330. // decorations 28 = strlen("Set-Cookie: C=V; secure; path=/;\r\n")
  2331. #define CCH_STATIC_COOKIE_BUF 88
  2332. char szCookieBuff[CCH_STATIC_COOKIE_BUF];
  2333. DWORD cchCookieBuff = 0;
  2334. AssertValid();
  2335. // Loop through any headers counting up the length
  2336. CHTTPHeader *pHeader = m_pData->m_pFirstHeader;
  2337. while (pHeader) {
  2338. cch += pHeader->CchLength();
  2339. pHeader = pHeader->PNext();
  2340. }
  2341. // Add the content-type tag
  2342. cch += sizeof(s_szContentTypeHeader)-1;
  2343. cch += strlen(PContentType())+2;
  2344. // Add the Character set tag
  2345. if (m_pData->m_pszCharSet) {
  2346. cch += sizeof(s_szCharSetHTML)-1;
  2347. cch += strlen(m_pData->m_pszCharSet);
  2348. }
  2349. // Add the Expires tag
  2350. if ((m_pData->m_tExpires != -1) || (m_pData->m_pszDefaultExpires != NULL))
  2351. cch += DATE_STRING_SIZE + 11; // DATE_STRING_SIZE + length("Expires: \r\n")
  2352. // Add the cookies that we will send
  2353. cch += m_pData->m_WriteCookies.QueryHeaderSize()+2;
  2354. // Account for space required by headers we always send back.
  2355. // Prepare cookie if any.
  2356. if (m_pData->m_szCookieVal) {
  2357. char *pchEnd = strcpyExA(szCookieBuff, "Set-Cookie: ");
  2358. pchEnd = strcpyExA(pchEnd, m_pData->m_pHitObj->PAppln()->GetSessionCookieName(m_pData->m_pHitObj->FSecure()));
  2359. pchEnd = strcpyExA(pchEnd, "=");
  2360. pchEnd = strcpyExA(pchEnd, m_pData->m_szCookieVal);
  2361. // If we keep secure sessions secure, and this connection is secure, add flag to cookie
  2362. if ((m_pData->m_pHitObj->QueryAppConfig()->fKeepSessionIDSecure()) &&
  2363. (m_pData->m_pHitObj->FSecure()))
  2364. {
  2365. pchEnd = strcpyExA(pchEnd,"; secure");
  2366. }
  2367. pchEnd = strcpyExA(pchEnd, "; path=/\r\n");
  2368. cchCookieBuff = strlen(szCookieBuff);
  2369. cch += cchCookieBuff;
  2370. Assert(cchCookieBuff < CCH_STATIC_COOKIE_BUF);
  2371. }
  2372. else {
  2373. szCookieBuff[0] = '\0';
  2374. cchCookieBuff = 0;
  2375. }
  2376. // Will len of cache control header
  2377. if (m_pData->m_pszCacheControl) {
  2378. cch += sizeof(s_szCacheControl)-1;
  2379. cch += strlen(m_pData->m_pszCacheControl)+2;
  2380. }
  2381. else {
  2382. cch += sizeof(s_szCacheControlPrivate)-1;
  2383. }
  2384. if (m_pData->FChunkData())
  2385. cch += sizeof(s_szTransferEncoding)-1;
  2386. // Will terminate with \r\n. Leave extra space
  2387. cch += 2;
  2388. /*
  2389. * We know how big; allocate memory and build the string.
  2390. */
  2391. if (!(szBuff = (LPSTR)malloc(cch + 1))) {
  2392. return E_OUTOFMEMORY;
  2393. }
  2394. *szBuff = '\0';
  2395. char *szTmpBuf = szBuff;
  2396. pHeader = m_pData->m_pFirstHeader;
  2397. while (pHeader) {
  2398. pHeader->Print(szTmpBuf);
  2399. szTmpBuf += pHeader->CchLength();
  2400. pHeader = pHeader->PNext();
  2401. }
  2402. // Send the content-type tag
  2403. szTmpBuf = strcpyExA(szTmpBuf, s_szContentTypeHeader);
  2404. szTmpBuf = strcpyExA(szTmpBuf, PContentType());
  2405. // Send the CharSet tag if exists
  2406. if (m_pData->m_pszCharSet) {
  2407. szTmpBuf = strcpyExA(szTmpBuf, s_szCharSetHTML);
  2408. szTmpBuf = strcpyExA(szTmpBuf, m_pData->m_pszCharSet);
  2409. }
  2410. szTmpBuf = strcpyExA(szTmpBuf, "\r\n");
  2411. // Send the Expires tag
  2412. if ((m_pData->m_tExpires != -1) || (m_pData->m_pszDefaultExpires != NULL)) {
  2413. // if the script set an expires value, than use it
  2414. if (m_pData->m_tExpires != -1) {
  2415. szTmpBuf = strcpyExA(szTmpBuf, "Expires: ");
  2416. if (FAILED(CTimeToStringGMT(&m_pData->m_tExpires, szTmpBuf))) {
  2417. hr = E_FAIL;
  2418. goto LExit;
  2419. }
  2420. szTmpBuf += strlen(szTmpBuf);
  2421. szTmpBuf = strcpyExA(szTmpBuf, "\r\n");
  2422. }
  2423. // else, use the default value in the metabase. Note that it already
  2424. // includes the Expires: prefix and \r\n suffix
  2425. else {
  2426. szTmpBuf = strcpyExA(szTmpBuf, m_pData->m_pszDefaultExpires);
  2427. }
  2428. }
  2429. // send the cookies
  2430. m_pData->m_WriteCookies.GetHeaders(szTmpBuf);
  2431. szTmpBuf += strlen(szTmpBuf);
  2432. // Send the required headers: session id cookie and cache control
  2433. szTmpBuf = strcpyExA(szTmpBuf, szCookieBuff);
  2434. // Send the cache-control tag
  2435. if (m_pData->m_pszCacheControl) {
  2436. szTmpBuf = strcpyExA(szTmpBuf, s_szCacheControl);
  2437. szTmpBuf = strcpyExA(szTmpBuf, m_pData->m_pszCacheControl);
  2438. szTmpBuf = strcpyExA(szTmpBuf, "\r\n");
  2439. }
  2440. else {
  2441. szTmpBuf = strcpyExA(szTmpBuf, s_szCacheControlPrivate);
  2442. }
  2443. // Chunked encoding
  2444. if (m_pData->FChunkData())
  2445. szTmpBuf = strcpyExA(szTmpBuf, s_szTransferEncoding);
  2446. // Add trailing \r\n to terminate headers
  2447. szTmpBuf = strcpyExA(szTmpBuf, "\r\n");
  2448. Assert(strlen(szBuff) <= cch);
  2449. // Output the headers
  2450. // Failure is not a fatal error, so we still return success
  2451. // but set the m_fWriteClient flag
  2452. CHAR *szStatus = m_pData->m_pszStatus ? m_pData->m_pszStatus
  2453. : (CHAR *)s_szDefaultStatus;
  2454. BOOL fKeepConnected =
  2455. (m_pData->m_fBufferingOn && !m_pData->m_fFlushed) || m_pData->FChunkData();
  2456. DWORD cchStatus = strlen(szStatus);
  2457. DWORD cchHeader = strlen(szBuff);
  2458. pHeaderInfo->pszStatus = StringDupA(szStatus);
  2459. pHeaderInfo->cchStatus = cchStatus;
  2460. pHeaderInfo->pszHeader = szBuff;
  2461. pHeaderInfo->cchHeader = cchHeader;
  2462. pHeaderInfo->fKeepConn = fKeepConnected;
  2463. LExit:
  2464. if (FAILED(hr) && szBuff)
  2465. free(szBuff);
  2466. return hr;
  2467. }
  2468. //IResponse interface functions
  2469. /*===================================================================
  2470. CResponse::WriteResponse
  2471. Generic routine to send headers and data to the client.
  2472. If headers have not been sent out yet, they will be sent the first time
  2473. this routine is called.
  2474. If transmission of the headers or data to the client fails, we still
  2475. want the calling script to finish execution, so we will return
  2476. S_OK, but set the m_fWriteClientError flag. If we are unable
  2477. to build the needed headers we will return E_FAIL.
  2478. Parameters:
  2479. None
  2480. Returns:
  2481. HRESULT S_OK on success
  2482. E_FAIL if unable to build expires headers
  2483. E_OUTOFMEMORY if memory failure
  2484. ===================================================================*/
  2485. HRESULT CResponse::WriteResponse()
  2486. {
  2487. HRESULT hr = S_OK;
  2488. HSE_SEND_ENTIRE_RESPONSE_INFO HseResponseInfo;
  2489. WSABUF_VECTORS WsabuffVectors;
  2490. LPWSABUF_VECTORS pWsabuffVectors = NULL;
  2491. BOOL fClearBuffers = FALSE;
  2492. CTemplate *pTemplate = m_pData->m_pBufferSet->PTemplate();
  2493. STACK_BUFFER( tempWSABUFs, 128 );
  2494. if (FAILED(CheckForTombstone()))
  2495. return E_FAIL;
  2496. if (FDontWrite())
  2497. return S_OK;
  2498. ZeroMemory( &HseResponseInfo.HeaderInfo, sizeof(HSE_SEND_HEADER_EX_INFO));
  2499. if (!FHeadersWritten())
  2500. {
  2501. if (FAILED(hr = ConstructHeaders( &HseResponseInfo.HeaderInfo)))
  2502. {
  2503. return hr;
  2504. }
  2505. }
  2506. HseResponseInfo.cWsaBuf = 0;
  2507. HseResponseInfo.rgWsaBuf = NULL;
  2508. if (IsHeadRequest())
  2509. {
  2510. if (FHeadersWritten())
  2511. goto LExit;
  2512. goto Send_Response;
  2513. }
  2514. BOOL fSendDebugBuffers = (m_pData->m_fClientDebugMode && m_pData->m_pBufferSet->PClientDebugBuffer());
  2515. fClearBuffers = TRUE;
  2516. // populate struct with response body buffers (and, if required, debug buffers)
  2517. if (fSendDebugBuffers)
  2518. {
  2519. CResponseBuffer * pClientDebugBuffer = m_pData->m_pBufferSet->PClientDebugBuffer();
  2520. DWORD cClientDebugBuffers = pClientDebugBuffer->CountOfBuffers();
  2521. if (cClientDebugBuffers)
  2522. {
  2523. HseResponseInfo.cWsaBuf = cClientDebugBuffers;
  2524. if (!tempWSABUFs.Resize(HseResponseInfo.cWsaBuf * sizeof(WSABUF)))
  2525. {
  2526. hr = E_OUTOFMEMORY;
  2527. goto LExit;
  2528. }
  2529. HseResponseInfo.rgWsaBuf = static_cast<WSABUF *>(tempWSABUFs.QueryPtr());
  2530. // fill debug buffers
  2531. for ( UINT i = 0; i < cClientDebugBuffers; i++ )
  2532. {
  2533. HseResponseInfo.rgWsaBuf[i].len = pClientDebugBuffer->GetBufferSize(i);
  2534. HseResponseInfo.rgWsaBuf[i].buf = pClientDebugBuffer->GetBuffer(i);
  2535. }
  2536. }
  2537. }
  2538. CResponseVector * pResponseVector = m_pData->m_pBufferSet->PResponseBuffer()->GetResponseVector();
  2539. pResponseVector->GetVectors( &WsabuffVectors);
  2540. pWsabuffVectors = &WsabuffVectors;
  2541. Send_Response:
  2542. BOOL fResponseSent;
  2543. // send entire response (headers and body) at once
  2544. fResponseSent = GetIReq()->SendClientResponse(CResponseBufferSet::SendResponseCompletion,
  2545. m_pData->m_pBufferSet,
  2546. &HseResponseInfo,
  2547. pWsabuffVectors);
  2548. if (fResponseSent)
  2549. {
  2550. m_pData->m_pBufferSet = new CResponseBufferSet();
  2551. if (m_pData->m_pBufferSet == NULL) {
  2552. hr = E_OUTOFMEMORY;
  2553. goto LExit;
  2554. }
  2555. hr = m_pData->m_pBufferSet->Init(m_pData->m_dwBufferLimit);
  2556. if (FAILED(hr))
  2557. goto LExit;
  2558. m_pData->m_pBufferSet->SetTemplate(pTemplate);
  2559. fClearBuffers = FALSE;
  2560. }
  2561. else
  2562. {
  2563. m_pData->m_fWriteClientError = TRUE;
  2564. }
  2565. // we have consumed the buffered data, so clear.
  2566. if (fClearBuffers)
  2567. {
  2568. if (m_pData->m_pBufferSet->PClientDebugBuffer())
  2569. {
  2570. m_pData->m_pBufferSet->PClientDebugBuffer()->Clear();
  2571. }
  2572. m_pData->m_pBufferSet->PResponseBuffer()->Clear();
  2573. }
  2574. LExit:
  2575. if (FAILED(hr)) {
  2576. if (HseResponseInfo.HeaderInfo.pszStatus)
  2577. free((PVOID)HseResponseInfo.HeaderInfo.pszStatus);
  2578. if (HseResponseInfo.HeaderInfo.pszHeader)
  2579. free((PVOID)HseResponseInfo.HeaderInfo.pszHeader);
  2580. }
  2581. return hr;
  2582. }
  2583. /*===================================================================
  2584. CResponse::Write
  2585. Writes a string to the client.
  2586. It accepts a variant as an argument and attempts to coerce that
  2587. variant into a BSTR. We convert that BSTR into an ANSI string,
  2588. and then hand that ANSI string to Response::WriteSz which sends
  2589. it back to the client.
  2590. Normally a VT_NULL variant cannot be coerced to a BSTR, but we want
  2591. VT_NULL to be a valid input, therefore we explictly handle the case of
  2592. variants of type VT_NULL. If the type of the input variant is VT_NULL
  2593. we return S_OK, but don't send anything back to the client.
  2594. If we are handed a VT_DISPATCH variant, we resolve it by repeatedly calling
  2595. Dispatch on the associated pdispVal, until we get back a variant that is not
  2596. a VT_DISPATCH. VariantChangeType would ordinarily handle this for us, but the
  2597. final resulting variant might be a VT_NULL which VariantChangeType would not
  2598. coerce into a BSTR. This is why we have to handle walking down the VT_DISPATC
  2599. variants outselves.
  2600. Parameters:
  2601. VARIANT varInput, value: the variant to be converted to string
  2602. and written to the client
  2603. Returns:
  2604. S_OK on success. E_FAIL on failure.
  2605. ===================================================================*/
  2606. STDMETHODIMP CResponse::Write(VARIANT varInput)
  2607. {
  2608. if (FAILED(CheckForTombstone()))
  2609. return E_FAIL;
  2610. HRESULT hr = S_OK;
  2611. DWORD cch;
  2612. LPSTR szT;
  2613. BSTR bstr;
  2614. VARIANT varResolved;
  2615. static char szTrue[MAX_MESSAGE_LENGTH];
  2616. static char szFalse[MAX_MESSAGE_LENGTH];
  2617. AssertValid();
  2618. // If we've already had an error writing to the client
  2619. // there is no point in proceding, so we immediately return
  2620. // with no error
  2621. if (FDontWrite())
  2622. goto lRet2;
  2623. // If already BSTR (directly or as VARIANT by ref)
  2624. bstr = VariantGetBSTR(&varInput);
  2625. if (bstr != NULL)
  2626. {
  2627. hr = WriteBSTR(bstr);
  2628. goto lRet2;
  2629. }
  2630. // If the variant passed in is a VT_DISPATCH, get its default property
  2631. if (FAILED(hr = VariantResolveDispatch(&varResolved, &varInput, IID_IResponse, IDE_RESPONSE)))
  2632. goto lRet2;
  2633. // Check if the variant in is VT_NULL
  2634. if (V_VT(&varResolved) == VT_NULL)
  2635. goto lRet; // S_OK, but don't send anything to the client
  2636. // Check if the variant in is VT_BOOL
  2637. if(V_VT(&varResolved) == VT_BOOL)
  2638. {
  2639. if (V_BOOL(&varResolved) == VARIANT_TRUE)
  2640. {
  2641. if (szTrue[0] == '\0')
  2642. cch = CchLoadStringOfId(IDS_TRUE, szTrue, MAX_MESSAGE_LENGTH);
  2643. szT = szTrue;
  2644. }
  2645. else
  2646. {
  2647. if(szFalse[0] == '\0')
  2648. cch = CchLoadStringOfId(IDS_FALSE, szFalse, MAX_MESSAGE_LENGTH);
  2649. szT = szFalse;
  2650. }
  2651. cch = strlen(szT);
  2652. if (FAILED(hr = WriteSz(szT, cch)))
  2653. {
  2654. if (E_OUTOFMEMORY == hr)
  2655. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  2656. else
  2657. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_UNEXPECTED);
  2658. }
  2659. goto lRet;
  2660. }
  2661. // Coerce the variant into a bstr if necessary
  2662. if (V_VT(&varResolved) != VT_BSTR)
  2663. {
  2664. if (FAILED(hr = VariantChangeTypeEx(&varResolved, &varResolved, m_pData->m_pHitObj->GetLCID(), 0, VT_BSTR)))
  2665. {
  2666. switch (GetScode(hr))
  2667. {
  2668. case E_OUTOFMEMORY:
  2669. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  2670. break;
  2671. case DISP_E_OVERFLOW:
  2672. hr = E_FAIL;
  2673. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_UNABLE_TO_CONVERT);
  2674. break;
  2675. case DISP_E_TYPEMISMATCH:
  2676. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_TYPE_MISMATCH);
  2677. break;
  2678. default:
  2679. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_UNEXPECTED);
  2680. }
  2681. goto lRet;
  2682. }
  2683. }
  2684. hr = WriteBSTR(V_BSTR(&varResolved));
  2685. lRet:
  2686. #ifdef DBG
  2687. hr =
  2688. #endif // DBG
  2689. VariantClear(&varResolved);
  2690. Assert(SUCCEEDED(hr));
  2691. lRet2:
  2692. return(hr);
  2693. }
  2694. /*===================================================================
  2695. CResponse::BinaryWrite
  2696. Function called from DispInvoke to invoke the BinaryWrite method.
  2697. Parameters:
  2698. varInput Variant which must resolve to an array of unsigned bytes
  2699. Returns:
  2700. S_OK on success. E_FAIL on failure.
  2701. ===================================================================*/
  2702. STDMETHODIMP CResponse::BinaryWrite(VARIANT varInput)
  2703. {
  2704. if (FAILED(CheckForTombstone()))
  2705. return E_FAIL;
  2706. HRESULT hr = S_OK;
  2707. DWORD nDim = 0;
  2708. long lLBound = 0;
  2709. long lUBound = 0;
  2710. void *lpData = NULL;
  2711. DWORD cch = 0;
  2712. VARIANT varResolved;
  2713. SAFEARRAY* pvarBuffer;
  2714. AssertValid();
  2715. // If we've already had an error writing to the client
  2716. // there is no point in proceding, so we immediately return
  2717. // with no error
  2718. if (FDontWrite())
  2719. goto lRet2;
  2720. // De-reference and de-dispatch the variant
  2721. if (FAILED(hr = VariantResolveDispatch(&varResolved, &varInput, IID_IResponse, IDE_RESPONSE)))
  2722. goto lRet2;
  2723. // Coerce the result into an array of VT_UI1 if needed
  2724. if (V_VT(&varResolved) != (VT_ARRAY|VT_UI1))
  2725. {
  2726. if (FAILED(hr = VariantChangeType(&varResolved, &varResolved, 0, VT_ARRAY|VT_UI1)))
  2727. {
  2728. switch (GetScode(hr))
  2729. {
  2730. case E_OUTOFMEMORY:
  2731. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  2732. break;
  2733. case DISP_E_OVERFLOW:
  2734. hr = E_FAIL;
  2735. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_UNABLE_TO_CONVERT);
  2736. break;
  2737. case DISP_E_TYPEMISMATCH:
  2738. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_TYPE_MISMATCH);
  2739. break;
  2740. default:
  2741. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_UNEXPECTED);
  2742. }
  2743. goto lRet;
  2744. }
  2745. }
  2746. // We got here, so we must have a variant containing a safe array of UI1 in varResolved
  2747. pvarBuffer = V_ARRAY(&varResolved);
  2748. nDim = SafeArrayGetDim(pvarBuffer);
  2749. if (nDim != 1)
  2750. {
  2751. hr = E_INVALIDARG;
  2752. goto lRet;
  2753. }
  2754. if (FAILED(SafeArrayGetLBound(pvarBuffer, 1, &lLBound)))
  2755. {
  2756. hr = E_INVALIDARG;
  2757. goto lRet;
  2758. }
  2759. if (FAILED(SafeArrayGetUBound(pvarBuffer, 1, &lUBound)))
  2760. {
  2761. hr = E_INVALIDARG;
  2762. goto lRet;
  2763. }
  2764. if (FAILED(SafeArrayAccessData(pvarBuffer, &lpData)))
  2765. {
  2766. hr = E_INVALIDARG;
  2767. goto lRet;
  2768. }
  2769. cch = lUBound - lLBound + 1;
  2770. hr = m_pData->m_pBufferSet->PResponseBuffer()->Write((char *) lpData,
  2771. cch,
  2772. m_pData->FChunkData());
  2773. if (FAILED(hr))
  2774. {
  2775. // We can't buffer the ouput, so quit
  2776. SafeArrayUnaccessData(pvarBuffer);
  2777. if (E_OUTOFMEMORY == hr)
  2778. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  2779. else
  2780. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_UNEXPECTED);
  2781. goto lRet;
  2782. }
  2783. else if (!m_pData->m_fBufferingOn)
  2784. {
  2785. // Buffering is off, Flush the data we just added to the response buffer
  2786. hr = WriteResponse();
  2787. if (FAILED(hr)) {
  2788. SafeArrayUnaccessData(pvarBuffer);
  2789. goto lRet;
  2790. }
  2791. }
  2792. hr = SafeArrayUnaccessData(pvarBuffer);
  2793. lRet:
  2794. VariantClear(&varResolved);
  2795. lRet2:
  2796. return(hr);
  2797. }
  2798. /*===================================================================
  2799. CResponse::WriteSz
  2800. Support routine for the Write method to write the string. Unlike
  2801. CResponse::Write(), this routine takes an Ascii string, and is
  2802. not intended to be exposed as a method
  2803. Parameters:
  2804. sz - String to write as an Ascii string
  2805. cch - Length of string to write
  2806. Returns:
  2807. S_OK on success.
  2808. ===================================================================*/
  2809. HRESULT CResponse::WriteSz(CHAR *sz, DWORD cch)
  2810. {
  2811. if (FAILED(CheckForTombstone()))
  2812. return E_FAIL;
  2813. HRESULT hr = S_OK;
  2814. AssertValid();
  2815. // If we've already had an error writing to the client
  2816. // there is no point in proceding, so we immediately return
  2817. // with no error
  2818. if (FDontWrite())
  2819. goto lRet;
  2820. // don't bother with zero byte writes...
  2821. if (cch == 0)
  2822. goto lRet;
  2823. hr = m_pData->m_pBufferSet->PResponseBuffer()->Write(sz,
  2824. cch,
  2825. m_pData->FChunkData());
  2826. if (SUCCEEDED(hr) && !m_pData->m_fBufferingOn)
  2827. {
  2828. hr = WriteResponse();
  2829. }
  2830. lRet:
  2831. return(hr);
  2832. }
  2833. /*===================================================================
  2834. CResponse::WriteBSTR
  2835. Support routine for the Write method
  2836. Parameters:
  2837. BSTR - String to write as an Ascii string
  2838. Returns:
  2839. S_OK on success.
  2840. ===================================================================*/
  2841. HRESULT CResponse::WriteBSTR(BSTR bstr)
  2842. {
  2843. CWCharToMBCS convStr;
  2844. HRESULT hr = NO_ERROR;
  2845. if (FAILED(hr = convStr.Init(bstr, m_pData->m_pHitObj->GetCodePage())));
  2846. else hr = WriteSz(convStr.GetString(), convStr.GetStringLen());
  2847. if (FAILED(hr))
  2848. {
  2849. if (E_OUTOFMEMORY == hr)
  2850. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  2851. else
  2852. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_UNEXPECTED);
  2853. }
  2854. return hr;
  2855. }
  2856. /*===================================================================
  2857. CResponse::WriteBlock
  2858. Function called from DispInvoke to invoke the WriteBlock method.
  2859. Parameters:
  2860. Identifier for the HTML block
  2861. Returns:
  2862. S_OK on success. E_FAIL on failure.
  2863. ===================================================================*/
  2864. HRESULT CResponse::WriteBlock(short iBlockNumber)
  2865. {
  2866. if (FAILED(CheckForTombstone()))
  2867. return E_FAIL;
  2868. HRESULT hr = S_OK;
  2869. char* pbHTML = NULL;
  2870. ULONG cbHTML = 0;
  2871. ULONG cbSrcOffset = 0;
  2872. char* pbIncSrcFileName = NULL;
  2873. AssertValid();
  2874. // If we've already had an error writing to the client
  2875. // there is no point in proceding, so we immediately return
  2876. // with no error
  2877. if (FDontWrite())
  2878. goto lRet;
  2879. // bail out (and assert) if template is null
  2880. Assert(m_pData->m_pBufferSet->PTemplate() != NULL);
  2881. if (m_pData->m_pBufferSet->PTemplate() == NULL)
  2882. {
  2883. hr = E_FAIL;
  2884. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_UNEXPECTED);
  2885. goto lRet;
  2886. }
  2887. /*
  2888. get ptr and byte count for html block from template
  2889. NOTE: by design, this public template call cannot fail because we give it a block id
  2890. generated during template compilation (instead we assert within and after the call)
  2891. I added the return HRESULT to catch for invalid user access of this method, if a user
  2892. attempts to access this method and passes an invalid array offset it will return the
  2893. error IDE_BAD_ARRAY_INDEX, this really should not happen except for the case of a user
  2894. attempting to access this hidden method.
  2895. */
  2896. hr = m_pData->m_pBufferSet->PTemplate()->GetHTMLBlock(iBlockNumber, &pbHTML, &cbHTML, &cbSrcOffset, &pbIncSrcFileName);
  2897. if ( hr != S_OK )
  2898. {
  2899. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_BAD_ARRAY_INDEX);
  2900. goto lRet;
  2901. }
  2902. Assert(pbHTML);
  2903. Assert(cbHTML > 0);
  2904. if (m_pData->m_fBufferingOn)
  2905. {
  2906. // Buffering is on
  2907. hr = S_OK;
  2908. // Take care of Client Debugger issues
  2909. if (m_pData->m_fClientDebugMode && m_pData->m_pBufferSet->PClientDebugBuffer())
  2910. {
  2911. if (cbSrcOffset) // only if source info is known
  2912. {
  2913. // Write a METADATA line corresponding to this block
  2914. // into ClientDebugBuffer
  2915. ULONG cbPos = m_pData->m_pBufferSet->PResponseBuffer()->BytesBuffered() + 1;
  2916. ULONG cbLen = cbHTML;
  2917. hr = m_pData->m_pBufferSet->PClientDebugBuffer()->AppendRecord(
  2918. cbPos, cbLen, cbSrcOffset, pbIncSrcFileName);
  2919. }
  2920. }
  2921. }
  2922. // Write the actual data
  2923. if (SUCCEEDED(hr))
  2924. {
  2925. hr = m_pData->m_pBufferSet->PResponseBuffer()->Write(pbHTML,
  2926. cbHTML,
  2927. m_pData->FChunkData(),
  2928. TRUE); // data's in template
  2929. }
  2930. if (FAILED(hr))
  2931. {
  2932. if (E_OUTOFMEMORY == hr)
  2933. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  2934. else
  2935. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_UNEXPECTED);
  2936. }
  2937. if (SUCCEEDED(hr) && !m_pData->m_fBufferingOn)
  2938. hr = WriteResponse();
  2939. lRet:
  2940. return(hr);
  2941. }
  2942. /*===================================================================
  2943. CResponse::GetClientVersion
  2944. Uses GetServerVariable to determine the HTTP version of the client.
  2945. Borrowed from simiarl code in w3 server Httpreq.cxx, OnVersion()
  2946. Parameters:
  2947. None
  2948. Returns:
  2949. None
  2950. ===================================================================*/
  2951. VOID CResponse::GetClientVerison()
  2952. {
  2953. if (FAILED(CheckForTombstone()))
  2954. return;
  2955. if (m_pData->m_pIReq)
  2956. {
  2957. m_pData->m_dwVersionMajor = (BYTE)m_pData->m_pIReq->QueryHttpVersionMajor();
  2958. m_pData->m_dwVersionMinor = (BYTE)m_pData->m_pIReq->QueryHttpVersionMinor();
  2959. }
  2960. else
  2961. {
  2962. // Assume version 0.9
  2963. m_pData->m_dwVersionMajor = 0;
  2964. m_pData->m_dwVersionMinor = 9;
  2965. }
  2966. }
  2967. /*===================================================================
  2968. CResponse::AppendHeader
  2969. Functions to add headers of different kind
  2970. (hardcoded and user-supplied)
  2971. Parameters:
  2972. Name, Value
  2973. Returns:
  2974. HRESULT S_OK if ok
  2975. ===================================================================*/
  2976. HRESULT CResponse::AppendHeader(BSTR wszName, BSTR wszValue)
  2977. {
  2978. CHTTPHeader *pHeader = new CHTTPHeader;
  2979. if (!pHeader)
  2980. return E_OUTOFMEMORY;
  2981. if (FAILED(pHeader->InitHeader(wszName, wszValue,m_pData->m_pHitObj->GetCodePage())))
  2982. {
  2983. delete pHeader;
  2984. return E_FAIL;
  2985. }
  2986. m_pData->AppendHeaderToList(pHeader);
  2987. return S_OK;
  2988. }
  2989. HRESULT CResponse::AppendHeader(char *szName, BSTR wszValue)
  2990. {
  2991. CHTTPHeader *pHeader = new CHTTPHeader;
  2992. if (!pHeader)
  2993. return E_OUTOFMEMORY;
  2994. if (FAILED(pHeader->InitHeader(szName, wszValue,m_pData->m_pHitObj->GetCodePage())))
  2995. {
  2996. delete pHeader;
  2997. return E_FAIL;
  2998. }
  2999. m_pData->AppendHeaderToList(pHeader);
  3000. return S_OK;
  3001. }
  3002. HRESULT CResponse::AppendHeader(char *szName, char *szValue, BOOL fCopyValue)
  3003. {
  3004. CHTTPHeader *pHeader = new CHTTPHeader;
  3005. if (!pHeader)
  3006. return E_OUTOFMEMORY;
  3007. if (FAILED(pHeader->InitHeader(szName, szValue, fCopyValue)))
  3008. {
  3009. delete pHeader;
  3010. return E_FAIL;
  3011. }
  3012. m_pData->AppendHeaderToList(pHeader);
  3013. return S_OK;
  3014. }
  3015. HRESULT CResponse::AppendHeader(char *szName, long lValue)
  3016. {
  3017. CHTTPHeader *pHeader = new CHTTPHeader;
  3018. if (!pHeader)
  3019. return E_OUTOFMEMORY;
  3020. if (FAILED(pHeader->InitHeader(szName, lValue)))
  3021. {
  3022. delete pHeader;
  3023. return E_FAIL;
  3024. }
  3025. m_pData->AppendHeaderToList(pHeader);
  3026. return S_OK;
  3027. }
  3028. /*===================================================================
  3029. CResponse::get_ContentType
  3030. Functions called from DispInvoke to return the ContentType property.
  3031. Parameters:
  3032. pbstrContentTypeRet BSTR FAR *, return value: pointer to the ContentType as a string
  3033. Returns:
  3034. HRESULT S_OK if ok
  3035. ===================================================================*/
  3036. STDMETHODIMP CResponse::get_ContentType
  3037. (
  3038. BSTR FAR * pbstrContentTypeRet
  3039. )
  3040. {
  3041. if (FAILED(CheckForTombstone()))
  3042. return E_FAIL;
  3043. HRESULT hr = S_OK;
  3044. hr = SysAllocStringFromSz((char *)PContentType(), 0, pbstrContentTypeRet);
  3045. if (FAILED(hr))
  3046. {
  3047. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3048. hr = E_FAIL;
  3049. }
  3050. return(hr);
  3051. }
  3052. /*===================================================================
  3053. CResponse::put_ContentType
  3054. Functions called from DispInvoke to set the ContentType property.
  3055. Parameters:
  3056. bstrContentType BSTR, value: the ContentType as a string
  3057. Returns:
  3058. HRESULT S_OK if ok
  3059. ===================================================================*/
  3060. STDMETHODIMP CResponse::put_ContentType
  3061. (
  3062. BSTR bstrContentType
  3063. )
  3064. {
  3065. if (FAILED(CheckForTombstone()))
  3066. return E_FAIL;
  3067. HRESULT hr = S_OK;
  3068. CWCharToMBCS convStr;
  3069. if (FHeadersWritten())
  3070. {
  3071. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  3072. hr = E_FAIL;
  3073. goto lRet;
  3074. }
  3075. if (m_pData->m_pszContentType) {
  3076. free(m_pData->m_pszContentType);
  3077. m_pData->m_pszContentType = NULL;
  3078. }
  3079. if (FAILED(hr = convStr.Init(bstrContentType)));
  3080. else if ((m_pData->m_pszContentType = convStr.GetString(TRUE)) == NULL) {
  3081. hr = E_OUTOFMEMORY;
  3082. }
  3083. lRet:
  3084. if (hr == E_OUTOFMEMORY) {
  3085. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3086. SetLastError((DWORD)E_OUTOFMEMORY);
  3087. }
  3088. return(hr);
  3089. }
  3090. /*===================================================================
  3091. CResponse::get_Status
  3092. Function called from DispInvoke to return the Status property.
  3093. Parameters:
  3094. pbstrStatusRet BSTR FAR *, return value: pointer to the Status as a string
  3095. Returns:
  3096. HRESULT S_OK if ok
  3097. ===================================================================*/
  3098. STDMETHODIMP CResponse::get_Status
  3099. (
  3100. BSTR FAR * pbstrStatusRet
  3101. )
  3102. {
  3103. if (FAILED(CheckForTombstone()))
  3104. return E_FAIL;
  3105. HRESULT hr = S_OK;
  3106. if (m_pData->m_pszStatus)
  3107. hr = SysAllocStringFromSz(m_pData->m_pszStatus, 0, pbstrStatusRet);
  3108. else
  3109. hr = SysAllocStringFromSz((CHAR *)s_szDefaultStatus, 0, pbstrStatusRet);
  3110. if (FAILED(hr))
  3111. {
  3112. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3113. hr = E_FAIL;
  3114. }
  3115. return(hr);
  3116. }
  3117. /*===================================================================
  3118. CResponse::put_Status
  3119. Function called from DispInvoke to set the ContentType property.
  3120. Parameters:
  3121. bstrStatus BSTR, value: the status as a string
  3122. Returns:
  3123. HRESULT S_OK if ok
  3124. ===================================================================*/
  3125. STDMETHODIMP CResponse::put_Status
  3126. (
  3127. BSTR bstrStatus
  3128. )
  3129. {
  3130. DWORD dwStatus = 200;
  3131. if (FAILED(CheckForTombstone()))
  3132. return E_FAIL;
  3133. HRESULT hr = S_OK;
  3134. CWCharToMBCS convStr;
  3135. if (FHeadersWritten())
  3136. {
  3137. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  3138. hr = E_FAIL;
  3139. goto lRet;
  3140. }
  3141. if (m_pData->m_pszStatus) {
  3142. free(m_pData->m_pszStatus);
  3143. m_pData->m_pszStatus = NULL;
  3144. }
  3145. if (FAILED(hr = convStr.Init(bstrStatus)));
  3146. else if ((m_pData->m_pszStatus = convStr.GetString(TRUE)) == NULL) {
  3147. hr = E_OUTOFMEMORY;
  3148. }
  3149. else {
  3150. dwStatus = atol(m_pData->m_pszStatus);
  3151. GetIReq()->SetDwHttpStatusCode(dwStatus);
  3152. }
  3153. lRet:
  3154. if (hr == E_OUTOFMEMORY) {
  3155. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3156. SetLastError((DWORD)E_OUTOFMEMORY);
  3157. }
  3158. return(hr);
  3159. }
  3160. /*===================================================================
  3161. CResponse::get_Expires
  3162. Function called from DispInvoke to return the Expires property.
  3163. Parameters:
  3164. plExpiresTimeRet long *, return value: pointer to number of minutes until response expires
  3165. Returns:
  3166. HRESULT S_OK if ok
  3167. ===================================================================*/
  3168. STDMETHODIMP CResponse::get_Expires
  3169. (
  3170. VARIANT * pvarExpiresTimeRet
  3171. )
  3172. {
  3173. if (FAILED(CheckForTombstone()))
  3174. return E_FAIL;
  3175. // return early if we can
  3176. //
  3177. if (m_pData->m_tExpires == -1)
  3178. {
  3179. V_VT(pvarExpiresTimeRet) = VT_NULL;
  3180. return S_OK;
  3181. }
  3182. // get the current time
  3183. //
  3184. time_t tNow;
  3185. time(&tNow);
  3186. // get the time difference and round to the nearest minute
  3187. //
  3188. V_VT(pvarExpiresTimeRet) = VT_I4;
  3189. V_I4(pvarExpiresTimeRet) = long((difftime(m_pData->m_tExpires, tNow) / 60) + 0.5);
  3190. return S_OK;
  3191. }
  3192. /*===================================================================
  3193. CResponse::put_Expires
  3194. Functions called from DispInvoke to set the expires property.
  3195. Parameters:
  3196. iValue int, value: the number of minutes until response should expire
  3197. Returns:
  3198. HRESULT S_OK if ok
  3199. ===================================================================*/
  3200. STDMETHODIMP CResponse::put_Expires
  3201. (
  3202. long lExpiresMinutes
  3203. )
  3204. {
  3205. if (FAILED(CheckForTombstone()))
  3206. return E_FAIL;
  3207. if (FHeadersWritten())
  3208. {
  3209. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  3210. return E_FAIL;
  3211. }
  3212. // get the current time
  3213. //
  3214. time_t tNow;
  3215. time(&tNow);
  3216. time_t tRelativeTime;
  3217. // add the number of minuites. (must convert to seconds first)
  3218. //
  3219. tRelativeTime = lExpiresMinutes * 60;
  3220. if ((lExpiresMinutes < 0 && tRelativeTime > 0)
  3221. || (lExpiresMinutes > 0 && tRelativeTime < 0))
  3222. {
  3223. // overflow, tRelativeTime could be a small positive integer if lExpiresMinutes is
  3224. // some value like 0x80000010
  3225. // tNow will be overflowed if tRelativeTime is negative
  3226. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_COOKIE_BAD_EXPIRATION);
  3227. return E_FAIL;
  3228. }
  3229. tNow += tRelativeTime;
  3230. // Store the date if
  3231. // a. No date was stored previously
  3232. // b. This date comes before the previously set date.
  3233. //
  3234. if (m_pData->m_tExpires == -1 || tNow < m_pData->m_tExpires)
  3235. {
  3236. struct tm *ptmGMT = gmtime(&tNow);
  3237. if (ptmGMT == NULL)
  3238. {
  3239. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_COOKIE_BAD_EXPIRATION);
  3240. return E_FAIL;
  3241. }
  3242. m_pData->m_tExpires = tNow;
  3243. }
  3244. // convert time to GMT
  3245. return S_OK;
  3246. }
  3247. /*===================================================================
  3248. CResponse::get_ExpiresAbsolute
  3249. Function called from DispInvoke to return the ExpiresAbsolute property.
  3250. Parameters:
  3251. pbstrTimeRet BSTR *, return value: pointer to string that will contain
  3252. the time response should expire
  3253. Returns:
  3254. HRESULT S_OK if ok
  3255. ===================================================================*/
  3256. STDMETHODIMP CResponse::get_ExpiresAbsolute
  3257. (
  3258. VARIANT *pvarTimeRet
  3259. )
  3260. {
  3261. if (FAILED(CheckForTombstone()))
  3262. return E_FAIL;
  3263. V_VT(pvarTimeRet) = VT_DATE;
  3264. CTimeToVariantDate(&m_pData->m_tExpires, &V_DATE(pvarTimeRet));
  3265. return S_OK;
  3266. }
  3267. /*===================================================================
  3268. CResponse::put_ExpiresAbsolute
  3269. Function called from DispInvoke to set the ExpiresAbsolute property.
  3270. Parameters:
  3271. pbstrTime BSTR, value: time response should expire
  3272. Returns:
  3273. HRESULT S_OK if ok
  3274. ===================================================================*/
  3275. STDMETHODIMP CResponse::put_ExpiresAbsolute
  3276. (
  3277. DATE dtExpires
  3278. )
  3279. {
  3280. if (FAILED(CheckForTombstone()))
  3281. return E_FAIL;
  3282. if (FHeadersWritten())
  3283. {
  3284. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  3285. return E_FAIL;
  3286. }
  3287. if (int(dtExpires) == 0) // time specified but no date (assume today)
  3288. {
  3289. time_t tToday; // get the date and time now
  3290. DATE dtToday;
  3291. time(&tToday);
  3292. struct tm *tmToday = localtime(&tToday);
  3293. tmToday->tm_hour = tmToday->tm_min = tmToday->tm_sec = 0; // reset to midnight
  3294. tToday = mktime(tmToday);
  3295. if (FAILED(CTimeToVariantDate(&tToday, &dtToday)))
  3296. return E_FAIL;
  3297. dtExpires += dtToday;
  3298. }
  3299. time_t tExpires;
  3300. if (FAILED(VariantDateToCTime(dtExpires, &tExpires)))
  3301. {
  3302. ExceptionId(IID_IWriteCookie, IDE_RESPONSE, IDE_COOKIE_BAD_EXPIRATION);
  3303. return E_FAIL;
  3304. }
  3305. if (m_pData->m_tExpires == -1 || tExpires < m_pData->m_tExpires)
  3306. {
  3307. m_pData->m_tExpires = tExpires;
  3308. }
  3309. return S_OK;
  3310. }
  3311. /*===================================================================
  3312. CResponse::put_Buffer
  3313. Function called from DispInvoke to set the Buffer property.
  3314. Parameters:
  3315. fIsBuffering VARIANT_BOOL, if true turn on buffering of HTML output
  3316. Returns:
  3317. HRESULT S_OK if ok
  3318. Side Effects:
  3319. Turning buffering on will cause memory to be allocated.
  3320. ===================================================================*/
  3321. STDMETHODIMP CResponse::put_Buffer
  3322. (
  3323. VARIANT_BOOL fIsBuffering
  3324. )
  3325. {
  3326. if (FAILED(CheckForTombstone()))
  3327. return E_FAIL;
  3328. // Assume TRUE if not 0
  3329. if (fIsBuffering != VARIANT_FALSE)
  3330. fIsBuffering = VARIANT_TRUE;
  3331. // Ignore no change requests
  3332. if ((fIsBuffering == VARIANT_TRUE) && m_pData->m_fBufferingOn)
  3333. return S_OK;
  3334. if ((fIsBuffering == VARIANT_FALSE) && !m_pData->m_fBufferingOn)
  3335. return S_OK;
  3336. // Ignore if change is not allowed to change (Client Dedug)
  3337. if (m_pData->m_fClientDebugMode)
  3338. return S_OK;
  3339. // Set the new value (error if cannot change)
  3340. if (fIsBuffering == VARIANT_TRUE)
  3341. {
  3342. if (FHeadersWritten())
  3343. {
  3344. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  3345. return E_FAIL;
  3346. }
  3347. m_pData->m_fBufferingOn = TRUE;
  3348. }
  3349. else // if (fIsBuffering == VARIANT_FALSE)
  3350. {
  3351. if ((m_pData->m_pBufferSet->PResponseBuffer()->BytesBuffered() > 0) ||
  3352. FHeadersWritten())
  3353. {
  3354. // If we already buffered some output it is too late to go back
  3355. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_CANT_STOP_BUFFER);
  3356. return E_FAIL;
  3357. }
  3358. m_pData->m_fBufferingOn = FALSE;
  3359. }
  3360. return S_OK;
  3361. }
  3362. /*===================================================================
  3363. CResponse::get_Buffer
  3364. Function called from DispInvoke to get the Buffer property.
  3365. Parameters:
  3366. fIsBuffering VARIANT_BOOL, value: if true turn buffering of HTML output
  3367. is turned on
  3368. Returns:
  3369. HRESULT S_OK if ok
  3370. Side Effects:
  3371. None
  3372. ===================================================================*/
  3373. STDMETHODIMP CResponse::get_Buffer
  3374. (
  3375. VARIANT_BOOL *fIsBuffering
  3376. )
  3377. {
  3378. if (FAILED(CheckForTombstone()))
  3379. return E_FAIL;
  3380. HRESULT hr = S_OK;
  3381. if (m_pData->m_fBufferingOn)
  3382. *fIsBuffering = VARIANT_TRUE;
  3383. else
  3384. *fIsBuffering = VARIANT_FALSE;
  3385. return(hr);
  3386. }
  3387. /*===================================================================
  3388. CResponse::Redirect
  3389. Function called from DispInvoke to invoke the Redirect method.
  3390. Parameters:
  3391. bstrURL Unicode BSTR Value: URL to rediect to
  3392. Returns:
  3393. S_OK on success. E_FAIL on failure.
  3394. ===================================================================*/
  3395. STDMETHODIMP CResponse::Redirect(BSTR bstrURL)
  3396. {
  3397. if (FAILED(CheckForTombstone()))
  3398. return E_FAIL;
  3399. AssertValid();
  3400. HRESULT hr = S_OK;
  3401. DWORD cch = 0;
  3402. DWORD cchURL = 0;
  3403. DWORD cchMessage = 0;
  3404. DWORD cchEncodedURL;
  3405. DWORD cchHtmlEncodedURL;
  3406. PSZ szURL = NULL;
  3407. PSZ szMessage = NULL;
  3408. PSZ pszEncodedURL = NULL;
  3409. PSZ pszURL = NULL;
  3410. CWCharToMBCS convURL;
  3411. STACK_BUFFER( tempURL, 256 );
  3412. STACK_BUFFER( tempMessage, 256 + 512 );
  3413. // Insist that we have a non-zero length URL
  3414. if (bstrURL)
  3415. cchURL = wcslen(bstrURL);
  3416. if (cchURL == 0)
  3417. {
  3418. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_NO_URL);
  3419. hr = E_FAIL;
  3420. goto lRet;
  3421. }
  3422. // Check that we haven't already passed data back to the client
  3423. if (FHeadersWritten())
  3424. {
  3425. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  3426. hr = E_FAIL;
  3427. goto lRet;
  3428. }
  3429. // If buffering is on, clear any pending output
  3430. if (m_pData->m_fBufferingOn)
  3431. Clear();
  3432. // turn buffering on for this response.
  3433. m_pData->m_fBufferingOn = TRUE;
  3434. if (FAILED(hr = convURL.Init(bstrURL, m_pData->m_pHitObj->GetCodePage())))
  3435. {
  3436. if (hr == E_OUTOFMEMORY)
  3437. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3438. goto lRet;
  3439. }
  3440. pszURL = convURL.GetString();
  3441. cchEncodedURL = URLPathEncodeLen(pszURL);
  3442. if (!tempURL.Resize(cchEncodedURL))
  3443. {
  3444. hr = E_OUTOFMEMORY;
  3445. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3446. goto lRet;
  3447. }
  3448. pszEncodedURL = (PSZ)tempURL.QueryPtr();
  3449. URLPathEncode(pszEncodedURL, pszURL);
  3450. // for the HTML body, further encode URL
  3451. cchHtmlEncodedURL = HTMLEncodeLen(pszEncodedURL,
  3452. m_pData->m_pHitObj->GetCodePage(),
  3453. NULL,
  3454. FALSE);
  3455. // We need to alloccate memory to build the body redirection message.
  3456. // If our memory requirement is small we allocate memory from the stack,
  3457. // otherwise we allocate from the heap.
  3458. cchMessage = cchHtmlEncodedURL;
  3459. cchMessage += 512; // Allow space for sub-strings coming from resource file.
  3460. if (!tempMessage.Resize(cchMessage))
  3461. {
  3462. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3463. hr = E_OUTOFMEMORY;
  3464. goto lRet;
  3465. }
  3466. szMessage = (PSZ)tempMessage.QueryPtr();
  3467. // Build the body redirection message
  3468. // Redirect(URL), URL must be a valid URL, that is, no DBCS string.
  3469. cch = CchLoadStringOfId(IDE_RESPONSE_REDIRECT1, szMessage, cchMessage);
  3470. if (cchHtmlEncodedURL) {
  3471. HTMLEncode(szMessage + cch,
  3472. pszEncodedURL,
  3473. m_pData->m_pHitObj->GetCodePage(),
  3474. NULL,
  3475. FALSE);
  3476. cch += cchHtmlEncodedURL-1; // get rid of the terminating \0
  3477. }
  3478. cch += CchLoadStringOfId(IDE_RESPONSE_REDIRECT2, szMessage + cch, cchMessage - cch);
  3479. // Set the status to redirect
  3480. put_Status(L"302 Object moved");
  3481. // Add the location header
  3482. AppendHeader("Location", pszEncodedURL, TRUE);
  3483. // Transmit redirect text to the client, headers will be
  3484. // sent automatically
  3485. if (FAILED(WriteSz(szMessage, cch)))
  3486. {
  3487. hr = E_FAIL;
  3488. goto lRet;
  3489. }
  3490. // No further processing of the script
  3491. End();
  3492. lRet:
  3493. return(hr);
  3494. }
  3495. /*===================================================================
  3496. CResponse::Add
  3497. Functions called from DispInvoke to Add a header.
  3498. This is a compatibility for the ISBU controls.
  3499. Parameters:
  3500. bstrHeaderValue Unicode BSTR, value: the value of header
  3501. bstrHeaderName Unicode BSTR, value: the name of the header
  3502. Returns:
  3503. HRESULT S_OK if ok
  3504. ===================================================================*/
  3505. STDMETHODIMP CResponse::Add
  3506. (
  3507. BSTR bstrHeaderValue,
  3508. BSTR bstrHeaderName
  3509. )
  3510. {
  3511. if (FAILED(CheckForTombstone()))
  3512. return E_FAIL;
  3513. return AddHeader(bstrHeaderName, bstrHeaderValue);
  3514. }
  3515. /*===================================================================
  3516. CResponse::AddHeader
  3517. Functions called from DispInvoke to Add a header.
  3518. Parameters:
  3519. bstrHeaderName Unicode BSTR, value: the name of the header
  3520. bstrHeaderValue Unicode BSTR, value: the value of header
  3521. Returns:
  3522. HRESULT S_OK if ok
  3523. ===================================================================*/
  3524. STDMETHODIMP CResponse::AddHeader
  3525. (
  3526. BSTR bstrHeaderName,
  3527. BSTR bstrHeaderValue
  3528. )
  3529. {
  3530. if (FAILED(CheckForTombstone()))
  3531. return E_FAIL;
  3532. AssertValid();
  3533. if (FHeadersWritten())
  3534. {
  3535. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  3536. return E_FAIL;
  3537. }
  3538. if (bstrHeaderName == NULL || wcslen(bstrHeaderName) == 0)
  3539. {
  3540. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_EXPECTING_STR);
  3541. return E_FAIL;
  3542. }
  3543. if (FAILED(AppendHeader(bstrHeaderName, bstrHeaderValue)))
  3544. {
  3545. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3546. SetLastError((DWORD)E_OUTOFMEMORY);
  3547. return E_OUTOFMEMORY;
  3548. }
  3549. return S_OK;
  3550. }
  3551. /*===================================================================
  3552. CResponse::Clear
  3553. Erases all output waiting in buffer.
  3554. Parameters
  3555. None
  3556. Returns:
  3557. HRESULT S_OK if ok
  3558. ===================================================================*/
  3559. STDMETHODIMP CResponse::Clear()
  3560. {
  3561. if (FAILED(CheckForTombstone()))
  3562. return E_FAIL;
  3563. HRESULT hr = S_OK;
  3564. if (m_pData->m_fClientDebugMode && m_pData->m_fClientDebugFlushIgnored)
  3565. {
  3566. // Clear after flush in ClientDebugMode is an error
  3567. hr = E_FAIL;
  3568. ExceptionId(IID_IResponse, IDE_RESPONSE,
  3569. IDE_RESPONSE_CLEAR_AFTER_FLUSH_IN_DEBUG);
  3570. }
  3571. else if (!m_pData->m_fBufferingOn)
  3572. {
  3573. hr = E_FAIL;
  3574. ExceptionId(IID_IResponse, IDE_RESPONSE,
  3575. IDE_RESPONSE_BUFFER_NOT_ON);
  3576. }
  3577. else
  3578. {
  3579. AssertValid();
  3580. hr = m_pData->m_pBufferSet->PResponseBuffer()->Clear();
  3581. if (SUCCEEDED(hr))
  3582. {
  3583. if (m_pData->m_fClientDebugMode && m_pData->m_pBufferSet->PClientDebugBuffer())
  3584. hr = m_pData->m_pBufferSet->PClientDebugBuffer()->ClearAndStart();
  3585. }
  3586. if (FAILED(hr))
  3587. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_UNEXPECTED);
  3588. }
  3589. return(hr);
  3590. }
  3591. /*===================================================================
  3592. CResponse::Flush
  3593. Sends out all HTML waiting in the buffer.
  3594. Returns:
  3595. HRESULT S_OK if ok
  3596. ===================================================================*/
  3597. STDMETHODIMP CResponse::Flush()
  3598. {
  3599. if (FAILED(CheckForTombstone()))
  3600. return E_FAIL;
  3601. HRESULT hr = S_OK;
  3602. AssertValid();
  3603. if (!m_pData->m_fBufferingOn)
  3604. {
  3605. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_BUFFER_NOT_ON);
  3606. hr = E_FAIL;
  3607. goto lRet;
  3608. }
  3609. // Ignore Response.Flush() in Client Debug Mode
  3610. if (m_pData->m_fClientDebugMode)
  3611. {
  3612. m_pData->m_fClientDebugFlushIgnored = TRUE;
  3613. goto lRet;
  3614. }
  3615. if (FHeadersWritten() && (m_pData->BytesBuffered() == 0))
  3616. goto lRet;
  3617. // We mark this response as having had flush called so
  3618. // that we won't try to do keep-alive
  3619. m_pData->m_fFlushed = TRUE;
  3620. if (FAILED(hr = WriteResponse()))
  3621. {
  3622. if (E_OUTOFMEMORY == hr)
  3623. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3624. else
  3625. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_UNEXPECTED);
  3626. }
  3627. lRet:
  3628. return(hr);
  3629. }
  3630. /*===================================================================
  3631. CResponse::FinalFlush
  3632. FinalFlush is called if a script terminates without having yet sent
  3633. the response headers. This means we can use the Content-Length headers
  3634. to increase efficiency. We add those headers, then send all headers,
  3635. and all waiting output.
  3636. Returns:
  3637. VOID
  3638. ===================================================================*/
  3639. VOID CResponse::FinalFlush(HRESULT hr_Status)
  3640. {
  3641. if (FAILED(CheckForTombstone()))
  3642. return;
  3643. HRESULT hr = S_OK;
  3644. AssertValid();
  3645. if (SUCCEEDED(hr_Status) && FHeadersWritten() && (m_pData->BytesBuffered() == 0) && !m_pData->FChunkData())
  3646. goto lRet;
  3647. if (!FHeadersWritten()
  3648. && FAILED(hr_Status)
  3649. && (hr_Status != E_SOURCE_FILE_IS_EMPTY)
  3650. && (m_pData->BytesBuffered() == 0))
  3651. {
  3652. // If there was an error and and nothing is buffered,
  3653. // send "server error" instead of an empty 200 OK response
  3654. Handle500Error(IDE_500_SERVER_ERROR, GetIReq());
  3655. goto lRet;
  3656. }
  3657. if (FDontWrite())
  3658. goto lRet;
  3659. if (m_pData->FChunkData())
  3660. {
  3661. // Add the closing chars when chunking
  3662. m_pData->m_pBufferSet->PResponseBuffer()->Write("0\r\n\r\n", 5, FALSE);
  3663. }
  3664. // If the headers have not yet been sent, see what needs to be added
  3665. if (!FHeadersWritten())
  3666. {
  3667. DWORD dwLength = m_pData->m_pBufferSet->PResponseBuffer()->BytesBuffered();
  3668. // If buffering, add the Content-Length header
  3669. if (m_pData->m_fBufferingOn)
  3670. {
  3671. if (m_pData->m_fClientDebugMode && m_pData->m_pBufferSet->PClientDebugBuffer())
  3672. {
  3673. // end the buffer with end of METADATA
  3674. m_pData->m_pBufferSet->PClientDebugBuffer()->End();
  3675. dwLength += m_pData->m_pBufferSet->PClientDebugBuffer()->BytesBuffered();
  3676. }
  3677. AppendHeader("Content-Length", (LONG)dwLength);
  3678. }
  3679. }
  3680. if (!m_pData->m_fBufferingOn && !m_pData->FChunkData())
  3681. {
  3682. // We mark this response as having had flush called so
  3683. // that we won't try to do keep-alive
  3684. m_pData->m_fFlushed = TRUE;
  3685. }
  3686. // Write response will send the buffered data, and the headers
  3687. // if they haven't already been sent.
  3688. // While WriteResponse can return an error, there isn't much point
  3689. // in checking the return value since FinalFlush is a void return.
  3690. WriteResponse();
  3691. lRet:
  3692. if (m_pData->m_pHitObj)
  3693. m_pData->m_pHitObj->SetDoneWithSession();
  3694. }
  3695. /*===================================================================
  3696. CResponse::End
  3697. Stops all further template processing, and returns the current response
  3698. Returns:
  3699. HRESULT S_OK if ok
  3700. ===================================================================*/
  3701. STDMETHODIMP CResponse::End()
  3702. {
  3703. if (FAILED(CheckForTombstone()))
  3704. return E_FAIL;
  3705. if (m_pData->m_pfnGetScript != NULL && m_pData->m_pvGetScriptContext != NULL)
  3706. {
  3707. int i = 0;
  3708. CScriptEngine* pEngine;
  3709. while (NULL != (pEngine = (*m_pData->m_pfnGetScript)(i, m_pData->m_pvGetScriptContext)))
  3710. {
  3711. pEngine->InterruptScript(/*fAbnormal*/ FALSE);
  3712. i++;
  3713. }
  3714. }
  3715. m_pData->m_fResponseAborted = TRUE;
  3716. return S_OK;
  3717. }
  3718. /*===================================================================
  3719. CResponse::AppendToLog
  3720. Append a string to the current log entry.
  3721. Parameters
  3722. bstrLogEntry Unicode BSTR, value: string to add to log entry
  3723. Returns:
  3724. HRESULT S_OK if ok
  3725. Side Effects:
  3726. NONE
  3727. ===================================================================*/
  3728. STDMETHODIMP CResponse::AppendToLog(BSTR bstrLogEntry)
  3729. {
  3730. if (FAILED(CheckForTombstone()))
  3731. return E_FAIL;
  3732. AssertValid();
  3733. HRESULT hr = S_OK;
  3734. CWCharToMBCS convEntry;
  3735. // BUGBUG - should this be 65001?
  3736. if (FAILED(hr = convEntry.Init(bstrLogEntry, m_pData->m_pHitObj->GetCodePage())));
  3737. else hr = GetIReq()->AppendLogParameter(convEntry.GetString());
  3738. if (FAILED(hr)) {
  3739. if (hr == E_OUTOFMEMORY) {
  3740. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3741. }
  3742. else {
  3743. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_LOG_FAILURE);
  3744. }
  3745. }
  3746. return(hr);
  3747. }
  3748. /*===================================================================
  3749. CResponse::get_Cookies
  3750. Return the write-only response cookie dictionary
  3751. Parameters
  3752. bstrLogEntry Unicode BSTR, value: string to add to log entry
  3753. Returns:
  3754. HRESULT S_OK if ok
  3755. ===================================================================*/
  3756. STDMETHODIMP CResponse::get_Cookies(IRequestDictionary **ppDictReturn)
  3757. {
  3758. if (FAILED(CheckForTombstone()))
  3759. return E_FAIL;
  3760. AssertValid();
  3761. return m_pData->m_WriteCookies.QueryInterface(IID_IRequestDictionary, reinterpret_cast<void **>(ppDictReturn));
  3762. }
  3763. #ifdef DBG
  3764. /*===================================================================
  3765. CResponse::AssertValid
  3766. Test to make sure that the CResponse object is currently correctly formed
  3767. and assert if it is not.
  3768. Returns:
  3769. Side effects:
  3770. None.
  3771. ===================================================================*/
  3772. VOID CResponse::AssertValid() const
  3773. {
  3774. Assert(m_fInited);
  3775. Assert(m_pData);
  3776. Assert(m_pData->m_pBufferSet->PResponseBuffer());
  3777. Assert(m_pData->m_pIReq);
  3778. }
  3779. #endif // DBG
  3780. /*===================================================================
  3781. IsHeadRequest
  3782. This function will check the REQUEST_METHOD and set a BOOL flag in
  3783. the class. If the request method is HEAD the flag will be set to
  3784. true.
  3785. Also the flag must be reset with each init/reinit call
  3786. m_IsHeadRequest == 0 // HEAD request status not set
  3787. m_IsHeadRequest == 1 // Not a HEAD request
  3788. m_IsHeadRequest == 2 // is a HEAD request
  3789. Parameters
  3790. Returns:
  3791. void
  3792. Side effects:
  3793. sets status flag m_IsHeadRequest
  3794. ===================================================================*/
  3795. BOOL CResponse::IsHeadRequest(void)
  3796. {
  3797. if (FAILED(CheckForTombstone()))
  3798. return FALSE;
  3799. AssertValid();
  3800. if (m_pData->m_IsHeadRequest != 0)
  3801. return ( m_pData->m_IsHeadRequest == 2);
  3802. if (stricmp(GetIReq()->QueryPszMethod(), "HEAD") == 0 )
  3803. m_pData->m_IsHeadRequest = 2;
  3804. else
  3805. m_pData->m_IsHeadRequest = 1;
  3806. return ( m_pData->m_IsHeadRequest == 2);
  3807. }
  3808. /*===================================================================
  3809. IsClientConnected
  3810. This function will return the status of the last attempt to write to
  3811. the client. If Ok, it check the connection using new CIsapiReqInfo method
  3812. Parameters
  3813. none
  3814. Returns:
  3815. VARIANT_BOOL reflecting the status of the client connection
  3816. ===================================================================*/
  3817. STDMETHODIMP CResponse::IsClientConnected(VARIANT_BOOL* fIsClientConnected)
  3818. {
  3819. if (FAILED(CheckForTombstone()))
  3820. return E_FAIL;
  3821. if (m_pData->m_fWriteClientError)
  3822. {
  3823. *fIsClientConnected = VARIANT_FALSE;
  3824. }
  3825. else
  3826. {
  3827. // assume connected
  3828. BOOL fConnected = TRUE;
  3829. // test
  3830. if (m_pData->m_pIReq)
  3831. m_pData->m_pIReq->TestConnection(&fConnected);
  3832. *fIsClientConnected = fConnected ? VARIANT_TRUE : VARIANT_FALSE;
  3833. }
  3834. return(S_OK);
  3835. }
  3836. /*===================================================================
  3837. CResponse::get_CharSet
  3838. Functions called from DispInvoke to return the CarSet property.
  3839. Parameters:
  3840. pbstrCharSetRet BSTR FAR *, return value: pointer to the CharSet as a string
  3841. Returns:
  3842. HRESULT S_OK if ok
  3843. ===================================================================*/
  3844. STDMETHODIMP CResponse::get_CharSet
  3845. (
  3846. BSTR FAR * pbstrCharSetRet
  3847. )
  3848. {
  3849. if (FAILED(CheckForTombstone()))
  3850. return E_FAIL;
  3851. HRESULT hr = S_OK;
  3852. if (m_pData->m_pszCharSet)
  3853. hr = SysAllocStringFromSz(m_pData->m_pszCharSet, 0, pbstrCharSetRet);
  3854. else
  3855. *pbstrCharSetRet = NULL;
  3856. if (FAILED(hr))
  3857. {
  3858. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3859. hr = E_FAIL;
  3860. }
  3861. return(hr);
  3862. }
  3863. /*===================================================================
  3864. CResponse::put_CharSet
  3865. Functions called from DispInvoke to set the CharSet property.
  3866. This function takses a string, which identifies the name of the
  3867. character set of the current page, and appends the name of the
  3868. character set (for example, " ISO-LATIN-7") specified by the
  3869. charsetname to the content-type header in the response object
  3870. Notes:
  3871. * this function inserts any string in the header, whether or not
  3872. it represents a valis charcter set.
  3873. * if a single page contains multiple tags contianing response.charset,
  3874. each response.charset will replace the cahrset by the previous entry.
  3875. As a result, the charset will be set to the value specified by the
  3876. last instance of response.charset on a page.
  3877. * this command must also be invoked before the first response.write
  3878. operation unless buffering is turned on.
  3879. Parameters:
  3880. bstrContentType BSTR, value: the ContentType as a string
  3881. Returns:
  3882. HRESULT S_OK if ok
  3883. ===================================================================*/
  3884. STDMETHODIMP CResponse::put_CharSet
  3885. (
  3886. BSTR bstrCharSet
  3887. )
  3888. {
  3889. if (FAILED(CheckForTombstone()))
  3890. return E_FAIL;
  3891. HRESULT hr = S_OK;
  3892. CWCharToMBCS convStr;
  3893. if (FHeadersWritten())
  3894. {
  3895. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  3896. hr = E_FAIL;
  3897. goto lRet;
  3898. }
  3899. if (m_pData->m_pszCharSet) {
  3900. free(m_pData->m_pszCharSet);
  3901. m_pData->m_pszCharSet = NULL;
  3902. }
  3903. if (FAILED(hr = convStr.Init(bstrCharSet)));
  3904. else if ((m_pData->m_pszCharSet = convStr.GetString(TRUE)) == NULL) {
  3905. hr = E_OUTOFMEMORY;
  3906. }
  3907. lRet:
  3908. if (hr == E_OUTOFMEMORY) {
  3909. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3910. SetLastError((DWORD)E_OUTOFMEMORY);
  3911. }
  3912. return(hr);
  3913. }
  3914. /*===================================================================
  3915. CResponse::Pics
  3916. Functions called from DispInvoke to Add a pics header.
  3917. Parameters:
  3918. bstrHeaderValue Unicode BSTR, value: the value of pics header
  3919. Takes a string, which is the properly formatted PICS label, and adds
  3920. the value specified by the picslabel to the pics-label field of the response header.
  3921. Note:
  3922. * this function inserts any string in the header, whether or not it
  3923. represents a valid PICS lavel.
  3924. * current implimentation is a wraper on the addheader method.
  3925. Returns:
  3926. HRESULT S_OK if ok
  3927. ===================================================================*/
  3928. STDMETHODIMP CResponse::Pics
  3929. (
  3930. BSTR bstrHeaderValue
  3931. )
  3932. {
  3933. if (FAILED(CheckForTombstone()))
  3934. return E_FAIL;
  3935. if (FHeadersWritten())
  3936. {
  3937. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  3938. return E_FAIL;
  3939. }
  3940. if (FAILED(AppendHeader("pics-label", bstrHeaderValue)))
  3941. {
  3942. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3943. SetLastError((DWORD)E_OUTOFMEMORY);
  3944. return E_OUTOFMEMORY;
  3945. }
  3946. return S_OK;
  3947. }
  3948. /*===================================================================
  3949. CResponse::get_CacheControl
  3950. Functions called from DispInvoke to return the CacheControl property.
  3951. Parameters:
  3952. pbstrCacheControl BSTR FAR *, return value: pointer to the CacheControl as a string
  3953. Returns:
  3954. HRESULT S_OK if ok
  3955. ===================================================================*/
  3956. STDMETHODIMP CResponse::get_CacheControl
  3957. (
  3958. BSTR FAR * pbstrCacheControl
  3959. )
  3960. {
  3961. if (FAILED(CheckForTombstone()))
  3962. return E_FAIL;
  3963. HRESULT hr = S_OK;
  3964. if (m_pData->m_pszCacheControl)
  3965. hr = SysAllocStringFromSz(m_pData->m_pszCacheControl, 0, pbstrCacheControl);
  3966. else
  3967. hr = SysAllocStringFromSz( "private", 0, pbstrCacheControl);
  3968. if (FAILED(hr))
  3969. {
  3970. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  3971. hr = E_FAIL;
  3972. }
  3973. return(hr);
  3974. }
  3975. /*===================================================================
  3976. CResponse::put_CacheControl
  3977. Functions called from DispInvoke to set the CacheControl property.
  3978. Parameters:
  3979. bstrCacheControl BSTR, value: the CacheControl as a string
  3980. Returns:
  3981. HRESULT S_OK if ok
  3982. ===================================================================*/
  3983. STDMETHODIMP CResponse::put_CacheControl
  3984. (
  3985. BSTR bstrCacheControl
  3986. )
  3987. {
  3988. if (FAILED(CheckForTombstone()))
  3989. return E_FAIL;
  3990. HRESULT hr = S_OK;
  3991. CWCharToMBCS convStr;
  3992. if (FHeadersWritten())
  3993. {
  3994. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_RESPONSE_HEADERS_WRITTEN);
  3995. hr = E_FAIL;
  3996. goto lRet;
  3997. }
  3998. if (m_pData->m_pszCacheControl) {
  3999. free(m_pData->m_pszCacheControl);
  4000. m_pData->m_pszCacheControl = NULL;
  4001. }
  4002. if (FAILED(hr = convStr.Init(bstrCacheControl)));
  4003. else if ((m_pData->m_pszCacheControl = convStr.GetString(TRUE)) == NULL) {
  4004. hr = E_OUTOFMEMORY;
  4005. }
  4006. lRet:
  4007. if (hr == E_OUTOFMEMORY) {
  4008. ExceptionId(IID_IResponse, IDE_RESPONSE, IDE_OOM);
  4009. SetLastError((DWORD)E_OUTOFMEMORY);
  4010. }
  4011. return(hr);
  4012. }
  4013. /*===================================================================
  4014. CResponse::get_CodePage
  4015. Returns the current code page value for the response
  4016. Parameters:
  4017. long *plVar [out] code page value
  4018. Returns:
  4019. HRESULT S_OK on success
  4020. ===================================================================*/
  4021. STDMETHODIMP CResponse::get_CodePage
  4022. (
  4023. long *plVar
  4024. )
  4025. {
  4026. Assert(m_pData);
  4027. Assert(m_pData->m_pHitObj);
  4028. *plVar = m_pData->m_pHitObj->GetCodePage();
  4029. // If code page is 0, look up default ANSI code page
  4030. if (*plVar == 0) {
  4031. *plVar = (long) GetACP();
  4032. }
  4033. return S_OK;
  4034. }
  4035. /*===================================================================
  4036. CResponse::put_CodePage
  4037. Sets the current code page value for the response
  4038. Parameters:
  4039. long lVar code page to assign to this response
  4040. Returns:
  4041. HRESULT S_OK on success
  4042. ===================================================================*/
  4043. STDMETHODIMP CResponse::put_CodePage
  4044. (
  4045. long lVar
  4046. )
  4047. {
  4048. Assert(m_pData);
  4049. Assert(m_pData->m_pHitObj);
  4050. // set code page member variable
  4051. HRESULT hr = m_pData->m_pHitObj->SetCodePage(lVar);
  4052. if (FAILED(hr)) {
  4053. ExceptionId
  4054. (
  4055. IID_IResponse,
  4056. IDE_RESPONSE,
  4057. IDE_SESSION_INVALID_CODEPAGE
  4058. );
  4059. return E_FAIL;
  4060. }
  4061. return S_OK;
  4062. }
  4063. /*===================================================================
  4064. CResponse::get_LCID
  4065. Returns the current LCID value for the response
  4066. Parameters:
  4067. long *plVar [out] LCID value
  4068. Returns:
  4069. HRESULT S_OK on success
  4070. ===================================================================*/
  4071. STDMETHODIMP CResponse::get_LCID
  4072. (
  4073. long *plVar
  4074. )
  4075. {
  4076. Assert(m_pData);
  4077. Assert(m_pData->m_pHitObj);
  4078. *plVar = m_pData->m_pHitObj->GetLCID();
  4079. // If code page is 0, look up default ANSI code page
  4080. if (*plVar == LOCALE_SYSTEM_DEFAULT) {
  4081. *plVar = (long) GetSystemDefaultLCID();
  4082. }
  4083. return S_OK;
  4084. }
  4085. /*===================================================================
  4086. CResponse::put_LCID
  4087. Sets the current LCID value for the response
  4088. Parameters:
  4089. long lVar LCID to assign to this response
  4090. Returns:
  4091. HRESULT S_OK on success
  4092. ===================================================================*/
  4093. STDMETHODIMP CResponse::put_LCID
  4094. (
  4095. long lVar
  4096. )
  4097. {
  4098. Assert(m_pData);
  4099. Assert(m_pData->m_pHitObj);
  4100. // set code page member variable
  4101. HRESULT hr = m_pData->m_pHitObj->SetLCID(lVar);
  4102. if (FAILED(hr)) {
  4103. ExceptionId
  4104. (
  4105. IID_IResponse,
  4106. IDE_RESPONSE,
  4107. IDE_TEMPLATE_BAD_LCID
  4108. );
  4109. return E_FAIL;
  4110. }
  4111. return S_OK;
  4112. }
  4113. /*===================================================================
  4114. IStream implementation for ADO/XML
  4115. ===================================================================*/
  4116. STDMETHODIMP CResponse::Read(
  4117. void *pv,
  4118. ULONG cb,
  4119. ULONG *pcbRead)
  4120. {
  4121. return E_NOTIMPL;
  4122. }
  4123. STDMETHODIMP CResponse::Write(
  4124. const void *pv,
  4125. ULONG cb,
  4126. ULONG *pcbWritten)
  4127. {
  4128. if (pcbWritten != NULL)
  4129. *pcbWritten = cb;
  4130. return WriteSz((CHAR*) pv, cb);
  4131. }
  4132. STDMETHODIMP CResponse::Seek(
  4133. LARGE_INTEGER dlibMove,
  4134. DWORD dwOrigin,
  4135. ULARGE_INTEGER *plibNewPosition)
  4136. {
  4137. return E_NOTIMPL;
  4138. }
  4139. STDMETHODIMP CResponse::SetSize(
  4140. ULARGE_INTEGER libNewSize)
  4141. {
  4142. return E_NOTIMPL;
  4143. }
  4144. STDMETHODIMP CResponse::CopyTo(
  4145. IStream *pstm,
  4146. ULARGE_INTEGER cb,
  4147. ULARGE_INTEGER *pcbRead,
  4148. ULARGE_INTEGER *pcbWritten)
  4149. {
  4150. return E_NOTIMPL;
  4151. }
  4152. STDMETHODIMP CResponse::Commit(
  4153. DWORD grfCommitFlags)
  4154. {
  4155. return E_NOTIMPL;
  4156. }
  4157. STDMETHODIMP CResponse::Revert()
  4158. {
  4159. return E_NOTIMPL;
  4160. }
  4161. STDMETHODIMP CResponse::LockRegion(
  4162. ULARGE_INTEGER libOffset,
  4163. ULARGE_INTEGER cb,
  4164. DWORD dwLockType)
  4165. {
  4166. return E_NOTIMPL;
  4167. }
  4168. STDMETHODIMP CResponse::UnlockRegion(
  4169. ULARGE_INTEGER libOffset,
  4170. ULARGE_INTEGER cb,
  4171. DWORD dwLockType)
  4172. {
  4173. return E_NOTIMPL;
  4174. }
  4175. STDMETHODIMP CResponse::Stat(
  4176. STATSTG *pstatstg,
  4177. DWORD grfStatFlag)
  4178. {
  4179. return E_NOTIMPL;
  4180. }
  4181. STDMETHODIMP CResponse::Clone(
  4182. IStream **ppstm)
  4183. {
  4184. return E_NOTIMPL;
  4185. }