Aladdin
Aladdin

Reputation: 339

CefSharp 3 set proxy at Runtime

I downloaded CEF (chromuim embedded framework) binary distributation that comes with (cefclient & cefsimple) c++ examples, And Realized that cefclient can change proxy settings on run-time.

And the key to do that is to Grab the RequestContext and call the function SetPreference.

on CefClient all works just nice.

but on CefSharp calling SetPreference always returns false, and also HasPreference returns false for the preference name "proxy".

Upvotes: 6

Views: 16995

Answers (5)

beligg
beligg

Reputation: 1

With the new version of CefSharp, it's quite simple to set proxy:

browser = new ChromiumWebBrowser();
panel1.Controls.Add(browser);
browser.Dock = DockStyle.Fill;
await browser.LoadUrlAsync("about:blank");
await Cef.UIThreadTaskFactory.StartNew(() =>
{
    browser.GetBrowser().GetHost().RequestContext.SetProxy("127.0.0.1", 1088, out string _);
});

Upvotes: 0

Sergei
Sergei

Reputation: 177

If you want dynamic proxy resolver (proxy hanlder), which allow you to use different proxy for different host - you should:

1) Prepare javascript

var proxy1Str = "PROXY 1.2.3.4:5678";
var proxy2Str = "PROXY 2.3.4.5:6789";

var ProxyPacScript = 
    $"var proxy1 = \"{(proxy1Str.IsNullOrEmpty() ? "DIRECT" : proxy1Str)}\";" +
    $"var proxy2 = \"{(proxy2Str.IsNullOrEmpty() ? "DIRECT" : proxy2Str)}\";" +

    @"function FindProxyForURL(url, host) {
        if (shExpMatch(host, ""*example.com"")) {
            return proxy1;
        }
        return proxy2;
    }";

var bytes = Encoding.UTF8.GetBytes(ProxyPacScript);
var base64 = Convert.ToBase64String(bytes);

2) Set it correctly

var v = new Dictionary<string, object>();
v["mode"] = "pac_script";
v["pac_url"] = "data:application/x-ns-proxy-autoconfig;base64," + base64;

3) Call SetPreference as in accepted answer https://stackoverflow.com/a/36106994/9252162

As result all request to *example.com will flow throught proxy1, all others through proxy2.

To do it I spent all day but with help of source (https://cs.chromium.org/) I found solution. Hope it helps someone.

Main problems:

1) In new version (72 or 74 as I remember) there is no ability to use "file://..." as pac_url.

2) We can't use https://developer.chrome.com/extensions/proxy in cef.. or i can't find how to do it.

p.s. How to use another types of proxy (https, socks) - https://chromium.googlesource.com/chromium/src/+/master/net/docs/proxy.md#evaluating-proxy-lists-proxy-fallback

Upvotes: 1

D. Nikitin
D. Nikitin

Reputation: 61

I downloaded CefSharp.WinForms 65.0.0 and made class, that can help to start working with proxy:

public class ChromeTest
{
    public static ChromiumWebBrowser Create(WebProxy proxy = null, Action<ChromiumWebBrowser> onInited = null)
    {
       var result = default(ChromiumWebBrowser);
        var settings = new CefSettings();
        result = new ChromiumWebBrowser("about:blank");
        if (proxy != null)
            result.RequestHandler = new _requestHandler(proxy?.Credentials as NetworkCredential);

        result.IsBrowserInitializedChanged += (s, e) =>
        {
            if (!e.IsBrowserInitialized)
                return;

            var br = (ChromiumWebBrowser)s;
            if (proxy != null)
            {
                var v = new Dictionary<string, object>
                {
                    ["mode"] = "fixed_servers",
                    ["server"] = $"{proxy.Address.Scheme}://{proxy.Address.Host}:{proxy.Address.Port}"
                };
                if (!br.GetBrowser().GetHost().RequestContext.SetPreference("proxy", v, out string error))
                    MessageBox.Show(error);
            }

            onInited?.Invoke(br);
        };

        return result;
    }

    private class _requestHandler : DefaultRequestHandler
    {
        private NetworkCredential _credential;

        public _requestHandler(NetworkCredential credential = null) : base()
        {
            _credential = credential;
        }

        public override bool GetAuthCredentials(IWebBrowser browserControl, IBrowser browser, IFrame frame, bool isProxy, string host, int port, string realm, string scheme, IAuthCallback callback)
        {
            if (isProxy == true)
            {
                if (_credential == null)
                    throw new NullReferenceException("credential is null");

                callback.Continue(_credential.UserName, _credential.Password);
                return true;
            }

            return false;
        }
    }
}

Using:

        var p = new WebProxy("Scheme://Host:Port", true, new[] { "" }, new NetworkCredential("login", "pass"));
        var p1 = new WebProxy("Scheme://Host:Port", true, new[] { "" }, new NetworkCredential("login", "pass"));
        var p2 = new WebProxy("Scheme://Host:Port", true, new[] { "" }, new NetworkCredential("login", "pass"));

        wb1 = ChromeTest.Create(p1, b => b.Load("http://speed-tester.info/check_ip.php"));
        groupBox1.Controls.Add(wb1);
        wb1.Dock = DockStyle.Fill;

        wb2 = ChromeTest.Create(p2, b => b.Load("http://speed-tester.info/check_ip.php"));
        groupBox2.Controls.Add(wb2);
        wb2.Dock = DockStyle.Fill;

        wb3 = ChromeTest.Create(p, b => b.Load("http://speed-tester.info/check_ip.php"));
        groupBox3.Controls.Add(wb3);
        wb3.Dock = DockStyle.Fill;

Upvotes: 3

FreeCLoud
FreeCLoud

Reputation: 79

if anyone need any other soulition i found this solution.

Cef.UIThreadTaskFactory.StartNew(delegate
        {
            string ip = "ip or adress";
            string port = "port";
            var rc = this.browser.GetBrowser().GetHost().RequestContext;
            var dict = new Dictionary<string, object>();
            dict.Add("mode", "fixed_servers");
            dict.Add("server", "" + ip + ":" + port + "");
            string error;
            bool success = rc.SetPreference("proxy", dict, out error);

        });

Upvotes: 4

Aladdin
Aladdin

Reputation: 339

thanks to amaitland the proper way to actively inforce changing the request-context prefrences, is to run the code on CEF UIThread as following:

    Cef.UIThreadTaskFactory.StartNew(delegate {
        var rc = this.browser.GetBrowser().GetHost().RequestContext;
        var v = new Dictionary<string, object>();
        v["mode"] = "fixed_servers";
        v["server"] = "scheme://host:port";
        string error;
        bool success = rc.SetPreference("proxy", v, out error);
        //success=true,error=""
    });

Upvotes: 8

Related Questions