-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature Request - Add proxy settings on ChromiumWebBrowser instantiation #3235
Comments
Based on your review of the CEF API what is your proposal for implementing this feature? Are planning on submitting a PR? |
I know it's actually possible to start CEF with command lines arguments to set proxies for each chromium process. So it's not possible to wrap CEF launch with these arguments ? (I'm not experienced with CEF, if you know will never be possible with actual API, i will trust you) Sources: https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-proxy-resolution |
We already provide a wrapper around these command line args.
CefSharp/CefSharp/CefSharpSettings.cs Line 77 in 5e89f71
There's nothing stopping you from launching multiple instances of your application with unique CachePath and doing this with the current API. The same command line args linked above will work with CefSharp.
Setting different proxies within the same process can only be achieve via using a different RequestContext per browser and calling SetPreference, this is currently the only API CEF provides. We could add some helper methods to simplify this, though exactly what that would look like isn't clear at this point in time.
|
I am not rich but if it can help you ^^ |
@Velka-DEV Thank you for the generious support 👍 Are you using WinForms/WPF/OffScreen? Can provide an example of the current code you are using? |
I'm actually using WinForms. There is a sample of my EmbedBrowser class.
|
this.requestContext = new RequestContext(); // EDIT: Or add proxy into RequestContext() constructor As the proxy is set per I'll post something here shortly for review. I'll include some improvements in the next version In the mean time to get you up and running, here is an example of using a IRequestContextHandler to set the proxy public partial class MainEmbedBrowser : Form
{
private string ID;
private ChromiumWebBrowser browser;
private RequestContext requestContext;
private ExtensionHandler extensionHandler;
public MainEmbedBrowser(string url, string combo, string proxy = null, int maxPlays = 0)
{
InitializeComponent();
this.ID = CreateMD5(DateTime.Now.Millisecond.ToString());
this.extensionHandler = new ExtensionHandler();
this.requestContext = new RequestContext(new RequestContextHandler());
// Extension - Here is an attemp to load unpacked CRX unpacked extension but throw error. I don't know if CEF can support it correctly
//this.extensionHandler = new ExtensionHandler();
//this.browser.RequestContext.LoadExtension("/vendors/static/fcfhplploccackoneaefokcmbjfbkenj", "/vendors/static/fcfhplploccackoneaefokcmbjfbkenj/manifest.json", extensionHandler);
// I think that can be a good idea to add proxy here.
this.browser = new ChromiumWebBrowser("https://exemple.com/", this.requestContext);
browser.FrameLoadEnd += (sender, args) =>
{
if (args.Frame.IsMain)
{
if (args.Url.ToLower().Contains("https://exemple.com/"))
{
// Do something on the loaded page
}
}
};
this.Controls.Add(browser);
this.browser.Dock = DockStyle.Fill;
this.Show();
}
public static string CreateMD5(string input)
{
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
{
byte[] inputBytes = Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hashBytes.Length; i++)
{
sb.Append(hashBytes[i].ToString("X2"));
}
return sb.ToString();
}
}
}
}
public class RequestContextHandler : IRequestContextHandler
{
IResourceRequestHandler IRequestContextHandler.GetResourceRequestHandler(IBrowser browser, IFrame frame, IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
{
return null;
}
bool IRequestContextHandler.OnBeforePluginLoad(string mimeType, string url, bool isMainFrame, string topOriginUrl, WebPluginInfo pluginInfo, ref PluginPolicy pluginPolicy)
{
return false;
}
void IRequestContextHandler.OnRequestContextInitialized(IRequestContext requestContext)
{
//You can set preferences here on your newly initialized request context.
//Note, there is called on the CEF UI Thread, so you can directly call SetPreference
//You can set the proxy with code similar to the code below
var v = new Dictionary<string, object>
{
["mode"] = "fixed_servers",
["server"] = "socks5://foobar:66"
};
string errorMessage;
bool success = requestContext.SetPreference("proxy", v, out errorMessage);
}
} |
Add helper method for setting proxy on RequestContext Issue #3235
- Add tests - Add better validation Issue #3235
I've already added a number of extension methods to public static bool SetProxy(this IRequestContext requestContext, string scheme, string host, int? port, out string errorMessage)
public static bool SetProxy(this IRequestContext requestContext, string host, int? port, out string errorMessage)
public static bool SetProxy(this IRequestContext requestContext, string host, out string errorMessage) I've created #3250 (still a work in progress) that contains some further enhancements //SetPreferenceAsync can be called on any Thread and will ensure the SetPreference call happens on the CEF UI Thread.
public static Task<SetPreferenceResponse> SetPreferenceAsync(this IRequestContext requestContext, string name, object value) I've added some additional helper classes around setting settings upon initialization of a new [Fact]
public async Task CanLoadGoogleUsingProxy()
{
var requestContextHander = new RequestContextHandler()
.SetProxyOnContextInitialized("localhost", 8080);
var requestContext = new RequestContext(requestContextHander);
using (var browser = new ChromiumWebBrowser("www.google.com", requestContext: requestContext))
{
await browser.LoadPageAsync();
var mainFrame = browser.GetMainFrame();
Assert.True(mainFrame.IsValid);
Assert.Contains("www.google", mainFrame.Url);
output.WriteLine("Url {0}", mainFrame.Url);
}
} Building upon this further and I think we can still go one step further to simplify things. Still not sure about the best implementation. Something static would look like (not yet implemented) //Share settings with Global RequestContext and use custom proxy
var requestContext = RequestContext.CreateNewWithProxy(Cef.GetGlobalRequestContext(), "http", "localhost", 8080);
//Custom CachePath with proxy settings
var requestContext = RequestContext.CreateNewWithProxy("cachePath", "http", "localhost", 8080) Something fluid might look like (not yet implemented)
As yet I'm not quite sure how to implement the fluid approach. I'll have a think about it some more. In the meantime, thoughts and feedback are welcome. |
I've implemented a fluent style API which looks like the following. It match var requestContext = RequestContext
.Configure()
.WithProxyServer("127.0.0.1", 8080)
.Create();
using (var browser = new ChromiumWebBrowser("http://cefsharp.github.io/", requestContext: requestContext))
{
await browser.LoadPageAsync();
var mainFrame = browser.GetMainFrame();
Assert.True(mainFrame.IsValid);
Assert.Contains("cefsharp.github.io", mainFrame.Url);
output.WriteLine("Url {0}", mainFrame.Url);
} I plan on merging #3250 in the next few days. Once that's done I'll package the next Thoughts and comments welcome. |
Is a really good implementation, thanks for your work @amaitland. Just some questions, i see you have tested the feature with a local proxy so is 1000% faster than a real proxy server and the project is mostly async. So have you tested if page loading is correctly done ? And also how the proxy load process is handled ? Will wait for request done before going to next instruction or not ? |
The proxy is set when the
Yes. Changing the port and the test will fail as expected. You could add say
Fundamentally we are just configuring Creating a
|
The |
Will test it start of the next week. Thanks for your work |
Version Let me know if you see any problems. |
Describe the solution you'd like
Actually we have 2 possibility to set proxies if i'm not wrong. We have the built-in helper with Cef.Initialize() but it will set same proxy for all ChromiumWebBrowser(). And we have the RequestContext.SetPreference("proxy", dict, out error); at runtime.
I don't uderstand why we can't set a proxy on browser initialization, so we can isolate each browsers without have to call SetPreference() at runtime that can cause problems.
Checklist:
PR
exists on the CEF Pull Requests and I'd like to propose this feature is added toCefSharp
when/if it's merged.The text was updated successfully, but these errors were encountered: