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.

2425 lines
61 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. autoprox.cxx
  5. Author:
  6. Stephen A Sulzer (ssulzer) 26-August-2001
  7. --*/
  8. #include <wininetp.h>
  9. #include "apdetect.h"
  10. #include <cscpsite.h>
  11. #include "..\http\httpp.h"
  12. //
  13. // definitions
  14. //
  15. #define DEFAULT_SCRIPT_BUFFER_SIZE 4000 // bytes.
  16. #define ONE_HOUR_DELTA (60 * 60 * (LONGLONG)10000000)
  17. GLOBAL LONGLONG dwdwHttpDefaultExpiryDelta = 12 * 60 * 60 * (LONGLONG)10000000; // 12 hours in 100ns units
  18. DWORD InProcGetProxyForUrl(
  19. INTERNET_HANDLE_OBJECT * hSessionMapped,
  20. LPCWSTR lpcwszUrl,
  21. WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions,
  22. WINHTTP_PROXY_INFO * pProxyInfo
  23. );
  24. DWORD OutProcGetProxyForUrl(
  25. INTERNET_HANDLE_OBJECT* hSessionMapped,
  26. LPCWSTR lpcwszUrl,
  27. WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions,
  28. WINHTTP_PROXY_INFO * pProxyInfo
  29. );
  30. //
  31. // private vars
  32. //
  33. BOOL IsAutoProxyServiceAvailable();
  34. //
  35. // functions
  36. //
  37. INTERNETAPI
  38. BOOL
  39. WinHttpDetectAutoProxyConfigUrl(DWORD dwAutoDetectFlags, LPWSTR * ppwstrAutoConfigUrl)
  40. {
  41. DWORD error = ERROR_SUCCESS;
  42. char * pszUrl;
  43. DEBUG_ENTER_API((DBG_API,
  44. Bool,
  45. "WinHttpDetectAutoProxyConfigUrl",
  46. "%#x, %#x",
  47. dwAutoDetectFlags,
  48. ppwstrAutoConfigUrl
  49. ));
  50. if (((dwAutoDetectFlags &
  51. ~(WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A)) != 0)
  52. || (ppwstrAutoConfigUrl == NULL)
  53. || IsBadWritePtr(ppwstrAutoConfigUrl, sizeof(char *)))
  54. {
  55. error = ERROR_INVALID_PARAMETER;
  56. goto quit;
  57. }
  58. if (!(dwAutoDetectFlags &
  59. (WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A)))
  60. {
  61. error = ERROR_INVALID_PARAMETER;
  62. goto quit;
  63. }
  64. if (!GlobalDataInitialized)
  65. {
  66. error = GlobalDataInitialize();
  67. if (error != ERROR_SUCCESS)
  68. {
  69. goto quit;
  70. }
  71. }
  72. error = ::DetectAutoProxyUrl(dwAutoDetectFlags, &pszUrl);
  73. if (error == ERROR_SUCCESS)
  74. {
  75. error = AsciiToWideChar_UsingGlobalAlloc(pszUrl, ppwstrAutoConfigUrl);
  76. FREE_MEMORY(pszUrl);
  77. }
  78. quit:
  79. if (error != ERROR_SUCCESS)
  80. {
  81. SetLastError(error);
  82. }
  83. DEBUG_LEAVE_API(error == ERROR_SUCCESS);
  84. return (error == ERROR_SUCCESS);
  85. }
  86. INTERNETAPI
  87. BOOL
  88. WinHttpGetProxyForUrl(
  89. IN HINTERNET hSession,
  90. IN LPCWSTR lpcwszUrl,
  91. IN WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions,
  92. OUT WINHTTP_PROXY_INFO * pProxyInfo
  93. )
  94. {
  95. DWORD error;
  96. DEBUG_ENTER_API((DBG_API,
  97. Bool,
  98. "WinHttpGetProxyForUrl",
  99. "%#x, %wq, %#x, %#x",
  100. hSession,
  101. lpcwszUrl,
  102. pAutoProxyOptions,
  103. pProxyInfo
  104. ));
  105. //
  106. // Validate the WinHttp session handle
  107. //
  108. if ((hSession == NULL) || IsBadReadPtr((void *)hSession, sizeof(void *)))
  109. {
  110. error = ERROR_INVALID_HANDLE;
  111. goto quit;
  112. }
  113. //
  114. // Validate the target URL, and AUTOPROXY_OPTIONS and PROXY_INFO structs.
  115. //
  116. if ((lpcwszUrl == NULL) || IsBadStringPtrW(lpcwszUrl, (UINT_PTR)-1)
  117. || (pAutoProxyOptions == NULL)
  118. || IsBadReadPtr(pAutoProxyOptions, sizeof(WINHTTP_AUTOPROXY_OPTIONS))
  119. || (pProxyInfo == NULL)
  120. || IsBadWritePtr(pProxyInfo, sizeof(WINHTTP_PROXY_INFO)))
  121. {
  122. goto ErrorInvalidParameter;
  123. }
  124. //
  125. // Validate that the caller specified at least one of the
  126. // AUTO_DETECT and CONFIG_URL flags.
  127. //
  128. if (!(pAutoProxyOptions->dwFlags &
  129. (WINHTTP_AUTOPROXY_AUTO_DETECT |
  130. WINHTTP_AUTOPROXY_CONFIG_URL)))
  131. {
  132. goto ErrorInvalidParameter;
  133. }
  134. //
  135. // Validate that the caller did not set any flags other than
  136. // AUTO_DETECT, CONFIG_URL, RUN_INPROCESS or RUN_OUTPROCESS_ONLY.
  137. //
  138. if (pAutoProxyOptions->dwFlags &
  139. ~(WINHTTP_AUTOPROXY_AUTO_DETECT |
  140. WINHTTP_AUTOPROXY_CONFIG_URL |
  141. WINHTTP_AUTOPROXY_RUN_INPROCESS |
  142. WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY))
  143. {
  144. goto ErrorInvalidParameter;
  145. }
  146. // make sure RUN_INPROC & RUN_OUTPROC_ONLY is mutually exclusive
  147. if ((pAutoProxyOptions->dwFlags & WINHTTP_AUTOPROXY_RUN_INPROCESS) &&
  148. (pAutoProxyOptions->dwFlags & WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY))
  149. {
  150. goto ErrorInvalidParameter;
  151. }
  152. //
  153. // Validate the detection flags if the application
  154. // requests autodetection.
  155. //
  156. if (pAutoProxyOptions->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT)
  157. {
  158. if ((pAutoProxyOptions->dwAutoDetectFlags &
  159. ~(WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A)) != 0)
  160. {
  161. goto ErrorInvalidParameter;
  162. }
  163. if (!(pAutoProxyOptions->dwAutoDetectFlags &
  164. (WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A)))
  165. {
  166. goto ErrorInvalidParameter;
  167. }
  168. }
  169. //
  170. // Validate if lpszAutoConfigUrl string if the application
  171. // specifies the CONFIG_URL option.
  172. //
  173. if ((pAutoProxyOptions->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL) &&
  174. (!pAutoProxyOptions->lpszAutoConfigUrl ||
  175. IsBadStringPtrW(pAutoProxyOptions->lpszAutoConfigUrl, (UINT_PTR)-1L) ||
  176. (*(pAutoProxyOptions->lpszAutoConfigUrl) == '\0')))
  177. {
  178. goto ErrorInvalidParameter;
  179. }
  180. if (!GlobalDataInitialized)
  181. {
  182. error = ERROR_WINHTTP_NOT_INITIALIZED;
  183. goto quit;
  184. }
  185. error = ERROR_SUCCESS;
  186. INTERNET_HANDLE_OBJECT * hSessionMapped = NULL;
  187. HINTERNET_HANDLE_TYPE handleType = (HINTERNET_HANDLE_TYPE)0;
  188. error = MapHandleToAddress(hSession, (LPVOID *)&hSessionMapped, FALSE);
  189. if ((error != ERROR_SUCCESS) && (hSessionMapped == NULL))
  190. {
  191. goto quit;
  192. }
  193. error = RGetHandleType(hSessionMapped, &handleType);
  194. if (error == ERROR_SUCCESS && handleType == TypeInternetHandle)
  195. {
  196. if ((pAutoProxyOptions->dwFlags & WINHTTP_AUTOPROXY_RUN_INPROCESS))
  197. {
  198. error = InProcGetProxyForUrl(hSessionMapped,
  199. lpcwszUrl,
  200. pAutoProxyOptions,
  201. pProxyInfo);
  202. }
  203. else
  204. {
  205. BOOL fOutProcSucceed = FALSE;
  206. if (IsAutoProxyServiceAvailable())
  207. {
  208. error = OutProcGetProxyForUrl(hSessionMapped,
  209. lpcwszUrl,
  210. pAutoProxyOptions,
  211. pProxyInfo);
  212. }
  213. else
  214. {
  215. error = ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR;
  216. }
  217. if ((error != ERROR_WINHTTP_AUTO_PROXY_SERVICE_ERROR) &&
  218. (error != ERROR_WINHTTP_LOGIN_FAILURE) // APSvc doesn't support auth fully.
  219. )
  220. {
  221. fOutProcSucceed = TRUE;
  222. }
  223. // when failed to detect a proxy thru the NT service, we fall back to try again in-proc if
  224. // app allows
  225. if (!fOutProcSucceed && !(pAutoProxyOptions->dwFlags & WINHTTP_AUTOPROXY_RUN_OUTPROCESS_ONLY))
  226. {
  227. error = InProcGetProxyForUrl(hSessionMapped,
  228. lpcwszUrl,
  229. pAutoProxyOptions,
  230. pProxyInfo);
  231. }
  232. }
  233. }
  234. else
  235. {
  236. error = ERROR_WINHTTP_INCORRECT_HANDLE_TYPE;
  237. }
  238. DereferenceObject(hSessionMapped);
  239. if (error != ERROR_SUCCESS)
  240. goto quit;
  241. quit:
  242. if (error != ERROR_SUCCESS)
  243. {
  244. SetLastError(error);
  245. }
  246. DEBUG_LEAVE_API(error == ERROR_SUCCESS);
  247. return (error == ERROR_SUCCESS);
  248. ErrorInvalidParameter:
  249. error = ERROR_INVALID_PARAMETER;
  250. goto quit;
  251. }
  252. DWORD InProcGetProxyForUrl(
  253. INTERNET_HANDLE_OBJECT * hSessionMapped,
  254. LPCWSTR lpcwszUrl,
  255. WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions,
  256. WINHTTP_PROXY_INFO * pProxyInfo
  257. )
  258. {
  259. DWORD error;
  260. CAutoProxy * pAutoProxy;
  261. pAutoProxy = hSessionMapped->GetAutoProxy();
  262. if (pAutoProxy)
  263. {
  264. error = pAutoProxy->GetProxyForURL(lpcwszUrl, pAutoProxyOptions, pProxyInfo);
  265. }
  266. else
  267. {
  268. error = ERROR_NOT_ENOUGH_MEMORY;
  269. }
  270. return error;
  271. }
  272. BOOL
  273. CAutoProxy::Initialize()
  274. {
  275. _pszAutoConfigUrl = NULL;
  276. _pdwDetectedInterfaceIp = NULL;
  277. _cDetectedInterfaceIpCount = 0;
  278. memset(&_ftLastDetectionTime, 0, sizeof(_ftLastDetectionTime));
  279. _pszConfigScript = NULL;
  280. memset(&_ftExpiryTime, 0, sizeof(_ftExpiryTime));
  281. memset(&_ftLastModifiedTime, 0, sizeof(_ftLastModifiedTime));
  282. memset(&_ftLastSyncTime, 0, sizeof(_ftLastSyncTime));
  283. _fHasExpiry = FALSE;
  284. _fHasLastModifiedTime = FALSE;
  285. _fMustRevalidate = FALSE;
  286. _ScriptResLock.Initialize();
  287. return (_ScriptResLock.IsInitialized() && _CritSec.Init());
  288. }
  289. CAutoProxy::~CAutoProxy()
  290. {
  291. if (_pszAutoConfigUrl)
  292. FREE_MEMORY(_pszAutoConfigUrl);
  293. if (_pdwDetectedInterfaceIp)
  294. FREE_MEMORY(_pdwDetectedInterfaceIp);
  295. if (_pszConfigScript)
  296. FREE_MEMORY(_pszConfigScript);
  297. }
  298. BOOL
  299. CAutoProxy::IsSessionAborted() const
  300. {
  301. INET_ASSERT(_hSession != NULL);
  302. return _hSession->IsInvalidated();
  303. }
  304. DWORD
  305. CAutoProxy::GetProxyForURL(
  306. LPCWSTR lpcwszUrl,
  307. WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions,
  308. WINHTTP_PROXY_INFO * pProxyInfo
  309. )
  310. {
  311. DWORD error = ERROR_SUCCESS;
  312. char * pszAutoConfigUrl = NULL;
  313. char * pszConfigScript = NULL;
  314. char * pszUrl = NULL;
  315. char * pszQueryResults = NULL;
  316. bool bReleaseScriptLock = false;
  317. //
  318. // If the application requests auto-detect, then attempt to detect
  319. // the autonconfig URL and download the autoproxy script.
  320. //
  321. if (pAutoProxyOptions->dwFlags & WINHTTP_AUTOPROXY_AUTO_DETECT)
  322. {
  323. error = DetectAutoProxyUrl(pAutoProxyOptions->dwAutoDetectFlags,
  324. &pszAutoConfigUrl);
  325. if (error == ERROR_SUCCESS)
  326. {
  327. INET_ASSERT(pszAutoConfigUrl);
  328. error = DownloadAutoConfigUrl(pszAutoConfigUrl, pAutoProxyOptions, &pszConfigScript);
  329. if (error != ERROR_SUCCESS)
  330. {
  331. FREE_MEMORY(pszAutoConfigUrl);
  332. pszAutoConfigUrl = NULL;
  333. }
  334. else
  335. {
  336. bReleaseScriptLock = true;
  337. INET_ASSERT(pszConfigScript != NULL);
  338. }
  339. }
  340. else
  341. {
  342. INET_ASSERT(pszAutoConfigUrl == NULL);
  343. }
  344. }
  345. //
  346. // If autodetection or downloading the autoproxy script fails,
  347. // or if autodetection is not requested, then fall back to an
  348. // (optional) autoconfig URL supplied by the application.
  349. //
  350. if ((error != ERROR_SUCCESS || pszAutoConfigUrl == NULL)
  351. && (pAutoProxyOptions->dwFlags & WINHTTP_AUTOPROXY_CONFIG_URL))
  352. {
  353. INET_ASSERT(pAutoProxyOptions->lpszAutoConfigUrl);
  354. error = WideCharToAscii(pAutoProxyOptions->lpszAutoConfigUrl,
  355. &pszAutoConfigUrl);
  356. if (error != ERROR_SUCCESS)
  357. goto quit;
  358. error = DownloadAutoConfigUrl(pszAutoConfigUrl, pAutoProxyOptions, &pszConfigScript);
  359. if (error == ERROR_SUCCESS)
  360. {
  361. bReleaseScriptLock = true;
  362. }
  363. }
  364. //
  365. // Could not obtain the autoproxy script, bail out.
  366. //
  367. if (error != ERROR_SUCCESS)
  368. goto quit;
  369. // Need the app's target URL in ANSI
  370. error = WideCharToAscii(lpcwszUrl, &pszUrl);
  371. if (error != ERROR_SUCCESS)
  372. goto quit;
  373. // This is an internal callback indicating we are about to execute the download proxy
  374. // script. Only the auto-proxy service subscribe this callback.
  375. LPINTERNET_THREAD_INFO lpThreadInfo = InternetGetThreadInfo();
  376. _InternetSetObjectHandle(lpThreadInfo, _hSession, _hSession);
  377. InternetIndicateStatus(WINHTTP_CALLBACK_STATUS_BEGIN_PROXY_SCRIPT_RUN, NULL, 0);
  378. if (IsSessionAborted())
  379. {
  380. error = ERROR_WINHTTP_OPERATION_CANCELLED;
  381. goto quit;
  382. }
  383. //
  384. // Execute the proxy script.
  385. //
  386. error = RunProxyScript(pszUrl, pszConfigScript, &pszQueryResults);
  387. if (error != ERROR_SUCCESS)
  388. goto quit;
  389. //
  390. // Parse the output from the autoproxy script and
  391. // convert it into a WINHTTP_PROXY_INFO struct for
  392. // the application.
  393. //
  394. error = ParseProxyQueryResults(pszQueryResults, pProxyInfo);
  395. quit:
  396. if (bReleaseScriptLock)
  397. {
  398. _ScriptResLock.Release();
  399. }
  400. if (pszUrl)
  401. {
  402. FREE_MEMORY(pszUrl);
  403. }
  404. if (pszAutoConfigUrl)
  405. {
  406. FREE_MEMORY(pszAutoConfigUrl);
  407. }
  408. if (pszQueryResults)
  409. {
  410. GlobalFree(pszQueryResults);
  411. }
  412. return error;
  413. }
  414. DWORD
  415. CAutoProxy::DetectAutoProxyUrl(DWORD dwAutoDetectFlags, LPSTR * ppszAutoConfigUrl)
  416. {
  417. char * pszAutoConfigUrl = NULL;
  418. BOOL fDetectionNeeded;
  419. DWORD error = ERROR_SUCCESS;
  420. fDetectionNeeded = IsDetectionNeeded(); // avoid holding a critsec across this
  421. if (_CritSec.Lock())
  422. {
  423. if (_pszAutoConfigUrl == NULL)
  424. {
  425. fDetectionNeeded = TRUE;
  426. }
  427. else if (!fDetectionNeeded)
  428. {
  429. pszAutoConfigUrl = NewString(_pszAutoConfigUrl);
  430. }
  431. _CritSec.Unlock();
  432. }
  433. // We should have either the AutoConfigUrl string or
  434. // fDetectionNeeded should be TRUE; otherwise raise
  435. // an out-of-memory error.
  436. if (!(pszAutoConfigUrl || fDetectionNeeded))
  437. {
  438. error = ERROR_NOT_ENOUGH_MEMORY;
  439. goto quit;
  440. }
  441. // check detection cache; also check for network changes or if
  442. // this machine's IP address have changed
  443. if (fDetectionNeeded)
  444. {
  445. int cInterfaces = 0;
  446. DWORD * pdwInterfaceIp = NULL;
  447. FILETIME ftDetectionTime;
  448. //
  449. // Save out the Host IP addresses, before we start the detection,
  450. // after the detection is complete, we confirm that we're still
  451. // on the same set of Host IPs, in case the user switched connections.
  452. //
  453. error = GetHostAddresses(&cInterfaces, &pdwInterfaceIp);
  454. if (error != ERROR_SUCCESS)
  455. {
  456. goto quit;
  457. }
  458. // Important: cannot hold the _CritSec lock across the autodetection
  459. // call, as it can take several seconds, which could cause
  460. // waiting EnterCriticalSection() calls to raise POSSIBLE_DEADLOCK
  461. // exceptions.
  462. error = ::DetectAutoProxyUrl(dwAutoDetectFlags, &pszAutoConfigUrl);
  463. if (error != ERROR_SUCCESS)
  464. {
  465. goto quit;
  466. }
  467. if (IsSessionAborted())
  468. {
  469. error = ERROR_WINHTTP_OPERATION_CANCELLED;
  470. goto quit;
  471. }
  472. GetCurrentGmtTime(&ftDetectionTime); // mark when detection was run.
  473. if (_CritSec.Lock())
  474. {
  475. //
  476. // Clear out any cached autoconfig script
  477. //
  478. if (_pszConfigScript)
  479. {
  480. FREE_MEMORY(_pszConfigScript);
  481. _pszConfigScript = NULL;
  482. }
  483. //
  484. // Cache new AutoConfigUrl string and detection time
  485. //
  486. if (_pszAutoConfigUrl)
  487. {
  488. FREE_MEMORY(_pszAutoConfigUrl);
  489. }
  490. _pszAutoConfigUrl = pszAutoConfigUrl;
  491. _ftLastDetectionTime = ftDetectionTime;
  492. //
  493. // Cache IP address of host machine at time of detection
  494. //
  495. if (_pdwDetectedInterfaceIp)
  496. {
  497. FREE_MEMORY(_pdwDetectedInterfaceIp);
  498. }
  499. _pdwDetectedInterfaceIp = pdwInterfaceIp;
  500. _cDetectedInterfaceIpCount = cInterfaces;
  501. //
  502. // Prepare return string for caller
  503. //
  504. *ppszAutoConfigUrl = NewString(pszAutoConfigUrl);
  505. if (*ppszAutoConfigUrl == NULL)
  506. {
  507. error = ERROR_NOT_ENOUGH_MEMORY;
  508. }
  509. // Exit lock
  510. _CritSec.Unlock();
  511. }
  512. else
  513. {
  514. error = ERROR_NOT_ENOUGH_MEMORY;
  515. }
  516. }
  517. else
  518. {
  519. INET_ASSERT(pszAutoConfigUrl);
  520. *ppszAutoConfigUrl = pszAutoConfigUrl;
  521. }
  522. quit:
  523. return error;
  524. }
  525. DWORD
  526. CAutoProxy::DownloadAutoConfigUrl(
  527. LPSTR lpszAutoConfigUrl,
  528. WINHTTP_AUTOPROXY_OPTIONS * pAutoProxyOptions,
  529. LPSTR * ppszConfigScript
  530. )
  531. {
  532. HINTERNET hInternet = NULL;
  533. HINTERNET hConnect = NULL;
  534. HINTERNET hRequest = NULL;
  535. LPSTR pszHostName = NULL;
  536. BOOL fSuccess;
  537. DWORD error = ERROR_SUCCESS;
  538. CHAR szContentType[MAX_PATH+1];
  539. LPSTR lpszScriptBuffer = NULL;
  540. DWORD dwScriptBufferSize;
  541. DWORD dwStatusCode = ERROR_SUCCESS;
  542. DWORD cbSize = sizeof(DWORD);
  543. bool bCloseInternetHandle = false;
  544. bool bValidateCachedScript = false;
  545. bool bAcquiredScriptLock = false;
  546. static const char * AcceptTypes[] = { "*/*", NULL };
  547. URL_COMPONENTSA Url;
  548. INET_ASSERT(lpszAutoConfigUrl);
  549. if (!_CritSec.Lock())
  550. return ERROR_NOT_ENOUGH_MEMORY;
  551. //
  552. // Does the given AutoConfig URL match the last one that
  553. // was downloaded? If so, the autoconfig script may
  554. // already be cached.
  555. //
  556. if (_pszAutoConfigUrl &&
  557. StrCmpIA(_pszAutoConfigUrl, lpszAutoConfigUrl) == 0)
  558. {
  559. //
  560. // If we have a cached script and it has not expired,
  561. // then we're done.
  562. //
  563. if (_pszConfigScript)
  564. {
  565. if (!IsCachedProxyScriptExpired())
  566. {
  567. lpszScriptBuffer = _pszConfigScript;
  568. // Acquire non-exclusive read lock
  569. if (_ScriptResLock.Acquire())
  570. {
  571. error = ERROR_SUCCESS;
  572. bAcquiredScriptLock = true;
  573. }
  574. else
  575. {
  576. error = ERROR_NOT_ENOUGH_MEMORY;
  577. }
  578. goto quit;
  579. }
  580. else
  581. {
  582. bValidateCachedScript = true;
  583. }
  584. }
  585. }
  586. else if (_pszAutoConfigUrl)
  587. {
  588. FREE_MEMORY(_pszAutoConfigUrl);
  589. _pszAutoConfigUrl = NULL;
  590. }
  591. //
  592. // Acquire exclusive write lock - this will wait for all the
  593. // outstanding reader locks to release.
  594. //
  595. if (!_ScriptResLock.AcquireExclusive())
  596. {
  597. error = ERROR_NOT_ENOUGH_MEMORY;
  598. goto quit;
  599. }
  600. bAcquiredScriptLock = true;
  601. //
  602. // Prepare to GET the auto proxy script.
  603. //
  604. ZeroMemory(&Url, sizeof(Url));
  605. Url.dwStructSize = sizeof(URL_COMPONENTSA);
  606. Url.dwHostNameLength = 1L;
  607. Url.dwUrlPathLength = 1L;
  608. Url.dwExtraInfoLength = 1L;
  609. if (!WinHttpCrackUrlA(lpszAutoConfigUrl, 0, 0, &Url))
  610. {
  611. goto quitWithLastError;
  612. }
  613. // Check for non-http schemes
  614. if (Url.nScheme != INTERNET_SCHEME_HTTP && Url.nScheme != INTERNET_SCHEME_HTTPS)
  615. {
  616. error = ERROR_WINHTTP_UNRECOGNIZED_SCHEME;
  617. goto quit;
  618. }
  619. if (Url.dwHostNameLength == 0)
  620. {
  621. error = ERROR_WINHTTP_INVALID_URL;
  622. goto quit;
  623. }
  624. // If the client does not specify a resource path,
  625. // then add the "/".
  626. if (Url.dwUrlPathLength == 0)
  627. {
  628. INET_ASSERT(Url.dwExtraInfoLength == 1);
  629. Url.lpszUrlPath = "/";
  630. Url.dwUrlPathLength = 1;
  631. }
  632. pszHostName = NewString(Url.lpszHostName, Url.dwHostNameLength);
  633. if (!pszHostName)
  634. {
  635. error = ERROR_NOT_ENOUGH_MEMORY;
  636. goto quit;
  637. }
  638. if (IsSessionAborted())
  639. {
  640. error = ERROR_WINHTTP_OPERATION_CANCELLED;
  641. goto quit;
  642. }
  643. //
  644. // Fire up a mini WinHttp Session to download a
  645. // config file found on some internal server.
  646. //
  647. if (_hSession->IsAsyncHandle())
  648. {
  649. hInternet = InternetOpenA(
  650. NULL,
  651. WINHTTP_ACCESS_TYPE_NO_PROXY,
  652. NULL,
  653. NULL,
  654. 0);
  655. if (!hInternet)
  656. {
  657. goto quitWithLastError;
  658. }
  659. bCloseInternetHandle = true;
  660. }
  661. else
  662. {
  663. hInternet = _hSession;
  664. }
  665. hConnect = InternetConnectA(hInternet, pszHostName, Url.nPort, WINHTTP_CONNECT_FLAG_NO_INDICATION, NULL);
  666. if (!hConnect)
  667. {
  668. goto quitWithLastError;
  669. }
  670. // disinherit user's session callback if set.
  671. WinHttpSetStatusCallback(hConnect, NULL, NULL, NULL);
  672. hRequest = HttpOpenRequestA(hConnect, NULL, // "GET"
  673. Url.lpszUrlPath ? Url.lpszUrlPath : "/",
  674. NULL, // Version
  675. NULL, // Referrer:
  676. AcceptTypes,
  677. (Url.nScheme == INTERNET_SCHEME_HTTPS) ?
  678. WINHTTP_FLAG_SECURE
  679. : 0, // Flags
  680. NULL); // Context
  681. if (!hRequest)
  682. {
  683. goto quitWithLastError;
  684. }
  685. //
  686. // Initialize the Request object
  687. //
  688. WINHTTP_PROXY_INFO ProxyInfo;
  689. ProxyInfo.dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
  690. ProxyInfo.lpszProxy = NULL;
  691. ProxyInfo.lpszProxyBypass = NULL;
  692. fSuccess = WinHttpSetOption(hRequest, WINHTTP_OPTION_PROXY,
  693. (void *) &ProxyInfo,
  694. sizeof(ProxyInfo));
  695. if (!fSuccess)
  696. {
  697. goto quitWithLastError;
  698. }
  699. if (pAutoProxyOptions->fAutoLogonIfChallenged)
  700. {
  701. DWORD dwAutoLogonPolicy = WINHTTP_AUTOLOGON_SECURITY_LEVEL_LOW;
  702. fSuccess = WinHttpSetOption(hRequest, WINHTTP_OPTION_AUTOLOGON_POLICY,
  703. (void *) &dwAutoLogonPolicy,
  704. sizeof(dwAutoLogonPolicy));
  705. if (!fSuccess)
  706. {
  707. goto quitWithLastError;
  708. }
  709. }
  710. //
  711. // We have an expired cached script; add If-Modified-Since request
  712. // header if possible to check if the cached script is still valid.
  713. //
  714. if (bValidateCachedScript)
  715. {
  716. AddIfModifiedSinceHeaders(hRequest);
  717. }
  718. if (IsSessionAborted())
  719. {
  720. error = ERROR_WINHTTP_OPERATION_CANCELLED;
  721. goto quit;
  722. }
  723. //
  724. // Send the request synchronously
  725. //
  726. if (!WinHttpSendRequest(hRequest, NULL, 0, NULL, 0, 0, NULL))
  727. {
  728. error = ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT;
  729. goto quit;
  730. }
  731. if (!WinHttpReceiveResponse(hRequest, NULL))
  732. {
  733. error = ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT;
  734. goto quit;
  735. }
  736. if (IsSessionAborted())
  737. {
  738. error = ERROR_WINHTTP_OPERATION_CANCELLED;
  739. goto quit;
  740. }
  741. //
  742. // Update LastSyncTime
  743. //
  744. GetCurrentGmtTime(&_ftLastSyncTime);
  745. //
  746. // Check status code
  747. //
  748. cbSize = sizeof(dwStatusCode);
  749. if (HttpQueryInfoA(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
  750. NULL,
  751. (LPVOID) &dwStatusCode,
  752. &cbSize,
  753. NULL))
  754. {
  755. if (dwStatusCode == HTTP_STATUS_DENIED)
  756. {
  757. error = ERROR_WINHTTP_LOGIN_FAILURE;
  758. goto quit;
  759. }
  760. else if (dwStatusCode >= HTTP_STATUS_NOT_FOUND)
  761. {
  762. error = ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT;
  763. goto quit;
  764. }
  765. else if (dwStatusCode == HTTP_STATUS_NOT_MODIFIED)
  766. {
  767. INET_ASSERT(bValidateCachedScript);
  768. INET_ASSERT(_pszConfigScript);
  769. error = ERROR_SUCCESS;
  770. lpszScriptBuffer = _pszConfigScript;
  771. //
  772. // Release exclusive write lock and take read lock.
  773. // This is atomic because we also have the general
  774. // autoproxy critical section.
  775. //
  776. _ScriptResLock.Release(); // Release exclusive write lock.
  777. _ScriptResLock.Acquire(); // Acquire non-exclusive read lock.
  778. goto quit;
  779. }
  780. }
  781. //
  782. // Clear existing cache config script if any before
  783. // downloading the new script code.
  784. //
  785. if (_pszConfigScript)
  786. {
  787. FREE_MEMORY(_pszConfigScript);
  788. _pszConfigScript = NULL;
  789. }
  790. DWORD dwIndex;
  791. DWORD dwTempSize;
  792. dwIndex = 0;
  793. dwTempSize = sizeof(dwScriptBufferSize);
  794. dwScriptBufferSize = 0;
  795. if (HttpQueryInfoA(hRequest, (HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER),
  796. NULL,
  797. (LPVOID) &dwScriptBufferSize,
  798. &dwTempSize,
  799. &dwIndex))
  800. {
  801. // Reject script files that exceed our limit.
  802. if (dwScriptBufferSize > MAX_PAC_SCRIPT_SIZE)
  803. {
  804. error = ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT;
  805. goto quit;
  806. }
  807. }
  808. else
  809. {
  810. // failure, just defaults
  811. dwScriptBufferSize = DEFAULT_SCRIPT_BUFFER_SIZE;
  812. }
  813. lpszScriptBuffer = (LPSTR)
  814. ALLOCATE_MEMORY(((dwScriptBufferSize + 2) * sizeof(CHAR)));
  815. if (lpszScriptBuffer == NULL)
  816. {
  817. error = ERROR_NOT_ENOUGH_MEMORY;
  818. goto quit;
  819. }
  820. //
  821. // read script data
  822. //
  823. DWORD dwBytes = 0;
  824. DWORD dwBytesRead = 0;
  825. DWORD dwBytesLeft = dwScriptBufferSize;
  826. LPSTR lpszDest = lpszScriptBuffer;
  827. do
  828. {
  829. fSuccess = WinHttpReadData(hRequest, lpszDest, dwBytesLeft, &dwBytes);
  830. if (!fSuccess)
  831. {
  832. error = GetLastError();
  833. goto quit;
  834. }
  835. if (dwBytes > 0)
  836. {
  837. dwBytesRead += dwBytes;
  838. dwBytesLeft -= dwBytes;
  839. if (dwBytesLeft == 0)
  840. {
  841. dwScriptBufferSize += DEFAULT_SCRIPT_BUFFER_SIZE;
  842. lpszScriptBuffer = (LPSTR)
  843. REALLOCATE_MEMORY(lpszScriptBuffer,
  844. (dwScriptBufferSize + 2) * sizeof(CHAR));
  845. if (lpszScriptBuffer == NULL)
  846. {
  847. error = ERROR_NOT_ENOUGH_MEMORY;
  848. goto quit;
  849. }
  850. dwBytesLeft = DEFAULT_SCRIPT_BUFFER_SIZE;
  851. }
  852. // Reject script files that exceed our limit.
  853. if (dwBytesRead > MAX_PAC_SCRIPT_SIZE)
  854. {
  855. error = ERROR_WINHTTP_UNABLE_TO_DOWNLOAD_SCRIPT;
  856. goto quit;
  857. }
  858. lpszDest = lpszScriptBuffer + dwBytesRead;
  859. }
  860. if (IsSessionAborted())
  861. {
  862. error = ERROR_WINHTTP_OPERATION_CANCELLED;
  863. goto quit;
  864. }
  865. } while (dwBytes != 0);
  866. lpszScriptBuffer[dwBytesRead] = '\0';
  867. //
  868. // Figure out what kind of file we're dealing with.
  869. // ONLY allow files with the correct extension or the correct MIME type.
  870. //
  871. szContentType[0] = '\0';
  872. dwBytes = ARRAY_ELEMENTS(szContentType)-1;
  873. fSuccess = HttpQueryInfoA(hRequest, HTTP_QUERY_CONTENT_TYPE, NULL,
  874. szContentType,
  875. &dwBytes,
  876. NULL);
  877. if (fSuccess && !IsSupportedMimeType(szContentType))
  878. {
  879. if (!IsSupportedFileExtension(lpszAutoConfigUrl))
  880. {
  881. error = ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT;
  882. goto quit;
  883. }
  884. }
  885. //
  886. // The script has been downloaded successfully, so now process
  887. // any Cache-Control and/or Expires headers.
  888. //
  889. CalculateTimeStampsForCache(hRequest);
  890. if (!_pszAutoConfigUrl)
  891. {
  892. _pszAutoConfigUrl = NewString(lpszAutoConfigUrl);
  893. // ok to ignore OOM
  894. }
  895. //
  896. // Cache script
  897. //
  898. _pszConfigScript = lpszScriptBuffer;
  899. //
  900. // Release exclusive write lock and take read lock.
  901. // This is atomic because we also have the general
  902. // autoproxy critical section.
  903. //
  904. _ScriptResLock.Release(); // Release exclusive write lock.
  905. _ScriptResLock.Acquire(); // Acquire non-exclusive read lock.
  906. quit:
  907. _CritSec.Unlock();
  908. if (error == ERROR_SUCCESS)
  909. {
  910. *ppszConfigScript = lpszScriptBuffer;
  911. INET_ASSERT(bAcquiredScriptLock);
  912. }
  913. else
  914. {
  915. if (bAcquiredScriptLock)
  916. {
  917. _ScriptResLock.Release();
  918. }
  919. if (lpszScriptBuffer)
  920. {
  921. FREE_MEMORY(lpszScriptBuffer);
  922. }
  923. }
  924. if (hRequest)
  925. {
  926. WinHttpCloseHandle(hRequest);
  927. }
  928. if (hConnect)
  929. {
  930. WinHttpCloseHandle(hConnect);
  931. }
  932. if (bCloseInternetHandle)
  933. {
  934. WinHttpCloseHandle(hInternet);
  935. }
  936. if (pszHostName)
  937. {
  938. FREE_MEMORY(pszHostName);
  939. }
  940. return error;
  941. quitWithLastError:
  942. error = GetLastError();
  943. INET_ASSERT(error != ERROR_SUCCESS);
  944. goto quit;
  945. }
  946. BOOL
  947. CAutoProxy::IsSupportedMimeType(char * szType)
  948. {
  949. return StrCmpIA(szType, "application/x-ns-proxy-autoconfig") == 0;
  950. }
  951. BOOL
  952. CAutoProxy::IsSupportedFileExtension(LPCSTR lpszUrl)
  953. {
  954. LPCSTR lpszExtension;
  955. LPCSTR lpszQuestion;
  956. static const char * rgszExtensionList[] = { ".dat", ".js", ".pac", ".jvs", NULL };
  957. BOOL fMatch = FALSE;
  958. //
  959. // We need to be careful about checking for a period on the end of an URL
  960. // Example: if we have: "http://auto-proxy-srv/fooboo.exe?autogenator.com.ex" ?
  961. //
  962. lpszQuestion = strchr(lpszUrl, '?');
  963. lpszUrl = (lpszQuestion) ? lpszQuestion : lpszUrl;
  964. lpszExtension = strrchr(lpszUrl, '.');
  965. if (lpszExtension)
  966. {
  967. for (int i = 0; rgszExtensionList[i] != NULL; i++)
  968. {
  969. if (StrCmpIA(lpszExtension, rgszExtensionList[i]) == 0)
  970. {
  971. fMatch = TRUE;
  972. break;
  973. }
  974. }
  975. }
  976. return fMatch;
  977. }
  978. BOOL
  979. CAutoProxy::IsCachedProxyScriptExpired()
  980. /*++
  981. Routine Description:
  982. Determines whether the cached proxy config script is expired. If it's
  983. expired then we need to synchronize (i.e. do a i-m-s request)
  984. Parameters:
  985. NONE
  986. Return Value:
  987. BOOL
  988. --*/
  989. {
  990. DEBUG_ENTER((DBG_PROXY,
  991. Bool,
  992. "CAutoProxy::IsCachedProxyScriptExpired",
  993. NULL
  994. ));
  995. BOOL fExpired = FALSE;
  996. FILETIME ftCurrentTime;
  997. GetCurrentGmtTime(&ftCurrentTime);
  998. // Always strictly honor expire time from the server.
  999. if (_fHasExpiry)
  1000. {
  1001. fExpired = FT2LL(_ftExpiryTime) <= FT2LL(ftCurrentTime);
  1002. }
  1003. else
  1004. {
  1005. // We'll assume the data could change within 12 hours of the last time
  1006. // we sync'ed.
  1007. fExpired = (FT2LL(ftCurrentTime) >= (FT2LL(_ftLastSyncTime) + dwdwHttpDefaultExpiryDelta));
  1008. }
  1009. DEBUG_LEAVE(fExpired);
  1010. return fExpired;
  1011. }
  1012. VOID
  1013. CAutoProxy::CalculateTimeStampsForCache(HINTERNET hRequest)
  1014. /*++
  1015. Routine Description:
  1016. extracts timestamps from the http response. If the timestamps don't exist,
  1017. does the default thing. has additional goodies like checking for expiry etc.
  1018. Side Effects:
  1019. The calculated time stamps values are saved as private members
  1020. _ftLastModifiedTime, _ftExpiryTime, _fHasExpiry,
  1021. _fHasLastModifiedTime, and _fMustRevalidate.
  1022. Return Value:
  1023. NONE
  1024. --*/
  1025. {
  1026. DEBUG_ENTER((DBG_PROXY,
  1027. None,
  1028. "CAutoProxy::CalculateTimeStampsForCache",
  1029. NULL
  1030. ));
  1031. TCHAR buf[256];
  1032. BOOL fRet = FALSE;
  1033. DWORD dwLen, index = 0;
  1034. // reset the private variables
  1035. _fHasLastModifiedTime = FALSE;
  1036. _fHasExpiry = FALSE;
  1037. _fMustRevalidate = FALSE;
  1038. // Determine if a Cache-Control: max-age header exists. If so, calculate expires
  1039. // time from current time + max-age minus any delta indicated by Age:
  1040. CHAR *ptr, *pToken;
  1041. BOOL fResult;
  1042. DWORD dwError;
  1043. while (1)
  1044. {
  1045. // Scan headers for Cache-Control: max-age header.
  1046. dwLen = sizeof(buf);
  1047. fResult = HttpQueryInfoA(hRequest,
  1048. WINHTTP_QUERY_CACHE_CONTROL,
  1049. NULL,
  1050. buf,
  1051. &dwLen,
  1052. &index);
  1053. if (fResult == TRUE)
  1054. dwError = ERROR_SUCCESS;
  1055. else
  1056. dwError = GetLastError();
  1057. switch (dwError)
  1058. {
  1059. case ERROR_SUCCESS:
  1060. buf[dwLen] = '\0';
  1061. pToken = ptr = buf;
  1062. // Parse a token from the string; test for sub headers.
  1063. while (NULL != (pToken = StrTokEx(&ptr, ","))) // <<-- Really test this out, used StrTokEx before
  1064. {
  1065. SKIPWS(pToken);
  1066. if (strnicmp(MAX_AGE_SZ, pToken, MAX_AGE_LEN) == 0)
  1067. {
  1068. // Found max-age. Convert to integer form.
  1069. // Parse out time in seconds, text and convert.
  1070. pToken += MAX_AGE_LEN;
  1071. SKIPWS(pToken);
  1072. if (*pToken != '=')
  1073. break;
  1074. pToken++;
  1075. SKIPWS(pToken);
  1076. INT nDeltaSecs = atoi(pToken);
  1077. INT nAge;
  1078. // See if an Age: header exists.
  1079. // Using a local index variable:
  1080. DWORD indexAge = 0;
  1081. dwLen = sizeof(INT)+1;
  1082. if (HttpQueryInfoA(hRequest,
  1083. HTTP_QUERY_AGE | HTTP_QUERY_FLAG_NUMBER,
  1084. NULL,
  1085. &nAge,
  1086. &dwLen,
  1087. &indexAge))
  1088. {
  1089. // Found Age header. Convert and subtact from max-age.
  1090. // If less or = 0, attempt to get expires header.
  1091. nAge = ((nAge < 0) ? 0 : nAge);
  1092. nDeltaSecs -= nAge;
  1093. if (nDeltaSecs <= 0)
  1094. {
  1095. // The server (or some caching intermediary) possibly sent an incorrectly
  1096. // calculated header. Use "Expires", if no "max-age" directives at higher indexes.
  1097. continue;
  1098. }
  1099. }
  1100. // Calculate expires time from max age.
  1101. GetCurrentGmtTime(&_ftExpiryTime);
  1102. AddLongLongToFT(&_ftExpiryTime, (nDeltaSecs * (LONGLONG) 10000000));
  1103. fRet = TRUE;
  1104. }
  1105. else if (strnicmp(MUST_REVALIDATE_SZ, pToken, MUST_REVALIDATE_LEN) == 0)
  1106. {
  1107. pToken += MUST_REVALIDATE_LEN;
  1108. SKIPWS(pToken);
  1109. if (*pToken == 0 || *pToken == ',')
  1110. _fMustRevalidate = TRUE;
  1111. }
  1112. }
  1113. // If an expires time has been found, break switch.
  1114. if (fRet)
  1115. break;
  1116. // Need to bump up index to prevent possibility of never-ending outer while(1) loop.
  1117. // Otherwise, on exit from inner while, we could be stuck here reading the
  1118. // Cache-Control at the same index.
  1119. // HttpQueryInfoA(WINHTTP_QUERY_CACHE_CONTROL, ...) will return either the next index,
  1120. // or an error, and we'll be good to go:
  1121. index++;
  1122. continue;
  1123. case ERROR_INSUFFICIENT_BUFFER:
  1124. index++;
  1125. continue;
  1126. default:
  1127. break; // no more Cache-Control headers.
  1128. }
  1129. break; // no more Cache-Control headers.
  1130. }
  1131. // If no expires time is calculated from max-age, check for expires header.
  1132. if (!fRet)
  1133. {
  1134. dwLen = sizeof(buf) - 1;
  1135. index = 0;
  1136. if (HttpQueryInfoA(hRequest, HTTP_QUERY_EXPIRES, NULL, buf, &dwLen, &index))
  1137. {
  1138. fRet = FParseHttpDate(&_ftExpiryTime, buf);
  1139. //
  1140. // as per HTTP spec, if the expiry time is incorrect, then the page is
  1141. // considered to have expired
  1142. //
  1143. if (!fRet)
  1144. {
  1145. GetCurrentGmtTime(&_ftExpiryTime);
  1146. AddLongLongToFT(&_ftExpiryTime, (-1)*ONE_HOUR_DELTA); // subtract 1 hour
  1147. fRet = TRUE;
  1148. }
  1149. }
  1150. }
  1151. // We found or calculated a valid expiry time, let us check it against the
  1152. // server date if possible
  1153. FILETIME ft;
  1154. dwLen = sizeof(buf) - 1;
  1155. index = 0;
  1156. if (HttpQueryInfoA(hRequest, HTTP_QUERY_DATE, NULL, buf, &dwLen, &index)
  1157. && FParseHttpDate(&ft, buf))
  1158. {
  1159. // we found a valid Date: header
  1160. // if the expires: date is less than or equal to the Date: header
  1161. // then we put an expired timestamp on this item.
  1162. // Otherwise we let it be the same as was returned by the server.
  1163. // This may cause problems due to mismatched clocks between
  1164. // the client and the server, but this is the best that can be done.
  1165. // Calulating an expires offset from server date causes pages
  1166. // coming from proxy cache to expire later, because proxies
  1167. // do not change the date: field even if the reponse has been
  1168. // sitting the proxy cache for days.
  1169. // This behaviour is as-per the HTTP spec.
  1170. if (FT2LL(_ftExpiryTime) <= FT2LL(ft))
  1171. {
  1172. GetCurrentGmtTime(&_ftExpiryTime);
  1173. AddLongLongToFT(&_ftExpiryTime, (-1)*ONE_HOUR_DELTA); // subtract 1 hour
  1174. }
  1175. }
  1176. _fHasExpiry = fRet;
  1177. if (!fRet)
  1178. {
  1179. _ftExpiryTime.dwLowDateTime = 0;
  1180. _ftExpiryTime.dwHighDateTime = 0;
  1181. }
  1182. fRet = FALSE;
  1183. dwLen = sizeof(buf) - 1;
  1184. index = 0;
  1185. if (HttpQueryInfoA(hRequest, HTTP_QUERY_LAST_MODIFIED, NULL, buf, &dwLen, &index))
  1186. {
  1187. DEBUG_PRINT(PROXY,
  1188. INFO,
  1189. ("Last Modified date is: %q\n",
  1190. buf
  1191. ));
  1192. fRet = FParseHttpDate(&_ftLastModifiedTime, buf);
  1193. if (!fRet)
  1194. {
  1195. DEBUG_PRINT(PROXY,
  1196. ERROR,
  1197. ("FParseHttpDate() returns FALSE\n"
  1198. ));
  1199. }
  1200. }
  1201. _fHasLastModifiedTime = fRet;
  1202. if (!fRet)
  1203. {
  1204. _ftLastModifiedTime.dwLowDateTime = 0;
  1205. _ftLastModifiedTime.dwHighDateTime = 0;
  1206. }
  1207. DEBUG_LEAVE(0);
  1208. }
  1209. VOID
  1210. CAutoProxy::AddIfModifiedSinceHeaders(HINTERNET hRequest)
  1211. /*++
  1212. Routine Description:
  1213. Add the necessary IMS request headers to validate whether a cache
  1214. entry can still be used to satisfy the GET request.
  1215. Return Value:
  1216. BOOL
  1217. --*/
  1218. {
  1219. DEBUG_ENTER((DBG_PROXY,
  1220. None,
  1221. "CAutoProxy::AddIfModifiedSinceHeaders",
  1222. NULL
  1223. ));
  1224. // add if-modified-since only if there is last modified time
  1225. // sent back by the site. This way you never get into trouble
  1226. // where the site doesn't send you an last modified time and you
  1227. // send if-modified-since based on a clock which might be ahead
  1228. // of the site. So the site might say nothing is modified even though
  1229. // something might be. www.microsoft.com is one such example
  1230. if (_fHasLastModifiedTime)
  1231. {
  1232. #define HTTP_IF_MODIFIED_SINCE_SZ "If-Modified-Since:"
  1233. #define HTTP_IF_MODIFIED_SINCE_LEN (sizeof(HTTP_IF_MODIFIED_SINCE_SZ) - 1)
  1234. TCHAR szBuf[80];
  1235. TCHAR szHeader[HTTP_IF_MODIFIED_SINCE_LEN + 80];
  1236. DWORD dwLen;
  1237. INET_ASSERT (FT2LL(_ftLastModifiedTime));
  1238. dwLen = sizeof(szBuf);
  1239. if (FFileTimetoHttpDateTime(&_ftLastModifiedTime, szBuf, &dwLen))
  1240. {
  1241. dwLen = wsprintf(szHeader, "%s %s", HTTP_IF_MODIFIED_SINCE_SZ, szBuf);
  1242. HttpAddRequestHeadersA(hRequest,
  1243. szHeader,
  1244. dwLen,
  1245. WINHTTP_ADDREQ_FLAG_ADD);
  1246. }
  1247. }
  1248. DEBUG_LEAVE(0);
  1249. }
  1250. DWORD
  1251. CAutoProxy::RunProxyScript(
  1252. LPCSTR lpszUrl,
  1253. LPCSTR pszProxyScript,
  1254. LPSTR * ppszQueryResults
  1255. )
  1256. {
  1257. CScriptSite * pScriptSite = NULL;
  1258. AUTO_PROXY_HELPER_APIS AutoProxyFuncs;
  1259. URL_COMPONENTSA Url;
  1260. char * pszHostName = NULL;
  1261. DWORD error = ERROR_SUCCESS;
  1262. HRESULT hrCoInit = E_FAIL;
  1263. HRESULT hr = NOERROR;
  1264. if(!DelayLoad( &g_moduleOle32))
  1265. {
  1266. error = ERROR_NOT_ENOUGH_MEMORY;
  1267. goto quit;
  1268. }
  1269. //
  1270. // Must initialize COM in order to host the JScript engine.
  1271. //
  1272. hrCoInit = DL(CoInitializeEx)(NULL, COINIT_MULTITHREADED);
  1273. pScriptSite = new CScriptSite(this);
  1274. if (!pScriptSite)
  1275. {
  1276. error = ERROR_NOT_ENOUGH_MEMORY;
  1277. goto quit;
  1278. }
  1279. ZeroMemory(&Url, sizeof(Url));
  1280. Url.dwStructSize = sizeof(URL_COMPONENTSA);
  1281. Url.dwHostNameLength = 1L;
  1282. Url.dwUrlPathLength = 1L;
  1283. if (!WinHttpCrackUrlA(lpszUrl, 0, 0, &Url))
  1284. {
  1285. error = ::GetLastError();
  1286. goto quit;
  1287. }
  1288. pszHostName = NewString(Url.lpszHostName, Url.dwHostNameLength);
  1289. if (!pszHostName)
  1290. {
  1291. error = ERROR_NOT_ENOUGH_MEMORY;
  1292. goto quit;
  1293. }
  1294. //
  1295. // Make the call into the external DLL,
  1296. // and let it run, possibly initilization and doing a bunch
  1297. // of stuff.
  1298. //
  1299. hr = pScriptSite->Init(&AutoProxyFuncs, pszProxyScript);
  1300. if (FAILED(hr))
  1301. {
  1302. goto quit;
  1303. }
  1304. __try
  1305. {
  1306. hr = pScriptSite->RunScript(lpszUrl, pszHostName, ppszQueryResults);
  1307. }
  1308. __except(EXCEPTION_EXECUTE_HANDLER)
  1309. {
  1310. hr = E_UNEXPECTED;
  1311. }
  1312. quit:
  1313. if (FAILED(hr))
  1314. {
  1315. error = ERROR_WINHTTP_BAD_AUTO_PROXY_SCRIPT;
  1316. }
  1317. if (pszHostName)
  1318. {
  1319. FREE_MEMORY(pszHostName);
  1320. }
  1321. if (pScriptSite)
  1322. {
  1323. pScriptSite->DeInit();
  1324. delete pScriptSite;
  1325. }
  1326. if (SUCCEEDED(hrCoInit))
  1327. {
  1328. DL(CoUninitialize)();
  1329. }
  1330. return error;
  1331. }
  1332. DWORD
  1333. CAutoProxy::ParseProxyQueryResults(
  1334. LPSTR pszQueryResults,
  1335. WINHTTP_PROXY_INFO * pProxyInfo
  1336. )
  1337. {
  1338. LPSTR pszProxy = NULL;
  1339. LPSTR psz;
  1340. size_t len;
  1341. DWORD error;
  1342. BOOL fReadProxy = FALSE;
  1343. memset(pProxyInfo, 0, sizeof(WINHTTP_PROXY_INFO));
  1344. pProxyInfo->dwAccessType = WINHTTP_ACCESS_TYPE_NO_PROXY;
  1345. for (;;)
  1346. {
  1347. // Skip any white space
  1348. while (*pszQueryResults == ' ')
  1349. pszQueryResults++;
  1350. //
  1351. // Skip to the end of the current token
  1352. //
  1353. psz = pszQueryResults;
  1354. while (*psz != '\0' && *psz != ' ' && *psz != ';' && *psz != ',')
  1355. psz++;
  1356. len = psz - pszQueryResults;
  1357. if (len == 0)
  1358. break;
  1359. if (!fReadProxy)
  1360. {
  1361. if (StrCmpNIA(pszQueryResults, "DIRECT", len) == 0)
  1362. {
  1363. break;
  1364. }
  1365. else if (StrCmpNIA(pszQueryResults, "PROXY", len) == 0)
  1366. {
  1367. fReadProxy = TRUE;
  1368. }
  1369. else // error
  1370. {
  1371. break;
  1372. }
  1373. }
  1374. else
  1375. {
  1376. if (!pszProxy)
  1377. {
  1378. pszProxy = new char[lstrlen(pszQueryResults)+1];
  1379. if (!pszProxy)
  1380. goto ErrorOutOfMemory;
  1381. *pszProxy = '\0';
  1382. }
  1383. else
  1384. {
  1385. StrCatA(pszProxy, ";");
  1386. }
  1387. StrNCatA(pszProxy, pszQueryResults, len+1);
  1388. fReadProxy = FALSE;
  1389. }
  1390. //
  1391. // Are we at the end of the query-results string?
  1392. // If not, advance to the next character.
  1393. //
  1394. if (*psz == '\0')
  1395. break;
  1396. else
  1397. pszQueryResults = psz + 1;
  1398. }
  1399. if (pszProxy)
  1400. {
  1401. error = AsciiToWideChar_UsingGlobalAlloc(pszProxy, &pProxyInfo->lpszProxy);
  1402. delete [] pszProxy;
  1403. if (error)
  1404. goto ErrorOutOfMemory;
  1405. pProxyInfo->dwAccessType = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
  1406. }
  1407. return ERROR_SUCCESS;
  1408. ErrorOutOfMemory:
  1409. error = ERROR_NOT_ENOUGH_MEMORY;
  1410. goto Error;
  1411. Error:
  1412. return error;
  1413. }
  1414. BOOL
  1415. CAutoProxy::IsDetectionNeeded()
  1416. /*++
  1417. Routine Description:
  1418. Detects whether we need to actually run a detection on the network,
  1419. or whether we can resuse current results from previous runs
  1420. Arguments:
  1421. lpProxySettings - structure to fill
  1422. Return Value:
  1423. DWORD
  1424. ERROR_SUCCESS - success
  1425. Win32 Error code - failure
  1426. --*/
  1427. {
  1428. int addressCount;
  1429. LPHOSTENT lpHostent;
  1430. BOOL fDetectionNeeded = FALSE;
  1431. if (_pdwDetectedInterfaceIp == NULL)
  1432. {
  1433. // no saved IP address, so detection required
  1434. fDetectionNeeded = TRUE;
  1435. }
  1436. else
  1437. {
  1438. //
  1439. // Check for IP addresses that no longer match, indicating a network change
  1440. //
  1441. __try
  1442. {
  1443. lpHostent = _I_gethostbyname(NULL);
  1444. }
  1445. __except(EXCEPTION_EXECUTE_HANDLER)
  1446. {
  1447. lpHostent = NULL;
  1448. }
  1449. if (lpHostent != NULL && _CritSec.Lock())
  1450. {
  1451. for (addressCount = 0;
  1452. lpHostent->h_addr_list[addressCount] != NULL;
  1453. addressCount++ ); // gather count
  1454. if (addressCount != _cDetectedInterfaceIpCount)
  1455. {
  1456. fDetectionNeeded = TRUE; // detect needed, the IP count is different
  1457. }
  1458. else
  1459. {
  1460. for (int i = 0; i < addressCount; i++)
  1461. {
  1462. if (*((DWORD *)(lpHostent->h_addr_list[i])) != _pdwDetectedInterfaceIp[i] )
  1463. {
  1464. fDetectionNeeded = TRUE; // detect needed, mismatched values
  1465. break;
  1466. }
  1467. }
  1468. }
  1469. _CritSec.Unlock();
  1470. }
  1471. }
  1472. return fDetectionNeeded; // default, do not need to redetect
  1473. }
  1474. DWORD
  1475. CAutoProxy::GetHostAddresses(int * pcInterfaces, DWORD ** ppdwInterfaceIp)
  1476. {
  1477. int addressCount = 0;
  1478. LPHOSTENT lpHostent;
  1479. DWORD error;
  1480. DWORD * pdwInterfaceIp = NULL;
  1481. error = LoadWinsock();
  1482. if ( error != ERROR_SUCCESS )
  1483. {
  1484. goto quit;
  1485. }
  1486. //
  1487. // Gather IP addresses and start copying them over
  1488. //
  1489. __try
  1490. {
  1491. lpHostent = _I_gethostbyname(NULL);
  1492. }
  1493. __except(EXCEPTION_EXECUTE_HANDLER)
  1494. {
  1495. lpHostent = NULL;
  1496. }
  1497. if (lpHostent == NULL )
  1498. {
  1499. goto quit;
  1500. }
  1501. for (addressCount = 0;
  1502. lpHostent->h_addr_list[addressCount] != NULL;
  1503. addressCount++ ); // gather count
  1504. pdwInterfaceIp = (DWORD *) ALLOCATE_FIXED_MEMORY(addressCount * sizeof(DWORD));
  1505. if (pdwInterfaceIp != NULL)
  1506. {
  1507. for (int i = 0; i < addressCount; i++)
  1508. {
  1509. (pdwInterfaceIp)[i] = *((DWORD *)(lpHostent->h_addr_list[i]));
  1510. }
  1511. }
  1512. else
  1513. {
  1514. error = ERROR_NOT_ENOUGH_MEMORY;
  1515. }
  1516. quit:
  1517. if (pdwInterfaceIp)
  1518. {
  1519. *ppdwInterfaceIp = pdwInterfaceIp;
  1520. *pcInterfaces = addressCount;
  1521. }
  1522. return error;
  1523. }
  1524. AUTO_PROXY_ASYNC_MSG::AUTO_PROXY_ASYNC_MSG(
  1525. IN INTERNET_SCHEME isUrlScheme,
  1526. IN LPSTR lpszUrl,
  1527. IN LPSTR lpszUrlHostName,
  1528. IN DWORD dwUrlHostNameLength
  1529. )
  1530. {
  1531. URL_COMPONENTSA urlComponents;
  1532. Initalize();
  1533. if ( lpszUrl )
  1534. {
  1535. _lpszUrl = lpszUrl;
  1536. _dwUrlLength = lstrlen(lpszUrl);
  1537. _tUrlProtocol = isUrlScheme;
  1538. _pmProxyQuery = PROXY_MSG_GET_PROXY_INFO;
  1539. _pmaAllocMode = MSG_ALLOC_STACK_ONLY;
  1540. memset(&urlComponents, 0, sizeof(urlComponents));
  1541. urlComponents.dwStructSize = sizeof(urlComponents);
  1542. urlComponents.lpszHostName = lpszUrlHostName;
  1543. urlComponents.dwHostNameLength = dwUrlHostNameLength;
  1544. //
  1545. // parse out the host name and port. The host name will be decoded; the
  1546. // original URL will not be modified
  1547. //
  1548. if (WinHttpCrackUrlA(lpszUrl, 0, ICU_DECODE, &urlComponents))
  1549. {
  1550. _nUrlPort = urlComponents.nPort;
  1551. _lpszUrlHostName = urlComponents.lpszHostName;
  1552. _dwUrlHostNameLength = urlComponents.dwHostNameLength;
  1553. if ( _tUrlProtocol == INTERNET_SCHEME_UNKNOWN )
  1554. {
  1555. _tUrlProtocol = urlComponents.nScheme;
  1556. }
  1557. }
  1558. else
  1559. {
  1560. _Error = GetLastError();
  1561. }
  1562. }
  1563. else
  1564. {
  1565. _Error = ERROR_NOT_ENOUGH_MEMORY;
  1566. }
  1567. }
  1568. AUTO_PROXY_ASYNC_MSG::AUTO_PROXY_ASYNC_MSG(
  1569. IN INTERNET_SCHEME isUrlScheme,
  1570. IN LPSTR lpszUrlHostName,
  1571. IN DWORD dwUrlHostNameLength
  1572. )
  1573. {
  1574. Initalize();
  1575. _tUrlProtocol = isUrlScheme;
  1576. _pmProxyQuery = PROXY_MSG_GET_PROXY_INFO;
  1577. _pmaAllocMode = MSG_ALLOC_STACK_ONLY;
  1578. _lpszUrlHostName = lpszUrlHostName;
  1579. _dwUrlHostNameLength = dwUrlHostNameLength;
  1580. }
  1581. AUTO_PROXY_ASYNC_MSG::AUTO_PROXY_ASYNC_MSG(
  1582. IN INTERNET_SCHEME isUrlScheme,
  1583. IN LPSTR lpszUrl,
  1584. IN DWORD dwUrlLength,
  1585. IN LPSTR lpszUrlHostName,
  1586. IN DWORD dwUrlHostNameLength,
  1587. IN INTERNET_PORT nUrlPort
  1588. )
  1589. {
  1590. Initalize();
  1591. _tUrlProtocol = isUrlScheme;
  1592. _pmProxyQuery = PROXY_MSG_GET_PROXY_INFO;
  1593. _pmaAllocMode = MSG_ALLOC_STACK_ONLY;
  1594. _nUrlPort = nUrlPort;
  1595. _lpszUrlHostName = lpszUrlHostName;
  1596. _dwUrlHostNameLength = dwUrlHostNameLength;
  1597. _lpszUrl = lpszUrl;
  1598. _dwUrlLength = dwUrlLength;
  1599. }
  1600. VOID
  1601. AUTO_PROXY_ASYNC_MSG::SetProxyMsg(
  1602. IN INTERNET_SCHEME isUrlScheme,
  1603. IN LPSTR lpszUrl,
  1604. IN DWORD dwUrlLength,
  1605. IN LPSTR lpszUrlHostName,
  1606. IN DWORD dwUrlHostNameLength,
  1607. IN INTERNET_PORT nUrlPort
  1608. )
  1609. {
  1610. _tUrlProtocol = isUrlScheme;
  1611. _pmProxyQuery = PROXY_MSG_GET_PROXY_INFO;
  1612. _pmaAllocMode = MSG_ALLOC_STACK_ONLY;
  1613. _nUrlPort = nUrlPort;
  1614. _lpszUrlHostName = lpszUrlHostName;
  1615. _dwUrlHostNameLength = dwUrlHostNameLength;
  1616. _lpszUrl = lpszUrl;
  1617. _dwUrlLength = dwUrlLength;
  1618. }
  1619. AUTO_PROXY_ASYNC_MSG::AUTO_PROXY_ASYNC_MSG(
  1620. IN PROXY_MESSAGE_TYPE pmProxyQuery
  1621. )
  1622. {
  1623. Initalize();
  1624. _pmaAllocMode = MSG_ALLOC_HEAP_MSG_OBJ_OWNS;
  1625. _pmProxyQuery = pmProxyQuery;
  1626. }
  1627. AUTO_PROXY_ASYNC_MSG::AUTO_PROXY_ASYNC_MSG(
  1628. IN AUTO_PROXY_ASYNC_MSG *pStaticAutoProxy
  1629. )
  1630. {
  1631. Initalize();
  1632. _tUrlProtocol = pStaticAutoProxy->_tUrlProtocol;
  1633. _lpszUrl = (pStaticAutoProxy->_lpszUrl) ? NewString(pStaticAutoProxy->_lpszUrl) : NULL;
  1634. _dwUrlLength = pStaticAutoProxy->_dwUrlLength;
  1635. _lpszUrlHostName =
  1636. (pStaticAutoProxy->_lpszUrlHostName ) ?
  1637. NewString(pStaticAutoProxy->_lpszUrlHostName, pStaticAutoProxy->_dwUrlHostNameLength) :
  1638. NULL;
  1639. _dwUrlHostNameLength = pStaticAutoProxy->_dwUrlHostNameLength;
  1640. _nUrlPort = pStaticAutoProxy->_nUrlPort;
  1641. _tProxyScheme = pStaticAutoProxy->_tProxyScheme;
  1642. //
  1643. // ProxyHostName is something that is generated by the request,
  1644. // therefore it should not be copied OR freed.
  1645. //
  1646. INET_ASSERT( pStaticAutoProxy->_lpszProxyHostName == NULL );
  1647. //_lpszProxyHostName = (pStaticAutoProxy->_lpszProxyHostName ) ? NewString(pStaticAutoProxy->_lpszProxyHostName) : NULL;
  1648. _dwProxyHostNameLength = pStaticAutoProxy->_dwProxyHostNameLength;
  1649. _nProxyHostPort = pStaticAutoProxy->_nProxyHostPort;
  1650. _pmProxyQuery = pStaticAutoProxy->_pmProxyQuery;
  1651. _pmaAllocMode = MSG_ALLOC_HEAP_MSG_OBJ_OWNS;
  1652. _pProxyState = pStaticAutoProxy->_pProxyState;
  1653. INET_ASSERT(_pProxyState == NULL);
  1654. _dwQueryResult = pStaticAutoProxy->_dwQueryResult;
  1655. _Error = pStaticAutoProxy->_Error;
  1656. _MessageFlags.Dword = pStaticAutoProxy->_MessageFlags.Dword;
  1657. _dwProxyVersion = pStaticAutoProxy->_dwProxyVersion;
  1658. }
  1659. AUTO_PROXY_ASYNC_MSG::~AUTO_PROXY_ASYNC_MSG(
  1660. VOID
  1661. )
  1662. {
  1663. DEBUG_ENTER((DBG_OBJECTS,
  1664. None,
  1665. "~AUTO_PROXY_ASYNC_MSG",
  1666. NULL
  1667. ));
  1668. if ( IsAlloced() )
  1669. {
  1670. DEBUG_PRINT(OBJECTS,
  1671. INFO,
  1672. ("Freeing Allocated MSG ptr=%x\n",
  1673. this
  1674. ));
  1675. if ( _lpszUrl )
  1676. {
  1677. //DEBUG_PRINT(OBJECTS,
  1678. // INFO,
  1679. // ("Url ptr=%x, %q\n",
  1680. // _lpszUrl,
  1681. // _lpszUrl
  1682. // ));
  1683. FREE_MEMORY(_lpszUrl);
  1684. }
  1685. if ( _lpszUrlHostName )
  1686. {
  1687. FREE_MEMORY(_lpszUrlHostName);
  1688. }
  1689. if ( _pProxyState )
  1690. {
  1691. delete _pProxyState;
  1692. }
  1693. }
  1694. if (_bFreeProxyHostName && (_lpszProxyHostName != NULL)) {
  1695. FREE_MEMORY(_lpszProxyHostName);
  1696. }
  1697. DEBUG_LEAVE(0);
  1698. }
  1699. DWORD
  1700. AUTO_PROXY_HELPER_APIS::ResolveHostName(
  1701. IN LPSTR lpszHostName,
  1702. IN OUT LPSTR lpszIPAddress,
  1703. IN OUT LPDWORD lpdwIPAddressSize
  1704. )
  1705. /*++
  1706. Routine Description:
  1707. Resolves a HostName to an IP address by using Winsock DNS.
  1708. Arguments:
  1709. lpszHostName - the host name that should be used.
  1710. lpszIPAddress - the output IP address as a string.
  1711. lpdwIPAddressSize - the size of the outputed IP address string.
  1712. Return Value:
  1713. DWORD
  1714. Win32 error code.
  1715. --*/
  1716. {
  1717. // Figure out if we're being asked to resolve a name or an address literal.
  1718. // If getaddrinfo() with the AI_NUMERICHOST flag succeeds then we were
  1719. // given a string respresentation of an IPv6 or IPv4 address. Otherwise
  1720. // we expect getaddrinfo to return EAI_NONAME.
  1721. //
  1722. DWORD dwIPAddressSize;
  1723. BOOL bResolved = FALSE;
  1724. ADDRINFO Hints;
  1725. LPADDRINFO lpAddrInfo;
  1726. DWORD error;
  1727. memset(&Hints, 0, sizeof(struct addrinfo));
  1728. Hints.ai_flags = AI_NUMERICHOST; // Only check for address literals.
  1729. Hints.ai_family = PF_UNSPEC; // Accept any protocol family.
  1730. Hints.ai_socktype = SOCK_STREAM; // Constrain results to stream socket.
  1731. Hints.ai_protocol = IPPROTO_TCP; // Constrain results to TCP.
  1732. error = _I_getaddrinfo(lpszHostName, NULL, &Hints, &lpAddrInfo);
  1733. if (error != EAI_NONAME) {
  1734. if (error != 0) {
  1735. if (error == EAI_MEMORY)
  1736. error = ERROR_NOT_ENOUGH_MEMORY;
  1737. else
  1738. error = ERROR_WINHTTP_NAME_NOT_RESOLVED;
  1739. goto quit;
  1740. }
  1741. //
  1742. // An IP address (either v4 or v6) was passed in.
  1743. // This is precisely what we want, so if we have the room,
  1744. // just copy it back out.
  1745. //
  1746. _I_freeaddrinfo(lpAddrInfo);
  1747. dwIPAddressSize = lstrlen(lpszHostName);
  1748. if ( *lpdwIPAddressSize < dwIPAddressSize ||
  1749. lpszIPAddress == NULL )
  1750. {
  1751. *lpdwIPAddressSize = dwIPAddressSize+1;
  1752. error = ERROR_INSUFFICIENT_BUFFER;
  1753. goto quit;
  1754. }
  1755. lstrcpy(lpszIPAddress, lpszHostName);
  1756. goto quit;
  1757. }
  1758. DEBUG_PRINT(SOCKETS,
  1759. INFO,
  1760. ("resolving %q\n",
  1761. lpszHostName
  1762. ));
  1763. error = _I_getaddrinfo(lpszHostName, NULL, &Hints, &lpAddrInfo);
  1764. DEBUG_PRINT(SOCKETS,
  1765. INFO,
  1766. ("%q %sresolved\n",
  1767. lpszHostName,
  1768. (error == 0) ? "" : "NOT "
  1769. ));
  1770. if (error == 0) {
  1771. bResolved = TRUE;
  1772. } else {
  1773. if (error == EAI_MEMORY)
  1774. error = ERROR_NOT_ENOUGH_MEMORY;
  1775. else
  1776. error = ERROR_WINHTTP_NAME_NOT_RESOLVED;
  1777. goto quit;
  1778. }
  1779. INET_ASSERT(lpAddrInfo != NULL);
  1780. //
  1781. // We have an addrinfo struct for lpszHostName.
  1782. // Convert its IP address into a string.
  1783. //
  1784. //
  1785. // BUGBUG: Until our caller can deal with IPv6 addresses, we'll only
  1786. // return IPv4 addresses here, regardless of what may be in the cache.
  1787. // Step through chain until we find an IPv4 address.
  1788. //
  1789. LPADDRINFO IPv4Only;
  1790. IPv4Only = lpAddrInfo;
  1791. while (IPv4Only->ai_family != AF_INET) {
  1792. IPv4Only = IPv4Only->ai_next;
  1793. if (IPv4Only == NULL) {
  1794. error = ERROR_WINHTTP_NAME_NOT_RESOLVED;
  1795. goto quit;
  1796. }
  1797. }
  1798. error = _I_getnameinfo(IPv4Only->ai_addr, IPv4Only->ai_addrlen,
  1799. lpszIPAddress, *lpdwIPAddressSize, NULL, 0,
  1800. NI_NUMERICHOST);
  1801. if (error != 0) {
  1802. error = ERROR_WINHTTP_NAME_NOT_RESOLVED;
  1803. }
  1804. quit:
  1805. if (bResolved)
  1806. {
  1807. _I_freeaddrinfo(lpAddrInfo);
  1808. }
  1809. return error;
  1810. }
  1811. BOOL
  1812. AUTO_PROXY_HELPER_APIS::IsResolvable(
  1813. IN LPSTR lpszHost
  1814. )
  1815. /*++
  1816. Routine Description:
  1817. Determines wheter a HostName can be resolved. Performs a Winsock DNS query,
  1818. and if it succeeds returns TRUE.
  1819. Arguments:
  1820. lpszHost - the host name that should be used.
  1821. Return Value:
  1822. BOOL
  1823. TRUE - the host is resolved.
  1824. FALSE - could not resolve.
  1825. --*/
  1826. {
  1827. DWORD dwDummySize;
  1828. DWORD error;
  1829. error = ResolveHostName(
  1830. lpszHost,
  1831. NULL,
  1832. &dwDummySize
  1833. );
  1834. if ( error == ERROR_INSUFFICIENT_BUFFER )
  1835. {
  1836. return TRUE;
  1837. }
  1838. else
  1839. {
  1840. INET_ASSERT(error != ERROR_SUCCESS );
  1841. return FALSE;
  1842. }
  1843. }
  1844. DWORD
  1845. AUTO_PROXY_HELPER_APIS::GetIPAddress(
  1846. IN OUT LPSTR lpszIPAddress,
  1847. IN OUT LPDWORD lpdwIPAddressSize
  1848. )
  1849. /*++
  1850. Routine Description:
  1851. Acquires the IP address string of this client machine WINHTTP is running on.
  1852. Arguments:
  1853. lpszIPAddress - the IP address of the machine, returned.
  1854. lpdwIPAddressSize - size of the IP address string.
  1855. Return Value:
  1856. DWORD
  1857. Win32 Error.
  1858. --*/
  1859. {
  1860. CHAR szHostBuffer[255];
  1861. int serr;
  1862. serr = _I_gethostname(
  1863. szHostBuffer,
  1864. 255-1
  1865. );
  1866. if ( serr != 0)
  1867. {
  1868. return ERROR_WINHTTP_INTERNAL_ERROR;
  1869. }
  1870. return ResolveHostName(
  1871. szHostBuffer,
  1872. lpszIPAddress,
  1873. lpdwIPAddressSize
  1874. );
  1875. }
  1876. BOOL
  1877. AUTO_PROXY_HELPER_APIS::IsInNet(
  1878. IN LPSTR lpszIPAddress,
  1879. IN LPSTR lpszDest,
  1880. IN LPSTR lpszMask
  1881. )
  1882. /*++
  1883. Routine Description:
  1884. Determines whether a given IP address is in a given dest/mask IP address.
  1885. Arguments:
  1886. lpszIPAddress - the host name that should be used.
  1887. lpszDest - the IP address dest to check against.
  1888. lpszMask - the IP mask string
  1889. Return Value:
  1890. BOOL
  1891. TRUE - the IP address is in the given dest/mask
  1892. FALSE - the IP address is NOT in the given dest/mask
  1893. --*/
  1894. {
  1895. DWORD dwDest, dwIpAddr, dwMask;
  1896. INET_ASSERT(lpszIPAddress);
  1897. INET_ASSERT(lpszDest);
  1898. INET_ASSERT(lpszMask);
  1899. dwIpAddr = _I_inet_addr(lpszIPAddress);
  1900. dwDest = _I_inet_addr(lpszDest);
  1901. dwMask = _I_inet_addr(lpszMask);
  1902. if ( dwDest == INADDR_NONE ||
  1903. dwIpAddr == INADDR_NONE )
  1904. {
  1905. INET_ASSERT(FALSE);
  1906. return FALSE;
  1907. }
  1908. if ( (dwIpAddr & dwMask) != dwDest)
  1909. {
  1910. return FALSE;
  1911. }
  1912. //
  1913. // Pass, its Matches.
  1914. //
  1915. return TRUE;
  1916. }