Windows2003-3790/inetcore/urlmon/eapp/cmimeft.cxx
2020-09-30 16:53:55 +02:00

1467 lines
38 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: CMimeFt.cxx
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
//----------------------------------------------------------------------------
#include <eapp.h>
PerfDbgTag(tagMft, "Pluggable MF ", "Log CMimeFt", DEB_PROT)
DbgTag(tagMftErr,"Pluggable MF", "Log CMimeFt Errors", DEB_PROT|DEB_ERROR)
PerfDbgTag(tagPF, "Pluggable MF ", "Log Perf", DEB_PROT)
#ifndef unix
#define JOB_MINS_PER_HOUR 60i64
#define JOB_HOURS_PER_DAY 24i64
#define JOB_MILLISECONDS_PER_SECOND 1000i64
#define JOB_MILLISECONDS_PER_MINUTE (60i64 * JOB_MILLISECONDS_PER_SECOND)
#define FILETIMES_PER_MILLISECOND 10000i64
#define FILETIMES_PER_MINUTE (FILETIMES_PER_MILLISECOND * JOB_MILLISECONDS_PER_MINUTE)
#define FILETIMES_PER_DAY (FILETIMES_PER_MINUTE * JOB_MINS_PER_HOUR * JOB_HOURS_PER_DAY)
#else
#define JOB_MINS_PER_HOUR 60LL
#define JOB_HOURS_PER_DAY 24LL
#define JOB_MILLISECONDS_PER_SECOND 1000LL
#define JOB_MILLISECONDS_PER_MINUTE (60LL * JOB_MILLISECONDS_PER_SECOND)
#define FILETIMES_PER_MILLISECOND 10000LL
#define FILETIMES_PER_MINUTE (FILETIMES_PER_MILLISECOND * JOB_MILLISECONDS_PER_MINUTE)
#define FILETIMES_PER_DAY (FILETIMES_PER_MINUTE * JOB_MINS_PER_HOUR * JOB_HOURS_PER_DAY)
#endif /* unix */
#define GZIPHACK 8624
void
AddDaysToFileTime(LPFILETIME pft, WORD Days)
{
if (!Days)
{
return; // Nothing to do.
}
//
// ft = ft + Days * FILETIMES_PER_DAY;
//
ULARGE_INTEGER uli, uliSum;
uli.LowPart = pft->dwLowDateTime;
uli.HighPart = pft->dwHighDateTime;
#ifndef unix
uliSum.QuadPart = uli.QuadPart + (__int64)Days * FILETIMES_PER_DAY;
#else
U_QUAD_PART(uliSum) = U_QUAD_PART(uli) + (__int64)Days * FILETIMES_PER_DAY;
#endif /* unix */
pft->dwLowDateTime = uliSum.LowPart;
pft->dwHighDateTime = uliSum.HighPart;
}
// helper from transapi.cxx
HRESULT GetMimeFileExtension(LPSTR, LPSTR, DWORD);
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::QueryInterface
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::QueryInterface(REFIID riid, void **ppvObj)
{
PerfDbgLog(tagMft, this, "+CMimeFt::QueryInterface");
VDATEPTROUT(ppvObj, void*);
VDATETHIS(this);
HRESULT hr = NOERROR;
*ppvObj = NULL;
if( (riid == IID_IUnknown) ||
(riid == IID_IOInetProtocol) ||
(riid == IID_IOInetProtocolRoot))
{
*ppvObj = (IOInetProtocol*) this;
AddRef();
}
else if (riid == IID_IOInetProtocolSink )
{
*ppvObj = (IOInetProtocolSink*) this;
AddRef();
}
else if (riid == IID_IOInetProtocolSinkStackable )
{
*ppvObj = (IOInetProtocolSinkStackable*) this;
AddRef();
}
else
hr = E_NOINTERFACE;
PerfDbgLog1(tagMft, this, "-CMimeFt::QueryInterface(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::AddRef
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG)
CMimeFt::AddRef(void)
{
PerfDbgLog(tagMft, this, "+CMimeFt::AddRef");
LONG lRet = ++_CRefs;
PerfDbgLog1(tagMft, this, "-CMimeFt::AddRef (cRef:%1d)", lRet);
return lRet;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Release
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG)
CMimeFt::Release(void)
{
PerfDbgLog(tagMft, this, "+CMimeFt::Release");
LONG lRet = --_CRefs;
if( !lRet )
delete this;
PerfDbgLog1(tagMft, this, "-CMimeFt::Release (cRef:%1d)", lRet);
return lRet;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Start
//
// Synopsis:
//
// Arguments: [pwzUrl] --
// [pProtSink] --
// [pOIBindInfo] --
// [grfSTI] --
// [dwReserved] --
//
// Returns: E_PENDING indicating the current filter is not empty
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::Start(
LPCWSTR pwzUrl,
IOInetProtocolSink *pProtSink,
IOInetBindInfo *pOIBindInfo,
DWORD grfPI,
DWORD_PTR dwReserved)
{
PerfDbgLog(tagMft, this, "+CMimeFt::Start");
PerfDbgLog(tagPF, this, "*************CMimeFt::Start");
PProtAssert( pwzUrl && (!_pProtSink) && pProtSink && dwReserved );
HRESULT hr = NOERROR;
PProtAssert((grfPI & PI_FILTER_MODE));
if( !(grfPI & PI_FILTER_MODE) )
hr = E_INVALIDARG;
// download or upload? from the rrfPI flag...
if( !hr )
{
//get the Prot pointer here
PROTOCOLFILTERDATA* FiltData = (PROTOCOLFILTERDATA*) dwReserved;
_pProt = FiltData->pProtocol;
_pProt->AddRef();
//get the sink pointer here
_pProtSink = pProtSink;
_pProtSink->AddRef();
// create or reload the data filter
if( _pDF )
{
_pDF->Release();
_pDF = NULL;
}
//
// this piece needs some more work
// 1. pEFtFac will be CoCreated according to reg setting
// 2. We will keep a linked list for existing EFFactory
//
IEncodingFilterFactory* pEFtFac = new CEncodingFilterFactory;
if( pEFtFac )
{
// should we use enum or string value?
hr = pEFtFac->GetDefaultFilter( pwzUrl, L"text", &_pDF);
PProtAssert(_pDF);
// don't need the factory anymore,
// but later, we will keep it on the list
pEFtFac->Release();
// reset all internal counter
_ulCurSizeFmtIn = 0;
_ulCurSizeFmtOut = 0;
_ulTotalSizeFmtIn = 0;
_ulTotalSizeFmtOut = 0;
_ulOutAvailable = 0;
_ulContentLength = 0;
hr = _pProtSink->ReportProgress(BINDSTATUS_DECODING, pwzUrl);
}
else
hr = E_OUTOFMEMORY;
BOOL fNeedCache = TRUE;
if( hr == NOERROR )
{
DWORD dwBINDF;
BINDINFO bindInfo;
bindInfo.cbSize = sizeof(BINDINFO);
hr = pOIBindInfo->GetBindInfo(&dwBINDF, &bindInfo);
// not generate cache file if user specifies BINDF_NOWRITECACHE
if( hr == NOERROR)
{
if( dwBINDF & BINDF_NOWRITECACHE )
{
fNeedCache = FALSE;
}
// BINDINFO_FIX(LaszloG) 8/15/96
ReleaseBindInfo(&bindInfo);
}
}
if( hr == NOERROR && fNeedCache )
{
// Create cache file entry
// 1. get url name
ULONG ulCount;
LPWSTR rgwzStr[1] = {NULL};
LPSTR pszURL = NULL;
hr = pOIBindInfo->GetBindString(
BINDSTRING_URL, (LPWSTR*)rgwzStr, 1, &ulCount);
if( hr == NOERROR && ulCount == 1 )
{
pszURL = DupW2A(rgwzStr[0]);
if( pszURL )
{
strncpy(_szURL, pszURL, MAX_PATH);
}
else
{
_szURL[0] = '\0';
}
}
delete [] rgwzStr[0];
delete [] pszURL;
/******** move to ::Read to get accurate file ext ******
// 2. get cache file name and create file handle
if( hr == NOERROR && _szURL[0] != '\0' )
{
LPSTR pszExt = NULL;
pszExt = FindFileExtension(_szURL);
if( pszExt && *pszExt == '.' )
{
// FindFileExtion will return ".htm" but wininet is
// expecting "htm", so remove the extra "."
pszExt++;
}
if( CreateUrlCacheEntry(_szURL, 0, pszExt, _szFileName, 0) )
{
if( _szFileName[0] != '\0' )
{
_hFile = CreateFile(_szFileName,
GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if( _hFile == INVALID_HANDLE_VALUE )
{
_hFile = NULL;
}
}
}
}
// Report the CACHE file name
LPWSTR pwzFileName = NULL;
if( _szFileName[0] != '\0' )
{
pwzFileName = DupA2W(_szFileName);
}
if( pwzFileName )
{
ReportProgress(
BINDSTATUS_CACHEFILENAMEAVAILABLE, pwzFileName);
delete [] pwzFileName;
}
******** move to ::Read to get accurate file ext ******/
}
}
PerfDbgLog1(tagMft, this, "-CMimeFt::Start (hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Continue
//
// Synopsis:
//
// Arguments: [pStateInfo] --
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::Continue( PROTOCOLDATA *pStateInfo)
{
PerfDbgLog(tagMft, this, "+CMimeFt::Continue");
PProtAssert( _pProt );
HRESULT hr = _pProt->Continue(pStateInfo);
PerfDbgLog1(tagMft, this, "-CMimeFt::Continue(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Abort
//
// Synopsis:
//
// Arguments: [hrReason] --
// [dwOptions] --
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::Abort( HRESULT hrReason, DWORD dwOptions)
{
PerfDbgLog(tagMft, this, "+CMimeFt::Abort");
PProtAssert( _pProt );
HRESULT hr = _pProt->Abort(hrReason, dwOptions);
PerfDbgLog1(tagMft, this, "-CMimeFt::Abort(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Terminate
//
// Synopsis:
//
// Arguments: [dwOptions] --
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::Terminate( DWORD dwOptions)
{
PerfDbgLog(tagMft, this, "+CMimeFt::Terminate");
PProtAssert( _pProt );
HRESULT hr = NOERROR;
// release the sink
if( _pProtSink )
{
_pProtSink->Release();
//_pProtSink = NULL;
}
// unload the data filter
if( _pDF )
{
_pDF->Release();
_pDF = NULL;
}
// get expire and lastmodified time from wininet
INTERNET_CACHE_TIMESTAMPS st;
DWORD cbSt = sizeof(st);
memset(&st, 0, cbSt);
if (_pProt)
{
IWinInetHttpInfo* pWin = NULL;
hr = _pProt->QueryInterface(IID_IWinInetHttpInfo, (void**)&pWin);
if( hr == NOERROR && pWin )
{
pWin->QueryOption( INTERNET_OPTION_CACHE_TIMESTAMPS, &st, &cbSt);
pWin->Release();
}
}
// close the file handle
if( _hFile )
{
CloseHandle(_hFile);
_hFile = NULL;
}
// Commit ( or delete) cache file entry
if( _szFileName[0] != '\0' && _szURL[0] != '\0' )
{
char szHeader[256];
char szMime[64];
W2A(_pwzMimeSuggested, szMime, 64);
wsprintf(szHeader, "HTTP/1.0 200 OK\r\nContent-Length: %d\r\nContent-Type: %s\r\n\r\n",
_ulContentLength, szMime);
DWORD dwLen = strlen(szHeader);
CommitUrlCacheEntry( _szURL, _szFileName, st.ftExpires,
st.ftLastModified, NORMAL_CACHE_ENTRY,
(LPBYTE)szHeader, dwLen, NULL, 0);
}
if (_pProt)
{
hr = _pProt->Terminate(dwOptions);
}
PerfDbgLog1(tagMft, this, "-CMimeFt::Terminate(hr:%1x)", hr);
PerfDbgLog(tagPF, this, "*************CMimeFt::Terminate");
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Suspend
//
// Synopsis:
//
// Arguments: [none]
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::Suspend()
{
PerfDbgLog(tagMft, this, "+CMimeFt::Suspend");
PProtAssert( _pProt );
HRESULT hr = _pProt->Suspend();
PerfDbgLog1(tagMft, this, "-CMimeFt::Suspend(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Resume
//
// Synopsis:
//
// Arguments: [none]
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::Resume()
{
PerfDbgLog(tagMft, this, "+CMimeFt::Resume");
PProtAssert( _pProt );
HRESULT hr = _pProt->Resume();
PerfDbgLog1(tagMft, this, "-CMimeFt::Suspend(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Read
//
// Synopsis: The real read is implemented in SmartRead, which also
// serves as a data sniffer
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::Read(void *pv, ULONG cb, ULONG *pcbRead)
{
HRESULT hr = NOERROR;
_fReadInProgress = TRUE;
hr = SmartRead(pv, cb, pcbRead, FALSE);
_fReadInProgress = FALSE;
// do delay report result
if( hr == S_FALSE && _fDelayReport )
{
ReportResult(_hrResult, _dwError, _wzResult);
}
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::SmartRead
//
// Synopsis: implementation of ::Read, we add one parameter indicating
// if this read is for data sniffing purpose,
// (the goal datasniff read is to ReportProgress(MIME),
// data is not returned to the user buffer, this is to overcome
// the problem that if you do data sniffing in the real Read and
// report progress from a free thread, the message won't get
// to the apartment thread until it finishs the read, which
// might be too late for BindToObject)
//
// Arguments:
//
// Returns:
//
// History: 11-24-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT
CMimeFt::SmartRead(void *pv, ULONG cb, ULONG *pcbRead, BOOL fSniff)
{
PerfDbgLog(tagMft, this, "+CMimeFt::Read");
if(fSniff)
{
PerfDbgLog(tagMft, this, "+CMimeFt::Read - sniffing");
}
else
{
PProtAssert( pv && _pOutBuf && pcbRead );
}
HRESULT hr = NOERROR;
LONG lRead = 0;
HRESULT hrRead = E_FAIL;
HRESULT hrCode = NOERROR;
BOOL fPullData = FALSE;
// no data, I have to pull more
if( _ulOutAvailable == 0 )
{
if( _ulInBufferLeft == 0)
{
hrRead = _pProt->Read(_pInBuf, FT_IBUF_SIZE-2, (ULONG*)&lRead);
PerfDbgLog2(tagMft, this, " CMimeFt::Read-Pull %u bytes (hr %1x)",
lRead, hrRead);
fPullData = TRUE;
}
else
{
lRead = _ulInBufferLeft;
}
}
if( lRead )
{
LONG lInUsed = 0;
LONG lOutUsed = 0;
BYTE* pInBuf = _pInBuf;
if( _bEncoding )
hrCode = _pDF->DoEncode(
0,
FT_IBUF_SIZE,
pInBuf,
FT_OBUF_SIZE,
_pOutBuf,
lRead,
&lInUsed,
&lOutUsed,
0);
else
{
hrCode = _pDF->DoDecode(
0,
FT_IBUF_SIZE,
pInBuf,
FT_OBUF_SIZE,
_pOutBuf,
lRead,
&lInUsed,
&lOutUsed,
0);
}
if( hrCode != NOERROR )
{
// error msg from winerr.h
_pProtSink->ReportResult(hr, CRYPT_E_BAD_ENCODE, NULL);
// make sure we clean up the filter
_ulOutAvailable = 0;
_ulInBufferLeft = 0;
PerfDbgLog(tagMft, this, " CMimeFt::Read-Encode/Decode Failed");
}
else
{
// update
_ulCurSizeFmtOut += lOutUsed;
_ulOutAvailable = lOutUsed;
// do we get all the data?
if( lInUsed < lRead )
{
// move mem to front
memcpy(_pInBuf, _pInBuf+lInUsed, lRead-lInUsed);
_ulInBufferLeft = lRead - lInUsed;
}
else
{
_ulInBufferLeft = 0;
}
if( !_bMimeVerified )
{
_bMimeVerified = TRUE;
LPWSTR pwzStr = NULL;
LPWSTR pwzFileName = NULL;
if( _szFileName[0] != '\0' )
{
pwzFileName = DupA2W(_szFileName);
}
FindMimeFromData(NULL, pwzFileName, _pOutBuf, lOutUsed,
_pwzMimeSuggested, 0, &pwzStr, 0);
pwzFileName = NULL;
if( !_bMimeReported && !_bEncoding )
{
_bMimeReported = TRUE;
if( pwzStr )
{
hr = _pProtSink->ReportProgress(
BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE, pwzStr);
}
else
{
hr = _pProtSink->ReportProgress(
BINDSTATUS_MIMETYPEAVAILABLE, L"text/html");
}
}
if( pwzStr )
{
delete [] _pwzMimeSuggested;
_pwzMimeSuggested = pwzStr;
pwzStr = NULL;
}
//------- moved from ::Start to get accurate file ext
if( hr == NOERROR && _szURL[0] != '\0' && _bCanCache)
{
LPSTR pszExt = NULL;
TCHAR szExt[MAX_PATH + 1];
szExt[0] = TEXT('\0'); // Initialize
if(_szSuggestedFileName[0])
{
pszExt = FindFileExtension(_szSuggestedFileName);
lstrcpy(_szFileName, _szSuggestedFileName);
}
else
{
if(pszExt = FindFileExtension(_szURL))
{
StrNCpy(szExt, pszExt, MAX_PATH);
szExt[MAX_PATH] = '\0';
pszExt = StrChr(szExt, '?');
if(pszExt)
{
*pszExt = '\0';
}
pszExt = szExt;
}
}
// HACK... need some API to tell if ext is valid...
// here we assume ext with 3 chars
// including the ".", it will be 4 char
if( pszExt && strlen(pszExt) > 5 )
{
LPSTR pszMime = DupW2A(_pwzMimeSuggested);
GetMimeFileExtension( pszMime, pszExt, 20);
delete [] pszMime;
}
if( pszExt && *pszExt == '.' )
{
// FindFileExtion will return ".htm" but wininet is
// expecting "htm", so remove the extra "."
pszExt++;
}
if( CreateUrlCacheEntry(_szURL, 0, pszExt, _szFileName, GZIPHACK) )
{
if( _szFileName[0] != '\0' )
{
_hFile = CreateFile(_szFileName,
GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if( _hFile == INVALID_HANDLE_VALUE )
{
_hFile = NULL;
}
}
}
}
// Report the CACHE file name
if( _szFileName[0] != '\0' )
{
pwzFileName = DupA2W(_szFileName);
}
if( pwzFileName )
{
ReportProgress(
BINDSTATUS_CACHEFILENAMEAVAILABLE, pwzFileName);
delete [] pwzFileName;
}
//------- moved from ::Start to get accurate file ext
}
// write to the file
if( _hFile )
{
DWORD dwBytesWritten;
WriteFile(_hFile, _pOutBuf, lOutUsed, &dwBytesWritten, NULL);
if( lOutUsed != (LONG)dwBytesWritten )
{
// write failed, clean up everything
CloseHandle(_hFile);
_hFile = NULL;
DeleteUrlCacheEntryA( _szURL );
_szFileName[0] = '\0';
_szURL[0] = '\0';
}
}
PerfDbgLog2(tagMft, this,
" CMimeFt::Read-Encode/Decode %u bytes-> %u bytes",
lInUsed, lOutUsed);
}
}
else
PerfDbgLog(tagMft, this, " CMimeFt::Read-in buffer empty");
// copy over (only for the purpose of non-sniffing)
if( !fSniff && (hrCode == NOERROR) && _ulOutAvailable )
{
if( cb >= _ulOutAvailable )
{
// client has bigger buffer
memcpy(pv, _pOutBuf, _ulOutAvailable);
*pcbRead = _ulOutAvailable;
_ulOutAvailable = 0;
hr = S_OK;
PerfDbgLog1(tagMft, this,
" CMimeFt::Read-enough buffer copied %u bytes", *pcbRead);
}
else
{
// client have smaller buffer
memcpy(pv, _pOutBuf, cb);
*pcbRead = cb;
// move mem to front
memcpy(_pOutBuf, _pOutBuf+cb, _ulOutAvailable-cb);
_ulOutAvailable -= cb;
hr = S_OK;
PerfDbgLog1(tagMft, this,
" CMimeFt::Read-not enough buffer copied %u bytes", cb);
}
// keep the total (content-length)
_ulContentLength += *pcbRead;
}
// If we pulled the data, we should report that hr
if( fPullData )
hr = hrRead;
// if encode-decode error occurs, we report it
if( hrCode != NOERROR )
hr = hrCode;
// if all data are gone and LASTNOTIFICATION, we should return S_FALSE
if(_grfBSCF & BSCF_LASTDATANOTIFICATION && (_ulOutAvailable == 0) )
{
PerfDbgLog(tagMft, this,
" CMimeFt::Read-Last Notification, set hr --> 1" );
hr = S_FALSE;
}
PerfDbgLog1(tagMft, this, "-CMimeFt::Read (hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Seek
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::Seek(
LARGE_INTEGER dlibMove,
DWORD dwOrigin,
ULARGE_INTEGER *plibNewPosition)
{
PerfDbgLog(tagMft, this, "+CMimeFt::Seek");
// Seek will be available later
HRESULT hr = E_NOTIMPL;
PerfDbgLog1(tagMft, this, "-CMimeFt::Seek (hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::LockRequest
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::LockRequest(DWORD dwOptions)
{
PerfDbgLog(tagMft, this, "+CMimeFt::LockRequest");
PProtAssert(_pProt);
HRESULT hr = _pProt->LockRequest(dwOptions);
PerfDbgLog1(tagMft, this, "-CMimeFt::LockRequest(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::UnlockRequest
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::UnlockRequest()
{
PerfDbgLog(tagMft, this, "+CMimeFt::UnLockRequest");
PProtAssert(_pProt);
HRESULT hr = _pProt->UnlockRequest();
PerfDbgLog1(tagMft, this, "-CMimeFt::UnLockRequest(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Switch
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::Switch(PROTOCOLDATA *pStateInfo)
{
PerfDbgLog(tagMft, this, "+CMimeFt::Switch");
PProtAssert(_pProtSink);
HRESULT hr = _pProtSink->Switch(pStateInfo);
PerfDbgLog1(tagMft, this, "-CMimeFt::Switch (hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::ReportProgress
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::ReportProgress( ULONG ulStatusCode, LPCWSTR szStatusText)
{
PerfDbgLog(tagMft, this, "+CMimeFt::ReportProgress");
PProtAssert(_pProtSink);
HRESULT hr = NOERROR;
if( ulStatusCode == BINDSTATUS_MIMETYPEAVAILABLE )
{
delete [] _pwzMimeSuggested;
_pwzMimeSuggested = OLESTRDuplicate(szStatusText);
if( !_pwzMimeSuggested )
{
hr = E_OUTOFMEMORY;
}
}
else if( ulStatusCode == BINDSTATUS_CACHECONTROL )
{
if(!lstrcmpiW(szStatusText, L"no-cache"))
{
_bCanCache = FALSE;
}
}
else if( ulStatusCode == BINDSTATUS_CONTENTDISPOSITIONATTACH )
{
W2A(szStatusText, _szSuggestedFileName, sizeof(_szSuggestedFileName));
PathUndecorate(_szSuggestedFileName);
}
else
{
hr = _pProtSink->ReportProgress(ulStatusCode, szStatusText);
}
PerfDbgLog1(tagMft, this, "-CMimeFt::ReportProgress(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::ReportData
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes: E_PENDING returned if the filter is not empty
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::ReportData( DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
{
PerfDbgLog(tagMft, this, "+CMimeFt::ReportData");
HRESULT hr = NOERROR;
// Do a data sniffing Read to get the mime type out of the buffer
// reason for _fSniffed, _fSniffInProgress and _fDelayReport
// is that if the data sniffing SmartRead() reaches EOF, the protocol
// will do ReportResult() which we want to delay until the Real Read
// finishs
if( !_fSniffed && !_fSniffInProgress && !_fReadInProgress )
{
_fSniffInProgress = TRUE;
hr = SmartRead( NULL, 0, 0, TRUE);
_fSniffInProgress = FALSE;
if(SUCCEEDED(hr))
_fSniffed = TRUE;
}
if(_fSniffed)
{
hr = _pProtSink->ReportData(grfBSCF, ulProgress, ulProgressMax);
}
PerfDbgLog1(tagMft, this, "-CMimeFt::ReportData(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::ReportResult
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::ReportResult(HRESULT hrResult, DWORD dwError, LPCWSTR wzResult)
{
PerfDbgLog(tagMft, this, "+CMimeFt::ReportResult");
// REVISIT
PProtAssert(_pProtSink);
HRESULT hr = NOERROR;
if( _fSniffInProgress || _fReadInProgress )
{
// keep it and report it after read completes
_hrResult = hrResult;
_dwError = dwError;
_wzResult = wzResult; // should be OLEDuplicateStr()
_fDelayReport = TRUE;
}
else
{
hr = _pProtSink->ReportResult(hrResult, dwError, wzResult);
}
PerfDbgLog1(tagMft, this, "-CMimeFt::ReportResult(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::SwitchSink
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 11-24-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::SwitchSink(IOInetProtocolSink* pSink)
{
PerfDbgLog(tagMft, this, "+CMimeFt::SwitchSink");
// REVISIT
PProtAssert(_pProtSink && pSink);
HRESULT hr = NOERROR;
// keep track the existing sink (support for Commit/Rollback)
// the release of the old sink will be done at the Commit time
_pProtSinkOld = _pProtSink;
// -----------------------------------------------------------
// BUG: remove this block once enable the Commit-Rollback func
// release the old sink
//
if( _pProtSinkOld )
{
_pProtSinkOld->Release();
}
// -----------------------------------------------------------
// Change the sink
_pProtSink = pSink;
_pProtSink->AddRef();
PerfDbgLog1(tagMft, this, "-CMimeFt::SwitchSink(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::CommitSwitch
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 11-24-97 DanpoZ (Danpo Zhang) Created
//
// Notes: Commit the sink switch, what we are doing here is
// Release the old sink (old sink is coming from the
// Start method and AddRef'ed there
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::CommitSwitch()
{
PerfDbgLog(tagMft, this, "+CMimeFt::CommitSwitch");
// release the old sink
//if( _pProtSinkOld )
//{
// _pProtSinkOld->Release();
//}
// reset
//_pProtSinkOld = NULL;
PerfDbgLog(tagMft, this, "-CMimeFt::CommitSwitch");
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::RollbackSwitch
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 11-24-97 DanpoZ (Danpo Zhang) Created
//
// Notes: Error occured (most possibly the StackFilter() call failed,
// we have to rollback the sink switch, what we are doing
// here is releasing the switched sink (AddRef'ed at SwitchSink
// time), and set the original sink back, no ref count work on
// the original sink
//
//----------------------------------------------------------------------------
STDMETHODIMP
CMimeFt::RollbackSwitch()
{
PerfDbgLog(tagMft, this, "+CMimeFt::RollbackSwitch");
// copy the old sink back, release the new sink
// (new sink is AddRef'ed at SwitchSink time)
//if( _pProtSink )
//{
// _pProtSink->Release();
//}
//_pProtSink = _pProtSinkOld;
// reset
//_pProtSinkOld = NULL;
PerfDbgLog(tagMft, this, "-CMimeFt::RollbackSwitch");
return NOERROR;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::Create
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT
CMimeFt::Create(CMimeFt** ppv)
{
PerfDbgLog(tagMft, NULL, "+CMimeFt::Create");
HRESULT hr = NOERROR;
// pProt can not be NULL
PProtAssert(ppv);
*ppv = NULL;
*ppv = new CMimeFt;
if( *ppv == NULL )
hr = E_OUTOFMEMORY;
else
hr = (*ppv)->CreateBuffer();
PerfDbgLog1(tagMft, NULL, "-CMimeFt::Create(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::CMimeFt
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
CMimeFt::CMimeFt()
: _CRefs()
{
PerfDbgLog(tagMft, this, "+CMimeFt::CMimeFt");
_pProtSink = NULL;
_pProt = NULL;
_pProtSinkOld = NULL;
_pDF = NULL;
_ulCurSizeFmtIn = 0;
_ulCurSizeFmtOut = 0;
_ulTotalSizeFmtIn = 0;
_ulTotalSizeFmtOut = 0;
_ulOutAvailable = 0;
_ulInBufferLeft = 0;
_pInBuf = NULL;
_pOutBuf = NULL;
_grfBSCF = 0x00;
_bMimeReported = FALSE;
_bMimeVerified = FALSE;
_bCanCache = TRUE;
_szFileName[0] = '\0';
_szSuggestedFileName[0] = '\0';
_szURL[0] = '\0';
_hFile = NULL;
_pwzMimeSuggested = NULL;
_fDelayReport = FALSE;
_fSniffed = FALSE;
_fSniffInProgress = FALSE;
_hrResult = NOERROR;
_dwError = 0;
_wzResult = NULL;
_fReadInProgress = FALSE;
DllAddRef();
PerfDbgLog(tagMft, this, "-CMimeFt::CMimeFt");
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::CreateBuffer
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-30-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
HRESULT
CMimeFt::CreateBuffer()
{
PerfDbgLog(tagMft, this, "+CMimeFt::CreateBuffer");
HRESULT hr = NOERROR;
_pInBuf = new BYTE[FT_IBUF_SIZE];
_pOutBuf = new BYTE[FT_OBUF_SIZE];
PProtAssert(_pInBuf && _pOutBuf);
if( !_pInBuf || !_pOutBuf )
hr = E_OUTOFMEMORY;
PerfDbgLog1(tagMft, this, "-CMimeFt::CreateBuffer(hr:%1x)", hr);
return hr;
}
//+---------------------------------------------------------------------------
//
// Method: CMimeFt::~CMimeFt
//
// Synopsis:
//
// Arguments:
//
// Returns:
//
// History: 04-16-97 DanpoZ (Danpo Zhang) Created
//
// Notes:
//
//----------------------------------------------------------------------------
CMimeFt::~CMimeFt()
{
PerfDbgLog(tagMft, this, "+CMimeFt::~CMimeFt");
if( _pInBuf )
delete [] _pInBuf;
if( _pOutBuf )
delete [] _pOutBuf;
delete [] _pwzMimeSuggested;
if( _pProt )
_pProt->Release();
if( _pDF)
_pDF->Release();
if( _hFile )
CloseHandle(_hFile);
DllRelease();
PerfDbgLog(tagMft, this, "-CMimeFt::~CMimeFt");
}