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.

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