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.

546 lines
14 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. ProtocolInfo.cpp
  5. Abstract:
  6. This file contains the implementation of the CHCPProtocolInfo class.
  7. Revision History:
  8. Davide Massarenti (Dmassare) 07/05/99
  9. created
  10. ******************************************************************************/
  11. #include "stdafx.h"
  12. /////////////////////////////////////////////////////////////////////////////
  13. #define CR L'\r'
  14. #define LF L'\n'
  15. #define TAB L'\t'
  16. #define SPC L' '
  17. #define SLASH L'/'
  18. #define WHACK L'\\'
  19. #define QUERY L'?'
  20. #define POUND L'#'
  21. #define SEMICOLON L';'
  22. #define COLON L':'
  23. #define BAR L'|'
  24. #define DOT L'.'
  25. static const WCHAR l_szScheme [] = L"://";
  26. static const WCHAR l_szProtocol [] = L"hcp://";
  27. static const WCHAR l_szCHM [] = L".chm";
  28. static const WCHAR l_szCHM_end [] = L".chm::";
  29. /////////////////////////////////////////////////////////////////////////////
  30. #define PU_FALLBACK (0x01)
  31. #define PU_DIRECT (0x02)
  32. #define PU_REDIRECTED (0x04)
  33. #define PU_PREPEND (0x08)
  34. /////////////////////////////////////////////////////////////////////////////
  35. CHCPProtocolInfo::CHCPProtocolInfo()
  36. {
  37. __HCP_FUNC_ENTRY("CHCPProtocolInfo::CHCPProtocolInfo");
  38. }
  39. CHCPProtocolInfo::~CHCPProtocolInfo()
  40. {
  41. __HCP_FUNC_ENTRY("CHCPProtocolInfo::~CHCPProtocolInfo");
  42. }
  43. /////////////////////////////////////////////////////////////////////////////
  44. bool CHCPProtocolInfo::LookForHCP( LPCWSTR pwzUrl ,
  45. bool& fRedirect ,
  46. LPCWSTR& pwzRedirect )
  47. {
  48. __HCP_FUNC_ENTRY("CHCPProtocolInfo::LookForHCP");
  49. bool fRes = false;
  50. LPCWSTR pwzPosMarker;
  51. LPCWSTR pwzPosQuery;
  52. fRedirect = false;
  53. pwzRedirect = NULL;
  54. pwzPosMarker = wcsstr( pwzUrl, l_szProtocol );
  55. if(pwzPosMarker)
  56. {
  57. fRes = true;
  58. pwzUrl = pwzPosMarker + MAXSTRLEN( l_szProtocol );
  59. pwzPosMarker = wcschr( pwzUrl, COLON );
  60. pwzPosQuery = wcschr( pwzUrl, QUERY );
  61. if(pwzPosMarker) // Found a colon, possible redirection.
  62. {
  63. if(pwzPosQuery == NULL ||
  64. pwzPosQuery > pwzPosMarker ) // Make sure the colon is not part of a query string.
  65. {
  66. pwzRedirect = pwzUrl;
  67. fRedirect = true;
  68. }
  69. }
  70. }
  71. __HCP_FUNC_EXIT(fRes);
  72. }
  73. /////////////////////////////////////////////////////////////////////////////
  74. static inline bool IsSeparator( LPCWSTR p )
  75. {
  76. return (p[0] == SLASH || p[0] == WHACK );
  77. }
  78. static inline BOOL IsDot( LPCWSTR p ) // if p == "." return TRUE
  79. {
  80. return (p[0] == DOT && (!p[1] || IsSeparator( &p[1] )));
  81. }
  82. static inline BOOL IsDotDot(LPCWSTR p) // if p == ".." return TRUE
  83. {
  84. return (p[0] == DOT && p[1] == DOT && (!p[2] || IsSeparator( &p[2] )));
  85. }
  86. static void Safe_Cut( LPWSTR pszStart ,
  87. LPWSTR pszCurrent ,
  88. LPWSTR pszSlash ,
  89. DWORD & cchLength )
  90. {
  91. DWORD cchBytesToMove = cchLength - (pszSlash - pszStart);
  92. DWORD cchLengthOfCut = pszSlash - pszCurrent;
  93. ::MoveMemory( pszCurrent, pszSlash, cchBytesToMove * sizeof( WCHAR ) ); pszCurrent[cchBytesToMove] = 0;
  94. cchLength -= cchLengthOfCut;
  95. }
  96. static HRESULT Safe_UrlCanonicalizeW( LPCWSTR pszUrl ,
  97. LPWSTR pszCanonicalized ,
  98. LPDWORD pcchCanonicalized ,
  99. DWORD dwFlags )
  100. {
  101. HRESULT hr;
  102. DWORD cchLength = *pcchCanonicalized;
  103. hr = UrlCanonicalizeW( pszUrl, pszCanonicalized, &cchLength, dwFlags );
  104. if((dwFlags & URL_DONT_SIMPLIFY) == 0)
  105. {
  106. LPWSTR pszLast = NULL;
  107. LPWSTR pszCurrent = pszCanonicalized;
  108. while(pszCurrent[0])
  109. {
  110. LPWSTR pszSlash;
  111. //
  112. // Make 'pszSlash' point to the characted AFTER the next slash or to the end of the string.
  113. //
  114. pszSlash = wcschr( pszCurrent, SLASH );
  115. if(pszSlash)
  116. {
  117. pszSlash++;
  118. }
  119. else
  120. {
  121. pszSlash = pszCurrent + wcslen( pszCurrent );
  122. }
  123. if(IsDot( pszCurrent ))
  124. {
  125. Safe_Cut( pszCanonicalized, pszCurrent, pszSlash, cchLength );
  126. continue;
  127. }
  128. if(IsDotDot( pszCurrent ))
  129. {
  130. Safe_Cut( pszCanonicalized, pszCurrent, pszSlash, cchLength );
  131. if(pszLast)
  132. {
  133. Safe_Cut( pszCanonicalized, pszLast, pszCurrent, cchLength );
  134. pszCurrent = pszLast;
  135. }
  136. continue;
  137. }
  138. pszLast = pszCurrent;
  139. pszCurrent = pszSlash;
  140. }
  141. }
  142. *pcchCanonicalized = cchLength;
  143. return hr;
  144. }
  145. static DWORD AppendString( LPWSTR& pwzResult ,
  146. DWORD& cchResult ,
  147. LPCWSTR pwzString ,
  148. DWORD dwLen = -1 )
  149. {
  150. __HCP_FUNC_ENTRY("CHCPProtocolInfo::AppendString");
  151. DWORD dwOffset = dwLen != -1 ? dwLen : wcslen( pwzString );
  152. if(pwzResult)
  153. {
  154. int len;
  155. pwzResult[cchResult-1] = 0;
  156. StringCchCopyNW( pwzResult, cchResult, pwzString, min( dwLen, cchResult-1 ));
  157. len = wcslen( pwzResult );
  158. pwzResult += len;
  159. cchResult -= len;
  160. }
  161. __HCP_FUNC_EXIT(dwOffset);
  162. }
  163. STDMETHODIMP CHCPProtocolInfo::CombineUrl( LPCWSTR pwzBaseUrl ,
  164. LPCWSTR pwzRelativeUrl,
  165. DWORD dwCombineFlags,
  166. LPWSTR pwzResult ,
  167. DWORD cchResult ,
  168. DWORD *pcchResult ,
  169. DWORD dwReserved )
  170. {
  171. __HCP_FUNC_ENTRY("CHCPProtocolInfo::CombineUrl");
  172. HRESULT hr;
  173. bool fRedirect;
  174. LPCWSTR pwzRedirect;
  175. DWORD dwAvailable = cchResult;
  176. DWORD dwOffset = 0;
  177. *pcchResult = 0;
  178. //
  179. // Don't process redirection if the second url is absolute.
  180. //
  181. if(wcsstr( pwzRelativeUrl, l_szScheme ) == NULL &&
  182. wcschr( pwzRelativeUrl, COLON ) == NULL )
  183. {
  184. if(LookForHCP( pwzBaseUrl, fRedirect, pwzRedirect ))
  185. {
  186. if(fRedirect)
  187. {
  188. //
  189. // Prepend "HCP://".
  190. //
  191. dwOffset = AppendString( pwzResult, cchResult, l_szProtocol );
  192. pwzBaseUrl = pwzRedirect;
  193. }
  194. }
  195. }
  196. *pcchResult = cchResult;
  197. //
  198. // Special case to handle combination for URL referring to MSITS protocol (InternetCombineUrlW doesn't do it for us...)
  199. //
  200. if(MPC::MSITS::IsCHM( pwzBaseUrl ))
  201. {
  202. LPCWSTR szEnd = wcsstr( pwzBaseUrl, l_szCHM_end );
  203. if(szEnd)
  204. {
  205. szEnd += MAXSTRLEN( l_szCHM_end );
  206. dwOffset += AppendString( pwzResult, cchResult, pwzBaseUrl, szEnd - pwzBaseUrl );
  207. pwzBaseUrl = szEnd;
  208. }
  209. }
  210. if(::InternetCombineUrlW( pwzBaseUrl, pwzRelativeUrl, pwzResult, pcchResult, dwCombineFlags ) == FALSE)
  211. {
  212. DWORD dwErr = ::GetLastError();
  213. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  214. }
  215. *pcchResult += dwOffset;
  216. hr = S_OK;
  217. __HCP_FUNC_CLEANUP;
  218. if(hr == S_OK)
  219. {
  220. hr = (*pcchResult > dwAvailable) ? S_FALSE : S_OK;
  221. }
  222. __HCP_FUNC_EXIT(hr);
  223. }
  224. STDMETHODIMP CHCPProtocolInfo::CompareUrl( LPCWSTR pwzUrl1 ,
  225. LPCWSTR pwzUrl2 ,
  226. DWORD dwCompareFlags )
  227. {
  228. __HCP_FUNC_ENTRY("CHCPProtocolInfo::CompareUrl");
  229. __HCP_FUNC_EXIT(E_NOTIMPL);
  230. }
  231. STDMETHODIMP CHCPProtocolInfo::ParseUrl( LPCWSTR pwzUrl ,
  232. PARSEACTION parseAction ,
  233. DWORD dwParseFlags,
  234. LPWSTR pwzResult ,
  235. DWORD cchResult ,
  236. DWORD *pcchResult ,
  237. DWORD dwReserved )
  238. {
  239. __HCP_FUNC_ENTRY("CHCPProtocolInfo::ParseUrl");
  240. HRESULT hr;
  241. bool fHCP;
  242. bool fRedirect;
  243. LPCWSTR pwzRedirect;
  244. DWORD dwAvailable = cchResult;
  245. DWORD dwOffset = 0;
  246. DWORD dwAction = PU_FALLBACK;
  247. *pcchResult = 0;
  248. if(pwzResult)
  249. {
  250. *pwzResult = 0;
  251. }
  252. switch(parseAction)
  253. {
  254. case PARSE_CANONICALIZE : dwAction = PU_DIRECT | PU_REDIRECTED | PU_PREPEND; break;
  255. case PARSE_FRIENDLY : dwAction = PU_FALLBACK ; break;
  256. case PARSE_SECURITY_URL : dwAction = PU_DIRECT | PU_REDIRECTED ; break;
  257. case PARSE_ROOTDOCUMENT : dwAction = PU_DIRECT | PU_REDIRECTED | PU_PREPEND; break;
  258. case PARSE_DOCUMENT : dwAction = PU_DIRECT | PU_REDIRECTED | PU_PREPEND; break;
  259. case PARSE_ANCHOR : dwAction = PU_DIRECT ; break;
  260. case PARSE_ENCODE : dwAction = PU_FALLBACK ; break;
  261. case PARSE_DECODE : dwAction = PU_FALLBACK ; break;
  262. case PARSE_PATH_FROM_URL : dwAction = PU_FALLBACK ; break;
  263. case PARSE_URL_FROM_PATH : dwAction = PU_FALLBACK ; break;
  264. case PARSE_MIME : dwAction = PU_FALLBACK ; break;
  265. case PARSE_SERVER : dwAction = PU_DIRECT | PU_REDIRECTED ; break;
  266. case PARSE_SCHEMA : dwAction = PU_DIRECT ; break;
  267. case PARSE_SITE : dwAction = PU_FALLBACK ; break;
  268. case PARSE_DOMAIN : dwAction = PU_DIRECT | PU_REDIRECTED ; break;
  269. case PARSE_LOCATION : dwAction = PU_DIRECT ; break;
  270. case PARSE_SECURITY_DOMAIN: dwAction = PU_FALLBACK ; break;
  271. // case PARSE_ESCAPE : dwAction = PU_FALLBACK ; break;
  272. // case PARSE_UNESCAPE : dwAction = PU_FALLBACK ; break;
  273. }
  274. ///////
  275. fHCP = LookForHCP( pwzUrl, fRedirect, pwzRedirect );
  276. if(fHCP == false)
  277. {
  278. //
  279. // If it's not a HCP url, let the system use the default action (this should never happen anyway...).
  280. //
  281. dwAction = PU_FALLBACK;
  282. }
  283. if(dwAction & PU_FALLBACK)
  284. {
  285. __MPC_SET_ERROR_AND_EXIT(hr, INET_E_DEFAULT_ACTION);
  286. }
  287. ///////
  288. if(fRedirect == false)
  289. {
  290. dwAction &= ~PU_REDIRECTED;
  291. dwAction &= ~PU_PREPEND;
  292. }
  293. if(dwAction & PU_REDIRECTED)
  294. {
  295. //
  296. // Use the real URL part.
  297. //
  298. pwzUrl = pwzRedirect;
  299. }
  300. if(dwAction & PU_PREPEND)
  301. {
  302. //
  303. // Prepend "HCP://".
  304. //
  305. dwOffset = AppendString( pwzResult, cchResult, l_szProtocol );
  306. }
  307. if(dwAction & PU_DIRECT)
  308. {
  309. switch(parseAction)
  310. {
  311. case PARSE_SECURITY_URL:
  312. //
  313. // Look for the end of the hostname, skipping the eventual protocol part.
  314. // If we can't find the end of the hostname, copy everything.
  315. //
  316. {
  317. LPWSTR pwzScheme = wcsstr( pwzUrl, l_szScheme );
  318. LPWSTR pwzEnd = wcschr( pwzScheme ? pwzScheme + MAXSTRLEN( l_szScheme ) : pwzUrl, SLASH );
  319. if(pwzEnd)
  320. {
  321. dwOffset = AppendString( pwzResult, cchResult, pwzUrl, (pwzEnd-pwzUrl) );
  322. }
  323. else
  324. {
  325. dwOffset = AppendString( pwzResult, cchResult, pwzUrl );
  326. }
  327. }
  328. hr = S_OK;
  329. break;
  330. case PARSE_CANONICALIZE:
  331. *pcchResult = cchResult;
  332. hr = Safe_UrlCanonicalizeW( pwzUrl, pwzResult, pcchResult, dwParseFlags );
  333. break;
  334. case PARSE_ROOTDOCUMENT:
  335. hr = INET_E_DEFAULT_ACTION;
  336. break;
  337. case PARSE_DOCUMENT:
  338. hr = INET_E_DEFAULT_ACTION;
  339. break;
  340. case PARSE_ANCHOR:
  341. hr = INET_E_DEFAULT_ACTION;
  342. break;
  343. case PARSE_SERVER:
  344. hr = INET_E_DEFAULT_ACTION;
  345. break;
  346. case PARSE_SCHEMA:
  347. *pcchResult = cchResult;
  348. hr = UrlGetPartW( pwzUrl, pwzResult, pcchResult, URL_PART_SCHEME, 0 );
  349. break;
  350. case PARSE_DOMAIN:
  351. *pcchResult = cchResult;
  352. hr = UrlGetPartW( pwzUrl, pwzResult, pcchResult, URL_PART_HOSTNAME, 0 );
  353. break;
  354. case PARSE_LOCATION:
  355. hr = INET_E_DEFAULT_ACTION;
  356. break;
  357. }
  358. }
  359. __HCP_FUNC_CLEANUP;
  360. if(hr == S_OK)
  361. {
  362. *pcchResult += dwOffset;
  363. hr = (*pcchResult > dwAvailable) ? S_FALSE : S_OK;
  364. }
  365. __HCP_FUNC_EXIT(hr);
  366. }
  367. STDMETHODIMP CHCPProtocolInfo::QueryInfo( LPCWSTR pwzUrl ,
  368. QUERYOPTION QueryOption ,
  369. DWORD dwQueryFlags,
  370. LPVOID pBuffer ,
  371. DWORD cbBuffer ,
  372. DWORD *pcbBuf ,
  373. DWORD dwReserved )
  374. {
  375. __HCP_FUNC_ENTRY("CHCPProtocolInfo::QueryInfo");
  376. HRESULT hr = INET_E_QUERYOPTION_UNKNOWN;
  377. bool fHCP;
  378. bool fRedirect;
  379. LPCWSTR pwzRedirect;
  380. fHCP = LookForHCP( pwzUrl, fRedirect, pwzRedirect );
  381. if(fHCP)
  382. {
  383. if(fRedirect)
  384. {
  385. hr = CoInternetQueryInfo( pwzRedirect, QueryOption, dwQueryFlags, pBuffer, cbBuffer, pcbBuf, dwReserved );
  386. if(hr == E_FAIL)
  387. {
  388. __MPC_SET_ERROR_AND_EXIT(hr, INET_E_QUERYOPTION_UNKNOWN);
  389. }
  390. }
  391. else
  392. {
  393. //
  394. // Implement HCP logic.
  395. //
  396. }
  397. }
  398. __HCP_FUNC_CLEANUP;
  399. __HCP_FUNC_EXIT(hr);
  400. }
  401. ////////////////////////////////////////////////////////////////////////////////
  402. STDMETHODIMP CHCPProtocolInfo::CreateInstance( /*[in] */ LPUNKNOWN pUnkOuter ,
  403. /*[in] */ REFIID riid ,
  404. /*[out]*/ void* *ppvObj )
  405. {
  406. HRESULT hr = E_POINTER;
  407. if(ppvObj)
  408. {
  409. *ppvObj = NULL;
  410. if(InlineIsEqualGUID( IID_IInternetProtocolInfo, riid ))
  411. {
  412. hr = QueryInterface( riid, ppvObj );
  413. }
  414. else if(InlineIsEqualGUID( IID_IUnknown , riid ) ||
  415. InlineIsEqualGUID( IID_IInternetProtocol , riid ) ||
  416. InlineIsEqualGUID( IID_IInternetProtocolRoot, riid ) )
  417. {
  418. CComPtr<IUnknown> obj;
  419. if(SUCCEEDED(hr = CHCPProtocol::CreateInstance( pUnkOuter, &obj )))
  420. {
  421. hr = obj->QueryInterface( riid, ppvObj );
  422. }
  423. }
  424. }
  425. return hr;
  426. }
  427. STDMETHODIMP CHCPProtocolInfo::LockServer( /*[in]*/ BOOL fLock )
  428. {
  429. return S_OK;
  430. }