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.

1466 lines
38 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. // File: CMimeFt.cxx
  7. //
  8. // Contents:
  9. //
  10. // Classes:
  11. //
  12. // Functions:
  13. //
  14. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <eapp.h>
  18. PerfDbgTag(tagMft, "Pluggable MF ", "Log CMimeFt", DEB_PROT)
  19. DbgTag(tagMftErr,"Pluggable MF", "Log CMimeFt Errors", DEB_PROT|DEB_ERROR)
  20. PerfDbgTag(tagPF, "Pluggable MF ", "Log Perf", DEB_PROT)
  21. #ifndef unix
  22. #define JOB_MINS_PER_HOUR 60i64
  23. #define JOB_HOURS_PER_DAY 24i64
  24. #define JOB_MILLISECONDS_PER_SECOND 1000i64
  25. #define JOB_MILLISECONDS_PER_MINUTE (60i64 * JOB_MILLISECONDS_PER_SECOND)
  26. #define FILETIMES_PER_MILLISECOND 10000i64
  27. #define FILETIMES_PER_MINUTE (FILETIMES_PER_MILLISECOND * JOB_MILLISECONDS_PER_MINUTE)
  28. #define FILETIMES_PER_DAY (FILETIMES_PER_MINUTE * JOB_MINS_PER_HOUR * JOB_HOURS_PER_DAY)
  29. #else
  30. #define JOB_MINS_PER_HOUR 60LL
  31. #define JOB_HOURS_PER_DAY 24LL
  32. #define JOB_MILLISECONDS_PER_SECOND 1000LL
  33. #define JOB_MILLISECONDS_PER_MINUTE (60LL * JOB_MILLISECONDS_PER_SECOND)
  34. #define FILETIMES_PER_MILLISECOND 10000LL
  35. #define FILETIMES_PER_MINUTE (FILETIMES_PER_MILLISECOND * JOB_MILLISECONDS_PER_MINUTE)
  36. #define FILETIMES_PER_DAY (FILETIMES_PER_MINUTE * JOB_MINS_PER_HOUR * JOB_HOURS_PER_DAY)
  37. #endif /* unix */
  38. #define GZIPHACK 8624
  39. void
  40. AddDaysToFileTime(LPFILETIME pft, WORD Days)
  41. {
  42. if (!Days)
  43. {
  44. return; // Nothing to do.
  45. }
  46. //
  47. // ft = ft + Days * FILETIMES_PER_DAY;
  48. //
  49. ULARGE_INTEGER uli, uliSum;
  50. uli.LowPart = pft->dwLowDateTime;
  51. uli.HighPart = pft->dwHighDateTime;
  52. #ifndef unix
  53. uliSum.QuadPart = uli.QuadPart + (__int64)Days * FILETIMES_PER_DAY;
  54. #else
  55. U_QUAD_PART(uliSum) = U_QUAD_PART(uli) + (__int64)Days * FILETIMES_PER_DAY;
  56. #endif /* unix */
  57. pft->dwLowDateTime = uliSum.LowPart;
  58. pft->dwHighDateTime = uliSum.HighPart;
  59. }
  60. // helper from transapi.cxx
  61. HRESULT GetMimeFileExtension(LPSTR, LPSTR, DWORD);
  62. //+---------------------------------------------------------------------------
  63. //
  64. // Method: CMimeFt::QueryInterface
  65. //
  66. // Synopsis:
  67. //
  68. // Arguments:
  69. //
  70. // Returns:
  71. //
  72. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  73. //
  74. // Notes:
  75. //
  76. //----------------------------------------------------------------------------
  77. STDMETHODIMP
  78. CMimeFt::QueryInterface(REFIID riid, void **ppvObj)
  79. {
  80. PerfDbgLog(tagMft, this, "+CMimeFt::QueryInterface");
  81. VDATEPTROUT(ppvObj, void*);
  82. VDATETHIS(this);
  83. HRESULT hr = NOERROR;
  84. *ppvObj = NULL;
  85. if( (riid == IID_IUnknown) ||
  86. (riid == IID_IOInetProtocol) ||
  87. (riid == IID_IOInetProtocolRoot))
  88. {
  89. *ppvObj = (IOInetProtocol*) this;
  90. AddRef();
  91. }
  92. else if (riid == IID_IOInetProtocolSink )
  93. {
  94. *ppvObj = (IOInetProtocolSink*) this;
  95. AddRef();
  96. }
  97. else if (riid == IID_IOInetProtocolSinkStackable )
  98. {
  99. *ppvObj = (IOInetProtocolSinkStackable*) this;
  100. AddRef();
  101. }
  102. else
  103. hr = E_NOINTERFACE;
  104. PerfDbgLog1(tagMft, this, "-CMimeFt::QueryInterface(hr:%1x)", hr);
  105. return hr;
  106. }
  107. //+---------------------------------------------------------------------------
  108. //
  109. // Method: CMimeFt::AddRef
  110. //
  111. // Synopsis:
  112. //
  113. // Arguments:
  114. //
  115. // Returns:
  116. //
  117. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  118. //
  119. // Notes:
  120. //
  121. //----------------------------------------------------------------------------
  122. STDMETHODIMP_(ULONG)
  123. CMimeFt::AddRef(void)
  124. {
  125. PerfDbgLog(tagMft, this, "+CMimeFt::AddRef");
  126. LONG lRet = ++_CRefs;
  127. PerfDbgLog1(tagMft, this, "-CMimeFt::AddRef (cRef:%1d)", lRet);
  128. return lRet;
  129. }
  130. //+---------------------------------------------------------------------------
  131. //
  132. // Method: CMimeFt::Release
  133. //
  134. // Synopsis:
  135. //
  136. // Arguments:
  137. //
  138. // Returns:
  139. //
  140. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  141. //
  142. // Notes:
  143. //
  144. //----------------------------------------------------------------------------
  145. STDMETHODIMP_(ULONG)
  146. CMimeFt::Release(void)
  147. {
  148. PerfDbgLog(tagMft, this, "+CMimeFt::Release");
  149. LONG lRet = --_CRefs;
  150. if( !lRet )
  151. delete this;
  152. PerfDbgLog1(tagMft, this, "-CMimeFt::Release (cRef:%1d)", lRet);
  153. return lRet;
  154. }
  155. //+---------------------------------------------------------------------------
  156. //
  157. // Method: CMimeFt::Start
  158. //
  159. // Synopsis:
  160. //
  161. // Arguments: [pwzUrl] --
  162. // [pProtSink] --
  163. // [pOIBindInfo] --
  164. // [grfSTI] --
  165. // [dwReserved] --
  166. //
  167. // Returns: E_PENDING indicating the current filter is not empty
  168. //
  169. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  170. //
  171. // Notes:
  172. //
  173. //----------------------------------------------------------------------------
  174. STDMETHODIMP
  175. CMimeFt::Start(
  176. LPCWSTR pwzUrl,
  177. IOInetProtocolSink *pProtSink,
  178. IOInetBindInfo *pOIBindInfo,
  179. DWORD grfPI,
  180. DWORD_PTR dwReserved)
  181. {
  182. PerfDbgLog(tagMft, this, "+CMimeFt::Start");
  183. PerfDbgLog(tagPF, this, "*************CMimeFt::Start");
  184. PProtAssert( pwzUrl && (!_pProtSink) && pProtSink && dwReserved );
  185. HRESULT hr = NOERROR;
  186. PProtAssert((grfPI & PI_FILTER_MODE));
  187. if( !(grfPI & PI_FILTER_MODE) )
  188. hr = E_INVALIDARG;
  189. // download or upload? from the rrfPI flag...
  190. if( !hr )
  191. {
  192. //get the Prot pointer here
  193. PROTOCOLFILTERDATA* FiltData = (PROTOCOLFILTERDATA*) dwReserved;
  194. _pProt = FiltData->pProtocol;
  195. _pProt->AddRef();
  196. //get the sink pointer here
  197. _pProtSink = pProtSink;
  198. _pProtSink->AddRef();
  199. // create or reload the data filter
  200. if( _pDF )
  201. {
  202. _pDF->Release();
  203. _pDF = NULL;
  204. }
  205. //
  206. // this piece needs some more work
  207. // 1. pEFtFac will be CoCreated according to reg setting
  208. // 2. We will keep a linked list for existing EFFactory
  209. //
  210. IEncodingFilterFactory* pEFtFac = new CEncodingFilterFactory;
  211. if( pEFtFac )
  212. {
  213. // should we use enum or string value?
  214. hr = pEFtFac->GetDefaultFilter( pwzUrl, L"text", &_pDF);
  215. PProtAssert(_pDF);
  216. // don't need the factory anymore,
  217. // but later, we will keep it on the list
  218. pEFtFac->Release();
  219. // reset all internal counter
  220. _ulCurSizeFmtIn = 0;
  221. _ulCurSizeFmtOut = 0;
  222. _ulTotalSizeFmtIn = 0;
  223. _ulTotalSizeFmtOut = 0;
  224. _ulOutAvailable = 0;
  225. _ulContentLength = 0;
  226. hr = _pProtSink->ReportProgress(BINDSTATUS_DECODING, pwzUrl);
  227. }
  228. else
  229. hr = E_OUTOFMEMORY;
  230. BOOL fNeedCache = TRUE;
  231. if( hr == NOERROR )
  232. {
  233. DWORD dwBINDF;
  234. BINDINFO bindInfo;
  235. bindInfo.cbSize = sizeof(BINDINFO);
  236. hr = pOIBindInfo->GetBindInfo(&dwBINDF, &bindInfo);
  237. // not generate cache file if user specifies BINDF_NOWRITECACHE
  238. if( hr == NOERROR)
  239. {
  240. if( dwBINDF & BINDF_NOWRITECACHE )
  241. {
  242. fNeedCache = FALSE;
  243. }
  244. // BINDINFO_FIX(LaszloG) 8/15/96
  245. ReleaseBindInfo(&bindInfo);
  246. }
  247. }
  248. if( hr == NOERROR && fNeedCache )
  249. {
  250. // Create cache file entry
  251. // 1. get url name
  252. ULONG ulCount;
  253. LPWSTR rgwzStr[1] = {NULL};
  254. LPSTR pszURL = NULL;
  255. hr = pOIBindInfo->GetBindString(
  256. BINDSTRING_URL, (LPWSTR*)rgwzStr, 1, &ulCount);
  257. if( hr == NOERROR && ulCount == 1 )
  258. {
  259. pszURL = DupW2A(rgwzStr[0]);
  260. if( pszURL )
  261. {
  262. strncpy(_szURL, pszURL, MAX_PATH);
  263. }
  264. else
  265. {
  266. _szURL[0] = '\0';
  267. }
  268. }
  269. delete [] rgwzStr[0];
  270. delete [] pszURL;
  271. /******** move to ::Read to get accurate file ext ******
  272. // 2. get cache file name and create file handle
  273. if( hr == NOERROR && _szURL[0] != '\0' )
  274. {
  275. LPSTR pszExt = NULL;
  276. pszExt = FindFileExtension(_szURL);
  277. if( pszExt && *pszExt == '.' )
  278. {
  279. // FindFileExtion will return ".htm" but wininet is
  280. // expecting "htm", so remove the extra "."
  281. pszExt++;
  282. }
  283. if( CreateUrlCacheEntry(_szURL, 0, pszExt, _szFileName, 0) )
  284. {
  285. if( _szFileName[0] != '\0' )
  286. {
  287. _hFile = CreateFile(_szFileName,
  288. GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
  289. NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  290. if( _hFile == INVALID_HANDLE_VALUE )
  291. {
  292. _hFile = NULL;
  293. }
  294. }
  295. }
  296. }
  297. // Report the CACHE file name
  298. LPWSTR pwzFileName = NULL;
  299. if( _szFileName[0] != '\0' )
  300. {
  301. pwzFileName = DupA2W(_szFileName);
  302. }
  303. if( pwzFileName )
  304. {
  305. ReportProgress(
  306. BINDSTATUS_CACHEFILENAMEAVAILABLE, pwzFileName);
  307. delete [] pwzFileName;
  308. }
  309. ******** move to ::Read to get accurate file ext ******/
  310. }
  311. }
  312. PerfDbgLog1(tagMft, this, "-CMimeFt::Start (hr:%1x)", hr);
  313. return hr;
  314. }
  315. //+---------------------------------------------------------------------------
  316. //
  317. // Method: CMimeFt::Continue
  318. //
  319. // Synopsis:
  320. //
  321. // Arguments: [pStateInfo] --
  322. //
  323. // Returns:
  324. //
  325. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  326. //
  327. // Notes:
  328. //
  329. //----------------------------------------------------------------------------
  330. STDMETHODIMP
  331. CMimeFt::Continue( PROTOCOLDATA *pStateInfo)
  332. {
  333. PerfDbgLog(tagMft, this, "+CMimeFt::Continue");
  334. PProtAssert( _pProt );
  335. HRESULT hr = _pProt->Continue(pStateInfo);
  336. PerfDbgLog1(tagMft, this, "-CMimeFt::Continue(hr:%1x)", hr);
  337. return hr;
  338. }
  339. //+---------------------------------------------------------------------------
  340. //
  341. // Method: CMimeFt::Abort
  342. //
  343. // Synopsis:
  344. //
  345. // Arguments: [hrReason] --
  346. // [dwOptions] --
  347. //
  348. // Returns:
  349. //
  350. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  351. //
  352. // Notes:
  353. //
  354. //----------------------------------------------------------------------------
  355. STDMETHODIMP
  356. CMimeFt::Abort( HRESULT hrReason, DWORD dwOptions)
  357. {
  358. PerfDbgLog(tagMft, this, "+CMimeFt::Abort");
  359. PProtAssert( _pProt );
  360. HRESULT hr = _pProt->Abort(hrReason, dwOptions);
  361. PerfDbgLog1(tagMft, this, "-CMimeFt::Abort(hr:%1x)", hr);
  362. return hr;
  363. }
  364. //+---------------------------------------------------------------------------
  365. //
  366. // Method: CMimeFt::Terminate
  367. //
  368. // Synopsis:
  369. //
  370. // Arguments: [dwOptions] --
  371. //
  372. // Returns:
  373. //
  374. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  375. //
  376. // Notes:
  377. //
  378. //----------------------------------------------------------------------------
  379. STDMETHODIMP
  380. CMimeFt::Terminate( DWORD dwOptions)
  381. {
  382. PerfDbgLog(tagMft, this, "+CMimeFt::Terminate");
  383. PProtAssert( _pProt );
  384. HRESULT hr = NOERROR;
  385. // release the sink
  386. if( _pProtSink )
  387. {
  388. _pProtSink->Release();
  389. //_pProtSink = NULL;
  390. }
  391. // unload the data filter
  392. if( _pDF )
  393. {
  394. _pDF->Release();
  395. _pDF = NULL;
  396. }
  397. // get expire and lastmodified time from wininet
  398. INTERNET_CACHE_TIMESTAMPS st;
  399. DWORD cbSt = sizeof(st);
  400. memset(&st, 0, cbSt);
  401. if (_pProt)
  402. {
  403. IWinInetHttpInfo* pWin = NULL;
  404. hr = _pProt->QueryInterface(IID_IWinInetHttpInfo, (void**)&pWin);
  405. if( hr == NOERROR && pWin )
  406. {
  407. pWin->QueryOption( INTERNET_OPTION_CACHE_TIMESTAMPS, &st, &cbSt);
  408. pWin->Release();
  409. }
  410. }
  411. // close the file handle
  412. if( _hFile )
  413. {
  414. CloseHandle(_hFile);
  415. _hFile = NULL;
  416. }
  417. // Commit ( or delete) cache file entry
  418. if( _szFileName[0] != '\0' && _szURL[0] != '\0' )
  419. {
  420. char szHeader[256];
  421. char szMime[64];
  422. W2A(_pwzMimeSuggested, szMime, 64);
  423. wsprintf(szHeader, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: %s\r\n\r\n",
  424. _ulContentLength, szMime);
  425. DWORD dwLen = strlen(szHeader);
  426. CommitUrlCacheEntry( _szURL, _szFileName, st.ftExpires,
  427. st.ftLastModified, NORMAL_CACHE_ENTRY,
  428. (LPBYTE)szHeader, dwLen, NULL, 0);
  429. }
  430. if (_pProt)
  431. {
  432. hr = _pProt->Terminate(dwOptions);
  433. }
  434. PerfDbgLog1(tagMft, this, "-CMimeFt::Terminate(hr:%1x)", hr);
  435. PerfDbgLog(tagPF, this, "*************CMimeFt::Terminate");
  436. return hr;
  437. }
  438. //+---------------------------------------------------------------------------
  439. //
  440. // Method: CMimeFt::Suspend
  441. //
  442. // Synopsis:
  443. //
  444. // Arguments: [none]
  445. //
  446. // Returns:
  447. //
  448. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  449. //
  450. // Notes:
  451. //
  452. //----------------------------------------------------------------------------
  453. STDMETHODIMP
  454. CMimeFt::Suspend()
  455. {
  456. PerfDbgLog(tagMft, this, "+CMimeFt::Suspend");
  457. PProtAssert( _pProt );
  458. HRESULT hr = _pProt->Suspend();
  459. PerfDbgLog1(tagMft, this, "-CMimeFt::Suspend(hr:%1x)", hr);
  460. return hr;
  461. }
  462. //+---------------------------------------------------------------------------
  463. //
  464. // Method: CMimeFt::Resume
  465. //
  466. // Synopsis:
  467. //
  468. // Arguments: [none]
  469. //
  470. // Returns:
  471. //
  472. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  473. //
  474. // Notes:
  475. //
  476. //----------------------------------------------------------------------------
  477. STDMETHODIMP
  478. CMimeFt::Resume()
  479. {
  480. PerfDbgLog(tagMft, this, "+CMimeFt::Resume");
  481. PProtAssert( _pProt );
  482. HRESULT hr = _pProt->Resume();
  483. PerfDbgLog1(tagMft, this, "-CMimeFt::Suspend(hr:%1x)", hr);
  484. return hr;
  485. }
  486. //+---------------------------------------------------------------------------
  487. //
  488. // Method: CMimeFt::Read
  489. //
  490. // Synopsis: The real read is implemented in SmartRead, which also
  491. // serves as a data sniffer
  492. //
  493. // Arguments:
  494. //
  495. // Returns:
  496. //
  497. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  498. //
  499. // Notes:
  500. //
  501. //----------------------------------------------------------------------------
  502. STDMETHODIMP
  503. CMimeFt::Read(void *pv, ULONG cb, ULONG *pcbRead)
  504. {
  505. HRESULT hr = NOERROR;
  506. _fReadInProgress = TRUE;
  507. hr = SmartRead(pv, cb, pcbRead, FALSE);
  508. _fReadInProgress = FALSE;
  509. // do delay report result
  510. if( hr == S_FALSE && _fDelayReport )
  511. {
  512. ReportResult(_hrResult, _dwError, _wzResult);
  513. }
  514. return hr;
  515. }
  516. //+---------------------------------------------------------------------------
  517. //
  518. // Method: CMimeFt::SmartRead
  519. //
  520. // Synopsis: implementation of ::Read, we add one parameter indicating
  521. // if this read is for data sniffing purpose,
  522. // (the goal datasniff read is to ReportProgress(MIME),
  523. // data is not returned to the user buffer, this is to overcome
  524. // the problem that if you do data sniffing in the real Read and
  525. // report progress from a free thread, the message won't get
  526. // to the apartment thread until it finishs the read, which
  527. // might be too late for BindToObject)
  528. //
  529. // Arguments:
  530. //
  531. // Returns:
  532. //
  533. // History: 11-24-97 DanpoZ (Danpo Zhang) Created
  534. //
  535. // Notes:
  536. //
  537. //----------------------------------------------------------------------------
  538. HRESULT
  539. CMimeFt::SmartRead(void *pv, ULONG cb, ULONG *pcbRead, BOOL fSniff)
  540. {
  541. PerfDbgLog(tagMft, this, "+CMimeFt::Read");
  542. if(fSniff)
  543. {
  544. PerfDbgLog(tagMft, this, "+CMimeFt::Read - sniffing");
  545. }
  546. else
  547. {
  548. PProtAssert( pv && _pOutBuf && pcbRead );
  549. }
  550. HRESULT hr = NOERROR;
  551. LONG lRead = 0;
  552. HRESULT hrRead = E_FAIL;
  553. HRESULT hrCode = NOERROR;
  554. BOOL fPullData = FALSE;
  555. // no data, I have to pull more
  556. if( _ulOutAvailable == 0 )
  557. {
  558. if( _ulInBufferLeft == 0)
  559. {
  560. hrRead = _pProt->Read(_pInBuf, FT_IBUF_SIZE-2, (ULONG*)&lRead);
  561. PerfDbgLog2(tagMft, this, " CMimeFt::Read-Pull %u bytes (hr %1x)",
  562. lRead, hrRead);
  563. fPullData = TRUE;
  564. }
  565. else
  566. {
  567. lRead = _ulInBufferLeft;
  568. }
  569. }
  570. if( lRead )
  571. {
  572. LONG lInUsed = 0;
  573. LONG lOutUsed = 0;
  574. BYTE* pInBuf = _pInBuf;
  575. if( _bEncoding )
  576. hrCode = _pDF->DoEncode(
  577. 0,
  578. FT_IBUF_SIZE,
  579. pInBuf,
  580. FT_OBUF_SIZE,
  581. _pOutBuf,
  582. lRead,
  583. &lInUsed,
  584. &lOutUsed,
  585. 0);
  586. else
  587. {
  588. hrCode = _pDF->DoDecode(
  589. 0,
  590. FT_IBUF_SIZE,
  591. pInBuf,
  592. FT_OBUF_SIZE,
  593. _pOutBuf,
  594. lRead,
  595. &lInUsed,
  596. &lOutUsed,
  597. 0);
  598. }
  599. if( hrCode != NOERROR )
  600. {
  601. // error msg from winerr.h
  602. _pProtSink->ReportResult(hr, CRYPT_E_BAD_ENCODE, NULL);
  603. // make sure we clean up the filter
  604. _ulOutAvailable = 0;
  605. _ulInBufferLeft = 0;
  606. PerfDbgLog(tagMft, this, " CMimeFt::Read-Encode/Decode Failed");
  607. }
  608. else
  609. {
  610. // update
  611. _ulCurSizeFmtOut += lOutUsed;
  612. _ulOutAvailable = lOutUsed;
  613. // do we get all the data?
  614. if( lInUsed < lRead )
  615. {
  616. // move mem to front
  617. memcpy(_pInBuf, _pInBuf+lInUsed, lRead-lInUsed);
  618. _ulInBufferLeft = lRead - lInUsed;
  619. }
  620. else
  621. {
  622. _ulInBufferLeft = 0;
  623. }
  624. if( !_bMimeVerified )
  625. {
  626. _bMimeVerified = TRUE;
  627. LPWSTR pwzStr = NULL;
  628. LPWSTR pwzFileName = NULL;
  629. if( _szFileName[0] != '\0' )
  630. {
  631. pwzFileName = DupA2W(_szFileName);
  632. }
  633. FindMimeFromData(NULL, pwzFileName, _pOutBuf, lOutUsed,
  634. _pwzMimeSuggested, 0, &pwzStr, 0);
  635. pwzFileName = NULL;
  636. if( !_bMimeReported && !_bEncoding )
  637. {
  638. _bMimeReported = TRUE;
  639. if( pwzStr )
  640. {
  641. hr = _pProtSink->ReportProgress(
  642. BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, pwzStr);
  643. }
  644. else
  645. {
  646. hr = _pProtSink->ReportProgress(
  647. BINDSTATUS_MIMETYPEAVAILABLE, L"text/html");
  648. }
  649. }
  650. if( pwzStr )
  651. {
  652. delete [] _pwzMimeSuggested;
  653. _pwzMimeSuggested = pwzStr;
  654. pwzStr = NULL;
  655. }
  656. //------- moved from ::Start to get accurate file ext
  657. if( hr == NOERROR && _szURL[0] != '\0' && _bCanCache)
  658. {
  659. LPSTR pszExt = NULL;
  660. TCHAR szExt[MAX_PATH + 1];
  661. szExt[0] = TEXT('\0'); // Initialize
  662. if(_szSuggestedFileName[0])
  663. {
  664. pszExt = FindFileExtension(_szSuggestedFileName);
  665. lstrcpy(_szFileName, _szSuggestedFileName);
  666. }
  667. else
  668. {
  669. if(pszExt = FindFileExtension(_szURL))
  670. {
  671. StrNCpy(szExt, pszExt, MAX_PATH);
  672. szExt[MAX_PATH] = '\0';
  673. pszExt = StrChr(szExt, '?');
  674. if(pszExt)
  675. {
  676. *pszExt = '\0';
  677. }
  678. pszExt = szExt;
  679. }
  680. }
  681. // HACK... need some API to tell if ext is valid...
  682. // here we assume ext with 3 chars
  683. // including the ".", it will be 4 char
  684. if( pszExt && strlen(pszExt) > 5 )
  685. {
  686. LPSTR pszMime = DupW2A(_pwzMimeSuggested);
  687. GetMimeFileExtension( pszMime, pszExt, 20);
  688. delete [] pszMime;
  689. }
  690. if( pszExt && *pszExt == '.' )
  691. {
  692. // FindFileExtion will return ".htm" but wininet is
  693. // expecting "htm", so remove the extra "."
  694. pszExt++;
  695. }
  696. if( CreateUrlCacheEntry(_szURL, 0, pszExt, _szFileName, GZIPHACK) )
  697. {
  698. if( _szFileName[0] != '\0' )
  699. {
  700. _hFile = CreateFile(_szFileName,
  701. GENERIC_WRITE,
  702. FILE_SHARE_WRITE | FILE_SHARE_READ,
  703. NULL,CREATE_ALWAYS,
  704. FILE_ATTRIBUTE_NORMAL, NULL);
  705. if( _hFile == INVALID_HANDLE_VALUE )
  706. {
  707. _hFile = NULL;
  708. }
  709. }
  710. }
  711. }
  712. // Report the CACHE file name
  713. if( _szFileName[0] != '\0' )
  714. {
  715. pwzFileName = DupA2W(_szFileName);
  716. }
  717. if( pwzFileName )
  718. {
  719. ReportProgress(
  720. BINDSTATUS_CACHEFILENAMEAVAILABLE, pwzFileName);
  721. delete [] pwzFileName;
  722. }
  723. //------- moved from ::Start to get accurate file ext
  724. }
  725. // write to the file
  726. if( _hFile )
  727. {
  728. DWORD dwBytesWritten;
  729. WriteFile(_hFile, _pOutBuf, lOutUsed, &dwBytesWritten, NULL);
  730. if( lOutUsed != (LONG)dwBytesWritten )
  731. {
  732. // write failed, clean up everything
  733. CloseHandle(_hFile);
  734. _hFile = NULL;
  735. DeleteUrlCacheEntryA( _szURL );
  736. _szFileName[0] = '\0';
  737. _szURL[0] = '\0';
  738. }
  739. }
  740. PerfDbgLog2(tagMft, this,
  741. " CMimeFt::Read-Encode/Decode %u bytes-> %u bytes",
  742. lInUsed, lOutUsed);
  743. }
  744. }
  745. else
  746. PerfDbgLog(tagMft, this, " CMimeFt::Read-in buffer empty");
  747. // copy over (only for the purpose of non-sniffing)
  748. if( !fSniff && (hrCode == NOERROR) && _ulOutAvailable )
  749. {
  750. if( cb >= _ulOutAvailable )
  751. {
  752. // client has bigger buffer
  753. memcpy(pv, _pOutBuf, _ulOutAvailable);
  754. *pcbRead = _ulOutAvailable;
  755. _ulOutAvailable = 0;
  756. hr = S_OK;
  757. PerfDbgLog1(tagMft, this,
  758. " CMimeFt::Read-enough buffer copied %u bytes", *pcbRead);
  759. }
  760. else
  761. {
  762. // client have smaller buffer
  763. memcpy(pv, _pOutBuf, cb);
  764. *pcbRead = cb;
  765. // move mem to front
  766. memcpy(_pOutBuf, _pOutBuf+cb, _ulOutAvailable-cb);
  767. _ulOutAvailable -= cb;
  768. hr = S_OK;
  769. PerfDbgLog1(tagMft, this,
  770. " CMimeFt::Read-not enough buffer copied %u bytes", cb);
  771. }
  772. // keep the total (content-length)
  773. _ulContentLength += *pcbRead;
  774. }
  775. // If we pulled the data, we should report that hr
  776. if( fPullData )
  777. hr = hrRead;
  778. // if encode-decode error occurs, we report it
  779. if( hrCode != NOERROR )
  780. hr = hrCode;
  781. // if all data are gone and LASTNOTIFICATION, we should return S_FALSE
  782. if(_grfBSCF & BSCF_LASTDATANOTIFICATION && (_ulOutAvailable == 0) )
  783. {
  784. PerfDbgLog(tagMft, this,
  785. " CMimeFt::Read-Last Notification, set hr --> 1" );
  786. hr = S_FALSE;
  787. }
  788. PerfDbgLog1(tagMft, this, "-CMimeFt::Read (hr:%1x)", hr);
  789. return hr;
  790. }
  791. //+---------------------------------------------------------------------------
  792. //
  793. // Method: CMimeFt::Seek
  794. //
  795. // Synopsis:
  796. //
  797. // Arguments:
  798. //
  799. // Returns:
  800. //
  801. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  802. //
  803. // Notes:
  804. //
  805. //----------------------------------------------------------------------------
  806. STDMETHODIMP
  807. CMimeFt::Seek(
  808. LARGE_INTEGER dlibMove,
  809. DWORD dwOrigin,
  810. ULARGE_INTEGER *plibNewPosition)
  811. {
  812. PerfDbgLog(tagMft, this, "+CMimeFt::Seek");
  813. // Seek will be available later
  814. HRESULT hr = E_NOTIMPL;
  815. PerfDbgLog1(tagMft, this, "-CMimeFt::Seek (hr:%1x)", hr);
  816. return hr;
  817. }
  818. //+---------------------------------------------------------------------------
  819. //
  820. // Method: CMimeFt::LockRequest
  821. //
  822. // Synopsis:
  823. //
  824. // Arguments:
  825. //
  826. // Returns:
  827. //
  828. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  829. //
  830. // Notes:
  831. //
  832. //----------------------------------------------------------------------------
  833. STDMETHODIMP
  834. CMimeFt::LockRequest(DWORD dwOptions)
  835. {
  836. PerfDbgLog(tagMft, this, "+CMimeFt::LockRequest");
  837. PProtAssert(_pProt);
  838. HRESULT hr = _pProt->LockRequest(dwOptions);
  839. PerfDbgLog1(tagMft, this, "-CMimeFt::LockRequest(hr:%1x)", hr);
  840. return hr;
  841. }
  842. //+---------------------------------------------------------------------------
  843. //
  844. // Method: CMimeFt::UnlockRequest
  845. //
  846. // Synopsis:
  847. //
  848. // Arguments:
  849. //
  850. // Returns:
  851. //
  852. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  853. //
  854. // Notes:
  855. //
  856. //----------------------------------------------------------------------------
  857. STDMETHODIMP
  858. CMimeFt::UnlockRequest()
  859. {
  860. PerfDbgLog(tagMft, this, "+CMimeFt::UnLockRequest");
  861. PProtAssert(_pProt);
  862. HRESULT hr = _pProt->UnlockRequest();
  863. PerfDbgLog1(tagMft, this, "-CMimeFt::UnLockRequest(hr:%1x)", hr);
  864. return hr;
  865. }
  866. //+---------------------------------------------------------------------------
  867. //
  868. // Method: CMimeFt::Switch
  869. //
  870. // Synopsis:
  871. //
  872. // Arguments:
  873. //
  874. // Returns:
  875. //
  876. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  877. //
  878. // Notes:
  879. //
  880. //----------------------------------------------------------------------------
  881. STDMETHODIMP
  882. CMimeFt::Switch(PROTOCOLDATA *pStateInfo)
  883. {
  884. PerfDbgLog(tagMft, this, "+CMimeFt::Switch");
  885. PProtAssert(_pProtSink);
  886. HRESULT hr = _pProtSink->Switch(pStateInfo);
  887. PerfDbgLog1(tagMft, this, "-CMimeFt::Switch (hr:%1x)", hr);
  888. return hr;
  889. }
  890. //+---------------------------------------------------------------------------
  891. //
  892. // Method: CMimeFt::ReportProgress
  893. //
  894. // Synopsis:
  895. //
  896. // Arguments:
  897. //
  898. // Returns:
  899. //
  900. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  901. //
  902. // Notes:
  903. //
  904. //----------------------------------------------------------------------------
  905. STDMETHODIMP
  906. CMimeFt::ReportProgress( ULONG ulStatusCode, LPCWSTR szStatusText)
  907. {
  908. PerfDbgLog(tagMft, this, "+CMimeFt::ReportProgress");
  909. PProtAssert(_pProtSink);
  910. HRESULT hr = NOERROR;
  911. if( ulStatusCode == BINDSTATUS_MIMETYPEAVAILABLE )
  912. {
  913. delete [] _pwzMimeSuggested;
  914. _pwzMimeSuggested = OLESTRDuplicate(szStatusText);
  915. if( !_pwzMimeSuggested )
  916. {
  917. hr = E_OUTOFMEMORY;
  918. }
  919. }
  920. else if( ulStatusCode == BINDSTATUS_CACHECONTROL )
  921. {
  922. if(!lstrcmpiW(szStatusText, L"no-cache"))
  923. {
  924. _bCanCache = FALSE;
  925. }
  926. }
  927. else if( ulStatusCode == BINDSTATUS_CONTENTDISPOSITIONATTACH )
  928. {
  929. W2A(szStatusText, _szSuggestedFileName, sizeof(_szSuggestedFileName));
  930. PathUndecorate(_szSuggestedFileName);
  931. }
  932. else
  933. {
  934. hr = _pProtSink->ReportProgress(ulStatusCode, szStatusText);
  935. }
  936. PerfDbgLog1(tagMft, this, "-CMimeFt::ReportProgress(hr:%1x)", hr);
  937. return hr;
  938. }
  939. //+---------------------------------------------------------------------------
  940. //
  941. // Method: CMimeFt::ReportData
  942. //
  943. // Synopsis:
  944. //
  945. // Arguments:
  946. //
  947. // Returns:
  948. //
  949. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  950. //
  951. // Notes: E_PENDING returned if the filter is not empty
  952. //
  953. //----------------------------------------------------------------------------
  954. STDMETHODIMP
  955. CMimeFt::ReportData( DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
  956. {
  957. PerfDbgLog(tagMft, this, "+CMimeFt::ReportData");
  958. HRESULT hr = NOERROR;
  959. // Do a data sniffing Read to get the mime type out of the buffer
  960. // reason for _fSniffed, _fSniffInProgress and _fDelayReport
  961. // is that if the data sniffing SmartRead() reaches EOF, the protocol
  962. // will do ReportResult() which we want to delay until the Real Read
  963. // finishs
  964. if( !_fSniffed && !_fSniffInProgress && !_fReadInProgress )
  965. {
  966. _fSniffInProgress = TRUE;
  967. hr = SmartRead( NULL, 0, 0, TRUE);
  968. _fSniffInProgress = FALSE;
  969. if(SUCCEEDED(hr))
  970. _fSniffed = TRUE;
  971. }
  972. if(_fSniffed)
  973. {
  974. hr = _pProtSink->ReportData(grfBSCF, ulProgress, ulProgressMax);
  975. }
  976. PerfDbgLog1(tagMft, this, "-CMimeFt::ReportData(hr:%1x)", hr);
  977. return hr;
  978. }
  979. //+---------------------------------------------------------------------------
  980. //
  981. // Method: CMimeFt::ReportResult
  982. //
  983. // Synopsis:
  984. //
  985. // Arguments:
  986. //
  987. // Returns:
  988. //
  989. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  990. //
  991. // Notes:
  992. //
  993. //----------------------------------------------------------------------------
  994. STDMETHODIMP
  995. CMimeFt::ReportResult(HRESULT hrResult, DWORD dwError, LPCWSTR wzResult)
  996. {
  997. PerfDbgLog(tagMft, this, "+CMimeFt::ReportResult");
  998. // REVISIT
  999. PProtAssert(_pProtSink);
  1000. HRESULT hr = NOERROR;
  1001. if( _fSniffInProgress || _fReadInProgress )
  1002. {
  1003. // keep it and report it after read completes
  1004. _hrResult = hrResult;
  1005. _dwError = dwError;
  1006. _wzResult = wzResult; // should be OLEDuplicateStr()
  1007. _fDelayReport = TRUE;
  1008. }
  1009. else
  1010. {
  1011. hr = _pProtSink->ReportResult(hrResult, dwError, wzResult);
  1012. }
  1013. PerfDbgLog1(tagMft, this, "-CMimeFt::ReportResult(hr:%1x)", hr);
  1014. return hr;
  1015. }
  1016. //+---------------------------------------------------------------------------
  1017. //
  1018. // Method: CMimeFt::SwitchSink
  1019. //
  1020. // Synopsis:
  1021. //
  1022. // Arguments:
  1023. //
  1024. // Returns:
  1025. //
  1026. // History: 11-24-97 DanpoZ (Danpo Zhang) Created
  1027. //
  1028. // Notes:
  1029. //
  1030. //----------------------------------------------------------------------------
  1031. STDMETHODIMP
  1032. CMimeFt::SwitchSink(IOInetProtocolSink* pSink)
  1033. {
  1034. PerfDbgLog(tagMft, this, "+CMimeFt::SwitchSink");
  1035. // REVISIT
  1036. PProtAssert(_pProtSink && pSink);
  1037. HRESULT hr = NOERROR;
  1038. // keep track the existing sink (support for Commit/Rollback)
  1039. // the release of the old sink will be done at the Commit time
  1040. _pProtSinkOld = _pProtSink;
  1041. // -----------------------------------------------------------
  1042. // BUG: remove this block once enable the Commit-Rollback func
  1043. // release the old sink
  1044. //
  1045. if( _pProtSinkOld )
  1046. {
  1047. _pProtSinkOld->Release();
  1048. }
  1049. // -----------------------------------------------------------
  1050. // Change the sink
  1051. _pProtSink = pSink;
  1052. _pProtSink->AddRef();
  1053. PerfDbgLog1(tagMft, this, "-CMimeFt::SwitchSink(hr:%1x)", hr);
  1054. return hr;
  1055. }
  1056. //+---------------------------------------------------------------------------
  1057. //
  1058. // Method: CMimeFt::CommitSwitch
  1059. //
  1060. // Synopsis:
  1061. //
  1062. // Arguments:
  1063. //
  1064. // Returns:
  1065. //
  1066. // History: 11-24-97 DanpoZ (Danpo Zhang) Created
  1067. //
  1068. // Notes: Commit the sink switch, what we are doing here is
  1069. // Release the old sink (old sink is coming from the
  1070. // Start method and AddRef'ed there
  1071. //
  1072. //----------------------------------------------------------------------------
  1073. STDMETHODIMP
  1074. CMimeFt::CommitSwitch()
  1075. {
  1076. PerfDbgLog(tagMft, this, "+CMimeFt::CommitSwitch");
  1077. // release the old sink
  1078. //if( _pProtSinkOld )
  1079. //{
  1080. // _pProtSinkOld->Release();
  1081. //}
  1082. // reset
  1083. //_pProtSinkOld = NULL;
  1084. PerfDbgLog(tagMft, this, "-CMimeFt::CommitSwitch");
  1085. return NOERROR;
  1086. }
  1087. //+---------------------------------------------------------------------------
  1088. //
  1089. // Method: CMimeFt::RollbackSwitch
  1090. //
  1091. // Synopsis:
  1092. //
  1093. // Arguments:
  1094. //
  1095. // Returns:
  1096. //
  1097. // History: 11-24-97 DanpoZ (Danpo Zhang) Created
  1098. //
  1099. // Notes: Error occured (most possibly the StackFilter() call failed,
  1100. // we have to rollback the sink switch, what we are doing
  1101. // here is releasing the switched sink (AddRef'ed at SwitchSink
  1102. // time), and set the original sink back, no ref count work on
  1103. // the original sink
  1104. //
  1105. //----------------------------------------------------------------------------
  1106. STDMETHODIMP
  1107. CMimeFt::RollbackSwitch()
  1108. {
  1109. PerfDbgLog(tagMft, this, "+CMimeFt::RollbackSwitch");
  1110. // copy the old sink back, release the new sink
  1111. // (new sink is AddRef'ed at SwitchSink time)
  1112. //if( _pProtSink )
  1113. //{
  1114. // _pProtSink->Release();
  1115. //}
  1116. //_pProtSink = _pProtSinkOld;
  1117. // reset
  1118. //_pProtSinkOld = NULL;
  1119. PerfDbgLog(tagMft, this, "-CMimeFt::RollbackSwitch");
  1120. return NOERROR;
  1121. }
  1122. //+---------------------------------------------------------------------------
  1123. //
  1124. // Method: CMimeFt::Create
  1125. //
  1126. // Synopsis:
  1127. //
  1128. // Arguments:
  1129. //
  1130. // Returns:
  1131. //
  1132. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  1133. //
  1134. // Notes:
  1135. //
  1136. //----------------------------------------------------------------------------
  1137. HRESULT
  1138. CMimeFt::Create(CMimeFt** ppv)
  1139. {
  1140. PerfDbgLog(tagMft, NULL, "+CMimeFt::Create");
  1141. HRESULT hr = NOERROR;
  1142. // pProt can not be NULL
  1143. PProtAssert(ppv);
  1144. *ppv = NULL;
  1145. *ppv = new CMimeFt;
  1146. if( *ppv == NULL )
  1147. hr = E_OUTOFMEMORY;
  1148. else
  1149. hr = (*ppv)->CreateBuffer();
  1150. PerfDbgLog1(tagMft, NULL, "-CMimeFt::Create(hr:%1x)", hr);
  1151. return hr;
  1152. }
  1153. //+---------------------------------------------------------------------------
  1154. //
  1155. // Method: CMimeFt::CMimeFt
  1156. //
  1157. // Synopsis:
  1158. //
  1159. // Arguments:
  1160. //
  1161. // Returns:
  1162. //
  1163. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  1164. //
  1165. // Notes:
  1166. //
  1167. //----------------------------------------------------------------------------
  1168. CMimeFt::CMimeFt()
  1169. : _CRefs()
  1170. {
  1171. PerfDbgLog(tagMft, this, "+CMimeFt::CMimeFt");
  1172. _pProtSink = NULL;
  1173. _pProt = NULL;
  1174. _pProtSinkOld = NULL;
  1175. _pDF = NULL;
  1176. _ulCurSizeFmtIn = 0;
  1177. _ulCurSizeFmtOut = 0;
  1178. _ulTotalSizeFmtIn = 0;
  1179. _ulTotalSizeFmtOut = 0;
  1180. _ulOutAvailable = 0;
  1181. _ulInBufferLeft = 0;
  1182. _pInBuf = NULL;
  1183. _pOutBuf = NULL;
  1184. _grfBSCF = 0x00;
  1185. _bMimeReported = FALSE;
  1186. _bMimeVerified = FALSE;
  1187. _bCanCache = TRUE;
  1188. _szFileName[0] = '\0';
  1189. _szSuggestedFileName[0] = '\0';
  1190. _szURL[0] = '\0';
  1191. _hFile = NULL;
  1192. _pwzMimeSuggested = NULL;
  1193. _fDelayReport = FALSE;
  1194. _fSniffed = FALSE;
  1195. _fSniffInProgress = FALSE;
  1196. _hrResult = NOERROR;
  1197. _dwError = 0;
  1198. _wzResult = NULL;
  1199. _fReadInProgress = FALSE;
  1200. DllAddRef();
  1201. PerfDbgLog(tagMft, this, "-CMimeFt::CMimeFt");
  1202. }
  1203. //+---------------------------------------------------------------------------
  1204. //
  1205. // Method: CMimeFt::CreateBuffer
  1206. //
  1207. // Synopsis:
  1208. //
  1209. // Arguments:
  1210. //
  1211. // Returns:
  1212. //
  1213. // History: 04-30-97 DanpoZ (Danpo Zhang) Created
  1214. //
  1215. // Notes:
  1216. //
  1217. //----------------------------------------------------------------------------
  1218. HRESULT
  1219. CMimeFt::CreateBuffer()
  1220. {
  1221. PerfDbgLog(tagMft, this, "+CMimeFt::CreateBuffer");
  1222. HRESULT hr = NOERROR;
  1223. _pInBuf = new BYTE[FT_IBUF_SIZE];
  1224. _pOutBuf = new BYTE[FT_OBUF_SIZE];
  1225. PProtAssert(_pInBuf && _pOutBuf);
  1226. if( !_pInBuf || !_pOutBuf )
  1227. hr = E_OUTOFMEMORY;
  1228. PerfDbgLog1(tagMft, this, "-CMimeFt::CreateBuffer(hr:%1x)", hr);
  1229. return hr;
  1230. }
  1231. //+---------------------------------------------------------------------------
  1232. //
  1233. // Method: CMimeFt::~CMimeFt
  1234. //
  1235. // Synopsis:
  1236. //
  1237. // Arguments:
  1238. //
  1239. // Returns:
  1240. //
  1241. // History: 04-16-97 DanpoZ (Danpo Zhang) Created
  1242. //
  1243. // Notes:
  1244. //
  1245. //----------------------------------------------------------------------------
  1246. CMimeFt::~CMimeFt()
  1247. {
  1248. PerfDbgLog(tagMft, this, "+CMimeFt::~CMimeFt");
  1249. if( _pInBuf )
  1250. delete [] _pInBuf;
  1251. if( _pOutBuf )
  1252. delete [] _pOutBuf;
  1253. delete [] _pwzMimeSuggested;
  1254. if( _pProt )
  1255. _pProt->Release();
  1256. if( _pDF)
  1257. _pDF->Release();
  1258. if( _hFile )
  1259. CloseHandle(_hFile);
  1260. DllRelease();
  1261. PerfDbgLog(tagMft, this, "-CMimeFt::~CMimeFt");
  1262. }