@@ -319,6 +319,24 @@ struct proxy_info : WINHTTP_PROXY_INFO
319
319
}
320
320
};
321
321
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
+
322
340
// WinHTTP client.
323
341
class winhttp_client : public _http_client_communicator
324
342
{
@@ -380,9 +398,13 @@ class winhttp_client : public _http_client_communicator
380
398
// Open session and connection with the server.
381
399
virtual unsigned long open () override
382
400
{
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
+
383
405
DWORD access_type;
384
406
LPCWSTR proxy_name;
385
- utility:: string_t proxy_str ;
407
+ LPCWSTR proxy_bypass = WINHTTP_NO_PROXY_BYPASS ;
386
408
http::uri uri;
387
409
388
410
const auto & config = client_config ();
@@ -394,43 +416,54 @@ class winhttp_client : public _http_client_communicator
394
416
}
395
417
else if (config.proxy ().is_default () || config.proxy ().is_auto_discovery ())
396
418
{
419
+ // Use the default WinHTTP proxy by default.
397
420
access_type = WINHTTP_ACCESS_TYPE_DEFAULT_PROXY;
398
421
proxy_name = WINHTTP_NO_PROXY_NAME;
422
+
399
423
#ifndef CPPREST_TARGET_XP
400
- if (IsWindows8Point1OrGreater ())
424
+ if (IsWindows8Point1OrGreater ())
401
425
{
402
426
access_type = WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY;
403
427
}
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)
405
433
{
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))
407
439
{
408
- raii_ie_proxy_config ( )
440
+ if (proxyIE. fAutoDetect )
409
441
{
410
- memset ( this , 0 , sizeof (WINHTTP_CURRENT_USER_IE_PROXY_CONFIG)) ;
442
+ m_proxy_auto_config = true ;
411
443
}
412
-
413
- ~raii_ie_proxy_config ()
444
+ else if (proxyIE.lpszAutoConfigUrl )
414
445
{
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 ;
421
448
}
422
- };
449
+ else if (proxyIE.lpszProxy )
450
+ {
451
+ access_type = WINHTTP_ACCESS_TYPE_NAMED_PROXY;
452
+ proxy_name = proxyIE.lpszProxy ;
423
453
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
+ }
431
459
}
432
460
}
433
461
#endif
462
+
463
+ if (config.proxy ().is_auto_discovery ())
464
+ {
465
+ m_proxy_auto_config = true ;
466
+ }
434
467
}
435
468
else
436
469
{
@@ -445,6 +478,7 @@ class winhttp_client : public _http_client_communicator
445
478
}
446
479
else
447
480
{
481
+ utility::string_t proxy_str;
448
482
if (uri.port () > 0 )
449
483
{
450
484
utility::ostringstream_t ss;
@@ -465,7 +499,7 @@ class winhttp_client : public _http_client_communicator
465
499
NULL ,
466
500
access_type,
467
501
proxy_name,
468
- WINHTTP_NO_PROXY_BYPASS ,
502
+ proxy_bypass ,
469
503
WINHTTP_FLAG_ASYNC);
470
504
if (!m_hSession)
471
505
{
@@ -543,13 +577,22 @@ class winhttp_client : public _http_client_communicator
543
577
proxy_info info;
544
578
bool proxy_info_required = false ;
545
579
546
- if ( client_config (). proxy (). is_auto_discovery () )
580
+ if (m_proxy_auto_config )
547
581
{
548
582
WINHTTP_AUTOPROXY_OPTIONS autoproxy_options;
549
583
memset ( &autoproxy_options, 0 , sizeof (WINHTTP_AUTOPROXY_OPTIONS) );
550
584
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
+
553
596
autoproxy_options.fAutoLogonIfChallenged = TRUE ;
554
597
555
598
auto result = WinHttpGetProxyForUrl (
@@ -1412,6 +1455,12 @@ class winhttp_client : public _http_client_communicator
1412
1455
HINTERNET m_hSession;
1413
1456
HINTERNET m_hConnection;
1414
1457
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;
1415
1464
};
1416
1465
1417
1466
std::shared_ptr<_http_client_communicator> create_platform_final_pipeline_stage (uri&& base_uri, http_client_config&& client_config)
0 commit comments