Source code of Windows XP (NT5)
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.

286 lines
8.5 KiB

  1. #include "stdafx.h"
  2. #if !defined(BITS_V12_ON_NT4)
  3. #include "proxy.tmh"
  4. #endif
  5. HRESULT
  6. CACHED_AUTOPROXY::Generate(
  7. const TCHAR Host[]
  8. )
  9. {
  10. if (GetTickCount() - m_TimeStamp > CACHED_PROXY_LIFETIME_IN_MSEC)
  11. {
  12. m_HostName = L"";
  13. }
  14. if (0 == _tcscmp( Host, m_HostName ))
  15. {
  16. LogInfo("using existing proxy info for '%S'", Host );
  17. return S_OK;
  18. }
  19. LogInfo( "detecting proxy for '%S'", Host );
  20. //
  21. // Detect IE settings and look up proxy if necessary.
  22. // Boilerplate from Stephen Sulzer.
  23. //
  24. WINHTTP_PROXY_INFO ProxyInfo;
  25. WINHTTP_AUTOPROXY_OPTIONS AutoProxyOptions;
  26. WINHTTP_CURRENT_USER_IE_PROXY_CONFIG IEProxyConfig;
  27. LPWSTR AutoConfigUrl = 0;
  28. BOOL fTryAutoProxy = FALSE;
  29. BOOL fSuccess = FALSE;
  30. ZeroMemory(&ProxyInfo, sizeof(ProxyInfo));
  31. ZeroMemory(&AutoProxyOptions, sizeof(AutoProxyOptions));
  32. ZeroMemory(&IEProxyConfig, sizeof(IEProxyConfig));
  33. if (WinHttpGetIEProxyConfigForCurrentUser(&IEProxyConfig))
  34. {
  35. LogInfo("got user's IE info");
  36. if (IEProxyConfig.fAutoDetect)
  37. {
  38. LogInfo("IE specifies auto-detect");
  39. AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
  40. AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
  41. WINHTTP_AUTO_DETECT_TYPE_DNS_A;
  42. fTryAutoProxy = TRUE;
  43. }
  44. if (IEProxyConfig.lpszAutoConfigUrl)
  45. {
  46. LogInfo("IE specifies auto-config URL '%S'", IEProxyConfig.lpszAutoConfigUrl ? IEProxyConfig.lpszAutoConfigUrl : NullString );
  47. AutoProxyOptions.dwFlags |= WINHTTP_AUTOPROXY_CONFIG_URL;
  48. AutoProxyOptions.lpszAutoConfigUrl = IEProxyConfig.lpszAutoConfigUrl;
  49. AutoConfigUrl = IEProxyConfig.lpszAutoConfigUrl;
  50. fTryAutoProxy = TRUE;
  51. }
  52. AutoProxyOptions.fAutoLogonIfChallenged = TRUE;
  53. }
  54. else
  55. {
  56. LogInfo("no user IE info: %d", GetLastError());
  57. // WinHttpGetIEProxyForCurrentUser failed, try autodetection anyway...
  58. AutoProxyOptions.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
  59. AutoProxyOptions.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP |
  60. WINHTTP_AUTO_DETECT_TYPE_DNS_A;
  61. fTryAutoProxy = TRUE;
  62. }
  63. if (fTryAutoProxy)
  64. {
  65. LogInfo("trying auto-detect...");
  66. fSuccess = WinHttpGetProxyForUrl( m_hInternet,
  67. Host,
  68. &AutoProxyOptions,
  69. &ProxyInfo
  70. );
  71. LogInfo("auto-detect returned %d (%d)", fSuccess, fSuccess ? 0 : GetLastError() );
  72. }
  73. // If we didn't do autoproxy or if it failed, see
  74. // if there's an explicit proxy server in the IE
  75. // proxy configuration...
  76. //
  77. // This is where the WinHttpGetIEProxyConfigForCurrentUser API
  78. // really comes in handy: in environments in which autoproxy is
  79. // not supported and so the user's IE browser must be
  80. // configured with an explicit proxy server.
  81. //
  82. if (!fTryAutoProxy || !fSuccess)
  83. {
  84. LogInfo("looking for backup ideas");
  85. if (IEProxyConfig.lpszProxy)
  86. {
  87. LogInfo("using named proxy '%S'", IEProxyConfig.lpszProxy ? IEProxyConfig.lpszProxy : NullString );
  88. ProxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  89. ProxyInfo.lpszProxy = IEProxyConfig.lpszProxy;
  90. ProxyInfo.lpszProxyBypass = IEProxyConfig.lpszProxyBypass;
  91. }
  92. }
  93. //
  94. // Sometimes the registry contains a single or double colon for the proxy or, oddly, bypass list.
  95. // SetRequestProxy rejects them. Both cases should be treated like a NULL string.
  96. //
  97. static wchar_t SingleColon[] = L":";
  98. static wchar_t DoubleColon[] = L"::";
  99. if (ProxyInfo.lpszProxy)
  100. {
  101. if (0 == wcscmp( ProxyInfo.lpszProxy, SingleColon ) ||
  102. 0 == wcscmp( ProxyInfo.lpszProxy, DoubleColon ))
  103. {
  104. LogWarning("suppressing invalid proxy string %S", ProxyInfo.lpszProxy );
  105. GlobalFree( ProxyInfo.lpszProxy );
  106. ProxyInfo.lpszProxy = NULL;
  107. }
  108. }
  109. if (ProxyInfo.lpszProxyBypass)
  110. {
  111. if (0 == wcscmp( ProxyInfo.lpszProxyBypass, SingleColon ) ||
  112. 0 == wcscmp( ProxyInfo.lpszProxyBypass, DoubleColon ))
  113. {
  114. LogWarning("suppressing invalid bypass string %S", ProxyInfo.lpszProxyBypass );
  115. GlobalFree( ProxyInfo.lpszProxyBypass );
  116. ProxyInfo.lpszProxyBypass = NULL;
  117. }
  118. }
  119. LogInfo("proxy '%S'", ProxyInfo.lpszProxy ? ProxyInfo.lpszProxy : NullString );
  120. LogInfo("bypass list '%S'", ProxyInfo.lpszProxyBypass ? ProxyInfo.lpszProxyBypass : NullString );
  121. LogInfo("access type %d", ProxyInfo.dwAccessType );
  122. if (AutoConfigUrl)
  123. {
  124. GlobalFree( AutoConfigUrl );
  125. }
  126. Clear();
  127. m_ProxyInfo = ProxyInfo;
  128. m_HostName = Host;
  129. m_fValid = true;
  130. m_TimeStamp = GetTickCount();
  131. //
  132. // We don't have to release the proxy server and proxy bypass strings
  133. // because Clear() will do that.
  134. //
  135. return S_OK;
  136. }
  137. void
  138. CACHED_AUTOPROXY::Clear()
  139. {
  140. if (m_fValid)
  141. {
  142. m_fValid = false;
  143. if (m_ProxyInfo.lpszProxy) GlobalFree(m_ProxyInfo.lpszProxy);
  144. if (m_ProxyInfo.lpszProxyBypass) GlobalFree(m_ProxyInfo.lpszProxyBypass);
  145. }
  146. ZeroMemory(&m_ProxyInfo, sizeof(m_ProxyInfo));
  147. m_HostName = NULL;
  148. }
  149. PROXY_SETTINGS_CONTAINER::PROXY_SETTINGS_CONTAINER(
  150. LPCWSTR Url,
  151. const PROXY_SETTINGS * ProxySettings
  152. ) :
  153. m_ProxyUsage( ProxyUsageFromJobProxyUsage( ProxySettings->ProxyUsage )),
  154. m_ProxyList( NULL ),
  155. m_BypassList( NULL ),
  156. m_TokenCursor( NULL )
  157. {
  158. //
  159. // Set up the list of proxy servers.
  160. //
  161. switch (m_ProxyUsage)
  162. {
  163. case INTERNET_OPEN_TYPE_DIRECT:
  164. break;
  165. case INTERNET_OPEN_TYPE_PROXY:
  166. {
  167. m_MasterProxyList = ProxySettings->ProxyList;
  168. m_BypassList = ProxySettings->ProxyBypassList;
  169. break;
  170. }
  171. case INTERNET_OPEN_TYPE_PRECONFIG:
  172. {
  173. THROW_HRESULT( g_ProxyCache->Generate( Url ));
  174. m_MasterProxyList = g_ProxyCache->GetProxyList();
  175. m_BypassList = g_ProxyCache->GetBypassList();
  176. m_AccessType = g_ProxyCache->GetAccessType();
  177. break;
  178. }
  179. default:
  180. ASSERT( 0 );
  181. break;
  182. }
  183. ResetCurrentProxy();
  184. }
  185. HRESULT
  186. SetRequestProxy(
  187. HINTERNET hRequest,
  188. PROXY_SETTINGS_CONTAINER * ProxySettings
  189. )
  190. {
  191. WINHTTP_PROXY_INFO ProxyInfo;
  192. ProxyInfo.dwAccessType = ProxySettings->GetProxyUsage();
  193. ProxyInfo.lpszProxy = const_cast<LPWSTR>( ProxySettings->GetCurrentProxy() );
  194. ProxyInfo.lpszProxyBypass = const_cast<LPWSTR>( ProxySettings->GetBypassList() );
  195. LogInfo("proxy info:");
  196. LogInfo("access: %d", ProxyInfo.dwAccessType );
  197. LogInfo("server '%S'", ProxyInfo.lpszProxy ? ProxyInfo.lpszProxy : NullString );
  198. LogInfo("bypass '%S'", ProxyInfo.lpszProxyBypass ? ProxyInfo.lpszProxyBypass : NullString );
  199. if (ProxyInfo.dwAccessType == INTERNET_OPEN_TYPE_DIRECT)
  200. {
  201. LogInfo("proxy usage disabled");
  202. return S_OK;
  203. }
  204. if (ProxyInfo.lpszProxy == NULL)
  205. {
  206. LogInfo("null proxy");
  207. return S_OK;
  208. }
  209. if (ProxyInfo.dwAccessType == INTERNET_OPEN_TYPE_PRECONFIG)
  210. {
  211. LogInfo("mapping PRECONFIG to named proxy");
  212. ProxyInfo.dwAccessType = INTERNET_OPEN_TYPE_PROXY;
  213. }
  214. if (!WinHttpSetOption( hRequest,
  215. WINHTTP_OPTION_PROXY,
  216. &ProxyInfo,
  217. sizeof(ProxyInfo)
  218. ))
  219. {
  220. DWORD err = GetLastError();
  221. LogWarning( "can't set proxy option: %!winerr!", err );
  222. return HRESULT_FROM_WIN32( err );
  223. }
  224. return S_OK;
  225. }
  226. bool IsPossibleProxyFailure( DWORD err )
  227. {
  228. switch (err)
  229. {
  230. case ERROR_WINHTTP_NAME_NOT_RESOLVED:
  231. case ERROR_WINHTTP_CANNOT_CONNECT:
  232. case ERROR_WINHTTP_CONNECTION_ERROR:
  233. case ERROR_WINHTTP_TIMEOUT:
  234. return true;
  235. default:
  236. return false;
  237. }
  238. }