// Copyright © 2015 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Threading.Tasks; using CefSharp.Internals; using CefSharp.Preferences; using CefSharp.SchemeHandler; namespace CefSharp { /// /// RequestContext extensions. /// public static class RequestContextExtensions { /// /// Array of valid proxy schemes /// private static string[] ProxySchemes = new string[] { "http", "socks", "socks4", "socks5" }; /// /// Gets the cookie manager associated with the . Once the cookie manager /// storage has been initialized the method will return. /// /// Thrown when an exception error condition occurs. /// The instance this method extends. /// returns if the store was successfully loaded otherwise null. public static async Task GetCookieManagerAsync(this IRequestContext requestContext) { if (requestContext == null) { throw new Exception("RequestContext is null, unable to obtain cookie manager"); } var callback = new TaskCompletionCallback(); var cookieManager = requestContext.GetCookieManager(callback); var success = await callback.Task; return success ? cookieManager : null; } /// /// Set the value associated with preference name. If value is null the /// preference will be restored to its default value. If setting the preference /// fails then error will be populated with a detailed description of the /// problem. This method must be called on the CEF UI thread. /// Preferences set via the command-line usually cannot be modified. /// /// request context /// preference key /// preference value /// returns true if successfull, false otherwise. /// Use Cef.UIThreadTaskFactory to execute this method if required, /// and ChromiumWebBrowser.IsBrowserInitializedChanged are both /// executed on the CEF UI thread, so can be called directly. /// When CefSettings.MultiThreadedMessageLoop == false (the default is true) then the main /// application thread will be the CEF UI thread. public static Task SetPreferenceAsync(this IRequestContext requestContext, string name, object value) { if (CefThread.HasShutdown) { return Task.FromResult(new SetPreferenceResponse(false, "Cef.Shutdown has already been called, it is no longer possible to call SetPreferenceAsync.")); } Func func = () => { string error; var success = requestContext.SetPreference(name, value, out error); return new SetPreferenceResponse(success, error); }; if (CefThread.CurrentlyOnUiThread) { return Task.FromResult(func()); } return CefThread.ExecuteOnUiThread(func); } /// /// Sets the proxy server for the specified . /// Protocol for the proxy server is http /// /// request context /// proxy host /// proxy port /// returns true if successfull, false otherwise. /// Internally calls with /// preference 'proxy' and mode of 'fixed_servers' public static Task SetProxyAsync(this IRequestContext requestContext, string host, int? port) { return requestContext.SetProxyAsync(null, host, port); } /// /// Sets the proxy server for the specified /// /// request context /// is the protocol of the proxy server, and is one of: 'http', 'socks', 'socks4', 'socks5'. Also note that 'socks' is equivalent to 'socks5'. /// proxy host /// proxy port /// returns true if successfull, false otherwise. /// Internally calls with /// preference 'proxy' and mode of 'fixed_servers' public static Task SetProxyAsync(this IRequestContext requestContext, string scheme, string host, int? port) { if (CefThread.HasShutdown) { return Task.FromResult(new SetProxyResponse(false, "Cef.Shutdown has already been called, it is no longer possible to call SetProxyAsync.")); } Func func = () => { string error; bool success = false; if (requestContext.CanSetPreference("proxy")) { var v = GetProxyDictionary(scheme, host, port); success = requestContext.SetPreference("proxy", v, out error); } else { error = "Unable to set the proxy preference, it is read-only. If you specified the proxy settings with command line args it is not possible to change the proxy settings via this method."; } return new SetProxyResponse(success, error); }; if (CefThread.CurrentlyOnUiThread) { return Task.FromResult(func()); } return CefThread.ExecuteOnUiThread(func); } /// /// Sets the proxy server for the specified /// MUST be called on the CEF UI Thread /// /// request context /// is the protocol of the proxy server, and is one of: 'http', 'socks', 'socks4', 'socks5'. Also note that 'socks' is equivalent to 'socks5'. /// proxy host /// proxy port /// error message /// returns true if successfull, false otherwise. /// Internally calls with /// preference 'proxy' and mode of 'fixed_servers' public static bool SetProxy(this IRequestContext requestContext, string scheme, string host, int? port, out string errorMessage) { var v = GetProxyDictionary(scheme, host, port); if (requestContext.CanSetPreference("proxy")) { return requestContext.SetPreference("proxy", v, out errorMessage); } throw new Exception("Unable to set the proxy preference, it is read-only. If you specified the proxy settings with command line args it is not possible to change the proxy settings via this method."); } /// /// Sets the proxy server for the specified . /// Protocol for the proxy server is http /// MUST be called on the CEF UI Thread /// /// request context /// proxy host /// proxy port /// error message /// returns true if successfull, false otherwise. /// Internally calls with /// preference 'proxy' and mode of 'fixed_servers' public static bool SetProxy(this IRequestContext requestContext, string host, int? port, out string errorMessage) { return requestContext.SetProxy(null, host, port, out errorMessage); } /// /// Sets the proxy server for the specified . /// Protocol for the proxy server is http /// MUST be called on the CEF UI Thread /// /// request context /// proxy host /// error message /// returns true if successfull, false otherwise. /// Internally calls with /// preference 'proxy' and mode of 'fixed_servers' public static bool SetProxy(this IRequestContext requestContext, string host, out string errorMessage) { return requestContext.SetProxy(null, host, null, out errorMessage); } /// /// Creates a Dictionary that can be used with /// /// is the protocol of the proxy server, and is one of: 'http', 'socks', 'socks4', 'socks5'. Also note that 'socks' is equivalent to 'socks5'. /// proxy host /// proxy port /// public static IDictionary GetProxyDictionary(string scheme, string host, int? port) { //Default to using http scheme if non provided if (string.IsNullOrWhiteSpace(scheme)) { scheme = "http"; } if (!ProxySchemes.Contains(scheme.ToLower())) { throw new ArgumentException("Invalid Scheme, see https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-proxy-resolution for a list of valid schemes.", "scheme"); } if (string.IsNullOrWhiteSpace(host)) { throw new ArgumentException("Cannot be null or empty", "host"); } if (port.HasValue && (port < IPEndPoint.MinPort || port > IPEndPoint.MaxPort)) { throw new ArgumentOutOfRangeException("port", port, "Invalid TCP Port"); } var dict = new Dictionary { ["mode"] = "fixed_servers", ["server"] = scheme + "://" + host + (port.HasValue ? (":" + port) : "") }; return dict; } /// /// Clears all HTTP authentication credentials that were added as part of handling /// . /// /// request context /// A task that represents the ClearHttpAuthCredentials operation. /// Result indicates if the credentials cleared successfully. public static Task ClearHttpAuthCredentialsAsync(this IRequestContext requestContext) { var handler = new TaskCompletionCallback(); requestContext.ClearHttpAuthCredentials(handler); return handler.Task; } /// /// Extension method to register a instance of the with the provided /// for the /// /// request context /// scheme name, e.g. http(s). If registering for a custom scheme then that scheme must be already registered. /// It's recommended that you use https or http with a domain name rather than using a custom scheme. /// Optional domain name /// OWIN AppFunc as defined at owin.org public static void RegisterOwinSchemeHandlerFactory(this IRequestContext requestContext, string schemeName, string domainName, Func, Task> appFunc) { requestContext.RegisterSchemeHandlerFactory(schemeName, domainName, new OwinSchemeHandlerFactory(appFunc)); } } }