windows-nt/Source/XPSP1/NT/admin/pchealth/helpctr/shell/namespace/protocolinfo.cpp

547 lines
13 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/******************************************************************************
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;
}