@@ -319,6 +319,24 @@ struct proxy_info : WINHTTP_PROXY_INFO
319319 }
320320};
321321
322+ struct ie_proxy_config : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
323+ {
324+ ie_proxy_config ()
325+ {
326+ memset ( this , 0 , sizeof (WINHTTP_CURRENT_USER_IE_PROXY_CONFIG) );
327+ }
328+
329+ ~ie_proxy_config ()
330+ {
331+ if ( lpszAutoConfigUrl )
332+ ::GlobalFree (lpszAutoConfigUrl);
333+ if ( lpszProxy )
334+ ::GlobalFree (lpszProxy);
335+ if ( lpszProxyBypass )
336+ ::GlobalFree (lpszProxyBypass);
337+ }
338+ };
339+
322340// WinHTTP client.
323341class winhttp_client : public _http_client_communicator
324342{
@@ -380,9 +398,13 @@ class winhttp_client : public _http_client_communicator
380398 // Open session and connection with the server.
381399 virtual unsigned long open () override
382400 {
401+ // This object have lifetime greater than proxy_name and proxy_bypass
402+ // which may point to its elements.
403+ ie_proxy_config proxyIE;
404+
383405 DWORD access_type;
384406 LPCWSTR proxy_name;
385- utility:: string_t proxy_str ;
407+ LPCWSTR proxy_bypass = WINHTTP_NO_PROXY_BYPASS ;
386408 http::uri uri;
387409
388410 const auto & config = client_config ();
@@ -394,43 +416,54 @@ class winhttp_client : public _http_client_communicator
394416 }
395417 else if (config.proxy ().is_default () || config.proxy ().is_auto_discovery ())
396418 {
419+ // Use the default WinHTTP proxy by default.
397420 access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
398421 proxy_name = WINHTTP_NO_PROXY_NAME;
422+
399423#ifndef CPPREST_TARGET_XP
400- if (IsWindows8Point1OrGreater ())
424+ if (IsWindows8Point1OrGreater ())
401425 {
402426 access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY;
403427 }
404- else
428+
429+ // However, if it is not configured...
430+ proxy_info proxyDefault;
431+ if (!WinHttpGetDefaultProxyConfiguration (&proxyDefault) ||
432+ proxyDefault.dwAccessType == WINHTTP_ACCESS_TYPE_NO_PROXY)
405433 {
406- struct raii_ie_proxy_config : WINHTTP_CURRENT_USER_IE_PROXY_CONFIG
434+ // ... then try to fall back on the default WinINET proxy, as
435+ // recommended for the desktop applications (if we're not
436+ // running under a user account, the function below will just
437+ // fail, so there is no real need to check for this explicitly)
438+ if (WinHttpGetIEProxyConfigForCurrentUser (&proxyIE))
407439 {
408- raii_ie_proxy_config ( )
440+ if (proxyIE. fAutoDetect )
409441 {
410- memset ( this , 0 , sizeof (WINHTTP_CURRENT_USER_IE_PROXY_CONFIG)) ;
442+ m_proxy_auto_config = true ;
411443 }
412-
413- ~raii_ie_proxy_config ()
444+ else if (proxyIE.lpszAutoConfigUrl )
414445 {
415- if (lpszProxy)
416- ::GlobalFree (lpszProxy);
417- if (lpszProxyBypass)
418- ::GlobalFree (lpszProxyBypass);
419- if (lpszAutoConfigUrl)
420- ::GlobalFree (lpszAutoConfigUrl);
446+ m_proxy_auto_config = true ;
447+ m_proxy_auto_config_url = proxyIE.lpszAutoConfigUrl ;
421448 }
422- };
449+ else if (proxyIE.lpszProxy )
450+ {
451+ access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
452+ proxy_name = proxyIE.lpszProxy ;
423453
424- raii_ie_proxy_config proxyInfo;
425- BOOL result = WinHttpGetIEProxyConfigForCurrentUser (&proxyInfo);
426- if (result && proxyInfo.lpszProxy != nullptr )
427- {
428- access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
429- proxy_str = proxyInfo.lpszProxy ;
430- proxy_name = proxy_str.c_str ();
454+ if (proxyIE.lpszProxyBypass )
455+ {
456+ proxy_bypass = proxyIE.lpszProxyBypass ;
457+ }
458+ }
431459 }
432460 }
433461#endif
462+
463+ if (config.proxy ().is_auto_discovery ())
464+ {
465+ m_proxy_auto_config = true ;
466+ }
434467 }
435468 else
436469 {
@@ -445,6 +478,7 @@ class winhttp_client : public _http_client_communicator
445478 }
446479 else
447480 {
481+ utility::string_t proxy_str;
448482 if (uri.port () > 0 )
449483 {
450484 utility::ostringstream_t ss;
@@ -465,7 +499,7 @@ class winhttp_client : public _http_client_communicator
465499 NULL ,
466500 access_type,
467501 proxy_name,
468- WINHTTP_NO_PROXY_BYPASS ,
502+ proxy_bypass ,
469503 WINHTTP_FLAG_ASYNC);
470504 if (!m_hSession)
471505 {
@@ -543,13 +577,22 @@ class winhttp_client : public _http_client_communicator
543577 proxy_info info;
544578 bool proxy_info_required = false ;
545579
546- if ( client_config (). proxy (). is_auto_discovery () )
580+ if (m_proxy_auto_config )
547581 {
548582 WINHTTP_AUTOPROXY_OPTIONS autoproxy_options;
549583 memset ( &autoproxy_options, 0 , sizeof (WINHTTP_AUTOPROXY_OPTIONS) );
550584
551- autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
552- autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
585+ if (m_proxy_auto_config_url.empty ())
586+ {
587+ autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_AUTO_DETECT;
588+ autoproxy_options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
589+ }
590+ else
591+ {
592+ autoproxy_options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
593+ autoproxy_options.lpszAutoConfigUrl = m_proxy_auto_config_url.c_str ();
594+ }
595+
553596 autoproxy_options.fAutoLogonIfChallenged = TRUE ;
554597
555598 auto result = WinHttpGetProxyForUrl (
@@ -1412,6 +1455,12 @@ class winhttp_client : public _http_client_communicator
14121455 HINTERNET m_hSession;
14131456 HINTERNET m_hConnection;
14141457 bool m_secure;
1458+
1459+ // If auto config is true, dynamically find the proxy for each URL using
1460+ // the proxy configuration script at the given URL if it's not empty or
1461+ // using WPAD otherwise.
1462+ bool m_proxy_auto_config{false };
1463+ utility::string_t m_proxy_auto_config_url;
14151464};
14161465
14171466std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage (uri&& base_uri, http_client_config&& client_config)
0 commit comments