547 lines
13 KiB
C++
547 lines
13 KiB
C++
|
/******************************************************************************
|
||
|
|
||
|
Copyright (c) 1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
ProtocolInfo.cpp
|
||
|
|
||
|
Abstract:
|
||
|
This file contains the implementation of the CHCPProtocolInfo class.
|
||
|
|
||
|
Revision History:
|
||
|
Davide Massarenti (Dmassare) 07/05/99
|
||
|
created
|
||
|
|
||
|
******************************************************************************/
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#define CR L'\r'
|
||
|
#define LF L'\n'
|
||
|
#define TAB L'\t'
|
||
|
#define SPC L' '
|
||
|
#define SLASH L'/'
|
||
|
#define WHACK L'\\'
|
||
|
#define QUERY L'?'
|
||
|
#define POUND L'#'
|
||
|
#define SEMICOLON L';'
|
||
|
#define COLON L':'
|
||
|
#define BAR L'|'
|
||
|
#define DOT L'.'
|
||
|
|
||
|
|
||
|
static const WCHAR l_szScheme [] = L"://";
|
||
|
static const WCHAR l_szProtocol [] = L"hcp://";
|
||
|
static const WCHAR l_szCHM [] = L".chm";
|
||
|
static const WCHAR l_szCHM_end [] = L".chm::";
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#define PU_FALLBACK (0x01)
|
||
|
#define PU_DIRECT (0x02)
|
||
|
#define PU_REDIRECTED (0x04)
|
||
|
#define PU_PREPEND (0x08)
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
CHCPProtocolInfo::CHCPProtocolInfo()
|
||
|
{
|
||
|
__HCP_FUNC_ENTRY("CHCPProtocolInfo::CHCPProtocolInfo");
|
||
|
}
|
||
|
|
||
|
CHCPProtocolInfo::~CHCPProtocolInfo()
|
||
|
{
|
||
|
__HCP_FUNC_ENTRY("CHCPProtocolInfo::~CHCPProtocolInfo");
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
bool CHCPProtocolInfo::LookForHCP( LPCWSTR pwzUrl ,
|
||
|
bool& fRedirect ,
|
||
|
LPCWSTR& pwzRedirect )
|
||
|
{
|
||
|
__HCP_FUNC_ENTRY("CHCPProtocolInfo::LookForHCP");
|
||
|
|
||
|
bool fRes = false;
|
||
|
LPCWSTR pwzPosMarker;
|
||
|
LPCWSTR pwzPosQuery;
|
||
|
|
||
|
|
||
|
fRedirect = false;
|
||
|
pwzRedirect = NULL;
|
||
|
|
||
|
pwzPosMarker = wcsstr( pwzUrl, l_szProtocol );
|
||
|
if(pwzPosMarker)
|
||
|
{
|
||
|
fRes = true;
|
||
|
pwzUrl = pwzPosMarker + MAXSTRLEN( l_szProtocol );
|
||
|
|
||
|
pwzPosMarker = wcschr( pwzUrl, COLON );
|
||
|
pwzPosQuery = wcschr( pwzUrl, QUERY );
|
||
|
|
||
|
if(pwzPosMarker) // Found a colon, possible redirection.
|
||
|
{
|
||
|
if(pwzPosQuery == NULL ||
|
||
|
pwzPosQuery > pwzPosMarker ) // Make sure the colon is not part of a query string.
|
||
|
{
|
||
|
pwzRedirect = pwzUrl;
|
||
|
fRedirect = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
__HCP_FUNC_EXIT(fRes);
|
||
|
}
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
static inline bool IsSeparator( LPCWSTR p )
|
||
|
{
|
||
|
return (p[0] == SLASH || p[0] == WHACK );
|
||
|
}
|
||
|
|
||
|
static inline BOOL IsDot( LPCWSTR p ) // if p == "." return TRUE
|
||
|
{
|
||
|
return (p[0] == DOT && (!p[1] || IsSeparator( &p[1] )));
|
||
|
}
|
||
|
|
||
|
static inline BOOL IsDotDot(LPCWSTR p) // if p == ".." return TRUE
|
||
|
{
|
||
|
return (p[0] == DOT && p[1] == DOT && (!p[2] || IsSeparator( &p[2] )));
|
||
|
}
|
||
|
|
||
|
static void Safe_Cut( LPWSTR pszStart ,
|
||
|
LPWSTR pszCurrent ,
|
||
|
LPWSTR pszSlash ,
|
||
|
DWORD & cchLength )
|
||
|
{
|
||
|
DWORD cchBytesToMove = cchLength - (pszSlash - pszStart);
|
||
|
DWORD cchLengthOfCut = pszSlash - pszCurrent;
|
||
|
|
||
|
::MoveMemory( pszCurrent, pszSlash, cchBytesToMove * sizeof( WCHAR ) ); pszCurrent[cchBytesToMove] = 0;
|
||
|
|
||
|
cchLength -= cchLengthOfCut;
|
||
|
}
|
||
|
|
||
|
static HRESULT Safe_UrlCanonicalizeW( LPCWSTR pszUrl ,
|
||
|
LPWSTR pszCanonicalized ,
|
||
|
LPDWORD pcchCanonicalized ,
|
||
|
DWORD dwFlags )
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
DWORD cchLength = *pcchCanonicalized;
|
||
|
|
||
|
hr = UrlCanonicalizeW( pszUrl, pszCanonicalized, &cchLength, dwFlags );
|
||
|
|
||
|
if((dwFlags & URL_DONT_SIMPLIFY) == 0)
|
||
|
{
|
||
|
LPWSTR pszLast = NULL;
|
||
|
LPWSTR pszCurrent = pszCanonicalized;
|
||
|
|
||
|
while(pszCurrent[0])
|
||
|
{
|
||
|
LPWSTR pszSlash;
|
||
|
|
||
|
//
|
||
|
// Make 'pszSlash' point to the characted AFTER the next slash or to the end of the string.
|
||
|
//
|
||
|
pszSlash = wcschr( pszCurrent, SLASH );
|
||
|
if(pszSlash)
|
||
|
{
|
||
|
pszSlash++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pszSlash = pszCurrent + wcslen( pszCurrent );
|
||
|
}
|
||
|
|
||
|
if(IsDot( pszCurrent ))
|
||
|
{
|
||
|
Safe_Cut( pszCanonicalized, pszCurrent, pszSlash, cchLength );
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if(IsDotDot( pszCurrent ))
|
||
|
{
|
||
|
Safe_Cut( pszCanonicalized, pszCurrent, pszSlash, cchLength );
|
||
|
|
||
|
if(pszLast)
|
||
|
{
|
||
|
Safe_Cut( pszCanonicalized, pszLast, pszCurrent, cchLength );
|
||
|
pszCurrent = pszLast;
|
||
|
}
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
pszLast = pszCurrent;
|
||
|
pszCurrent = pszSlash;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pcchCanonicalized = cchLength;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
static DWORD AppendString( LPWSTR& pwzResult ,
|
||
|
DWORD& cchResult ,
|
||
|
LPCWSTR pwzString ,
|
||
|
DWORD dwLen = -1 )
|
||
|
{
|
||
|
__HCP_FUNC_ENTRY("CHCPProtocolInfo::AppendString");
|
||
|
|
||
|
DWORD dwOffset = dwLen != -1 ? dwLen : wcslen( pwzString );
|
||
|
|
||
|
if(pwzResult)
|
||
|
{
|
||
|
int len;
|
||
|
|
||
|
pwzResult[cchResult-1] = 0;
|
||
|
|
||
|
wcsncpy( pwzResult, pwzString, min( dwLen, cchResult-1 ) );
|
||
|
|
||
|
len = wcslen( pwzResult );
|
||
|
|
||
|
pwzResult += len;
|
||
|
cchResult -= len;
|
||
|
}
|
||
|
|
||
|
|
||
|
__HCP_FUNC_EXIT(dwOffset);
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CHCPProtocolInfo::CombineUrl( LPCWSTR pwzBaseUrl ,
|
||
|
LPCWSTR pwzRelativeUrl,
|
||
|
DWORD dwCombineFlags,
|
||
|
LPWSTR pwzResult ,
|
||
|
DWORD cchResult ,
|
||
|
DWORD *pcchResult ,
|
||
|
DWORD dwReserved )
|
||
|
{
|
||
|
__HCP_FUNC_ENTRY("CHCPProtocolInfo::CombineUrl");
|
||
|
|
||
|
HRESULT hr;
|
||
|
bool fRedirect;
|
||
|
LPCWSTR pwzRedirect;
|
||
|
DWORD dwAvailable = cchResult;
|
||
|
DWORD dwOffset = 0;
|
||
|
|
||
|
|
||
|
*pcchResult = 0;
|
||
|
|
||
|
//
|
||
|
// Don't process redirection if the second url is absolute.
|
||
|
//
|
||
|
if(wcsstr( pwzRelativeUrl, l_szScheme ) == NULL &&
|
||
|
wcschr( pwzRelativeUrl, COLON ) == NULL )
|
||
|
{
|
||
|
if(LookForHCP( pwzBaseUrl, fRedirect, pwzRedirect ))
|
||
|
{
|
||
|
if(fRedirect)
|
||
|
{
|
||
|
//
|
||
|
// Prepend "HCP://".
|
||
|
//
|
||
|
dwOffset = AppendString( pwzResult, cchResult, l_szProtocol );
|
||
|
|
||
|
pwzBaseUrl = pwzRedirect;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*pcchResult = cchResult;
|
||
|
|
||
|
//
|
||
|
// Special case to handle combination for URL referring to MSITS protocol (InternetCombineUrlW doesn't do it for us...)
|
||
|
//
|
||
|
if(MPC::MSITS::IsCHM( pwzBaseUrl ))
|
||
|
{
|
||
|
LPCWSTR szEnd = wcsstr( pwzBaseUrl, l_szCHM_end );
|
||
|
if(szEnd)
|
||
|
{
|
||
|
szEnd += MAXSTRLEN( l_szCHM_end );
|
||
|
|
||
|
dwOffset += AppendString( pwzResult, cchResult, pwzBaseUrl, szEnd - pwzBaseUrl );
|
||
|
|
||
|
pwzBaseUrl = szEnd;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(::InternetCombineUrlW( pwzBaseUrl, pwzRelativeUrl, pwzResult, pcchResult, dwCombineFlags ) == FALSE)
|
||
|
{
|
||
|
DWORD dwErr = ::GetLastError();
|
||
|
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
||
|
}
|
||
|
|
||
|
*pcchResult += dwOffset;
|
||
|
hr = S_OK;
|
||
|
|
||
|
|
||
|
__HCP_FUNC_CLEANUP;
|
||
|
|
||
|
if(hr == S_OK)
|
||
|
{
|
||
|
hr = (*pcchResult > dwAvailable) ? S_FALSE : S_OK;
|
||
|
}
|
||
|
|
||
|
__HCP_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CHCPProtocolInfo::CompareUrl( LPCWSTR pwzUrl1 ,
|
||
|
LPCWSTR pwzUrl2 ,
|
||
|
DWORD dwCompareFlags )
|
||
|
{
|
||
|
__HCP_FUNC_ENTRY("CHCPProtocolInfo::CompareUrl");
|
||
|
|
||
|
__HCP_FUNC_EXIT(E_NOTIMPL);
|
||
|
}
|
||
|
|
||
|
|
||
|
STDMETHODIMP CHCPProtocolInfo::ParseUrl( LPCWSTR pwzUrl ,
|
||
|
PARSEACTION parseAction ,
|
||
|
DWORD dwParseFlags,
|
||
|
LPWSTR pwzResult ,
|
||
|
DWORD cchResult ,
|
||
|
DWORD *pcchResult ,
|
||
|
DWORD dwReserved )
|
||
|
{
|
||
|
__HCP_FUNC_ENTRY("CHCPProtocolInfo::ParseUrl");
|
||
|
|
||
|
HRESULT hr;
|
||
|
bool fHCP;
|
||
|
bool fRedirect;
|
||
|
LPCWSTR pwzRedirect;
|
||
|
DWORD dwAvailable = cchResult;
|
||
|
DWORD dwOffset = 0;
|
||
|
DWORD dwAction = PU_FALLBACK;
|
||
|
|
||
|
|
||
|
*pcchResult = 0;
|
||
|
if(pwzResult)
|
||
|
{
|
||
|
*pwzResult = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
switch(parseAction)
|
||
|
{
|
||
|
case PARSE_CANONICALIZE : dwAction = PU_DIRECT | PU_REDIRECTED | PU_PREPEND; break;
|
||
|
case PARSE_FRIENDLY : dwAction = PU_FALLBACK ; break;
|
||
|
case PARSE_SECURITY_URL : dwAction = PU_DIRECT | PU_REDIRECTED ; break;
|
||
|
case PARSE_ROOTDOCUMENT : dwAction = PU_DIRECT | PU_REDIRECTED | PU_PREPEND; break;
|
||
|
case PARSE_DOCUMENT : dwAction = PU_DIRECT | PU_REDIRECTED | PU_PREPEND; break;
|
||
|
case PARSE_ANCHOR : dwAction = PU_DIRECT ; break;
|
||
|
case PARSE_ENCODE : dwAction = PU_FALLBACK ; break;
|
||
|
case PARSE_DECODE : dwAction = PU_FALLBACK ; break;
|
||
|
case PARSE_PATH_FROM_URL : dwAction = PU_FALLBACK ; break;
|
||
|
case PARSE_URL_FROM_PATH : dwAction = PU_FALLBACK ; break;
|
||
|
case PARSE_MIME : dwAction = PU_FALLBACK ; break;
|
||
|
case PARSE_SERVER : dwAction = PU_DIRECT | PU_REDIRECTED ; break;
|
||
|
case PARSE_SCHEMA : dwAction = PU_DIRECT ; break;
|
||
|
case PARSE_SITE : dwAction = PU_FALLBACK ; break;
|
||
|
case PARSE_DOMAIN : dwAction = PU_DIRECT | PU_REDIRECTED ; break;
|
||
|
case PARSE_LOCATION : dwAction = PU_DIRECT ; break;
|
||
|
case PARSE_SECURITY_DOMAIN: dwAction = PU_FALLBACK ; break;
|
||
|
// case PARSE_ESCAPE : dwAction = PU_FALLBACK ; break;
|
||
|
// case PARSE_UNESCAPE : dwAction = PU_FALLBACK ; break;
|
||
|
}
|
||
|
|
||
|
///////
|
||
|
|
||
|
fHCP = LookForHCP( pwzUrl, fRedirect, pwzRedirect );
|
||
|
if(fHCP == false)
|
||
|
{
|
||
|
//
|
||
|
// If it's not a HCP url, let the system use the default action (this should never happen anyway...).
|
||
|
//
|
||
|
dwAction = PU_FALLBACK;
|
||
|
}
|
||
|
|
||
|
if(dwAction & PU_FALLBACK)
|
||
|
{
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, INET_E_DEFAULT_ACTION);
|
||
|
}
|
||
|
|
||
|
///////
|
||
|
|
||
|
if(fRedirect == false)
|
||
|
{
|
||
|
dwAction &= ~PU_REDIRECTED;
|
||
|
dwAction &= ~PU_PREPEND;
|
||
|
}
|
||
|
|
||
|
if(dwAction & PU_REDIRECTED)
|
||
|
{
|
||
|
//
|
||
|
// Use the real URL part.
|
||
|
//
|
||
|
pwzUrl = pwzRedirect;
|
||
|
}
|
||
|
|
||
|
if(dwAction & PU_PREPEND)
|
||
|
{
|
||
|
//
|
||
|
// Prepend "HCP://".
|
||
|
//
|
||
|
dwOffset = AppendString( pwzResult, cchResult, l_szProtocol );
|
||
|
}
|
||
|
|
||
|
if(dwAction & PU_DIRECT)
|
||
|
{
|
||
|
switch(parseAction)
|
||
|
{
|
||
|
case PARSE_SECURITY_URL:
|
||
|
//
|
||
|
// Look for the end of the hostname, skipping the eventual protocol part.
|
||
|
// If we can't find the end of the hostname, copy everything.
|
||
|
//
|
||
|
{
|
||
|
LPWSTR pwzScheme = wcsstr( pwzUrl, l_szScheme );
|
||
|
LPWSTR pwzEnd = wcschr( pwzScheme ? pwzScheme + MAXSTRLEN( l_szScheme ) : pwzUrl, SLASH );
|
||
|
|
||
|
if(pwzEnd)
|
||
|
{
|
||
|
dwOffset = AppendString( pwzResult, cchResult, pwzUrl, (pwzEnd-pwzUrl) );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwOffset = AppendString( pwzResult, cchResult, pwzUrl );
|
||
|
}
|
||
|
}
|
||
|
hr = S_OK;
|
||
|
break;
|
||
|
|
||
|
case PARSE_CANONICALIZE:
|
||
|
*pcchResult = cchResult;
|
||
|
hr = Safe_UrlCanonicalizeW( pwzUrl, pwzResult, pcchResult, dwParseFlags );
|
||
|
break;
|
||
|
|
||
|
case PARSE_ROOTDOCUMENT:
|
||
|
hr = INET_E_DEFAULT_ACTION;
|
||
|
break;
|
||
|
|
||
|
case PARSE_DOCUMENT:
|
||
|
hr = INET_E_DEFAULT_ACTION;
|
||
|
break;
|
||
|
|
||
|
case PARSE_ANCHOR:
|
||
|
hr = INET_E_DEFAULT_ACTION;
|
||
|
break;
|
||
|
|
||
|
case PARSE_SERVER:
|
||
|
hr = INET_E_DEFAULT_ACTION;
|
||
|
break;
|
||
|
|
||
|
case PARSE_SCHEMA:
|
||
|
*pcchResult = cchResult;
|
||
|
hr = UrlGetPartW( pwzUrl, pwzResult, pcchResult, URL_PART_SCHEME, 0 );
|
||
|
break;
|
||
|
|
||
|
case PARSE_DOMAIN:
|
||
|
*pcchResult = cchResult;
|
||
|
hr = UrlGetPartW( pwzUrl, pwzResult, pcchResult, URL_PART_HOSTNAME, 0 );
|
||
|
break;
|
||
|
|
||
|
case PARSE_LOCATION:
|
||
|
hr = INET_E_DEFAULT_ACTION;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
__HCP_FUNC_CLEANUP;
|
||
|
|
||
|
if(hr == S_OK)
|
||
|
{
|
||
|
*pcchResult += dwOffset;
|
||
|
|
||
|
hr = (*pcchResult > dwAvailable) ? S_FALSE : S_OK;
|
||
|
}
|
||
|
|
||
|
__HCP_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CHCPProtocolInfo::QueryInfo( LPCWSTR pwzUrl ,
|
||
|
QUERYOPTION QueryOption ,
|
||
|
DWORD dwQueryFlags,
|
||
|
LPVOID pBuffer ,
|
||
|
DWORD cbBuffer ,
|
||
|
DWORD *pcbBuf ,
|
||
|
DWORD dwReserved )
|
||
|
{
|
||
|
__HCP_FUNC_ENTRY("CHCPProtocolInfo::QueryInfo");
|
||
|
|
||
|
HRESULT hr = INET_E_QUERYOPTION_UNKNOWN;
|
||
|
bool fHCP;
|
||
|
bool fRedirect;
|
||
|
LPCWSTR pwzRedirect;
|
||
|
|
||
|
|
||
|
fHCP = LookForHCP( pwzUrl, fRedirect, pwzRedirect );
|
||
|
if(fHCP)
|
||
|
{
|
||
|
if(fRedirect)
|
||
|
{
|
||
|
hr = CoInternetQueryInfo( pwzRedirect, QueryOption, dwQueryFlags, pBuffer, cbBuffer, pcbBuf, dwReserved );
|
||
|
if(hr == E_FAIL)
|
||
|
{
|
||
|
__MPC_SET_ERROR_AND_EXIT(hr, INET_E_QUERYOPTION_UNKNOWN);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Implement HCP logic.
|
||
|
//
|
||
|
}
|
||
|
}
|
||
|
|
||
|
__HCP_FUNC_CLEANUP;
|
||
|
|
||
|
__HCP_FUNC_EXIT(hr);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
STDMETHODIMP CHCPProtocolInfo::CreateInstance( /*[in] */ LPUNKNOWN pUnkOuter ,
|
||
|
/*[in] */ REFIID riid ,
|
||
|
/*[out]*/ void* *ppvObj )
|
||
|
{
|
||
|
HRESULT hr = E_POINTER;
|
||
|
|
||
|
if(ppvObj)
|
||
|
{
|
||
|
*ppvObj = NULL;
|
||
|
|
||
|
if(InlineIsEqualGUID( IID_IInternetProtocolInfo, riid ))
|
||
|
{
|
||
|
hr = QueryInterface( riid, ppvObj );
|
||
|
}
|
||
|
else if(InlineIsEqualGUID( IID_IUnknown , riid ) ||
|
||
|
InlineIsEqualGUID( IID_IInternetProtocol , riid ) ||
|
||
|
InlineIsEqualGUID( IID_IInternetProtocolRoot, riid ) )
|
||
|
{
|
||
|
CComPtr<IUnknown> obj;
|
||
|
|
||
|
if(SUCCEEDED(hr = CHCPProtocol::CreateInstance( pUnkOuter, &obj )))
|
||
|
{
|
||
|
hr = obj->QueryInterface( riid, ppvObj );
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHODIMP CHCPProtocolInfo::LockServer( /*[in]*/ BOOL fLock )
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|