// 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));
}
}
}