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.

3632 lines
86 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. proxysup.cxx
  5. Abstract:
  6. Contains class implementation for proxy server and proxy bypass list
  7. Contents:
  8. IsLocalMacro
  9. PROXY_SERVER_LIST_ENTRY::WriteEntry
  10. PROXY_SERVER_LIST::AddList
  11. PROXY_SERVER_LIST::Find
  12. PROXY_SERVER_LIST::Add
  13. PROXY_SERVER_LIST::ProxyScheme
  14. PROXY_SERVER_LIST::GetProxyHostName
  15. PROXY_SERVER_LIST::AddToBypassList
  16. PROXY_SERVER_LIST::GetList
  17. PROXY_BYPASS_LIST_ENTRY::WriteEntry
  18. PROXY_BYPASS_LIST::AddList
  19. PROXY_BYPASS_LIST::Find
  20. PROXY_BYPASS_LIST::Add
  21. PROXY_BYPASS_LIST::IsBypassed
  22. PROXY_BYPASS_LIST::IsHostInBypassList
  23. PROXY_BYPASS_LIST::GetList
  24. PROXY_INFO::GetProxyStringInfo
  25. PROXY_INFO::HostBypassesProxy
  26. PROXY_INFO::RedoSendRequest
  27. PROXY_INFO::Terminate
  28. PROXY_INFO::CleanOutLists
  29. PROXY_STATE::GetNextProxy
  30. (GetRegistryProxyParameter)
  31. Author:
  32. Richard L Firth (rfirth) 03-Feb-1996
  33. Revision History:
  34. 03-Feb-1996 rfirth
  35. Created
  36. --*/
  37. #include <wininetp.h>
  38. //
  39. // private manifests
  40. //
  41. #define DEFAULT_PROXY_BUFFER_LENGTH (4 K)
  42. #define MAX_IP_ADDRESS_STRING_LENGTH (4 * 4 - 1) // ###.###.###.###
  43. #define PROXY_REGISTRY_STRING_LENGTH (4 K)
  44. //
  45. // private types
  46. //
  47. typedef enum {
  48. STATE_START,
  49. STATE_PROTOCOL,
  50. STATE_SCHEME,
  51. STATE_SERVER,
  52. STATE_PORT,
  53. STATE_END,
  54. STATE_ERROR
  55. } PARSER_STATE;
  56. //
  57. // private prototypes
  58. //
  59. PRIVATE
  60. LPSTR
  61. GetRegistryProxyParameter(
  62. IN LPSTR lpszParameterName
  63. );
  64. //
  65. // functions
  66. //
  67. BOOL
  68. IsLocalMacro(
  69. IN LPSTR lpszMetaName,
  70. IN DWORD dwMetaNameLength
  71. )
  72. /*++
  73. Routine Description:
  74. Checks for local macro name
  75. Arguments:
  76. lpszMetaName - name to check
  77. dwMetaNameLength - length
  78. Return Value:
  79. BOOL
  80. TRUE - it is <local>
  81. FALSE - not
  82. --*/
  83. {
  84. INET_ASSERT(lpszMetaName != NULL);
  85. static const char s_local[] = "<local>";
  86. return (strnicmp(s_local, lpszMetaName, dwMetaNameLength) == 0);
  87. }
  88. //
  89. // member functions
  90. //
  91. BOOL
  92. PROXY_SERVER_LIST_ENTRY::WriteEntry(
  93. OUT LPSTR lpszBuffer,
  94. IN OUT LPDWORD lpdwBufferLength
  95. )
  96. /*++
  97. Routine Description:
  98. Writes this proxy server list entry as a string in the supplied buffer
  99. Arguments:
  100. lpszBuffer - pointer to buffer where string is written
  101. lpdwBufferLength - IN: amount of space in buffer
  102. OUT: number of bytes copied, or required size
  103. Return Value:
  104. BOOL
  105. TRUE - entry written to buffer
  106. FALSE - entry not written to buffer - *lpdwBufferLength contains
  107. required size
  108. --*/
  109. {
  110. DWORD requiredLength;
  111. LPSTR protocolName;
  112. DWORD protocolNameLength;
  113. LPSTR schemeName;
  114. DWORD schemeNameLength;
  115. INTERNET_PORT magnitude = 1;
  116. protocolName = MapUrlScheme(_Protocol, &protocolNameLength);
  117. if (protocolName != NULL) {
  118. requiredLength = protocolNameLength + 1; // for '='
  119. } else {
  120. requiredLength = 0;
  121. }
  122. schemeName = MapUrlScheme(_Scheme, &schemeNameLength);
  123. if (schemeName != NULL) {
  124. requiredLength += schemeNameLength + sizeof("://") - 1;
  125. }
  126. requiredLength += _ProxyName.StringLength();
  127. if (_ProxyPort != INTERNET_INVALID_PORT_NUMBER) {
  128. for (INTERNET_PORT n = 10000, i = 5; n > 0; n /= 10, --i) {
  129. if (_ProxyPort / n) {
  130. requiredLength += i + 1; // for ':'
  131. magnitude = n;
  132. break;
  133. }
  134. }
  135. }
  136. BOOL success;
  137. if (*lpdwBufferLength > requiredLength) {
  138. if (protocolName != NULL) {
  139. memcpy(lpszBuffer, protocolName, protocolNameLength);
  140. lpszBuffer += protocolNameLength;
  141. *lpszBuffer++ = '=';
  142. }
  143. if (schemeName != NULL) {
  144. memcpy(lpszBuffer, schemeName, schemeNameLength);
  145. lpszBuffer += schemeNameLength;
  146. memcpy(lpszBuffer, "://", sizeof("://") - 1);
  147. lpszBuffer += sizeof("://") - 1;
  148. }
  149. _ProxyName.CopyTo(lpszBuffer);
  150. lpszBuffer += _ProxyName.StringLength();
  151. if (_ProxyPort != INTERNET_INVALID_PORT_NUMBER) {
  152. *lpszBuffer++ = ':';
  153. for (INTERNET_PORT n = _ProxyPort, i = magnitude; i; i /= 10) {
  154. *lpszBuffer++ = (char)(n / i) + '0';
  155. n %= i;
  156. }
  157. }
  158. success = TRUE;
  159. } else {
  160. success = FALSE;
  161. }
  162. *lpdwBufferLength = requiredLength;
  163. return success;
  164. }
  165. DWORD
  166. PROXY_SERVER_LIST::AddList(
  167. IN LPSTR lpszList
  168. )
  169. /*++
  170. Routine Description:
  171. Parses a list of proxy servers and creates a PROXY_SERVER_LIST_ENTRY for
  172. each one
  173. Arguments:
  174. lpszList - pointer to list of proxies of the form:
  175. [<scheme>=][<scheme>"://"]<server>[":"<port>][";"*]
  176. The list can be NULL, in which case we read it from the
  177. registry
  178. Return Value:
  179. DWORD
  180. Success - ERROR_SUCCESS
  181. Failure - ERROR_INVALID_PARAMETER
  182. At least one entry in lpszList is bogus
  183. --*/
  184. {
  185. DEBUG_ENTER((DBG_PROXY,
  186. Dword,
  187. "PROXY_SERVER_LIST::AddList",
  188. "%.80q",
  189. lpszList
  190. ));
  191. DWORD entryLength;
  192. LPSTR protocolName;
  193. DWORD protocolLength;
  194. LPSTR schemeName;
  195. DWORD schemeLength;
  196. LPSTR serverName;
  197. DWORD serverLength;
  198. PARSER_STATE state;
  199. DWORD nSlashes;
  200. INTERNET_PORT port;
  201. BOOL done;
  202. entryLength = 0;
  203. protocolName = lpszList;
  204. protocolLength = 0;
  205. schemeName = NULL;
  206. schemeLength = 0;
  207. serverName = NULL;
  208. serverLength = 0;
  209. state = STATE_PROTOCOL;
  210. nSlashes = 0;
  211. port = 0;
  212. done = FALSE;
  213. //
  214. // walk the list, pulling out the various scheme parts
  215. //
  216. do {
  217. char ch = *lpszList++;
  218. if ((nSlashes == 1) && (ch != '/')) {
  219. state = STATE_ERROR;
  220. break;
  221. }
  222. switch (ch) {
  223. case '=':
  224. if ((state == STATE_PROTOCOL) && (entryLength != 0)) {
  225. protocolLength = entryLength;
  226. entryLength = 0;
  227. state = STATE_SCHEME;
  228. schemeName = lpszList;
  229. } else {
  230. //
  231. // '=' can't legally appear anywhere else
  232. //
  233. state = STATE_ERROR;
  234. }
  235. break;
  236. case ':':
  237. switch (state) {
  238. case STATE_PROTOCOL:
  239. if (*lpszList == '/') {
  240. schemeName = protocolName;
  241. protocolName = NULL;
  242. schemeLength = entryLength;
  243. protocolLength = 0;
  244. state = STATE_SCHEME;
  245. } else if (*lpszList != '\0') {
  246. serverName = protocolName;
  247. serverLength = entryLength;
  248. state = STATE_PORT;
  249. } else {
  250. state = STATE_ERROR;
  251. }
  252. entryLength = 0;
  253. break;
  254. case STATE_SCHEME:
  255. if (*lpszList == '/') {
  256. schemeLength = entryLength;
  257. } else if (*lpszList != '\0') {
  258. serverName = schemeName;
  259. serverLength = entryLength;
  260. state = STATE_PORT;
  261. } else {
  262. state = STATE_ERROR;
  263. }
  264. entryLength = 0;
  265. break;
  266. case STATE_SERVER:
  267. serverLength = entryLength;
  268. state = STATE_PORT;
  269. entryLength = 0;
  270. break;
  271. default:
  272. state = STATE_ERROR;
  273. break;
  274. }
  275. break;
  276. case '/':
  277. if ((state == STATE_SCHEME) && (nSlashes < 2) && (entryLength == 0)) {
  278. if (++nSlashes == 2) {
  279. state = STATE_SERVER;
  280. serverName = lpszList;
  281. }
  282. } else {
  283. state = STATE_ERROR;
  284. }
  285. break;
  286. default:
  287. if (state != STATE_PORT) {
  288. ++entryLength;
  289. } else if (isdigit(ch)) {
  290. //
  291. // BUGBUG - we will overflow if >65535
  292. //
  293. port = port * 10 + (ch - '0');
  294. } else {
  295. //
  296. // STATE_PORT && non-digit character - error
  297. //
  298. state = STATE_ERROR;
  299. }
  300. break;
  301. case '\0':
  302. done = TRUE;
  303. //
  304. // fall through
  305. //
  306. case '\t':
  307. case '\n':
  308. case '\v': // vertical tab, 0x0b
  309. case '\f': // form feed, 0x0c
  310. case '\r':
  311. case ' ':
  312. case ';':
  313. case ',':
  314. if (serverLength == 0) {
  315. serverLength = entryLength;
  316. }
  317. if (serverLength != 0) {
  318. if (serverName == NULL) {
  319. serverName = (schemeName != NULL)
  320. ? schemeName
  321. : protocolName;
  322. }
  323. INET_ASSERT(serverName != NULL);
  324. INTERNET_SCHEME protocol;
  325. if (protocolLength != 0) {
  326. protocol = MapUrlSchemeName(protocolName, protocolLength);
  327. } else {
  328. protocol = INTERNET_SCHEME_DEFAULT;
  329. }
  330. INTERNET_SCHEME scheme;
  331. if (schemeLength != 0) {
  332. scheme = MapUrlSchemeName(schemeName, schemeLength);
  333. } else {
  334. scheme = INTERNET_SCHEME_DEFAULT;
  335. }
  336. //
  337. // add an entry if this is a protocol we handle and we don't
  338. // already have an entry for it
  339. //
  340. if ((protocol != INTERNET_SCHEME_UNKNOWN)
  341. && (scheme != INTERNET_SCHEME_UNKNOWN)
  342. //
  343. // we can only currently handle CERN (secure or unsecure) and
  344. // FTP proxies, so kick out anything that wants to go via any
  345. // other proxy scheme
  346. //
  347. && ((scheme == INTERNET_SCHEME_DEFAULT)
  348. || (scheme == INTERNET_SCHEME_HTTP)
  349. || (scheme == INTERNET_SCHEME_HTTPS))) {
  350. if (!Find(protocol)) {
  351. //
  352. // don't worry if Add() fails - we just continue
  353. //
  354. Add(protocol, scheme, serverName, serverLength, port);
  355. }
  356. }
  357. }
  358. entryLength = 0;
  359. protocolName = lpszList;
  360. protocolLength = 0;
  361. schemeName = NULL;
  362. schemeLength = 0;
  363. serverName = NULL;
  364. serverLength = 0;
  365. nSlashes = 0;
  366. port = 0;
  367. state = STATE_PROTOCOL;
  368. break;
  369. }
  370. if (state == STATE_ERROR) {
  371. break;
  372. }
  373. } while (!done);
  374. DWORD error;
  375. if (state == STATE_ERROR) {
  376. error = ERROR_INVALID_PARAMETER;
  377. } else {
  378. error = ERROR_SUCCESS;
  379. }
  380. DEBUG_LEAVE(error);
  381. return error;
  382. }
  383. BOOL
  384. PROXY_SERVER_LIST::Find(
  385. IN INTERNET_SCHEME tScheme
  386. )
  387. /*++
  388. Routine Description:
  389. Find a PROXY_SERVER_LIST_ENTRY based on the scheme
  390. Arguments:
  391. tScheme - protocol scheme to find
  392. Return Value:
  393. BOOL
  394. --*/
  395. {
  396. DEBUG_ENTER((DBG_PROXY,
  397. Bool,
  398. "PROXY_SERVER_LIST::Find",
  399. "%s",
  400. InternetMapScheme(tScheme)
  401. ));
  402. BOOL found = FALSE;
  403. if (!LockSerializedList(&_List))
  404. goto quit;
  405. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  406. entry != (PLIST_ENTRY)SlSelf(&_List);
  407. entry = entry->Flink) {
  408. PROXY_SERVER_LIST_ENTRY * info;
  409. info = CONTAINING_RECORD(entry, PROXY_SERVER_LIST_ENTRY, _List);
  410. if (info->_Protocol == tScheme) {
  411. found = TRUE;
  412. break;
  413. }
  414. }
  415. UnlockSerializedList(&_List);
  416. quit:
  417. DEBUG_LEAVE(found);
  418. return found;
  419. }
  420. DWORD
  421. PROXY_SERVER_LIST::Add(
  422. IN INTERNET_SCHEME tProtocol,
  423. IN INTERNET_SCHEME tScheme,
  424. IN LPSTR lpszHostName,
  425. IN DWORD dwHostNameLength,
  426. IN INTERNET_PORT nPort
  427. )
  428. /*++
  429. Routine Description:
  430. Create an add a PROXY_SERVER_LIST_ENTRY to the PROXY_SERVER_LIST
  431. Arguments:
  432. tProtocol - protocol which uses the proxy
  433. tScheme - scheme used to talk to the proxy
  434. lpszHostName - proxy host name
  435. dwHostNameLength - length of proxy host name
  436. nPort - port at proxy host
  437. Return Value:
  438. DWORD
  439. Success - ERROR_SUCCESS
  440. Failure - ERROR_NOT_ENOUGH_MEMORY
  441. --*/
  442. {
  443. DEBUG_ENTER((DBG_PROXY,
  444. Dword,
  445. "PROXY_SERVER_LIST::Add",
  446. "%s, %s, %.*q, %d, %d",
  447. InternetMapScheme(tProtocol),
  448. InternetMapScheme(tScheme),
  449. dwHostNameLength,
  450. lpszHostName,
  451. dwHostNameLength,
  452. nPort
  453. ));
  454. PROXY_SERVER_LIST_ENTRY * entry;
  455. entry = New PROXY_SERVER_LIST_ENTRY(tProtocol,
  456. tScheme,
  457. lpszHostName,
  458. dwHostNameLength,
  459. nPort
  460. );
  461. DWORD error = ERROR_SUCCESS;
  462. if (entry != NULL) {
  463. //error = entry->ResolveAddress();
  464. //if (error == ERROR_SUCCESS) {
  465. // InsertAtTailOfSerializedList(&_List, &entry->_List);
  466. //}
  467. if (entry->_Protocol == INTERNET_SCHEME_DEFAULT) {
  468. if (!InsertAtTailOfSerializedList(&_List, &entry->_List)) {
  469. delete entry;
  470. error = ERROR_NOT_ENOUGH_MEMORY;
  471. }
  472. } else {
  473. if (!InsertAtHeadOfSerializedList(&_List, &entry->_List)) {
  474. delete entry;
  475. error = ERROR_NOT_ENOUGH_MEMORY;
  476. }
  477. }
  478. } else {
  479. error = ERROR_NOT_ENOUGH_MEMORY;
  480. }
  481. DEBUG_LEAVE(error);
  482. return error;
  483. }
  484. INTERNET_SCHEME
  485. PROXY_SERVER_LIST::ProxyScheme(
  486. IN INTERNET_SCHEME tProtocol
  487. )
  488. /*++
  489. Routine Description:
  490. Determines protocol over which tScheme goes through proxy
  491. Arguments:
  492. tProtocol - protocol scheme used to retrieve data (e.g. FTP)
  493. Return Value:
  494. INTERNET_SCHEME
  495. Success - scheme by which protocol goes via proxy
  496. Failure - INTERNET_SCHEME_UNKNOWN
  497. --*/
  498. {
  499. DEBUG_ENTER((DBG_PROXY,
  500. Int,
  501. "PROXY_SERVER_LIST::ProxyScheme",
  502. "%s",
  503. InternetMapScheme(tProtocol)
  504. ));
  505. INTERNET_SCHEME tScheme = INTERNET_SCHEME_UNKNOWN;
  506. if (!LockSerializedList(&_List))
  507. goto quit;
  508. //
  509. // the list really shouldn't be empty if we're here
  510. //
  511. INET_ASSERT(!IsSerializedListEmpty(&_List));
  512. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  513. entry != (PLIST_ENTRY)SlSelf(&_List);
  514. entry = entry->Flink) {
  515. PROXY_SERVER_LIST_ENTRY * info;
  516. info = CONTAINING_RECORD(entry, PROXY_SERVER_LIST_ENTRY, _List);
  517. //
  518. // if we find a match for the protocol, or this protocol is handled by
  519. // the default proxy entry then we are done
  520. //
  521. if ((info->_Protocol == tProtocol)
  522. || (info->_Protocol == INTERNET_SCHEME_DEFAULT)) {
  523. tScheme = info->_Scheme;
  524. //
  525. // the default scheme is HTTP (CERN proxy)
  526. //
  527. if (tScheme == INTERNET_SCHEME_DEFAULT) {
  528. tScheme = INTERNET_SCHEME_HTTP;
  529. }
  530. break;
  531. }
  532. }
  533. UnlockSerializedList(&_List);
  534. quit:
  535. DEBUG_LEAVE(tScheme);
  536. return tScheme;
  537. }
  538. BOOL
  539. PROXY_SERVER_LIST::GetProxyHostName(
  540. IN INTERNET_SCHEME tProtocol,
  541. IN OUT LPINTERNET_SCHEME lptScheme,
  542. OUT LPSTR * lplpszHostName,
  543. OUT LPBOOL lpbFreeHostName,
  544. OUT LPDWORD lpdwHostNameLength,
  545. OUT LPINTERNET_PORT lpHostPort
  546. )
  547. /*++
  548. Routine Description:
  549. Given a protocol, map it to the proxy we use to retrieve the data
  550. Arguments:
  551. tProtocol - protocol to map (e.g. find the proxy for FTP)
  552. lptScheme - IN: preferred scheme if INTERNET_SCHEME_DEFAULT
  553. OUT: returned scheme
  554. lplpszHostName - pointer to returned pointer to host name
  555. lpbFreeHostName - returned TRUE if *lplpszHostName allocated
  556. lpdwHostNameLength - pointer to returned host name length
  557. lpHostPort - pointer to returned host port
  558. Return Value:
  559. BOOL
  560. TRUE - requested info has been returned
  561. FALSE - requested info was not found
  562. --*/
  563. {
  564. DEBUG_ENTER((DBG_PROXY,
  565. Bool,
  566. "PROXY_SERVER_LIST::GetProxyHostName",
  567. "%s, %#x, %#x, %#x, %#x, %#x",
  568. InternetMapScheme(tProtocol),
  569. lptScheme,
  570. lplpszHostName,
  571. lpbFreeHostName,
  572. lpdwHostNameLength,
  573. lpHostPort
  574. ));
  575. INET_ASSERT(tProtocol != INTERNET_SCHEME_UNKNOWN);
  576. //
  577. // *lptScheme must now be one of the recognized schemes, or the default
  578. //
  579. INET_ASSERT((*lptScheme == INTERNET_SCHEME_DEFAULT)
  580. || (*lptScheme == INTERNET_SCHEME_HTTP)
  581. || (*lptScheme == INTERNET_SCHEME_HTTPS)
  582. || (*lptScheme == INTERNET_SCHEME_SOCKS)
  583. );
  584. BOOL found = FALSE;
  585. if (!LockSerializedList(&_List))
  586. goto quit;
  587. //
  588. // the list really shouldn't be empty if we're here
  589. //
  590. INET_ASSERT(!IsSerializedListEmpty(&_List));
  591. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  592. entry != (PLIST_ENTRY)SlSelf(&_List);
  593. entry = entry->Flink) {
  594. PROXY_SERVER_LIST_ENTRY * info;
  595. info = CONTAINING_RECORD(entry, PROXY_SERVER_LIST_ENTRY, _List);
  596. //
  597. // if we find a match for the protocol, or this protocol is handled by
  598. // the default proxy entry then we are done
  599. //
  600. // Hack: But make sure its NOT socks since, socks must be
  601. // an exact match !!! No defaults.
  602. //
  603. if ((info->_Protocol == tProtocol)
  604. || ((info->_Protocol == INTERNET_SCHEME_DEFAULT)
  605. && (tProtocol != INTERNET_SCHEME_SOCKS) )) {
  606. INTERNET_SCHEME scheme = info->_Scheme;
  607. //
  608. // the returned scheme is the input preferred scheme unless it was
  609. // the default scheme in which case we return HTTP (CERN proxy)
  610. //
  611. if (scheme == INTERNET_SCHEME_DEFAULT) {
  612. scheme = (*lptScheme == INTERNET_SCHEME_DEFAULT)
  613. ? INTERNET_SCHEME_HTTP
  614. : *lptScheme;
  615. }
  616. *lptScheme = scheme;
  617. *lpbFreeHostName = FALSE;
  618. *lpdwHostNameLength = 0;
  619. *lplpszHostName = NewString(info->_ProxyName.StringAddress(),
  620. info->_ProxyName.StringLength()
  621. );
  622. if (*lplpszHostName != NULL) {
  623. *lpbFreeHostName = TRUE;
  624. *lpdwHostNameLength = info->_ProxyName.StringLength();
  625. }
  626. INTERNET_PORT port = info->_ProxyPort;
  627. //
  628. // map the default port value
  629. //
  630. if (port == INTERNET_INVALID_PORT_NUMBER) {
  631. switch (scheme) {
  632. case INTERNET_SCHEME_HTTP:
  633. port = INTERNET_DEFAULT_HTTP_PORT;
  634. break;
  635. case INTERNET_SCHEME_HTTPS:
  636. port = INTERNET_DEFAULT_HTTPS_PORT;
  637. break;
  638. case INTERNET_SCHEME_SOCKS:
  639. port = INTERNET_DEFAULT_SOCKS_PORT;
  640. break;
  641. }
  642. }
  643. *lpHostPort = port;
  644. found = TRUE;
  645. DEBUG_PRINT(PROXY,
  646. INFO,
  647. ("proxy = %s://%s:%d\n",
  648. MapUrlSchemeToName(scheme),
  649. info->_ProxyName.StringAddress(),
  650. port
  651. ));
  652. break;
  653. }
  654. }
  655. UnlockSerializedList(&_List);
  656. quit:
  657. DEBUG_LEAVE(found);
  658. return found;
  659. }
  660. DWORD
  661. PROXY_SERVER_LIST::AddToBypassList(
  662. IN PROXY_BYPASS_LIST * lpBypassList
  663. )
  664. /*++
  665. Routine Description:
  666. For all proxy servers in the server list, we add the details to the bypass
  667. list. By default, an app mustn't send a request to the proxy via the proxy!
  668. Additionally, the app should not have to specifically nominate the proxy
  669. server(s) as bypassing the proxy
  670. Arguments:
  671. lpBypassList - pointer to bypass proxy list where proxy servers will be
  672. added
  673. Return Value:
  674. DWORD
  675. Success - ERROR_SUCCESS
  676. Failure - ERROR_NOT_ENOUGH_MEMORY
  677. --*/
  678. {
  679. DWORD error = ERROR_SUCCESS;
  680. PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  681. while ((entry != (PLIST_ENTRY)SlSelf(&_List)) && (error == ERROR_SUCCESS)) {
  682. PROXY_SERVER_LIST_ENTRY * info = (PROXY_SERVER_LIST_ENTRY *)entry;
  683. if (!lpBypassList->Find(info->_Scheme,
  684. info->_ProxyName.StringAddress(),
  685. info->_ProxyName.StringLength(),
  686. info->_ProxyPort)) {
  687. error = lpBypassList->Add(info->_Scheme,
  688. info->_ProxyName.StringAddress(),
  689. info->_ProxyName.StringLength(),
  690. info->_ProxyPort
  691. );
  692. }
  693. entry = entry->Flink;
  694. }
  695. return error;
  696. }
  697. VOID
  698. PROXY_SERVER_LIST::GetList(
  699. OUT LPSTR * lplpszList,
  700. IN DWORD dwBufferLength,
  701. IN OUT LPDWORD lpdwRequiredLength
  702. )
  703. /*++
  704. Routine Description:
  705. Writes the list of proxy servers to a buffer, and/or returns the required
  706. buffer length
  707. Arguments:
  708. lplpszList - pointer to pointer to buffer where list is written, if
  709. sufficient space
  710. dwBufferLength - amount of space in *lplpszList
  711. lpdwRequiredLength - OUT: cumulative size of data
  712. Return Value:
  713. None.
  714. --*/
  715. {
  716. LPSTR lpszList = *lplpszList;
  717. BOOL firstTime = TRUE;
  718. BOOL outOfBuffer = FALSE;
  719. if (!LockSerializedList(&_List))
  720. return;
  721. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  722. entry != (PLIST_ENTRY)SlSelf(&_List);
  723. entry = entry->Flink) {
  724. PROXY_SERVER_LIST_ENTRY * info;
  725. info = CONTAINING_RECORD(entry, PROXY_SERVER_LIST_ENTRY, _List);
  726. if (!firstTime) {
  727. //
  728. // write delimiter if enough space
  729. //
  730. if (dwBufferLength >= 1) {
  731. *lpszList++ = ' ';
  732. --dwBufferLength;
  733. }
  734. ++*lpdwRequiredLength;
  735. } else {
  736. firstTime = FALSE;
  737. }
  738. //
  739. // find the length of the current entry & write it to the buffer if
  740. // enough space
  741. //
  742. DWORD length = dwBufferLength;
  743. info->WriteEntry(lpszList, &length);
  744. if (dwBufferLength >= length) {
  745. //
  746. // we wrote it
  747. //
  748. dwBufferLength -= length;
  749. } else {
  750. //
  751. // no buffer left
  752. //
  753. dwBufferLength = 0;
  754. outOfBuffer = TRUE;
  755. }
  756. *lpdwRequiredLength += length;
  757. lpszList += length;
  758. }
  759. if (!outOfBuffer) {
  760. if (dwBufferLength > 0) {
  761. *lpszList++ = '\0';
  762. *lplpszList = lpszList;
  763. }
  764. }
  765. //
  766. // add 1 for the terminating NUL
  767. //
  768. ++*lpdwRequiredLength;
  769. UnlockSerializedList(&_List);
  770. }
  771. BOOL
  772. PROXY_BYPASS_LIST_ENTRY::WriteEntry(
  773. OUT LPSTR lpszBuffer,
  774. IN OUT LPDWORD lpdwBufferLength
  775. )
  776. /*++
  777. Routine Description:
  778. Writes this proxy bypass list entry as a string in the supplied buffer
  779. Arguments:
  780. lpszBuffer - pointer to buffer where string is written
  781. lpdwBufferLength - IN: amount of space in buffer
  782. OUT: number of bytes copied, or required size
  783. Return Value:
  784. BOOL
  785. TRUE - entry written to buffer
  786. FALSE - entry not written to buffer - *lpdwBufferLength contains
  787. required size
  788. --*/
  789. {
  790. DWORD requiredLength;
  791. LPSTR schemeName;
  792. DWORD schemeNameLength;
  793. INTERNET_PORT magnitude = 1;
  794. if (_Scheme != INTERNET_SCHEME_DEFAULT) {
  795. schemeName = MapUrlScheme(_Scheme, &schemeNameLength);
  796. requiredLength = schemeNameLength + sizeof("://") - 1;
  797. } else {
  798. schemeName = NULL;
  799. requiredLength = 0;
  800. }
  801. if (IsLocal()) {
  802. requiredLength += sizeof("<local>") - 1;
  803. } else {
  804. requiredLength += _Name.StringLength();
  805. }
  806. if (_Port != INTERNET_INVALID_PORT_NUMBER) {
  807. for (INTERNET_PORT n = 10000, i = 5; n > 0; n /= 10, --i) {
  808. if (_Port / n) {
  809. requiredLength += i + 1;
  810. magnitude = n;
  811. break;
  812. }
  813. }
  814. }
  815. BOOL success;
  816. if (*lpdwBufferLength > requiredLength) {
  817. if (schemeName != NULL) {
  818. memcpy(lpszBuffer, schemeName, schemeNameLength);
  819. lpszBuffer += schemeNameLength;
  820. memcpy(lpszBuffer, "://", sizeof("://") - 1);
  821. lpszBuffer += sizeof("://") - 1;
  822. }
  823. if (IsLocal()) {
  824. memcpy(lpszBuffer, "<local>", sizeof("<local>") - 1);
  825. lpszBuffer += sizeof("<local>") - 1;
  826. } else {
  827. _Name.CopyTo(lpszBuffer);
  828. lpszBuffer += _Name.StringLength();
  829. }
  830. if (_Port != INTERNET_INVALID_PORT_NUMBER) {
  831. *lpszBuffer++ = ':';
  832. for (INTERNET_PORT n = _Port, i = magnitude; i; i /= 10) {
  833. *lpszBuffer++ = (char)(n / i) + '0';
  834. n %= i;
  835. }
  836. }
  837. success = TRUE;
  838. } else {
  839. success = FALSE;
  840. }
  841. *lpdwBufferLength = requiredLength;
  842. return success;
  843. }
  844. DWORD
  845. PROXY_BYPASS_LIST::AddList(
  846. IN LPSTR lpszList
  847. )
  848. /*++
  849. Routine Description:
  850. Parses a list of proxy bypass specifiers and adds them to the list
  851. Arguments:
  852. lpszList - pointer to string containing list of proxy bypass specifiers.
  853. The format is:
  854. [<scheme>"://"][<server>][":"<port>"]
  855. The list can be NULL, in which case we read it from the
  856. registry
  857. Return Value:
  858. DWORD
  859. Success - ERROR_SUCCESS
  860. Failure - ERROR_INVALID_PARAMETER
  861. --*/
  862. {
  863. DEBUG_ENTER((DBG_PROXY,
  864. Dword,
  865. "PROXY_BYPASS_LIST::AddList",
  866. "%.80q",
  867. lpszList
  868. ));
  869. DWORD entryLength;
  870. LPSTR schemeName;
  871. DWORD schemeLength;
  872. LPSTR serverName;
  873. DWORD serverLength;
  874. PARSER_STATE state;
  875. DWORD nSlashes;
  876. INTERNET_PORT port;
  877. BOOL done;
  878. entryLength = 0;
  879. schemeName = lpszList;
  880. schemeLength = 0;
  881. serverName = NULL;
  882. serverLength = 0;
  883. state = STATE_SCHEME;
  884. nSlashes = 0;
  885. port = 0;
  886. done = FALSE;
  887. //
  888. // walk the list, pulling out the various scheme parts
  889. //
  890. do {
  891. char ch = *lpszList++;
  892. if ((nSlashes == 1) && (ch != '/')) {
  893. state = STATE_ERROR;
  894. break;
  895. }
  896. switch (ch) {
  897. case ':':
  898. switch (state) {
  899. case STATE_SCHEME:
  900. if (*lpszList == '/') {
  901. schemeLength = entryLength;
  902. } else if (*lpszList != '\0') {
  903. serverName = schemeName;
  904. serverLength = entryLength;
  905. if (serverLength == 0) {
  906. serverLength = 1;
  907. serverName = "*";
  908. }
  909. state = STATE_PORT;
  910. } else {
  911. state = STATE_ERROR;
  912. }
  913. entryLength = 0;
  914. break;
  915. case STATE_SERVER:
  916. serverLength = entryLength;
  917. state = STATE_PORT;
  918. entryLength = 0;
  919. break;
  920. default:
  921. state = STATE_ERROR;
  922. break;
  923. }
  924. break;
  925. case '/':
  926. if ((state == STATE_SCHEME) && (nSlashes < 2) && (entryLength == 0)) {
  927. if (++nSlashes == 2) {
  928. state = STATE_SERVER;
  929. serverName = lpszList;
  930. }
  931. } else {
  932. state = STATE_ERROR;
  933. }
  934. break;
  935. default:
  936. if (state != STATE_PORT) {
  937. ++entryLength;
  938. } else if (isdigit(ch)) {
  939. //
  940. // BUGBUG - we will overflow if >65535
  941. //
  942. port = port * 10 + (ch - '0');
  943. } else {
  944. //
  945. // STATE_PORT && non-digit character - error
  946. //
  947. state = STATE_ERROR;
  948. }
  949. break;
  950. case '\0':
  951. done = TRUE;
  952. //
  953. // fall through
  954. //
  955. case '\t':
  956. case '\n':
  957. case '\v': // vertical tab, 0x0b
  958. case '\f': // form feed, 0x0c
  959. case '\r':
  960. case ' ':
  961. case ';':
  962. case ',':
  963. if (serverLength == 0) {
  964. serverLength = entryLength;
  965. if ((serverLength == 0)
  966. && ((state == STATE_SERVER) || (state == STATE_PORT))) {
  967. //
  968. // we found e.g. "http://" or "http://:80". We allow this as
  969. // "http://*" or "http://*:80"
  970. //
  971. serverLength = 1;
  972. serverName = "*";
  973. }
  974. }
  975. if (serverLength != 0) {
  976. if (serverName == NULL) {
  977. serverName = schemeName;
  978. }
  979. INTERNET_SCHEME scheme;
  980. if (schemeLength != 0) {
  981. scheme = MapUrlSchemeName(schemeName, schemeLength);
  982. } else {
  983. scheme = INTERNET_SCHEME_DEFAULT;
  984. }
  985. //
  986. // add an entry if this is a protocol we handle and we don't
  987. // already have an entry for it
  988. //
  989. if ((scheme != INTERNET_SCHEME_UNKNOWN)
  990. && !Find(scheme, serverName, serverLength, port)) {
  991. //
  992. // don't worry if Add() fails - we just continue
  993. //
  994. Add(scheme, serverName, serverLength, port);
  995. }
  996. }
  997. entryLength = 0;
  998. schemeName = lpszList;
  999. schemeLength = 0;
  1000. serverName = NULL;
  1001. serverLength = 0;
  1002. nSlashes = 0;
  1003. port = 0;
  1004. state = STATE_SCHEME;
  1005. break;
  1006. }
  1007. if (state == STATE_ERROR) {
  1008. break;
  1009. }
  1010. } while (!done);
  1011. DWORD error;
  1012. if (state == STATE_ERROR) {
  1013. error = ERROR_INVALID_PARAMETER;
  1014. } else {
  1015. error = ERROR_SUCCESS;
  1016. }
  1017. DEBUG_LEAVE(error);
  1018. return error;
  1019. }
  1020. BOOL
  1021. PROXY_BYPASS_LIST::Find(
  1022. IN INTERNET_SCHEME tScheme,
  1023. IN LPSTR lpszHostName OPTIONAL,
  1024. IN DWORD dwHostNameLength,
  1025. IN INTERNET_PORT nPort
  1026. )
  1027. /*++
  1028. Routine Description:
  1029. Determines if a proxy bypass entry matches the criteria.
  1030. Currently, name matching is simplistic: e.g. "*.com" and "**.com" are
  1031. treated as 2 separate strings, where we should collapse multiple wildcard
  1032. specifiers, etc. Also: "w*" should replace "ww*", etc.
  1033. Arguments:
  1034. tScheme - scheme for this entry
  1035. lpszHostName - host name or address. May contain wildcards (*)
  1036. dwHostNameLength - length of host name or address
  1037. nPort - port
  1038. Return Value:
  1039. BOOL
  1040. TRUE - an entry corresponding to the arguments was found
  1041. FALSE - didn't find entry
  1042. --*/
  1043. {
  1044. DEBUG_ENTER((DBG_PROXY,
  1045. Bool,
  1046. "PROXY_BYPASS_LIST::Find",
  1047. "%s, %.*q, %d, %d",
  1048. InternetMapScheme(tScheme),
  1049. dwHostNameLength,
  1050. lpszHostName,
  1051. dwHostNameLength,
  1052. nPort
  1053. ));
  1054. BOOL isLocal = IsLocalMacro(lpszHostName, dwHostNameLength);
  1055. BOOL found = FALSE;
  1056. if (!LockSerializedList(&_List))
  1057. goto quit;
  1058. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  1059. entry != (PLIST_ENTRY)SlSelf(&_List);
  1060. entry = entry->Flink) {
  1061. PROXY_BYPASS_LIST_ENTRY * info;
  1062. info = CONTAINING_RECORD(entry, PROXY_BYPASS_LIST_ENTRY, _List);
  1063. //
  1064. // do the easy bits first
  1065. //
  1066. if (!((info->_Scheme == tScheme)
  1067. || (info->_Scheme == INTERNET_SCHEME_DEFAULT))) {
  1068. continue;
  1069. }
  1070. if (!((info->_Port == nPort)
  1071. || (info->_Port == INTERNET_INVALID_PORT_NUMBER))) {
  1072. continue;
  1073. }
  1074. //
  1075. // check for name match
  1076. //
  1077. if (info->_LocalSemantics) {
  1078. if (isLocal) {
  1079. found = TRUE;
  1080. break;
  1081. } else {
  1082. continue;
  1083. }
  1084. }
  1085. //
  1086. // not local semantics, have to match target
  1087. //
  1088. //
  1089. // BUGBUG - we only do simplistic matching. If the strings don't match
  1090. // exactly, except for case, they are deemed to be different
  1091. //
  1092. if (info->_Name.Strnicmp(lpszHostName, (int)dwHostNameLength) != 0) {
  1093. continue;
  1094. }
  1095. //
  1096. // any path that didn't continue, or has not already broken out has
  1097. // succeeded in finding a match
  1098. //
  1099. DEBUG_PRINT(PROXY,
  1100. INFO,
  1101. ("Matched: %q, %q\n",
  1102. lpszHostName,
  1103. info->_Name.StringAddress()
  1104. ));
  1105. found = TRUE;
  1106. break;
  1107. }
  1108. UnlockSerializedList(&_List);
  1109. quit:
  1110. DEBUG_LEAVE(found);
  1111. return found;
  1112. }
  1113. DWORD
  1114. PROXY_BYPASS_LIST::Add(
  1115. IN INTERNET_SCHEME tScheme,
  1116. IN LPSTR lpszHostName,
  1117. IN DWORD dwHostNameLength,
  1118. IN INTERNET_PORT nPort
  1119. )
  1120. /*++
  1121. Routine Description:
  1122. Create and add a PROXY_BYPASS_LIST_ENTRY to the PROXY_BYPASS_LIST
  1123. Arguments:
  1124. tScheme - scheme to bypass. May be 0 meaning any protocol
  1125. lpszHostName - name of host to bypass. May be name or IP address and
  1126. may contain wildcard characters
  1127. dwHostNameLength - length of bypass name string
  1128. nPort - port to bypass. May be 0, meaning any port
  1129. Return Value:
  1130. DWORD
  1131. Success - ERROR_SUCCESS
  1132. Failure - ERROR_NOT_ENOUGH_MEMORY
  1133. --*/
  1134. {
  1135. DEBUG_ENTER((DBG_PROXY,
  1136. Dword,
  1137. "PROXY_BYPASS_LIST::Add",
  1138. "%s, %.*q, %d, %d",
  1139. InternetMapScheme(tScheme),
  1140. dwHostNameLength,
  1141. lpszHostName,
  1142. dwHostNameLength,
  1143. nPort
  1144. ));
  1145. PROXY_BYPASS_LIST_ENTRY * entry;
  1146. entry = New PROXY_BYPASS_LIST_ENTRY(tScheme,
  1147. lpszHostName,
  1148. dwHostNameLength,
  1149. nPort
  1150. );
  1151. DWORD error = ERROR_SUCCESS;
  1152. if (entry != NULL) {
  1153. //
  1154. // if the bypass entry uses local name matching semantics, then we add
  1155. // it to the end of the list, else the head. The reason we do this is
  1156. // to allow <local> to be a default after all other (possibly also
  1157. // local) entries are checked
  1158. //
  1159. if (entry->IsLocal()) {
  1160. if (!InsertAtTailOfSerializedList(&_List, &entry->_List)) {
  1161. delete entry;
  1162. error = ERROR_NOT_ENOUGH_MEMORY;
  1163. }
  1164. } else {
  1165. if (!InsertAtHeadOfSerializedList(&_List, &entry->_List)) {
  1166. delete entry;
  1167. error = ERROR_NOT_ENOUGH_MEMORY;
  1168. }
  1169. }
  1170. } else {
  1171. error = ERROR_NOT_ENOUGH_MEMORY;
  1172. }
  1173. DEBUG_LEAVE(error);
  1174. return error;
  1175. }
  1176. BOOL
  1177. PROXY_BYPASS_LIST::IsBypassed(
  1178. IN INTERNET_HANDLE_OBJECT* pSessionObject,
  1179. IN INTERNET_SCHEME tScheme,
  1180. IN LPSTR lpszHostName,
  1181. IN DWORD dwHostNameLength,
  1182. IN INTERNET_PORT nPort
  1183. )
  1184. /*++
  1185. Routine Description:
  1186. Determines if a scheme/name/port is bypassed
  1187. Arguments:
  1188. tScheme - can be 0, meaning match any scheme
  1189. lpszHostName - can contain wildcards. May be name or IP address
  1190. dwHostNameLength - length of name/address part. May be 0, meaning match
  1191. any name/address
  1192. nPort - can be 0, meaning match any port
  1193. Return Value:
  1194. BOOL
  1195. TRUE - an entry on the bypass list matched the criteria
  1196. FALSE - the host identified by the parameters is not on this bypass
  1197. list
  1198. --*/
  1199. {
  1200. DEBUG_ENTER((DBG_PROXY,
  1201. Bool,
  1202. "PROXY_BYPASS_LIST::IsBypassed",
  1203. "%s, %.*q, %d, %d",
  1204. InternetMapScheme(tScheme),
  1205. dwHostNameLength,
  1206. lpszHostName,
  1207. dwHostNameLength,
  1208. nPort
  1209. ));
  1210. INET_ASSERT(lpszHostName != NULL);
  1211. INET_ASSERT(dwHostNameLength != 0);
  1212. //
  1213. // determine if what we were given is an address, in which case we don't
  1214. // perform <local> semantics matching
  1215. //
  1216. BOOL isAddress = FALSE;
  1217. LPSTR mappedName = NULL;
  1218. LPSTR allocedName = NULL;
  1219. if (dwHostNameLength <= MAX_IP_ADDRESS_STRING_LENGTH) {
  1220. char addressBuffer[MAX_IP_ADDRESS_STRING_LENGTH + 1];
  1221. //
  1222. // make the host name/address an ASCIIZ string
  1223. //
  1224. memcpy((LPVOID)addressBuffer, (LPVOID)lpszHostName, dwHostNameLength);
  1225. addressBuffer[dwHostNameLength] = '\0';
  1226. if (_I_inet_addr(addressBuffer) != INADDR_NONE) {
  1227. //
  1228. // looks like we were given an IP address
  1229. //
  1230. //
  1231. // maybe this is the IP address of a known server (in cache)
  1232. //
  1233. mappedName = MapNetAddressToName(pSessionObject, addressBuffer, &allocedName);
  1234. if (mappedName == addressBuffer) {
  1235. //
  1236. // BUGBUG - transport independence?
  1237. //
  1238. isAddress = TRUE;
  1239. } else {
  1240. lpszHostName = mappedName;
  1241. dwHostNameLength = lstrlen(lpszHostName);
  1242. }
  1243. }
  1244. }
  1245. BOOL found;
  1246. found = IsHostInBypassList (
  1247. tScheme,
  1248. lpszHostName,
  1249. dwHostNameLength,
  1250. nPort,
  1251. isAddress);
  1252. if (allocedName != NULL) {
  1253. allocedName = (LPSTR)FREE_MEMORY(allocedName);
  1254. INET_ASSERT(allocedName == NULL);
  1255. }
  1256. DEBUG_LEAVE(found);
  1257. return found;
  1258. }
  1259. BOOL
  1260. PROXY_BYPASS_LIST::IsHostInBypassList(
  1261. IN INTERNET_SCHEME tScheme,
  1262. IN LPSTR lpszHostName,
  1263. IN DWORD dwHostNameLength,
  1264. IN INTERNET_PORT nPort,
  1265. IN BOOL isAddress
  1266. )
  1267. /*++
  1268. Routine Description:
  1269. description-of-function.
  1270. Arguments:
  1271. tScheme -
  1272. lpszHostName -
  1273. dwHostNameLength -
  1274. nPort -
  1275. isAddress -
  1276. Return Value:
  1277. BOOL
  1278. --*/
  1279. {
  1280. DEBUG_ENTER((DBG_PROXY,
  1281. Bool,
  1282. "PROXY_BYPASS_LIST::IsHostInBypassList",
  1283. "%d (%s), %.*q, %d, %d, %B",
  1284. tScheme,
  1285. InternetMapScheme(tScheme),
  1286. dwHostNameLength,
  1287. lpszHostName,
  1288. dwHostNameLength,
  1289. nPort,
  1290. isAddress
  1291. ));
  1292. BOOL found = FALSE;
  1293. //
  1294. // if not an address, determine if the name contains at least one dot
  1295. //
  1296. BOOL isDot;
  1297. if (!isAddress) {
  1298. isDot = FALSE;
  1299. for (DWORD i = 0; i < dwHostNameLength; ++i) {
  1300. if (lpszHostName[i] == '.') {
  1301. isDot = TRUE;
  1302. break;
  1303. }
  1304. }
  1305. } else {
  1306. //
  1307. // addresses have dots
  1308. //
  1309. isDot = TRUE;
  1310. }
  1311. if (!LockSerializedList(&_List))
  1312. goto quit;
  1313. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  1314. entry != (PLIST_ENTRY)SlSelf(&_List);
  1315. entry = entry->Flink) {
  1316. PROXY_BYPASS_LIST_ENTRY * info;
  1317. info = CONTAINING_RECORD(entry, PROXY_BYPASS_LIST_ENTRY, _List);
  1318. //
  1319. // do the easy bits first
  1320. //
  1321. if (!((info->_Scheme == tScheme)
  1322. || (info->_Scheme == INTERNET_SCHEME_DEFAULT))) {
  1323. continue;
  1324. }
  1325. if (!((info->_Port == nPort)
  1326. || (info->_Port == INTERNET_INVALID_PORT_NUMBER))) {
  1327. continue;
  1328. }
  1329. //
  1330. // check local semantics
  1331. //
  1332. if (info->_LocalSemantics) {
  1333. if (!isDot) {
  1334. DEBUG_PRINT(PROXY,
  1335. INFO,
  1336. ("%q matched by <local>\n",
  1337. lpszHostName
  1338. ));
  1339. found = TRUE;
  1340. //
  1341. // <local> is in the bypass list and the name does not contain a
  1342. // dot. It bypasses the proxy
  1343. //
  1344. break;
  1345. } else {
  1346. //
  1347. // the name contains a dot, but it may be matched by another
  1348. // proxy bypass entry
  1349. //
  1350. continue;
  1351. }
  1352. }
  1353. //
  1354. // check for name match. Note that we take no special action if the host
  1355. // name contains wildcard characters
  1356. //
  1357. LPSTR target = info->_Name.StringAddress();
  1358. //
  1359. // NULL target name matches any server name/address
  1360. //
  1361. if (target != NULL) {
  1362. DEBUG_PRINT(PROXY,
  1363. INFO,
  1364. ("trying to match %q with %q\n",
  1365. lpszHostName,
  1366. target
  1367. ));
  1368. DWORD i = 0;
  1369. DWORD j = 0;
  1370. DWORD i_back = (DWORD)-1;
  1371. while ((target[i] != '\0') && (j < dwHostNameLength)) {
  1372. if (target[i] == tolower(lpszHostName[j])) {
  1373. ++i;
  1374. ++j;
  1375. } else if (target[i] == '*') {
  1376. while (target[i + 1] == '*') {
  1377. ++i;
  1378. }
  1379. i_back = i;
  1380. ++i;
  1381. while ((tolower(lpszHostName[j]) != target[i])
  1382. && (j < dwHostNameLength)) {
  1383. ++j;
  1384. }
  1385. } else if (i_back != (DWORD)-1) {
  1386. //
  1387. // '*' is greedy closure. We already saw a '*' but later we
  1388. // discovered a mismatch. We will go back and try to eat as
  1389. // many characters as we can till the next match, or we hit
  1390. // the end of the string
  1391. //
  1392. i = i_back;
  1393. } else {
  1394. //
  1395. // no match; quit
  1396. //
  1397. j = 0;
  1398. break;
  1399. }
  1400. //
  1401. // if we reached the end of the target, but not the host name
  1402. // AND we already met a '*' then back up
  1403. //
  1404. if ((target[i] == '\0')
  1405. && (j != dwHostNameLength)
  1406. && (i_back != (DWORD)-1)) {
  1407. i = i_back;
  1408. }
  1409. }
  1410. //
  1411. // if we hit the end of the host name while matching any character,
  1412. // bump the target to the next non-star character
  1413. //
  1414. while (target[i] == '*') {
  1415. ++i;
  1416. }
  1417. //
  1418. // the host name matched if we reached the end of the target and end
  1419. // of the host name
  1420. //
  1421. if (!((target[i] == '\0') && (j == dwHostNameLength))) {
  1422. continue;
  1423. }
  1424. }
  1425. //
  1426. // any path that didn't continue, or has not already broken out has
  1427. // succeeded in finding a match
  1428. //
  1429. DEBUG_PRINT(PROXY,
  1430. INFO,
  1431. ("Matched: %q, %q\n",
  1432. lpszHostName,
  1433. target
  1434. ));
  1435. found = TRUE;
  1436. break;
  1437. }
  1438. UnlockSerializedList(&_List);
  1439. //
  1440. // "localhost", "loopback" and "127.0.0.1" always bypass proxy
  1441. //
  1442. if (!found)
  1443. {
  1444. if ((strnicmp(lpszHostName, "localhost", dwHostNameLength) == 0) ||
  1445. (strnicmp(lpszHostName, "loopback", dwHostNameLength) == 0))
  1446. {
  1447. found = TRUE;
  1448. }
  1449. else //
  1450. // if the host name length is of reasonable size, it may represent
  1451. // the IP address of loopback (127.0.0.1 or its variations).
  1452. //
  1453. if (dwHostNameLength < 16)
  1454. {
  1455. static ULONG ipAddr127_0_0_1 = INADDR_NONE;
  1456. char szHostName[16];
  1457. INET_ASSERT(dwHostNameLength < 16);
  1458. lstrcpyn(szHostName,
  1459. lpszHostName,
  1460. (dwHostNameLength + 1) // must add in "+1" for the NULL char
  1461. );
  1462. //
  1463. // convert "127.0.0.1" to a DWORD once, and save it.
  1464. //
  1465. if (ipAddr127_0_0_1 == INADDR_NONE)
  1466. {
  1467. ipAddr127_0_0_1 = _I_inet_addr("127.0.0.1");
  1468. INET_ASSERT(ipAddr127_0_0_1 != INADDR_NONE);
  1469. }
  1470. found = (_I_inet_addr(szHostName) == ipAddr127_0_0_1);
  1471. }
  1472. }
  1473. quit:
  1474. DEBUG_LEAVE(found);
  1475. return found;
  1476. }
  1477. VOID
  1478. PROXY_BYPASS_LIST::GetList(
  1479. OUT LPSTR * lplpszList,
  1480. IN DWORD dwBufferLength,
  1481. IN OUT LPDWORD lpdwRequiredLength
  1482. )
  1483. /*++
  1484. Routine Description:
  1485. Writes the list of proxy bypass servers to a buffer, and/or returns the
  1486. required buffer length
  1487. Arguments:
  1488. lplpszList - pointer to pointer to buffer where list is written, if
  1489. sufficient space
  1490. dwBufferLength - amount of space in *lplpszList
  1491. lpdwRequiredLength - OUT: cumulative size of data
  1492. Return Value:
  1493. None.
  1494. --*/
  1495. {
  1496. LPSTR lpszList = *lplpszList;
  1497. BOOL firstTime = TRUE;
  1498. BOOL outOfBuffer = FALSE;
  1499. if (!LockSerializedList(&_List))
  1500. return;
  1501. for (PLIST_ENTRY entry = HeadOfSerializedList(&_List);
  1502. entry != (PLIST_ENTRY)SlSelf(&_List);
  1503. entry = entry->Flink) {
  1504. PROXY_BYPASS_LIST_ENTRY * info;
  1505. info = CONTAINING_RECORD(entry, PROXY_BYPASS_LIST_ENTRY, _List);
  1506. if (!firstTime) {
  1507. //
  1508. // write delimiter if enough space
  1509. //
  1510. if (dwBufferLength >= 1) {
  1511. *lpszList++ = ' ';
  1512. --dwBufferLength;
  1513. }
  1514. ++*lpdwRequiredLength;
  1515. } else {
  1516. firstTime = FALSE;
  1517. }
  1518. //
  1519. // find the length of the current entry & write it to the buffer if
  1520. // enough space
  1521. //
  1522. DWORD length = dwBufferLength;
  1523. info->WriteEntry(lpszList, &length);
  1524. if (dwBufferLength >= length) {
  1525. //
  1526. // we wrote it
  1527. //
  1528. dwBufferLength -= length;
  1529. } else {
  1530. //
  1531. // no buffer left
  1532. //
  1533. dwBufferLength = 0;
  1534. outOfBuffer = TRUE;
  1535. }
  1536. *lpdwRequiredLength += length;
  1537. lpszList += length;
  1538. }
  1539. if (!outOfBuffer) {
  1540. if (dwBufferLength > 0) {
  1541. *lpszList++ = '\0';
  1542. *lplpszList = lpszList;
  1543. }
  1544. }
  1545. //
  1546. // add 1 for the terminating NUL
  1547. //
  1548. ++*lpdwRequiredLength;
  1549. UnlockSerializedList(&_List);
  1550. }
  1551. //
  1552. // PROXY_INFO - methods are defined below
  1553. //
  1554. VOID
  1555. PROXY_INFO::InitializeProxySettings(
  1556. VOID
  1557. )
  1558. /*++
  1559. Routine Description:
  1560. Initalizes Proxy_Info objects
  1561. Arguments:
  1562. None.
  1563. Return Value:
  1564. None.
  1565. --*/
  1566. {
  1567. _ProxyServerList = NULL;
  1568. _ProxyBypassList = NULL;
  1569. _fDisableDirect = FALSE;
  1570. _fModifiedInProcess = FALSE;
  1571. _Lock.Initialize();
  1572. _Error = _Lock.IsInitialized()
  1573. ? ERROR_SUCCESS
  1574. : ERROR_WINHTTP_INTERNAL_ERROR;
  1575. }
  1576. VOID
  1577. PROXY_INFO::TerminateProxySettings(
  1578. VOID
  1579. )
  1580. /*++
  1581. Routine Description:
  1582. Cleans up and destroys Proxy_Info objects
  1583. Arguments:
  1584. None.
  1585. Return Value:
  1586. None.
  1587. --*/
  1588. {
  1589. //DEBUG_ENTER((DBG_OBJECTS,
  1590. // None,
  1591. // "PROXY_INFO::TerminateProxySettings",
  1592. // NULL
  1593. // ));
  1594. Lock(TRUE);
  1595. CleanOutLists();
  1596. Unlock();
  1597. //DEBUG_LEAVE(0);
  1598. }
  1599. DWORD
  1600. PROXY_INFO::SetProxySettings(
  1601. IN LPINTERNET_PROXY_INFO_EX lpProxySettings,
  1602. IN BOOL fModifiedInProcess
  1603. )
  1604. /*++
  1605. Routine Description:
  1606. Sets the proxy info. Either creates new proxy server and bypass lists, or
  1607. removes them (proxy to direct)
  1608. Assumes: 1. The parameters have already been validated in the API that calls
  1609. this method (i.e. InternetOpen(), InternetSetOption())
  1610. Arguments:
  1611. lpProxySettings - a set of relevent fields describing proxy settings
  1612. fModifiedInProcess - TRUE, if this object keeps a seperate set of values from those
  1613. stored in the registry store
  1614. Return Value:
  1615. DWORD
  1616. Success - ERROR_SUCCESS
  1617. Failure - ERROR_INVALID_PARAMETER
  1618. The lpszProxy or lpszProxyBypass list was bad
  1619. ERROR_NOT_ENOUGH_MEMORY
  1620. Failed to create an object or allocate space for a list,
  1621. etc.
  1622. --*/
  1623. {
  1624. DEBUG_ENTER((DBG_PROXY,
  1625. Dword,
  1626. "PROXY_INFO::SetProxySettings",
  1627. "%x, %B",
  1628. lpProxySettings,
  1629. fModifiedInProcess
  1630. ));
  1631. //
  1632. // parameters should already be validated by caller
  1633. //
  1634. BOOL newList;
  1635. BOOL possibleNewAutoProxy;
  1636. LPCTSTR serverList;
  1637. LPCTSTR bypassList;
  1638. DWORD error = ERROR_SUCCESS;
  1639. serverList = NULL;
  1640. bypassList = NULL;
  1641. newList = FALSE;
  1642. _fModifiedInProcess = fModifiedInProcess;
  1643. _dwSettingsVersion = lpProxySettings->dwCurrentSettingsVersion;
  1644. UPDATE_GLOBAL_PROXY_VERSION();
  1645. if ( lpProxySettings->dwFlags & PROXY_TYPE_PROXY )
  1646. {
  1647. serverList = lpProxySettings->lpszProxy;
  1648. bypassList = lpProxySettings->lpszProxyBypass;
  1649. if (serverList != NULL) {
  1650. newList = TRUE;
  1651. }
  1652. }
  1653. //
  1654. // about to start changing contents - acquire lock
  1655. //
  1656. Lock(TRUE);
  1657. // remember disable direct flag...
  1658. SetDisableDirect( (lpProxySettings->dwFlags & PROXY_TYPE_DIRECT) ? FALSE : TRUE );
  1659. //
  1660. // clear out current contents,
  1661. //
  1662. CleanOutLists();
  1663. //
  1664. // Set the Static Proxy Lists
  1665. //
  1666. if (newList)
  1667. {
  1668. INET_ASSERT((serverList != NULL) && (*serverList != 0));
  1669. _ProxyServerList = New PROXY_SERVER_LIST(serverList);
  1670. _ProxyBypassList = New PROXY_BYPASS_LIST(bypassList);
  1671. if ((_ProxyServerList != NULL) && (_ProxyBypassList != NULL)) {
  1672. _Error = _ProxyServerList->GetError();
  1673. if (_Error == ERROR_SUCCESS) {
  1674. _Error = _ProxyBypassList->GetError();
  1675. if (_Error == ERROR_SUCCESS) {
  1676. //
  1677. // add all proxy servers to bypass list
  1678. //
  1679. _ProxyServerList->AddToBypassList(_ProxyBypassList);
  1680. }
  1681. }
  1682. } else {
  1683. _Error = ERROR_NOT_ENOUGH_MEMORY;
  1684. CleanOutLists();
  1685. }
  1686. error = _Error;
  1687. }
  1688. //
  1689. // other threads free to access this PROXY_INFO again
  1690. //
  1691. Unlock();
  1692. DEBUG_LEAVE(error);
  1693. return error;
  1694. }
  1695. DWORD
  1696. PROXY_INFO::GetProxySettings(
  1697. OUT LPINTERNET_PROXY_INFO_EX lpProxySettings,
  1698. IN BOOL fCheckVersion = FALSE
  1699. )
  1700. /*++
  1701. Routine Description:
  1702. Gets the proxy info.
  1703. Assumes: 1. The parameters have already been validated in the API that calls
  1704. this method (i.e. InternetOpen(), InternetSetOption())
  1705. Arguments:
  1706. lpProxySettings - a set of relevent fields describing proxy settings
  1707. fCheckVersion - ignored
  1708. Return Value:
  1709. DWORD
  1710. Success - ERROR_SUCCESS
  1711. Failure -
  1712. --*/
  1713. {
  1714. DEBUG_ENTER((DBG_PROXY,
  1715. Dword,
  1716. "PROXY_INFO::GetProxySettings",
  1717. "%x, %B",
  1718. lpProxySettings,
  1719. fCheckVersion
  1720. ));
  1721. DWORD error = ERROR_SUCCESS;
  1722. if ( fCheckVersion == TRUE )
  1723. {
  1724. INET_ASSERT(FALSE);
  1725. error = ERROR_INVALID_PARAMETER;
  1726. goto quit;
  1727. }
  1728. //
  1729. // about to start reading contents - acquire lock
  1730. //
  1731. Lock(FALSE);
  1732. if ( ! IsDisableDirect() ) {
  1733. lpProxySettings->dwFlags |= PROXY_TYPE_DIRECT;
  1734. }
  1735. if ( IsProxySettingsConfigured() )
  1736. {
  1737. lpProxySettings->dwFlags |= PROXY_TYPE_PROXY;
  1738. lpProxySettings->lpszProxy = _ProxyServerList->CopyString();
  1739. lpProxySettings->lpszProxyBypass = _ProxyBypassList->CopyString();
  1740. if ( lpProxySettings->lpszProxy == NULL ||
  1741. lpProxySettings->lpszProxyBypass == NULL )
  1742. {
  1743. error = ERROR_NOT_ENOUGH_MEMORY;
  1744. }
  1745. }
  1746. //
  1747. // other threads free to access this PROXY_INFO again
  1748. //
  1749. Unlock();
  1750. quit:
  1751. DEBUG_LEAVE(error);
  1752. return error;
  1753. }
  1754. DWORD
  1755. PROXY_INFO::RefreshProxySettings(
  1756. IN BOOL fForceRefresh
  1757. )
  1758. /*++
  1759. Routine Description:
  1760. Refreshes the Proxy Information
  1761. This doesn't make sense on PROXY_INFO, nothing done
  1762. Arguments:
  1763. fForceRefresh - forces a resync of all settings, turning this on slows things down
  1764. Return Value:
  1765. DWORD
  1766. Success - ERROR_SUCCESS
  1767. Failure -
  1768. --*/
  1769. {
  1770. DEBUG_ENTER((DBG_PROXY,
  1771. Dword,
  1772. "PROXY_INFO::RefreshProxySettings",
  1773. "%B",
  1774. fForceRefresh
  1775. ));
  1776. DEBUG_LEAVE(ERROR_SUCCESS);
  1777. return ERROR_SUCCESS;
  1778. }
  1779. DWORD
  1780. PROXY_INFO::QueryProxySettings(
  1781. IN AUTO_PROXY_ASYNC_MSG **ppQueryForProxyInfo
  1782. )
  1783. /*++
  1784. Routine Description:
  1785. Determines what proxy type, proxy name, and port the caller should use
  1786. given an Url, its length, a target host, a target port, and output space
  1787. to store the result.
  1788. The result may be a complete string containing a Netscape style string with
  1789. a delimited set of proxies, and access methods. An example of this may
  1790. look like:
  1791. "PROXY itgproxy:80; PROXY proxy:80; PROXY 192.168.100.2:1080; SOCKS 192.168.100.2; DIRECT"
  1792. This means we must try itgproxy, if this proxy fails we go on to proxy, and on to 192.168.100.2, etc.
  1793. Note that if itgproxy, proxy, and 192.168.100.2 all fail we can try a SOCKS proxy, and if this fails we
  1794. can try a direct connection.
  1795. If there is an external proxy DLL registered and valid, we defer to it to decide
  1796. what proxy to use, and thus ignore internal proxy information.
  1797. Note this function can also be used to retrive mapping of protocol to proxy. For example,
  1798. if tUrlProtocol == INTERNET_SCHEME_FTP, the result *lptProxyScheme == INTERNET_SCHEME_SOCKS
  1799. which means we should use a socks proxy/firewall for FTP accesss.
  1800. Arguments:
  1801. tScheme - can be 0, meaning match any scheme
  1802. lpszHostName - can contain wildcards. May be name or IP address
  1803. nPort - can be 0, meaning match any port
  1804. pfAutoProxy - TRUE if an auto-proxy is being used.
  1805. Return Value:
  1806. BOOL
  1807. TRUE - an entry on the bypass list matched the criteria
  1808. FALSE - the host identified by the parameters is not on this bypass
  1809. list
  1810. --*/
  1811. {
  1812. DEBUG_ENTER((DBG_PROXY,
  1813. Dword,
  1814. "PROXY_INFO::QueryProxySettings",
  1815. "%#X",
  1816. ppQueryForProxyInfo
  1817. ));
  1818. AUTO_PROXY_ASYNC_MSG *pQueryForProxyInfo = *ppQueryForProxyInfo;
  1819. INTERNET_SCHEME tProxyScheme = pQueryForProxyInfo->_tUrlProtocol;
  1820. BOOL fIsByPassed = FALSE;
  1821. BOOL fProxyConnect = FALSE;
  1822. DWORD error = ERROR_SUCCESS;
  1823. Lock(FALSE);
  1824. if (!IsProxySettingsConfigured()) // virtual func, perhaps replace with faster internal?
  1825. {
  1826. fProxyConnect = FALSE;
  1827. goto quit;
  1828. }
  1829. //
  1830. // Ok, if we're here we are NOT using the Auto-Proxy DLL.
  1831. // 1. Determine if we are Bypassed ( and thus prevented from using a proxy )
  1832. // 2. Map the Protocol to a Proxy type.
  1833. // 3. Grab the hostname of the proxy we wish to use.
  1834. //
  1835. if ( pQueryForProxyInfo->_lpszUrlHostName && pQueryForProxyInfo->_dwUrlHostNameLength > 0 )
  1836. {
  1837. fIsByPassed = IsBypassed(
  1838. pQueryForProxyInfo->_tUrlProtocol,
  1839. pQueryForProxyInfo->_lpszUrlHostName,
  1840. pQueryForProxyInfo->_dwUrlHostNameLength,
  1841. pQueryForProxyInfo->_nUrlPort
  1842. );
  1843. if ( fIsByPassed )
  1844. {
  1845. goto quit;
  1846. }
  1847. }
  1848. pQueryForProxyInfo->_tProxyScheme = ProxyScheme(pQueryForProxyInfo->_tUrlProtocol);
  1849. if ( pQueryForProxyInfo->_tProxyScheme == INTERNET_SCHEME_UNKNOWN )
  1850. {
  1851. pQueryForProxyInfo->_tProxyScheme = INTERNET_SCHEME_SOCKS;
  1852. pQueryForProxyInfo->_tUrlProtocol = INTERNET_SCHEME_SOCKS;
  1853. }
  1854. if (pQueryForProxyInfo->_bFreeProxyHostName
  1855. && (pQueryForProxyInfo->_lpszProxyHostName != NULL)) {
  1856. FREE_MEMORY(pQueryForProxyInfo->_lpszProxyHostName);
  1857. }
  1858. fProxyConnect = GetProxyHostName(
  1859. pQueryForProxyInfo->_tUrlProtocol,
  1860. &(pQueryForProxyInfo->_tProxyScheme),
  1861. &(pQueryForProxyInfo->_lpszProxyHostName),
  1862. &(pQueryForProxyInfo->_bFreeProxyHostName),
  1863. &(pQueryForProxyInfo->_dwProxyHostNameLength),
  1864. &(pQueryForProxyInfo->_nProxyHostPort)
  1865. );
  1866. quit:
  1867. pQueryForProxyInfo->_dwQueryResult = (DWORD) fProxyConnect;
  1868. //
  1869. // If we've disabled direct connections, then fail
  1870. // when there is no proxy
  1871. //
  1872. if ( !fProxyConnect && IsDisableDirect() ) {
  1873. error = ERROR_WINHTTP_CANNOT_CONNECT;
  1874. }
  1875. Unlock();
  1876. DEBUG_LEAVE(error);
  1877. return error;
  1878. }
  1879. DWORD
  1880. PROXY_INFO::GetProxyStringInfo(
  1881. OUT LPVOID lpBuffer,
  1882. IN OUT LPDWORD lpdwBufferLength
  1883. )
  1884. /*++
  1885. Routine Description:
  1886. IMPORTANT PLEASE READ: LEGACY FUNCTION, this does not support all the new
  1887. proxy behaviors, left here for Wininet compat with older programs
  1888. Returns the proxy server and bypass lists in an INTERNET_PROXY_INFO. Called
  1889. by InternetQueryOption(WINHTTP_OPTION_PROXY)
  1890. Assumes: Access to this is serialized while we are getting this info
  1891. Arguments:
  1892. lpBuffer - pointer to buffer where information will be returned
  1893. lpdwBufferLength - IN: size of lpBuffer in BYTEs
  1894. OUT: number of BYTEs returned in lpBuffer
  1895. Return Value:
  1896. DWORD
  1897. Success - ERROR_SUCCESS
  1898. Failure - ERROR_INSUFFICIENT_BUFFER
  1899. *lpdwBufferLength contains the required buffer length
  1900. --*/
  1901. {
  1902. DEBUG_ENTER((DBG_PROXY,
  1903. Dword,
  1904. "PROXY_INFO::GetProxyStringInfo",
  1905. "%#x, %#x [%d]",
  1906. lpBuffer,
  1907. lpdwBufferLength,
  1908. *lpdwBufferLength
  1909. ));
  1910. DEBUG_PRINT(PROXY,
  1911. INFO,
  1912. ("Calling Legacy GetProxyStringInfo, NEW CODE SHOULD AVOID THIS CODE PATH\n"
  1913. ));
  1914. DWORD requiredSize = sizeof(WINHTTP_PROXY_INFOA);
  1915. LPSTR lpVariable = (LPSTR)(((WINHTTP_PROXY_INFOA *)lpBuffer) + 1);
  1916. LPSTR lpszProxy;
  1917. Lock(FALSE);
  1918. if (_ProxyServerList != NULL) {
  1919. lpszProxy = lpVariable;
  1920. _ProxyServerList->GetList(&lpVariable,
  1921. (*lpdwBufferLength > requiredSize)
  1922. ? (*lpdwBufferLength - requiredSize)
  1923. : 0,
  1924. &requiredSize
  1925. );
  1926. } else {
  1927. lpszProxy = NULL;
  1928. }
  1929. LPSTR lpszProxyBypass;
  1930. if (_ProxyBypassList != NULL) {
  1931. DWORD size = requiredSize;
  1932. lpszProxyBypass = lpVariable;
  1933. _ProxyBypassList->GetList(&lpVariable,
  1934. (*lpdwBufferLength > requiredSize)
  1935. ? (*lpdwBufferLength - requiredSize)
  1936. : 0,
  1937. &requiredSize
  1938. );
  1939. if (requiredSize == size) {
  1940. lpszProxyBypass = NULL;
  1941. }
  1942. } else {
  1943. lpszProxyBypass = NULL;
  1944. }
  1945. DWORD error;
  1946. if (*lpdwBufferLength >= requiredSize) {
  1947. LPINTERNET_PROXY_INFO lpInfo = (LPINTERNET_PROXY_INFO)lpBuffer;
  1948. lpInfo->dwAccessType = (lpszProxy == NULL)
  1949. ? INTERNET_OPEN_TYPE_DIRECT
  1950. : INTERNET_OPEN_TYPE_PROXY;
  1951. lpInfo->lpszProxy = lpszProxy;
  1952. lpInfo->lpszProxyBypass = lpszProxyBypass;
  1953. error = ERROR_SUCCESS;
  1954. } else {
  1955. error = ERROR_INSUFFICIENT_BUFFER;
  1956. }
  1957. *lpdwBufferLength = requiredSize;
  1958. Unlock();
  1959. DEBUG_LEAVE(error);
  1960. return error;
  1961. }
  1962. BOOL
  1963. PROXY_INFO::RedoSendRequest(
  1964. IN OUT LPDWORD lpdwError,
  1965. IN DWORD dwSecureStatus,
  1966. IN AUTO_PROXY_ASYNC_MSG *pQueryForProxyInfo,
  1967. IN CServerInfo *pOriginServer,
  1968. IN CServerInfo *pProxyServer
  1969. )
  1970. /*++
  1971. Routine Description:
  1972. Determines whether a connection needs to be retried do to a failed proxy.
  1973. Arguments:
  1974. lpdwError - Error code of connection.
  1975. pProxyState - Pointer to proxy_state returned when acquiring the proxy information.
  1976. Return Value:
  1977. LPSTR
  1978. Success - pointer to allocated buffer
  1979. Failure - NULL
  1980. --*/
  1981. {
  1982. DEBUG_ENTER((DBG_PROXY,
  1983. Bool,
  1984. "PROXY_INFO::RedoSendRequest",
  1985. "%#x [%d, %d], %#x",
  1986. lpdwError,
  1987. lpdwError ? *lpdwError : 0,
  1988. dwSecureStatus,
  1989. pQueryForProxyInfo
  1990. ));
  1991. BOOL fReturn = FALSE;
  1992. PROXY_STATE *pProxyState = NULL;
  1993. DWORD dwVersion;
  1994. LPSTR lpszConnection;
  1995. BOOL fCanCache = FALSE;
  1996. if ( pQueryForProxyInfo )
  1997. {
  1998. pProxyState = pQueryForProxyInfo->_pProxyState;
  1999. //
  2000. // On success,
  2001. //
  2002. if ( *lpdwError == ERROR_SUCCESS )
  2003. {
  2004. if ( pQueryForProxyInfo->IsCanCacheResult() &&
  2005. pProxyState &&
  2006. pOriginServer &&
  2007. pProxyServer )
  2008. {
  2009. pOriginServer->SetCachedProxyServerInfo(
  2010. pProxyServer,
  2011. pQueryForProxyInfo->GetVersion(),
  2012. pQueryForProxyInfo->IsUseProxy(),
  2013. pQueryForProxyInfo->_tUrlProtocol,
  2014. pQueryForProxyInfo->_nUrlPort,
  2015. pQueryForProxyInfo->_tProxyScheme,
  2016. pQueryForProxyInfo->_nProxyHostPort
  2017. );
  2018. }
  2019. }
  2020. else if ( *lpdwError != ERROR_SUCCESS &&
  2021. *lpdwError != ERROR_WINHTTP_OPERATION_CANCELLED &&
  2022. (*lpdwError != ERROR_WINHTTP_SECURE_FAILURE ||
  2023. dwSecureStatus & ~(WINHTTP_CALLBACK_STATUS_FLAG_INVALID_CA |
  2024. WINHTTP_CALLBACK_STATUS_FLAG_CERT_DATE_INVALID |
  2025. WINHTTP_CALLBACK_STATUS_FLAG_CERT_CN_INVALID |
  2026. WINHTTP_CALLBACK_STATUS_FLAG_SECURITY_CHANNEL_ERROR |
  2027. WINHTTP_CALLBACK_STATUS_FLAG_CERT_REVOKED |
  2028. WINHTTP_CALLBACK_STATUS_FLAG_CERT_REV_FAILED)) &&
  2029. *lpdwError != ERROR_WINHTTP_CLIENT_AUTH_CERT_NEEDED )
  2030. {
  2031. //
  2032. // For backround detection, we need to retry
  2033. // waiting for the backround results to complete
  2034. //
  2035. // Otherwise, If we have additional proxies,
  2036. // we need to retry them as well.
  2037. //
  2038. if ( pQueryForProxyInfo->IsBackroundDetectionPending() )
  2039. {
  2040. *lpdwError = ERROR_SUCCESS;
  2041. fReturn = TRUE;
  2042. }
  2043. else if ( pProxyState &&
  2044. !pProxyState->IsEmpty() &&
  2045. pProxyState->IsAnotherProxyAvail() )
  2046. {
  2047. INTERNET_PORT LastProxyUsedPort;
  2048. LPSTR lpszLastProxyUsed = pProxyState->GetLastProxyUsed(&LastProxyUsedPort);
  2049. Lock(FALSE);
  2050. if ( ( lpszLastProxyUsed == NULL ) ||
  2051. _BadProxyList.AddEntry(lpszLastProxyUsed, LastProxyUsedPort) != ERROR_SUCCESS )
  2052. {
  2053. fReturn = FALSE;
  2054. }
  2055. else
  2056. {
  2057. *lpdwError = ERROR_SUCCESS;
  2058. fReturn = TRUE;
  2059. }
  2060. Unlock();
  2061. }
  2062. }
  2063. }
  2064. DEBUG_LEAVE(fReturn);
  2065. return fReturn;
  2066. }
  2067. VOID PROXY_INFO::SetSessionObject(INTERNET_HANDLE_OBJECT * pSessionObject)
  2068. {
  2069. INET_ASSERT(pSessionObject->GetHandleType() == TypeInternetHandle);
  2070. _pSessionObject = pSessionObject;
  2071. }
  2072. VOID
  2073. PROXY_INFO::CleanOutLists(
  2074. VOID
  2075. )
  2076. /*++
  2077. Routine Description:
  2078. Delete proxy server and bypass lists if not empty
  2079. N.B. Exclusive lock MUST be acquired before calling this method
  2080. Arguments:
  2081. None.
  2082. Return Value:
  2083. None.
  2084. --*/
  2085. {
  2086. DEBUG_ENTER((DBG_PROXY,
  2087. None,
  2088. "PROXY_INFO::CleanOutLists",
  2089. NULL
  2090. ));
  2091. if (_ProxyServerList != NULL) {
  2092. delete _ProxyServerList;
  2093. _ProxyServerList = NULL;
  2094. }
  2095. if (_ProxyBypassList != NULL) {
  2096. delete _ProxyBypassList;
  2097. _ProxyBypassList = NULL;
  2098. }
  2099. DEBUG_LEAVE(0);
  2100. }
  2101. //
  2102. // PROXY_INFO_GLOBAL - Global Object thats inherits and expands the basic functionality
  2103. // of basic PROXY_INFO behavior. The new functionality includes wrapping Auto-Proxy
  2104. /// and Auto-detection routines
  2105. //
  2106. VOID
  2107. PROXY_INFO_GLOBAL::TerminateProxySettings(
  2108. VOID
  2109. )
  2110. /*++
  2111. Routine Description:
  2112. Destroy PROXY_INFO_GLOBAL object
  2113. Arguments:
  2114. None.
  2115. Return Value:
  2116. None.
  2117. --*/
  2118. {
  2119. PROXY_INFO::TerminateProxySettings();
  2120. }
  2121. DWORD
  2122. PROXY_INFO_GLOBAL::SetProxySettings(
  2123. IN LPINTERNET_PROXY_INFO_EX lpProxySettings,
  2124. IN BOOL fModifiedInProcess
  2125. )
  2126. /*++
  2127. Routine Description:
  2128. Sets the proxy info. Mainly handles Auto-Config, its decendent will handle static stuff
  2129. Assumes: 1. The parameters have already been validated in the API that calls
  2130. this method (i.e. InternetOpen(), InternetSetOption())
  2131. Arguments:
  2132. lpProxySettings - a set of relevent fields describing proxy settings
  2133. fModifiedInProcess - TRUE if this object is not from the registry, but
  2134. a modifed setting for this process (that overrides reg values)
  2135. Return Value:
  2136. DWORD
  2137. Success - ERROR_SUCCESS
  2138. Failure - ERROR_INVALID_PARAMETER
  2139. The lpszProxy or lpszProxyBypass list was bad
  2140. ERROR_NOT_ENOUGH_MEMORY
  2141. Failed to create an object or allocate space for a list,
  2142. etc.
  2143. --*/
  2144. {
  2145. DEBUG_ENTER((DBG_PROXY,
  2146. Dword,
  2147. "PROXY_INFO_GLOBAL::SetProxySettings",
  2148. "%x, %B",
  2149. lpProxySettings,
  2150. fModifiedInProcess
  2151. ));
  2152. DWORD error = ERROR_SUCCESS;
  2153. //
  2154. // about to start changing contents - acquire lock
  2155. //
  2156. Lock(TRUE);
  2157. //
  2158. // Once we're set to Modified, we're modified for the lifetime of the
  2159. // the process, and thus we no longer accept Registry settings
  2160. //
  2161. if ( IsModifiedInProcess() &&
  2162. !fModifiedInProcess )
  2163. {
  2164. error = ERROR_SUCCESS;
  2165. goto quit;
  2166. }
  2167. if ( _lpszConnectionName != NULL ) {
  2168. FREE_MEMORY(_lpszConnectionName);
  2169. }
  2170. _lpszConnectionName = lpProxySettings->lpszConnectionName ?
  2171. NewString(lpProxySettings->lpszConnectionName) :
  2172. NULL;
  2173. _dwProxyFlags = lpProxySettings->dwFlags;
  2174. //
  2175. // Set the Static Proxy Lists
  2176. //
  2177. error = PROXY_INFO::SetProxySettings(lpProxySettings, fModifiedInProcess);
  2178. quit:
  2179. //
  2180. // other threads free to access this PROXY_INFO again
  2181. //
  2182. Unlock();
  2183. DEBUG_LEAVE(error);
  2184. return error;
  2185. }
  2186. DWORD
  2187. PROXY_INFO_GLOBAL::GetProxySettings(
  2188. IN LPINTERNET_PROXY_INFO_EX lpProxySettings,
  2189. IN BOOL fCheckVersion = FALSE
  2190. )
  2191. /*++
  2192. Routine Description:
  2193. Gather the proxy info. Mainly handles Auto-Config, its decendent will handle static stuff
  2194. Arguments:
  2195. lpProxySettings - a set of relevent fields describing proxy settings
  2196. fCheckVersion -
  2197. Return Value:
  2198. DWORD
  2199. Success - ERROR_SUCCESS
  2200. Failure - ERROR_INVALID_PARAMETER
  2201. The lpszProxy or lpszProxyBypass list was bad
  2202. ERROR_NOT_ENOUGH_MEMORY
  2203. Failed to create an object or allocate space for a list,
  2204. etc.
  2205. --*/
  2206. {
  2207. DEBUG_ENTER((DBG_PROXY,
  2208. Dword,
  2209. "PROXY_INFO_GLOBAL::GetProxySettings",
  2210. "%x, %B",
  2211. lpProxySettings,
  2212. fCheckVersion
  2213. ));
  2214. //
  2215. // about to start reading contents - acquire lock
  2216. //
  2217. Lock(FALSE);
  2218. DWORD error = ERROR_SUCCESS;
  2219. lpProxySettings->lpszConnectionName =
  2220. _lpszConnectionName ?
  2221. NewString(_lpszConnectionName) :
  2222. NULL;
  2223. lpProxySettings->dwFlags = _dwProxyFlags;
  2224. //
  2225. // Get the Static Proxy Lists
  2226. //
  2227. error = PROXY_INFO::GetProxySettings(lpProxySettings, fCheckVersion);
  2228. //quit:
  2229. //
  2230. // other threads free to access this PROXY_INFO again
  2231. //
  2232. Unlock();
  2233. DEBUG_LEAVE(error);
  2234. return error;
  2235. }
  2236. DWORD
  2237. PROXY_INFO_GLOBAL::RefreshProxySettings(
  2238. IN BOOL fForceRefresh
  2239. )
  2240. /*++
  2241. Routine Description:
  2242. Force a refresh of automatic settings, such as auto-proxy, auto-detect
  2243. Arguments:
  2244. fForceRefresh - Forces a hard refresh
  2245. Return Value:
  2246. DWORD
  2247. Success - ERROR_SUCCESS
  2248. Failure - ERROR_INVALID_PARAMETER
  2249. The lpszProxy or lpszProxyBypass list was bad
  2250. ERROR_NOT_ENOUGH_MEMORY
  2251. Failed to create an object or allocate space for a list,
  2252. etc.
  2253. --*/
  2254. {
  2255. DEBUG_ENTER((DBG_PROXY,
  2256. Dword,
  2257. "PROXY_INFO_GLOBAL::RefreshProxySettings",
  2258. "%B",
  2259. fForceRefresh
  2260. ));
  2261. DWORD error = ERROR_SUCCESS;
  2262. Lock(FALSE);
  2263. //
  2264. // Force reload of registry settings and download of auto-proxy file from server
  2265. //
  2266. if ( IsRefreshDisabled())
  2267. {
  2268. QueueRefresh();
  2269. goto quit;
  2270. }
  2271. //
  2272. // Get the Static Proxy Lists
  2273. //
  2274. //error = PROXY_INFO::RefreshProxySettings(fForceRefresh);
  2275. quit:
  2276. //
  2277. // other threads free to access this PROXY_INFO again
  2278. //
  2279. Unlock();
  2280. DEBUG_LEAVE(error);
  2281. return error;
  2282. }
  2283. VOID
  2284. PROXY_INFO_GLOBAL::ReleaseQueuedRefresh(
  2285. VOID
  2286. )
  2287. /*++
  2288. Routine Description:
  2289. Force a refresh of automatic settings, such as auto-proxy, auto-detect,
  2290. When InternetOpen is called, allowing async threads.
  2291. Arguments:
  2292. None.
  2293. Return Value:
  2294. None.
  2295. --*/
  2296. {
  2297. DWORD error = ERROR_SUCCESS;
  2298. Lock(FALSE);
  2299. SetRefreshDisabled(FALSE);
  2300. if ( _fQueuedRefresh )
  2301. {
  2302. error = RefreshProxySettings(
  2303. FALSE
  2304. );
  2305. }
  2306. _fQueuedRefresh = FALSE;
  2307. //
  2308. // other threads free to access this PROXY_INFO again
  2309. //
  2310. Unlock();
  2311. }
  2312. DWORD
  2313. PROXY_INFO_GLOBAL::QueryProxySettings(
  2314. IN AUTO_PROXY_ASYNC_MSG **ppQueryForProxyInfo
  2315. )
  2316. /*++
  2317. Routine Description:
  2318. Aquries Proxy Information.
  2319. Note: if ppProxyState returns a non-NULL pointer than the Proxy
  2320. strings can be assumed to be allocated pointers to strings. Freeing
  2321. the ppProxyState object will result in the pointers being freed as well.
  2322. Otherwise the pointers will be to global string data that will not be
  2323. freed unexpectedly.
  2324. Arguments:
  2325. tUrlProtocol - Scheme type, protocol that is being used.
  2326. lpszUrl - Url being accessed.
  2327. dwUrlLength - size of Url.
  2328. lpszUrlHostName - Host name of site to connect to.
  2329. dwUrlHostNameLength - Host name length.
  2330. nUrlPort - Port of server to connect to.
  2331. lptProxyScheme - On output contains the correct proxy server type to use.
  2332. ex: if a SOCKS proxy is to be used to handle the FTP protocol,
  2333. this will be a INTERNET_SCHEME_SOCKS.
  2334. lplpszProxyHostName - Pointer to allocated memory containing the address of
  2335. the proxy host name.
  2336. Return Value:
  2337. LPSTR
  2338. Success - pointer to allocated buffer
  2339. Failure - NULL
  2340. --*/
  2341. {
  2342. DEBUG_ENTER((DBG_PROXY,
  2343. Dword,
  2344. "PROXY_INFO_GLOBAL::QueryProxySettings",
  2345. "%#x",
  2346. ppQueryForProxyInfo
  2347. ));
  2348. INET_ASSERT(ppQueryForProxyInfo);
  2349. BOOL fReturn = FALSE;
  2350. DWORD error = ERROR_SUCCESS;
  2351. BOOL fNeedsGetNextProxy = FALSE;
  2352. BOOL fLocked = FALSE;
  2353. AUTO_PROXY_ASYNC_MSG *pQueryForProxyInfo = *ppQueryForProxyInfo;
  2354. //
  2355. // If we're dealing with a list of Proxies, we may have already tried one
  2356. // proxy and failed. So go to the next proxy in the list
  2357. // and see if another one is availble to try.
  2358. //
  2359. if ( pQueryForProxyInfo->IsProxyEnumeration() )
  2360. {
  2361. fNeedsGetNextProxy = TRUE;
  2362. goto quit;
  2363. }
  2364. if ( pQueryForProxyInfo->IsQueryOnCallback() &&
  2365. ! pQueryForProxyInfo->IsAvoidAsyncCall())
  2366. {
  2367. goto quit;
  2368. }
  2369. Lock(FALSE);
  2370. fLocked = TRUE;
  2371. //
  2372. // Use normal Proxy infomation stored in the registry
  2373. //
  2374. error = PROXY_INFO::QueryProxySettings(&pQueryForProxyInfo);
  2375. if ( error != ERROR_SUCCESS)
  2376. {
  2377. goto quit;
  2378. }
  2379. quit:
  2380. if ( error == ERROR_SUCCESS &&
  2381. ( fNeedsGetNextProxy ||
  2382. pQueryForProxyInfo->IsProxyEnumeration()) )
  2383. {
  2384. error = pQueryForProxyInfo->GetNextProxy(_BadProxyList);
  2385. }
  2386. if ( fLocked )
  2387. {
  2388. Unlock();
  2389. }
  2390. //fastquit:
  2391. DEBUG_LEAVE(error);
  2392. return error;
  2393. }
  2394. BOOL
  2395. PROXY_INFO_GLOBAL::HostBypassesProxy(
  2396. IN INTERNET_SCHEME tScheme,
  2397. IN LPSTR lpszHostName,
  2398. IN DWORD cchHostName
  2399. )
  2400. /*++
  2401. Routine Description:
  2402. Determine if request should bypass proxy for host
  2403. Arguments:
  2404. tScheme -
  2405. lpszHostName -
  2406. cchHostName -
  2407. Return Value:
  2408. BOOL
  2409. --*/
  2410. {
  2411. BOOL bReturn = FALSE;
  2412. DWORD dwServiceType;
  2413. BOOL bTryByPassList = TRUE;
  2414. // Only do this if it is for a scheme wininet supports.
  2415. if (tScheme == INTERNET_SCHEME_HTTP ||
  2416. tScheme == INTERNET_SCHEME_HTTPS ||
  2417. tScheme == INTERNET_SCHEME_DEFAULT)
  2418. {
  2419. dwServiceType = INTERNET_SERVICE_HTTP;
  2420. }
  2421. else
  2422. {
  2423. return bReturn;
  2424. }
  2425. // LOCK
  2426. Lock(FALSE);
  2427. if (bTryByPassList) {
  2428. bReturn = IsHostInBypassList(lpszHostName, cchHostName);
  2429. }
  2430. Unlock();
  2431. return bReturn;
  2432. }
  2433. //
  2434. // PROXY_STATE - an abstraction object used to provice simple string enumeration
  2435. // given a list of proxies that need to be tested
  2436. //
  2437. BOOL
  2438. PROXY_STATE::GetNextProxy(
  2439. IN INTERNET_SCHEME tUrlScheme,
  2440. IN BAD_PROXY_LIST & BadProxyList,
  2441. OUT LPINTERNET_SCHEME lptProxyScheme,
  2442. OUT LPSTR * lplpszProxyHostName,
  2443. OUT LPBOOL lpbFreeProxyHostName,
  2444. OUT LPDWORD lpdwProxyHostNameLength,
  2445. OUT LPINTERNET_PORT lpProxyHostPort
  2446. )
  2447. /*++
  2448. Routine Description:
  2449. Parses the current Proxy State information to acquire the
  2450. proxy name, port, type to use.
  2451. Arguments:
  2452. tUrlScheme - Scheme type, protocol that is being used.
  2453. BadProxyList - Reference to array of bad proxies that we can add/remove/check
  2454. from.
  2455. lptProxyScheme - On output contains the correct proxy server type to use.
  2456. ex: if a SOCKS proxy is to be used to handle the FTP protocol,
  2457. this will be a INTERNET_SCHEME_SOCKS.
  2458. lplpszProxyHostName - Pointer to allocated memory containing the address of
  2459. the proxy host name.
  2460. lpbFreeProxyHostName - TRUE if *lplpszProxyHostName was allocated
  2461. lpdwProxyHostNameLength - length of lplpszProxyHostName.
  2462. lpProxyHostPort - Host Port of Proxy.
  2463. Return Value:
  2464. LPSTR
  2465. Success - pointer to allocated buffer
  2466. Failure - NULL
  2467. --*/
  2468. {
  2469. LPSTR lpszDelimiter = NULL;
  2470. BOOL fReturn = FALSE;
  2471. LPSTR lpszPortDelim = NULL;
  2472. LPSTR lpszPort = NULL;
  2473. if ( !_fIsMultiProxyList )
  2474. {
  2475. *lptProxyScheme = _tProxyScheme;
  2476. *lplpszProxyHostName = _lpszAutoProxyList;
  2477. *lpbFreeProxyHostName = FALSE;
  2478. *lpdwProxyHostNameLength = _dwcbAutoProxyList;
  2479. *lpProxyHostPort = _proxyHostPort;
  2480. }
  2481. _fIsAnotherProxyAvail = FALSE;
  2482. while ( *_lpszOffset != '\0' )
  2483. {
  2484. LPSTR lpszNewOffset ;
  2485. //
  2486. // Remove the delimiter so we can see the next token.
  2487. // ex: PROXY foo:80; DIRECT
  2488. // we would find DIRECT first with strstr, if we didn't
  2489. // delimit first.
  2490. //
  2491. lpszDelimiter = strchr(_lpszOffset, ';' );
  2492. if ( lpszDelimiter == NULL )
  2493. {
  2494. lpszDelimiter = strchr(_lpszOffset, ',' );
  2495. }
  2496. if ( lpszDelimiter )
  2497. {
  2498. *lpszDelimiter = '\0';
  2499. }
  2500. lpszNewOffset=
  2501. strstr(_lpszOffset, "DIRECT");
  2502. if ( lpszNewOffset )
  2503. {
  2504. lpszNewOffset += sizeof("DIRECT");
  2505. _lpszOffset = lpszNewOffset;
  2506. //
  2507. // FALSE means direct.
  2508. //
  2509. fReturn = FALSE;
  2510. goto quit;
  2511. }
  2512. //
  2513. // Its not direct, try PROXY or SOCKS.
  2514. //
  2515. lpszNewOffset =
  2516. strstr(_lpszOffset, "PROXY");
  2517. if ( lpszNewOffset)
  2518. {
  2519. lpszNewOffset += sizeof("PROXY");
  2520. *lpProxyHostPort = INTERNET_DEFAULT_HTTP_PORT;
  2521. if ( tUrlScheme == INTERNET_SCHEME_HTTPS )
  2522. {
  2523. *lptProxyScheme = INTERNET_SCHEME_HTTPS;
  2524. }
  2525. else
  2526. {
  2527. *lptProxyScheme = INTERNET_SCHEME_HTTP;
  2528. }
  2529. }
  2530. else
  2531. {
  2532. lpszNewOffset =
  2533. strstr(_lpszOffset, "SOCKS");
  2534. if ( lpszNewOffset )
  2535. {
  2536. lpszNewOffset += sizeof("SOCKS");
  2537. *lptProxyScheme = INTERNET_SCHEME_SOCKS;
  2538. *lpProxyHostPort = INTERNET_DEFAULT_SOCKS_PORT;
  2539. }
  2540. }
  2541. //
  2542. // Now do the generic common things for SOCKS, or PROXY
  2543. // entries, ie: get port, hostname, and hostname size.
  2544. //
  2545. if ( lpszNewOffset )
  2546. {
  2547. _lpszOffset = lpszNewOffset;
  2548. SKIPWS(_lpszOffset);
  2549. *lplpszProxyHostName = _lpszOffset;
  2550. *lpbFreeProxyHostName = FALSE;
  2551. lpszPortDelim = strchr(_lpszOffset, ':');
  2552. if ( lpszPortDelim )
  2553. {
  2554. *lpszPortDelim = '\0';
  2555. lpszPort = lpszPortDelim+1;
  2556. *lpProxyHostPort = (INTERNET_PORT)
  2557. atoi(lpszPort);
  2558. }
  2559. *lpdwProxyHostNameLength = lstrlen(_lpszOffset);
  2560. if (BadProxyList.IsBadProxyName(*lplpszProxyHostName, *lpProxyHostPort))
  2561. {
  2562. if ( lpszDelimiter )
  2563. {
  2564. _lpszOffset = (lpszDelimiter+1);
  2565. }
  2566. else
  2567. {
  2568. _lpszOffset = _lpszAutoProxyList + _dwcbAutoProxyList;
  2569. }
  2570. continue;
  2571. }
  2572. fReturn = TRUE;
  2573. }
  2574. break;
  2575. }
  2576. quit:
  2577. //if ( lpszPortDelim )
  2578. //{
  2579. // *lpszPortDelim = ':';
  2580. //}
  2581. if ( lpszDelimiter )
  2582. {
  2583. *lpszDelimiter = ';';
  2584. _lpszOffset = (lpszDelimiter+1);
  2585. }
  2586. else
  2587. {
  2588. _lpszOffset = _lpszAutoProxyList + _dwcbAutoProxyList;
  2589. }
  2590. if ( fReturn )
  2591. {
  2592. _lpszLastProxyUsed = *lplpszProxyHostName;
  2593. _LastProxyUsedPort = *lpProxyHostPort;
  2594. //
  2595. // If theres another possible proxy in this list,
  2596. // then we'll need to remember that
  2597. //
  2598. if ( _lpszOffset &&
  2599. *_lpszOffset &&
  2600. (strstr(_lpszOffset, "PROXY") ||
  2601. strstr(_lpszOffset, "DIRECT") ||
  2602. strstr(_lpszOffset, "SOCKS"))
  2603. )
  2604. {
  2605. _fIsAnotherProxyAvail = TRUE;
  2606. }
  2607. }
  2608. return fReturn;
  2609. }
  2610. #ifndef WININET_SERVER_CORE
  2611. PRIVATE
  2612. LPSTR
  2613. GetRegistryProxyParameter(
  2614. IN LPSTR lpszParameterName
  2615. )
  2616. /*++
  2617. Routine Description:
  2618. Reads a string from the registry into a buffer, then shrinks the buffer
  2619. Arguments:
  2620. lpszParameterName - name of string to retrieve
  2621. Return Value:
  2622. LPSTR
  2623. Success - pointer to allocated buffer
  2624. Failure - NULL
  2625. --*/
  2626. {
  2627. LPSTR buffer = NULL;
  2628. DWORD length = PROXY_REGISTRY_STRING_LENGTH;
  2629. BOOL done = FALSE;
  2630. do {
  2631. buffer = (LPSTR)ResizeBuffer(buffer, length, FALSE);
  2632. if (done || (buffer == NULL)) {
  2633. break;
  2634. }
  2635. DWORD error;
  2636. error = InternetReadRegistryString(lpszParameterName, buffer, &length);
  2637. length = (error == ERROR_SUCCESS) ? ((length == 0) ? 0 : (length + 1)) : 0;
  2638. done = TRUE;
  2639. } while (TRUE);
  2640. return buffer;
  2641. }
  2642. #endif //!WININET_SERVER_CORE
  2643. //
  2644. // wrapper function for urlzones.
  2645. //
  2646. BOOLAPI IsHostInProxyBypassList (INTERNET_SCHEME tScheme, LPCSTR pszHost, DWORD cchHost)
  2647. {
  2648. BOOL fRet = FALSE;
  2649. if (!GlobalDataInitialized) {
  2650. GlobalDataInitialize();
  2651. }
  2652. if(ERROR_SUCCESS == LoadWinsock())
  2653. {
  2654. fRet = g_pGlobalProxyInfo->HostBypassesProxy(tScheme, (LPSTR)pszHost, cchHost);
  2655. }
  2656. return fRet;
  2657. }