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.

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