Calling REST function via proxy using PAC file

Sep 4, 2015 at 5:01 PM
Edited Sep 4, 2015 at 5:26 PM
Hi there, I recently replaced a c# REST api call in my application with calls via C++ REST SDK. It works fine apart from one of my customers who use a proxy. I've trawled through these forums and have tried something like this
   http_client_config config;

   config.set_proxy (web::web_proxy (web::web_proxy::use_auto_discovery));
which doesn't work. Also neither does use_default.

The problem I think is how their proxy is set up. They use automatic configuration scripts (PAC files).

I've read various snippets about using WinHttpGetProxyForUrl to determine the URL and then passing that to the C++ SDK but I can't see how to get this working.

Anybody got any ideas? I'm no network expert, and I thought using C++ was the way to go but I'm struggling to find an answer to this.

regards

UPDATE

I've managed to get some code that allows me to get the eventual URL of a proxy I've defined in a PAC file. It feels pretty hacky though.
        WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieinfo_;

        if (WinHttpGetIEProxyConfigForCurrentUser (&ieinfo_))
        {
            auto px = ieinfo_.lpszAutoConfigUrl;

            WINHTTP_AUTOPROXY_OPTIONS  options = { 0 };
            options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
            options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
            options.lpszAutoConfigUrl = px;
            options.fAutoLogonIfChallenged = TRUE;


            // Use WinHttpOpen to obtain an HINTERNET handle.
            HINTERNET hSession = WinHttpOpen (L"A WinHTTP Example Program/1.0",
                WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                WINHTTP_NO_PROXY_NAME,
                WINHTTP_NO_PROXY_BYPASS, 0);
            if (hSession)
            {
                if (WinHttpGetProxyForUrl (hSession,
                    L"L"http://www.microsoft.com",",
                    &options,
                    &info_))
                {
                    proxy_server = info_.lpszProxy;                      
                }
then I can pass this URL into the config
          http_client_config config;
           auto fullProxy = L"http://" + proxy_server;
            web_proxy wp (fullProxy);
            config.set_proxy (wp);
Is there not a nicer way?
Sep 11, 2015 at 5:54 PM
Edited Sep 11, 2015 at 5:55 PM
I wrote a little C# test app that uses WebClient to call onto my REST api, and all I need to do to this to work is make the following config file change
<system.net>
   <defaultProxy enabled="true" useDefaultCredentials="true">
    </defaultProxy>
    <settings>
      <servicePointManager expect100Continue="false" />
    </settings>
  </system.net>
and IJW! No faffing around trying to get hold of a proxy URL. Pretty pain free to be honest.

Am I missing something here? Shouldn't the .cpp version be relatively painless too? I can't be the only person having to deal with proxies.

thanks
Sep 16, 2015 at 3:38 PM
Edited Sep 16, 2015 at 3:38 PM
For what it's worth, I've wrapped the above code in a utility function. I'll probably ditch casablanca now, given C# just works, but someone may find this useful
std::wstring TryToGetProxyURL (const std::wstring& base_url)
{
    std::wstring proxy_server;

    WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieinfo;

    if (WinHttpGetIEProxyConfigForCurrentUser (&ieinfo))
    {
        if (ieinfo.lpszAutoConfigUrl != nullptr)
        {
            WINHTTP_AUTOPROXY_OPTIONS  options = { 0 };
            options.dwFlags = WINHTTP_AUTOPROXY_CONFIG_URL;
            options.dwAutoDetectFlags = WINHTTP_AUTO_DETECT_TYPE_DHCP | WINHTTP_AUTO_DETECT_TYPE_DNS_A;
            options.lpszAutoConfigUrl = ieinfo.lpszAutoConfigUrl;
            options.fAutoLogonIfChallenged = TRUE;


            // Use WinHttpOpen to obtain an HINTERNET handle.
            HINTERNET hSession = WinHttpOpen (L"TryToGetProxyURL",
                                                WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                                                WINHTTP_NO_PROXY_NAME,
                                                WINHTTP_NO_PROXY_BYPASS, 0);
            if (hSession)
            {
                WINHTTP_PROXY_INFO info;

                if (WinHttpGetProxyForUrl (hSession,
                    base_url.c_str (),
                    &options,
                    &info))
                {
                    proxy_server = info.lpszProxy;
                }
                WinHttpCloseHandle (hSession);

            }
        }
        else if (ieinfo.lpszProxy != nullptr)
        {
            proxy_server = ieinfo.lpszProxy;
        }
    }

    return proxy_server;
}
which I then call like this (given a base_url string)
   http_client_config config;
   std::wstring proxy_server = TryToGetProxyURL (base_url);
    if (proxy_server.length () > 0)
    {
        auto fullProxy = L"http://" + proxy_server;
        web_proxy wp (fullProxy);
        config.set_proxy (wp);
    }


    http_client client (base_url, config);